diff --git a/mxrouter/mxrouterctl b/mxrouter/mxrouterctl index b9d2696..4105180 100755 --- a/mxrouter/mxrouterctl +++ b/mxrouter/mxrouterctl @@ -373,9 +373,30 @@ sub radvd { $radvd{$if}=$conf; } -our $want_if; +# 'lo' implied without config. Note: ipv6 seems to *need* lo for unknown reasons +our $want_if = {'lo' => 1}; # includes lo, veth and physical devices but not vlan devices our $want_veth; +sub configure_if { + my ($want_if)=@_; + for my $if (keys %$want_if) { + netif_is_up($if) or sys('ip', 'link', 'set', $if, "up"); + } +} + +sub unconfigure_if { + my ($have_if)=@_; + for my $if (keys %$have_if) { + if (-d "/sys/class/net/$if/device") { + # hardware device + sys('ip', 'link', 'set', $if, 'netns', 1); + } else { + # virtual device + sys('ip', 'link', 'del', $if); + } + } +} + our $DHCRELAY_FORWARD; our %DHCRELAY_IF; @@ -411,7 +432,6 @@ sub disable_ipv4_rp_filter { - sub start { -d "/var/run/mxrouter/$NETNS" or sys ('mkdir','-p',"/var/run/mxrouter/$NETNS"); @@ -480,12 +500,16 @@ sub start { my $have_addr=read_active_ip(); my ($new_addr,$del_addr)=({},{}); - # for some yet unknown reason, ipv6 seems to need loopback.... - - netif_is_up('lo') or sys('ip link set lo up'); - - for my $dev (keys %$want_if, keys %$want_veth) { - netif_is_up($dev) or sys('ip','link','set',$dev,'up'); + my $have_if = {map {$_ => 1} network_devices()}; + for (keys %$want_if) { + exists $have_if->{$_} or warn "Interface $_ not available\n"; + } + my $del_if={}; + for (keys %$have_if) { + exists $want_if->{$_} + || exists $want_vlan->{$_} + || $_ eq 'lo' + or $del_if->{$_} = 1; } my ($have_vlan)=read_active_vlans(); @@ -554,7 +578,9 @@ sub start { unconfigure_route($del_route); unconfigure_ip($del_addr); unconfigure_vlans($del_vlan,{}); + unconfigure_if($del_if); + configure_if($want_if); configure_vlans($new_vlan,{}); configure_ip($new_addr); configure_route($new_route); @@ -625,6 +651,7 @@ sub interface { sub veth { my ($dev) = @_; + $want_if->{$dev} = 1; $want_veth->{$dev} = 1; } @@ -793,6 +820,21 @@ if (!$opt_this_ns) { have_netns($NETNS) or die "not running (network namespace $NETNS does not exist)\n"; system('ip','netns','exec',$NETNS,$0,'--this-ns',@SAVED_ARGV) and exit 1; delete_netns($NETNS); + } elsif ($cmd eq 'reload') { + have_netns($NETNS) or die "not running (network namespace $NETNS does not exist)\n"; + # create veth pair if not yet available + for my $dev (sort keys %$want_veth) { + -d "/sys/class/net/$dev" and next; + sys('ip', 'link', 'add', $dev, 'type', 'veth', 'peer', 'name', $dev, 'netns', $NETNS); + sys('ip', 'link', 'set', $dev, 'up'); + } + # move interfaces which are still in the init namespace + # ignore veth devices and lo, which exists in both namespaces + for my $dev (sort keys %$want_if) { + $dev eq 'lo' || $want_veth->{$dev} and next; + -d "/sys/class/net/$dev" and sys('ip', 'link', 'set', $dev, 'netns', $NETNS); + } + system('ip', 'netns', 'exec', $NETNS,$0,'--this-ns', @SAVED_ARGV) and exit 1; } else { have_netns($NETNS) or die "not running (network namespace $NETNS does not exist)\n"; system('ip','netns','exec',$NETNS,$0,'--this-ns',@SAVED_ARGV) and exit 1;