#!/usr/bin/perl

use strict;
use warnings;

use Time::HiRes qw(usleep);

use PVE::Cluster;
use PVE::Network;
use PVE::Network::SDN;
use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Controllers;
use PVE::Tools;

for (my $i = 0; !PVE::Cluster::check_cfs_quorum(1); $i++) {
    print "waiting for pmxcfs mount to appear and get quorate...\n"
        if $i % 50 == 0;

    usleep(100 * 1000);
}

sub has_pending_changes {
    my ($pending_config) = @_;

    for my $entity (values $pending_config->{ids}->%*) {
        return 1 if $entity->{state};
    }

    return 0;
}

sub ip_link_is_non_vlan_aware_bridge {
    my ($ip_link) = @_;

    return
        defined($ip_link->{linkinfo})
        && defined($ip_link->{linkinfo}->{info_kind})
        && $ip_link->{linkinfo}->{info_kind} eq 'bridge'
        && defined($ip_link->{linkinfo}->{info_data})
        && defined($ip_link->{linkinfo}->{info_data}->{vlan_filtering})
        && $ip_link->{linkinfo}->{info_data}->{vlan_filtering} == 0;
}

sub zone_uses_non_vlan_aware_bridge {
    my ($zone, $ip_links) = @_;

    return 0 if ($zone->{type} ne 'vlan' && $zone->{type} ne 'qinq');

    my $ip_link = $ip_links->{ $zone->{bridge} };
    return 0 if !defined($ip_link);

    return ip_link_is_non_vlan_aware_bridge($ip_link);
}

sub sdn_changed {
    my $running_config = PVE::Network::SDN::running_config();

    my $configs = {
        zones => PVE::Network::SDN::Zones::config(),
        vnets => PVE::Network::SDN::Vnets::config(),
        subnets => PVE::Network::SDN::Subnets::config(),
        controllers => PVE::Network::SDN::Controllers::config(),
    };

    for my $type (keys $configs->%*) {
        my $pending_config = PVE::Network::SDN::pending_config(
            $running_config, $configs->{$type}, $type,
        );

        return 1 if has_pending_changes($pending_config);
    }

    my $ip_links = PVE::Network::ip_link_details();

    for my $zone (values $configs->{zones}->{ids}->%*) {
        return 1 if zone_uses_non_vlan_aware_bridge($zone, $ip_links);
    }

    for my $running_zone (values $running_config->{zones}->{ids}->%*) {
        return 1 if zone_uses_non_vlan_aware_bridge($running_zone, $ip_links);
    }

    return 0;
}

if (!sdn_changed()) {
    print "No changes to SDN configuration detected, skipping reload\n";
    exit 0;
}

PVE::Network::SDN::commit_config();

PVE::Network::SDN::generate_zone_config();
PVE::Network::SDN::generate_dhcp_config();

my $err = sub {
    my $line = shift;
    if ($line =~ /(warning|error): (\S+):/) {
        print "$2 : $line \n";
    }
};

PVE::Tools::run_command(['ifreload', '-a'], errfunc => $err);

PVE::Network::SDN::generate_controller_config(1);

exit 0;
