1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

ipv6-addrgen: add ifquery check/running/ifreload support using netlink cache

[13:09:20] root:~ # ifquery -a
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

auto vlan1903
iface vlan1903
	vlan-id 1903
	vlan-raw-device bridge
	ipv6-addrgen no
	address-virtual-ipv6-addrgen no
	address-virtual 00:00:5e:00:01:a3 2a06:c01:1:1903::1/64 fe80::1/64 185.98.123.1/24

auto bridge
iface bridge
	bridge-ports swp1

[13:09:25] root:~ # ifup -a -v
info: loading builtin modules from ['/usr/share/ifupdown2/addons']
info: executing /var/lib/ifupdown2/hooks/get_reserved_vlan_range.sh
info: executing /sbin/sysctl net.bridge.bridge-allow-multiple-vlans
info: executing /bin/pidof mstpd
info: executing /bin/ip rule show
info: executing /bin/ip -6 rule show
info: address: using default mtu 1500
info: 'link_master_slave' is set. slave admin state changes will be delayed till the masters admin state change.
info: processing interfaces file /etc/network/interfaces
info: lo: running ops ...
info: netlink: ip link show
info: netlink: ip addr show
info: executing /bin/ip addr help
info: address metric support: KO
info: lo: netlink: ip link set dev lo up
info: reading '/proc/sys/net/mpls/conf/lo/input'
info: reading '/proc/sys/net/ipv4/conf/lo/forwarding'
info: reading '/proc/sys/net/ipv6/conf/lo/forwarding'
info: reading '/proc/sys/net/ipv4/conf/lo/accept_local'
info: executing /bin/systemctl is-enabled vxrd.service
info: eth0: running ops ...
info: executing /sbin/ethtool eth0
info: reading '/sys/class/net/eth0/speed'
info: reading '/sys/class/net/eth0/duplex'
info: eth0: netlink: ip link set dev eth0 up
info: dhclient4 already running on eth0. Not restarting.
info: reading '/proc/sys/net/mpls/conf/eth0/input'
info: reading '/proc/sys/net/ipv4/conf/eth0/forwarding'
info: reading '/proc/sys/net/ipv6/conf/eth0/forwarding'
info: reading '/proc/sys/net/ipv4/conf/eth0/accept_local'
info: swp1: running ops ...
info: executing /sbin/ethtool swp1
info: reading '/sys/class/net/swp1/speed'
info: reading '/sys/class/net/swp1/duplex'
info: executing /sbin/ethtool -s swp1  speed 1000 duplex full
info: reading '/proc/sys/net/mpls/conf/swp1/input'
info: reading '/proc/sys/net/ipv4/conf/swp1/accept_local'
info: bridge: running ops ...
info: bridge: netlink: ip link add bridge type bridge
info: bridge: apply bridge settings
info: bridge: set bridge-ageing 1800
info: bridge: set bridge-hashel 4096
info: bridge: set bridge-hashmax 4096
info: bridge: set bridge-mcstats on
info: reading '/sys/class/net/bridge/bridge/stp_state'
info: bridge: stp state reset, reapplying port settings
info: bridge: netlink: ip link set bridge type bridge with attributes
info: writing '1' to file /proc/sys/net/ipv6/conf/swp1/disable_ipv6
info: executing /bin/ip -force -batch - [link set dev swp1 master bridge
addr flush dev swp1
]
info: bridge: applying bridge port configuration: ['swp1']
info: bridge: swp1: set bridge-portprios 8
info: swp1: netlink: ip link set dev swp1: bridge slave attributes
info: executing /sbin/brctl showmcqv4src bridge
info: bridge: applying bridge configuration specific to ports
info: bridge: processing bridge config for port swp1
info: swp1: netlink: ip link set dev swp1 up
info: bridge: setting bridge mac to port swp1 mac
info: executing /bin/ip link set dev bridge address 90:e2:ba:2c:b1:96
info: executing /sbin/mstpctl showportdetail bridge json
info: executing /sbin/mstpctl showbridge json bridge
info: bridge: applying mstp configuration specific to ports
info: bridge: processing mstp config for port swp1
info: bridge: netlink: ip link set dev bridge up
info: reading '/proc/sys/net/mpls/conf/bridge/input'
info: executing /sbin/sysctl net.ipv4.conf.bridge.forwarding
info: executing /sbin/sysctl net.ipv6.conf.bridge.forwarding
info: executing /bin/ip -force -batch - [link set dev bridge down
link set dev bridge addrgenmode eui64
link set dev bridge up
]
info: reading '/proc/sys/net/ipv4/conf/bridge/accept_local'
info: vlan1903: running ops ...
info: vlan1903: netlink: ip link add link bridge name vlan1903 type vlan id 1903 protocol 802.1q
info: vlan1903: netlink: ip link set dev vlan1903 up
info: reading '/proc/sys/net/mpls/conf/vlan1903/input'
info: reading '/proc/sys/net/ipv4/conf/vlan1903/forwarding'
info: reading '/proc/sys/net/ipv6/conf/vlan1903/forwarding'
info: executing /bin/ip -force -batch - [link set dev vlan1903 down
link set dev vlan1903 addrgenmode none
link set dev vlan1903 up
]
info: vlan1903: netlink: ip link add link vlan1903 name vlan1903-v0 type macvlan mode private
info: executing /sbin/sysctl net.ipv6.conf.vlan1903-v0.accept_dad
info: executing /sbin/sysctl net.ipv6.conf.vlan1903-v0.accept_dad=0
info: executing /sbin/sysctl net.ipv6.conf.vlan1903-v0.dad_transmits
info: executing /sbin/sysctl net.ipv6.conf.vlan1903-v0.dad_transmits=0
info: executing /bin/ip -force -batch - [link set dev vlan1903-v0 addrgenmode none
link set dev vlan1903-v0 down
link set dev vlan1903-v0 address 00:00:5e:00:01:a3
link set dev vlan1903-v0 up
addr add 2a06:c01:1:1903::1/64 dev vlan1903-v0
addr add fe80::1/64 dev vlan1903-v0
addr add 185.98.123.1/24 dev vlan1903-v0
route del 2a06:c01:1:1903::/64 dev vlan1903-v0
route del fe80::/64 dev vlan1903-v0
route add 2a06:c01:1:1903::/64 dev vlan1903-v0 proto kernel metric 9999
route add fe80::/64 dev vlan1903-v0 proto kernel metric 9999
]
info: reading '/proc/sys/net/ipv4/conf/vlan1903/accept_local'
[13:09:29] root:~ #
[13:09:30] root:~ #
[13:09:30] root:~ # ifquery -a -c
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp                                                [pass]

