1 package PVE
::Network
::SDN
::Zones
;
9 use PVE
::Tools
qw(extract_param dir_glob_regex run_command);
10 use PVE
::Cluster
qw(cfs_read_file cfs_write_file cfs_lock_file);
12 use PVE
::Network
::SDN
::Vnets
;
13 use PVE
::Network
::SDN
::Zones
::VlanPlugin
;
14 use PVE
::Network
::SDN
::Zones
::QinQPlugin
;
15 use PVE
::Network
::SDN
::Zones
::VxlanPlugin
;
16 use PVE
::Network
::SDN
::Zones
::EvpnPlugin
;
17 use PVE
::Network
::SDN
::Zones
::FaucetPlugin
;
18 use PVE
::Network
::SDN
::Zones
::Plugin
;
20 PVE
::Network
::SDN
::Zones
::VlanPlugin-
>register();
21 PVE
::Network
::SDN
::Zones
::QinQPlugin-
>register();
22 PVE
::Network
::SDN
::Zones
::VxlanPlugin-
>register();
23 PVE
::Network
::SDN
::Zones
::EvpnPlugin-
>register();
24 PVE
::Network
::SDN
::Zones
::FaucetPlugin-
>register();
25 PVE
::Network
::SDN
::Zones
::Plugin-
>init();
28 sub sdn_zones_config
{
29 my ($cfg, $id, $noerr) = @_;
31 die "no sdn zone ID specified\n" if !$id;
33 my $scfg = $cfg->{ids
}->{$id};
34 die "sdn '$id' does not exists\n" if (!$noerr && !$scfg);
40 my $config = cfs_read_file
("sdn/zones.cfg.new");
41 $config = cfs_read_file
("sdn/zones.cfg") if !keys %{$config->{ids
}};
48 cfs_write_file
("sdn/zones.cfg.new", $cfg);
51 sub lock_sdn_zones_config
{
52 my ($code, $errmsg) = @_;
54 cfs_lock_file
("sdn/zones.cfg.new", undef, $code);
56 $errmsg ?
die "$errmsg: $err" : die $err;
63 return keys %{$cfg->{ids
}};
66 sub complete_sdn_zone
{
67 my ($cmdname, $pname, $cvalue) = @_;
69 my $cfg = PVE
::Network
::SDN
::config
();
71 return $cmdname eq 'add' ?
[] : [ PVE
::Network
::SDN
::sdn_zones_ids
($cfg) ];
75 sub generate_etc_network_config
{
77 my $vnet_cfg = PVE
::Cluster
::cfs_read_file
('sdn/vnets.cfg');
78 my $zone_cfg = PVE
::Cluster
::cfs_read_file
('sdn/zones.cfg');
79 my $controller_cfg = PVE
::Cluster
::cfs_read_file
('sdn/controllers.cfg');
80 return if !$vnet_cfg && !$zone_cfg;
82 #read main config for physical interfaces
83 my $current_config_file = "/etc/network/interfaces";
84 my $fh = IO
::File-
>new($current_config_file);
85 my $interfaces_config = PVE
::INotify
::read_etc_network_interfaces
(1,$fh);
90 foreach my $id (keys %{$interfaces_config->{ifaces
}}) {
91 my $interface = $interfaces_config->{ifaces
}->{$id};
92 if (my $uplink = $interface->{'uplink-id'}) {
93 die "uplink-id $uplink is already defined on $uplinks->{$uplink}" if $uplinks->{$uplink};
94 $interface->{name
} = $id;
95 $uplinks->{$interface->{'uplink-id'}} = $interface;
99 #generate configuration
101 my $nodename = PVE
::INotify
::nodename
();
103 foreach my $id (keys %{$vnet_cfg->{ids
}}) {
104 my $vnet = $vnet_cfg->{ids
}->{$id};
105 my $zone = $vnet->{zone
};
108 warn "can't generate vnet $vnet : zone $zone don't exist";
112 my $plugin_config = $zone_cfg->{ids
}->{$zone};
114 if (!defined($plugin_config)) {
115 warn "can't generate vnet $vnet : zone $zone don't exist";
119 next if defined($plugin_config->{nodes
}) && !$plugin_config->{nodes
}->{$nodename};
121 my $controller = undef;
122 if($plugin_config->{controller
}) {
123 my $controllerid = $plugin_config->{controller
};
124 $controller = $controller_cfg->{ids
}->{$controllerid};
127 my $plugin = PVE
::Network
::SDN
::Zones
::Plugin-
>lookup($plugin_config->{type
});
128 $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $uplinks, $controller, $config);
131 my $raw_network_config = "";
132 foreach my $iface (keys %$config) {
133 $raw_network_config .= "\n";
134 $raw_network_config .= "auto $iface\n";
135 $raw_network_config .= "iface $iface\n";
136 foreach my $option (@{$config->{$iface}}) {
137 $raw_network_config .= "\t$option\n";
141 return $raw_network_config;
144 sub write_etc_network_config
{
145 my ($rawconfig) = @_;
147 return if !$rawconfig;
148 my $sdn_interfaces_file = "/etc/network/interfaces.d/sdn";
150 my $writefh = IO
::File-
>new($sdn_interfaces_file,">");
151 print $writefh $rawconfig;
157 my $cmd = ['ifquery', '-a', '-c', '-o','json'];
160 my $reader = sub { $result .= shift };
163 run_command
($cmd, outfunc
=> $reader);
166 my $resultjson = decode_json
($result);
169 foreach my $interface (@$resultjson) {
170 my $name = $interface->{name
};
171 $interfaces->{$name} = {
172 status
=> $interface->{status
},
173 config
=> $interface->{config
},
174 config_status
=> $interface->{config_status
},
181 # improve me : move status code inside plugins ?
184 my $cluster_vnet_file = "/etc/pve/sdn/vnets.cfg";
185 my $cluster_zone_file = "/etc/pve/sdn/zones.cfg";
186 my $local_sdn_file = "/etc/network/interfaces.d/sdn";
187 my $err_config = undef;
189 return if !-e
$cluster_vnet_file && !-e
$cluster_zone_file;
191 if (!-e
$local_sdn_file) {
193 $err_config = "local sdn network configuration is not yet generated, please reload";
196 # fixme : use some kind of versioning info?
197 my $cluster_vnet_timestamp = (stat($cluster_vnet_file))[9];
198 my $cluster_zone_timestamp = (stat($cluster_zone_file))[9];
199 my $local_sdn_timestamp = (stat($local_sdn_file))[9];
201 if ($local_sdn_timestamp < $cluster_vnet_timestamp || $local_sdn_timestamp < $cluster_zone_timestamp) {
202 $err_config = "local sdn network configuration is too old, please reload";
207 my $status = ifquery_check
();
209 my $vnet_cfg = PVE
::Cluster
::cfs_read_file
('sdn/vnets.cfg');
210 my $zone_cfg = PVE
::Cluster
::cfs_read_file
('sdn/zones.cfg');
211 my $nodename = PVE
::INotify
::nodename
();
213 my $vnet_status = {};
214 my $zone_status = {};
216 foreach my $id (keys %{$vnet_cfg->{ids
}}) {
217 my $zone = $vnet_cfg->{ids
}->{$id}->{zone
};
218 next if defined($zone_cfg->{ids
}->{$zone}->{nodes
}) && !$zone_cfg->{ids
}->{$zone}->{nodes
}->{$nodename};
220 $vnet_status->{$id}->{zone
} = $zone;
221 $zone_status->{$zone}->{status
} = 'available' if !defined($zone_status->{$zone}->{status
});
224 $vnet_status->{$id}->{status
} = 'pending';
225 $vnet_status->{$id}->{statusmsg
} = $err_config;
226 $zone_status->{$zone}->{status
} = 'pending';
227 } elsif ($status->{$id}->{status
} && $status->{$id}->{status
} eq 'pass') {
228 $vnet_status->{$id}->{status
} = 'available';
229 my $bridgeport = $status->{$id}->{config
}->{'bridge-ports'};
231 if ($status->{$bridgeport}->{status
} && $status->{$bridgeport}->{status
} ne 'pass') {
232 $vnet_status->{$id}->{status
} = 'error';
233 $vnet_status->{$id}->{statusmsg
} = 'configuration not fully applied';
234 $zone_status->{$zone}->{status
} = 'error';
237 $vnet_status->{$id}->{status
} = 'error';
238 $vnet_status->{$id}->{statusmsg
} = 'missing';
239 $zone_status->{$zone}->{status
} = 'error';
242 return($zone_status, $vnet_status);