auto vlan1903
iface vlan1903                                                      [pass]
	vlan-raw-device bridge                                      [pass]
	vlan-id 1903                                                [pass]
	ipv6-addrgen no                                             [pass]
	address-virtual 00:00:5e:00:01:a3 2a06:c01:1:1903::1/64 fe80::1/64 185.98.123.1/24     [pass]
	address-virtual-ipv6-addrgen no                             [pass]

auto bridge
iface bridge                                                        [pass]
	bridge-ports swp1                                           [pass]

[13:09:33] root:~ #
[13:09:35] root:~ #
[13:09:35] root:~ # ifquery -a -r
auto vlan1903-v0
iface vlan1903-v0
	ipv6-addrgen off
	address 185.98.123.1/24
	address 2a06:c01:1:1903::1/64

auto vlan1903
iface vlan1903
	vlan-id 1903
	vlan-protocol 802.1Q
	vlan-raw-device bridge
	ipv6-addrgen off
	address-virtual 00:00:5e:00:01:a3 185.98.123.1/242a06:c01:1:1903::1/64
	address-virtual-ipv6-addrgen off

auto bridge
iface bridge
	bridge-vlan-stats off
	bridge-mcstats 1
	bridge-ports swp1
	bridge-stp yes
	mstpctl-portp2p  swp1=auto
	mstpctl-treeportcost  swp1=20000
	mstpctl-portautoedge  swp1=yes

auto swp1
iface swp1

auto eth0
iface eth0 inet dhcp

auto lo
iface lo inet loopback
	mtu 65536

[13:09:38] root:~ # ip -d link show vlan1903
20: vlan1903@bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 90:e2:ba:2c:b1:96 brd ff:ff:ff:ff:ff:ff promiscuity 1
    vlan protocol 802.1Q id 1903 <REORDER_HDR> addrgenmode none
[13:09:50] root:~ # ip -d link show vlan1903-v0
21: vlan1903-v0@vlan1903: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 00:00:5e:00:01:a3 brd ff:ff:ff:ff:ff:ff promiscuity 0
    macvlan  mode private addrgenmode none
[13:09:53] root:~ #
[13:09:56] root:~ # ip link set dev vlan1903-v0 addrgenmode eui64
[13:10:23] root:~ # ifquery -a -c
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp                                                [pass]

auto vlan1903
iface vlan1903                                                      [fail]
	vlan-raw-device bridge                                      [pass]
	vlan-id 1903                                                [pass]
	ipv6-addrgen no                                             [pass]
	address-virtual 00:00:5e:00:01:a3 2a06:c01:1:1903::1/64 fe80::1/64 185.98.123.1/24     [pass]
	address-virtual-ipv6-addrgen no                             [fail]

auto bridge
iface bridge                                                        [pass]
	bridge-ports swp1                                           [pass]

[13:10:29] root:~ # ifquery -a -r
auto vlan1903-v0
iface vlan1903-v0
	address 185.98.123.1/24
	address 2a06:c01:1:1903::1/64

auto vlan1903
iface vlan1903
	vlan-id 1903
	vlan-protocol 802.1Q
	vlan-raw-device bridge
	ipv6-addrgen off
	address-virtual 00:00:5e:00:01:a3 185.98.123.1/242a06:c01:1:1903::1/64
	address-virtual-ipv6-addrgen on

auto bridge
iface bridge
	bridge-vlan-stats off
	bridge-mcstats 1
	bridge-ports swp1
	bridge-stp yes
	mstpctl-portp2p  swp1=auto
	mstpctl-treeportcost  swp1=20000
	mstpctl-portautoedge  swp1=yes

auto swp1
iface swp1

auto eth0
iface eth0 inet dhcp

auto lo
iface lo inet loopback
	mtu 65536

[13:10:33] root:~ #

Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
This commit is contained in:
Julien Fortin
2018-07-10 00:18:39 +02:00
parent f8f6549ba7
commit 007cae3525
4 changed files with 140 additions and 18 deletions

View File

@@ -4,6 +4,8 @@
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import socket
from ipaddr import IPNetwork, IPv4Network, IPv6Network, _BaseV6
try:
@@ -751,9 +753,34 @@ class address(moduleBase):
self._process_mtu_config(ifaceobj, ifaceobj_getfunc, mtu)
def up_ipv6_addrgen(self, ifaceobj):
ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
if ipv6_addrgen:
self.ipcmd.ipv6_addrgen(ifaceobj.name, utils.get_boolean_from_string(ipv6_addrgen))
user_configured_ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
if not user_configured_ipv6_addrgen:
for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
old_config_ipv6_addrgen = old_ifaceobj.get_attr_value_first('ipv6-addrgen')
if old_config_ipv6_addrgen:
user_configured_ipv6_addrgen = self.get_attr_default_value('ipv6-addrgen')
break
if not user_configured_ipv6_addrgen:
# no previous config detected we dont have to configure ipv6-addrgen
return
ipv6_addrgen_nl = {
'on': 0,
'yes': 0,
'0': 0,
'off': 1,
'no': 1,
'1': 1
}.get(user_configured_ipv6_addrgen.lower(), None)
if ipv6_addrgen_nl is not None:
self.ipcmd.ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
# link_create=False will flush the addr cache of that intf
else:
self.logger.warning('%s: invalid value "%s" for attribute ipv6-addrgen' % (ifaceobj.name, user_configured_ipv6_addrgen))
def _up(self, ifaceobj, ifaceobj_getfunc=None):
if not self.ipcmd.link_exists(ifaceobj.name):
@@ -958,11 +985,29 @@ class address(moduleBase):
mpls_enable != running_mpls_enable)
return
def query_check_ipv6_addrgen(self, ifaceobj, ifaceobjcurr):
ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
if not ipv6_addrgen:
return
if ipv6_addrgen in utils._string_values:
ifaceobjcurr.update_config_with_status(
'ipv6-addrgen',
ipv6_addrgen,
utils.get_boolean_from_string(ipv6_addrgen) == self.ipcmd.get_ipv6_addrgen_mode(ifaceobj.name)
)
else:
ifaceobjcurr.update_config_with_status('ipv6-addrgen', ipv6_addrgen, 1)
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
runningaddrsdict = None
if not self.ipcmd.link_exists(ifaceobj.name):
self.logger.debug('iface %s not found' %ifaceobj.name)
return
self.query_check_ipv6_addrgen(ifaceobj, ifaceobjcurr)
addr_method = ifaceobj.addr_method
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
'mtu', self.ipcmd.link_get_mtu)
@@ -1036,10 +1081,19 @@ class address(moduleBase):
#XXXX Check broadcast address, scope, etc
return
def query_running_ipv6_addrgen(self, ifaceobjrunning):
ipv6_addrgen = self.ipcmd.get_ipv6_addrgen_mode(ifaceobjrunning.name)
if ipv6_addrgen:
ifaceobjrunning.update_config('ipv6-addrgen', 'off')
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
if not self.ipcmd.link_exists(ifaceobjrunning.name):
self.logger.debug('iface %s not found' %ifaceobjrunning.name)
return
self.query_running_ipv6_addrgen(ifaceobjrunning)
dhclientcmd = dhclient()
if (dhclientcmd.is_running(ifaceobjrunning.name) or
dhclientcmd.is_running6(ifaceobjrunning.name)):

View File

@@ -6,6 +6,7 @@
import os
import glob
import socket
from ipaddr import IPNetwork, IPv6Network
@@ -203,7 +204,17 @@ class addressvirtual(moduleBase):
ipv6_addrgen = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
if ipv6_addrgen:
return True, utils.get_boolean_from_string(ipv6_addrgen)
# IFLA_INET6_ADDR_GEN_MODE values:
# 0 = eui64
# 1 = none
ipv6_addrgen_nl = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}.get(ipv6_addrgen.lower(), None)
if ipv6_addrgen_nl is None:
self.logger.warning('%s: value "%s" not allowed for attribute "ipv6-addrgen"' % (ifaceobj.name, user_configured_ipv6_addrgen))
self.logger.warning('%s: invalid value "%s" for attribute address-virtual-ipv6-addrgen' % (ifaceobj.name, ipv6_addrgen))
else:
return True, ipv6_addrgen_nl
return False, None
@@ -215,7 +226,7 @@ class addressvirtual(moduleBase):
if ifaceobj.lowerifaces and address_virtual_list:
update_mtu = True
should_configure_ipv6_addrgen, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
user_configured_ipv6_addrgenmode, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
hwaddress = []
self.ipcmd.batch_start()
@@ -243,20 +254,13 @@ class addressvirtual(moduleBase):
except:
self.ipcmd.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
link_created = True
else:
if should_configure_ipv6_addrgen:
# When setting addrgenmode it is necessary to flap the macvlan
# device. After flapping the device we also need to re-add all
# the user configuration. The best way to add the user config
# is to flush our internal address cache
self.ipcmd.reset_addr_cache(macvlan_ifacename)
# first thing we need to handle vrf enslavement
if (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
self._handle_vrf_slaves(macvlan_ifacename, ifaceobj)
if should_configure_ipv6_addrgen:
self.ipcmd.ipv6_addrgen(macvlan_ifacename, ipv6_addrgen_user_value)
if user_configured_ipv6_addrgenmode:
self.ipcmd.ipv6_addrgen(macvlan_ifacename, ipv6_addrgen_user_value, link_created)
ips = av_attrs[1:]
if mac != 'None':
@@ -486,6 +490,13 @@ class addressvirtual(moduleBase):
return
if not self.ipcmd.link_exists(ifaceobj.name):
return
user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
if user_config_address_virtual_ipv6_addr and user_config_address_virtual_ipv6_addr not in utils._string_values:
ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
user_config_address_virtual_ipv6_addr = None
macvlans_running_ipv6_addr = []
av_idx = 0
macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
for address_virtual in address_virtual_list:
@@ -503,6 +514,10 @@ class addressvirtual(moduleBase):
'', 1)
av_idx += 1
continue
if user_config_address_virtual_ipv6_addr:
macvlans_running_ipv6_addr.append(self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename))
# Check mac and ip address
rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
raddrs = self.ipcmd.get_running_addrs(
@@ -537,11 +552,19 @@ class addressvirtual(moduleBase):
ifaceobjcurr.update_config_with_status('address-virtual',
raddress_virtual, 1)
av_idx += 1
return
if user_config_address_virtual_ipv6_addr:
bool_user_ipv6_addrgen = utils.get_boolean_from_string(user_config_address_virtual_ipv6_addr)
for running_ipv6_addrgen in macvlans_running_ipv6_addr:
if (not bool_user_ipv6_addrgen) != running_ipv6_addrgen:
ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
return
ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 0)
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
macvlans_ipv6_addrgen_list = []
for av in address_virtuals:
macvlan_ifacename = os.path.basename(av)
rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
@@ -552,7 +575,22 @@ class addressvirtual(moduleBase):
raddress = []
ifaceobjrunning.update_config('address-virtual',
'%s %s' %(rhwaddress, ''.join(raddress)))
return
macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename)))
macvlan_count = len(address_virtuals)
if not macvlan_count:
return
ipv6_addrgen = macvlans_ipv6_addrgen_list[0][1]
for macvlan_ifname, macvlan_ipv6_addrgen in macvlans_ipv6_addrgen_list:
if macvlan_ipv6_addrgen != ipv6_addrgen:
# one macvlan has a different ipv6-addrgen configuration
# we simply return, ifquery-running will print the macvlan
# stanzas with the ipv6-addrgen on/off attribute
return
ifaceobjrunning.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen else 'on')
_run_ops = {'up' : _up,
'down' : _down,

View File

@@ -335,6 +335,11 @@ class Netlink(utilsBase):
'attr': Link.IFLA_OPERSTATE,
'name': 'state',
'func': lambda x: '0%x' % int(x) if x > len(Link.oper_to_string) else Link.oper_to_string[x][8:]
},
{
'attr': Link.IFLA_AF_SPEC,
'name': 'af_spec',
'func': dict
}
]

View File

@@ -10,6 +10,7 @@ import re
import glob
import shlex
import signal
import socket
import subprocess
from ipaddr import IPNetwork, IPv6Network
@@ -2645,8 +2646,32 @@ class LinkUtils(utilsBase):
except:
pass
def ipv6_addrgen(self, ifname, addrgen):
cmd = 'link set dev %s addrgenmode %s' % (ifname, 'eui64' if addrgen else 'none')
def get_ipv6_addrgen_mode(self, ifname):
try:
return self._cache_get('link', [ifname, 'af_spec', socket.AF_INET6])[Link.IFLA_INET6_ADDR_GEN_MODE]
except:
# default to 0 (eui64)
return 0
def ipv6_addrgen(self, ifname, addrgen, link_created):
try:
# IFLA_INET6_ADDR_GEN_MODE values:
# 0 = eui64
# 1 = none
if self._link_cache_get([ifname, 'af_spec', socket.AF_INET6])[Link.IFLA_INET6_ADDR_GEN_MODE] == addrgen:
self.logger.debug('%s: ipv6 addrgen already %s' % (ifname, 'off' if addrgen else 'on'))
return
except:
pass
if not link_created:
# When setting addrgenmode it is necessary to flap the macvlan
# device. After flapping the device we also need to re-add all
# the user configuration. The best way to add the user config
# is to flush our internal address cache
self.reset_addr_cache(ifname)
cmd = 'link set dev %s addrgenmode %s' % (ifname, 'none' if addrgen else 'eui64')
is_link_up = self.is_link_up(ifname)