Add ability to manipulate MACs
Special care is taken for bondethernet, where the MAC changes when the first member is added to it. BondEthernet requires its MAC to be set in the bondethernets section, disallowing the MAC of individual members to be set. Also write a dumper for MACs of all types. Update integration test cases to stress the MAC changes on loops, bonds, and phys.
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
bondethernets:
|
bondethernets:
|
||||||
BondEthernet0:
|
BondEthernet0:
|
||||||
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
||||||
|
mac: 02:b0:b0:01:02:03
|
||||||
mode: xor
|
mode: xor
|
||||||
load-balance: l2
|
load-balance: l2
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ interfaces:
|
|||||||
|
|
||||||
HundredGigabitEthernet12/0/0:
|
HundredGigabitEthernet12/0/0:
|
||||||
lcp: "ice12-0-0"
|
lcp: "ice12-0-0"
|
||||||
|
mac: f2:01:00:12:00:00
|
||||||
mtu: 9000
|
mtu: 9000
|
||||||
addresses: [ 192.0.2.17/30, 2001:db8:3::1/64 ]
|
addresses: [ 192.0.2.17/30, 2001:db8:3::1/64 ]
|
||||||
sub-interfaces:
|
sub-interfaces:
|
||||||
@ -74,6 +76,7 @@ loopbacks:
|
|||||||
loop1:
|
loop1:
|
||||||
lcp: "bvi1"
|
lcp: "bvi1"
|
||||||
mtu: 2000
|
mtu: 2000
|
||||||
|
mac: 02:de:ad:01:be:ef
|
||||||
addresses: [ 10.0.1.1/24, 2001:db8:1::1/64 ]
|
addresses: [ 10.0.1.1/24, 2001:db8:1::1/64 ]
|
||||||
|
|
||||||
bridgedomains:
|
bridgedomains:
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
GigabitEthernet3/0/0:
|
GigabitEthernet3/0/0:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
mac: 00:25:90:0c:05:00
|
||||||
state: down
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
GigabitEthernet3/0/1:
|
GigabitEthernet3/0/1:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
mac: 00:25:90:0c:05:01
|
||||||
state: down
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
HundredGigabitEthernet12/0/0:
|
HundredGigabitEthernet12/0/0:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
mac: b4:96:91:b3:b1:10
|
||||||
state: down
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
HundredGigabitEthernet12/0/1:
|
HundredGigabitEthernet12/0/1:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
mac: b4:96:91:b3:b1:11
|
||||||
state: down
|
state: down
|
||||||
description: Not Used
|
description: Not Used
|
||||||
|
@ -70,6 +70,7 @@ interfaces:
|
|||||||
loopbacks:
|
loopbacks:
|
||||||
loop0:
|
loop0:
|
||||||
lcp: "lo0"
|
lcp: "lo0"
|
||||||
|
mac: de:ad:00:be:ef:00
|
||||||
addresses: [ 10.0.0.1/32, 2001:db8::1/128 ]
|
addresses: [ 10.0.0.1/32, 2001:db8::1/128 ]
|
||||||
loop1:
|
loop1:
|
||||||
mtu: 2000
|
mtu: 2000
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
bondethernets:
|
bondethernets:
|
||||||
BondEthernet0:
|
BondEthernet0:
|
||||||
|
mac: 02:b0:b0:00:00:01
|
||||||
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
||||||
|
|
||||||
interfaces:
|
interfaces:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
bondethernets:
|
bondethernets:
|
||||||
BondEthernet1:
|
BondEthernet1:
|
||||||
|
mac: 02:b0:b0:00:00:02
|
||||||
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
||||||
mode: round-robin
|
mode: round-robin
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
GigabitEthernet3/0/0:
|
GigabitEthernet3/0/0:
|
||||||
|
mac: 12:00:ba:03:00:00
|
||||||
mtu: 9216
|
mtu: 9216
|
||||||
sub-interfaces:
|
sub-interfaces:
|
||||||
100:
|
100:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
GigabitEthernet3/0/0:
|
GigabitEthernet3/0/0:
|
||||||
|
mac: 02:ff:ba:03:00:00
|
||||||
mtu: 9216
|
mtu: 9216
|
||||||
sub-interfaces:
|
sub-interfaces:
|
||||||
100:
|
100:
|
||||||
|
@ -45,6 +45,7 @@ interfaces:
|
|||||||
loopbacks:
|
loopbacks:
|
||||||
loop11:
|
loop11:
|
||||||
mtu: 3000
|
mtu: 3000
|
||||||
|
mac: de:ad:00:be:ef:11
|
||||||
lcp: "bvi11"
|
lcp: "bvi11"
|
||||||
addresses: [ 2001:db8:1::1/64, 192.0.2.1/30 ]
|
addresses: [ 2001:db8:1::1/64, 192.0.2.1/30 ]
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
bondethernets:
|
bondethernets:
|
||||||
BondEthernet0:
|
BondEthernet0:
|
||||||
|
mac: 02:b0:b0:00:00:00
|
||||||
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
interfaces: [ GigabitEthernet3/0/0, GigabitEthernet3/0/1 ]
|
||||||
|
|
||||||
interfaces:
|
interfaces:
|
||||||
@ -11,6 +12,7 @@ interfaces:
|
|||||||
description: "LAG #2"
|
description: "LAG #2"
|
||||||
|
|
||||||
HundredGigabitEthernet12/0/0:
|
HundredGigabitEthernet12/0/0:
|
||||||
|
mac: 02:ff:ba:12:00:00
|
||||||
lcp: "ice0"
|
lcp: "ice0"
|
||||||
|
|
||||||
HundredGigabitEthernet12/0/1:
|
HundredGigabitEthernet12/0/1:
|
||||||
|
@ -25,5 +25,9 @@
|
|||||||
|
|
||||||
echo " - Checking that from $j to $j is empty"
|
echo " - Checking that from $j to $j is empty"
|
||||||
../vppcfg plan -s ../schema.yaml -c $j -o /tmp/vppcfg-exec_${j}_${j}_null
|
../vppcfg plan -s ../schema.yaml -c $j -o /tmp/vppcfg-exec_${j}_${j}_null
|
||||||
|
[ -s /tmp/vppcfg-exec_${j}_${j}_null ] && {
|
||||||
|
echo " - ERROR Transition is not empty"
|
||||||
|
cat /tmp/vppcfg-exec_${j}_${j}_null
|
||||||
|
}
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
@ -613,6 +613,9 @@ class Reconciler():
|
|||||||
continue
|
continue
|
||||||
instance = int(ifname[4:])
|
instance = int(ifname[4:])
|
||||||
cli="create loopback interface instance %d" % (instance)
|
cli="create loopback interface instance %d" % (instance)
|
||||||
|
ifname, iface = loopback.get_by_name(self.cfg, ifname)
|
||||||
|
if 'mac' in iface:
|
||||||
|
cli += " mac %s" % iface['mac']
|
||||||
self.cli['create'].append(cli);
|
self.cli['create'].append(cli);
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -627,6 +630,8 @@ class Reconciler():
|
|||||||
lb = bondethernet.get_lb(self.cfg, ifname)
|
lb = bondethernet.get_lb(self.cfg, ifname)
|
||||||
if lb:
|
if lb:
|
||||||
cli += " load-balance %s" % lb
|
cli += " load-balance %s" % lb
|
||||||
|
if 'mac' in iface:
|
||||||
|
cli += " hw-addr %s" % iface['mac']
|
||||||
self.cli['create'].append(cli);
|
self.cli['create'].append(cli);
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -727,6 +732,9 @@ class Reconciler():
|
|||||||
|
|
||||||
def sync(self):
|
def sync(self):
|
||||||
ret = True
|
ret = True
|
||||||
|
if not self.sync_loopbacks():
|
||||||
|
self.logger.warning("Could not sync Loopbacks in VPP")
|
||||||
|
ret = False
|
||||||
if not self.sync_bondethernets():
|
if not self.sync_bondethernets():
|
||||||
self.logger.warning("Could not sync bondethernets in VPP")
|
self.logger.warning("Could not sync bondethernets in VPP")
|
||||||
ret = False
|
ret = False
|
||||||
@ -742,18 +750,46 @@ class Reconciler():
|
|||||||
if not self.sync_addresses():
|
if not self.sync_addresses():
|
||||||
self.logger.warning("Could not sync interface addresses in VPP")
|
self.logger.warning("Could not sync interface addresses in VPP")
|
||||||
ret = False
|
ret = False
|
||||||
|
if not self.sync_phys():
|
||||||
|
self.logger.warning("Could not sync PHYs in VPP")
|
||||||
|
ret = False
|
||||||
if not self.sync_admin_state():
|
if not self.sync_admin_state():
|
||||||
self.logger.warning("Could not sync interface adminstate in VPP")
|
self.logger.warning("Could not sync interface adminstate in VPP")
|
||||||
ret = False
|
ret = False
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def sync_loopbacks(self):
|
||||||
|
for ifname in loopback.get_loopbacks(self.cfg):
|
||||||
|
if not ifname in self.vpp.cache['interface_names']:
|
||||||
|
## New loopback
|
||||||
|
continue
|
||||||
|
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
||||||
|
config_ifname, config_iface = loopback.get_by_name(self.cfg, ifname)
|
||||||
|
if 'mac' in config_iface and config_iface['mac'] != str(vpp_iface.l2_address):
|
||||||
|
cli="set interface mac address %s %s" % (config_ifname, config_iface['mac'])
|
||||||
|
self.cli['sync'].append(cli)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def sync_phys(self):
|
||||||
|
for ifname in interface.get_phys(self.cfg):
|
||||||
|
if not ifname in self.vpp.cache['interface_names']:
|
||||||
|
## New interface
|
||||||
|
continue
|
||||||
|
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
||||||
|
config_ifname, config_iface = interface.get_by_name(self.cfg, ifname)
|
||||||
|
if 'mac' in config_iface and config_iface['mac'] != str(vpp_iface.l2_address):
|
||||||
|
cli="set interface mac address %s %s" % (config_ifname, config_iface['mac'])
|
||||||
|
self.cli['sync'].append(cli)
|
||||||
|
return True
|
||||||
|
|
||||||
def sync_bondethernets(self):
|
def sync_bondethernets(self):
|
||||||
for ifname in bondethernet.get_bondethernets(self.cfg):
|
for ifname in bondethernet.get_bondethernets(self.cfg):
|
||||||
if ifname in self.vpp.cache['interface_names']:
|
if ifname in self.vpp.cache['interface_names']:
|
||||||
vpp_bond_sw_if_index = self.vpp.cache['interface_names'][ifname].sw_if_index
|
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
||||||
vpp_members = [self.vpp.cache['interfaces'][x].interface_name for x in self.vpp.cache['bondethernet_members'][vpp_bond_sw_if_index]]
|
vpp_members = [self.vpp.cache['interfaces'][x].interface_name for x in self.vpp.cache['bondethernet_members'][vpp_iface.sw_if_index]]
|
||||||
else:
|
else:
|
||||||
## New BondEthernet
|
## New BondEthernet
|
||||||
|
vpp_iface = None
|
||||||
vpp_members = []
|
vpp_members = []
|
||||||
|
|
||||||
config_bond_ifname, config_bond_iface = bondethernet.get_by_name(self.cfg, ifname)
|
config_bond_ifname, config_bond_iface = bondethernet.get_by_name(self.cfg, ifname)
|
||||||
@ -769,7 +805,10 @@ class Reconciler():
|
|||||||
bondmac = member_iface.l2_address
|
bondmac = member_iface.l2_address
|
||||||
cli="bond add %s %s" % (config_bond_ifname, member_iface.interface_name)
|
cli="bond add %s %s" % (config_bond_ifname, member_iface.interface_name)
|
||||||
self.cli['sync'].append(cli);
|
self.cli['sync'].append(cli);
|
||||||
if bondmac and 'lcp' in config_iface:
|
if vpp_iface and 'mac' in config_iface and str(vpp_iface.l2_address) != config_iface['mac']:
|
||||||
|
cli="set interface mac address %s %s" % (config_ifname, config_iface['mac'])
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
elif bondmac and 'lcp' in config_iface:
|
||||||
## TODO(pim) - Ensure LCP has the same MAC as the BondEthernet
|
## TODO(pim) - Ensure LCP has the same MAC as the BondEthernet
|
||||||
## VPP, when creating a BondEthernet, will give it an ephemeral MAC. Then, when the
|
## VPP, when creating a BondEthernet, will give it an ephemeral MAC. Then, when the
|
||||||
## first member is enslaved, the MAC address changes to that of the first member.
|
## first member is enslaved, the MAC address changes to that of the first member.
|
||||||
|
@ -272,17 +272,19 @@ class VPPApiDumper(VPPApi):
|
|||||||
|
|
||||||
def cache_to_config(self):
|
def cache_to_config(self):
|
||||||
config = {"loopbacks": {}, "bondethernets": {}, "interfaces": {}, "bridgedomains": {}, "vxlan_tunnels": {} }
|
config = {"loopbacks": {}, "bondethernets": {}, "interfaces": {}, "bridgedomains": {}, "vxlan_tunnels": {} }
|
||||||
for idx, iface in self.cache['bondethernets'].items():
|
for idx, bond_iface in self.cache['bondethernets'].items():
|
||||||
bond = {"description": ""}
|
bond = {"description": ""}
|
||||||
if iface.sw_if_index in self.cache['bondethernet_members']:
|
if bond_iface.sw_if_index in self.cache['bondethernet_members']:
|
||||||
members = [self.cache['interfaces'][x].interface_name for x in self.cache['bondethernet_members'][iface.sw_if_index]]
|
members = [self.cache['interfaces'][x].interface_name for x in self.cache['bondethernet_members'][bond_iface.sw_if_index]]
|
||||||
if len(members) > 0:
|
if len(members) > 0:
|
||||||
bond['interfaces'] = members
|
bond['interfaces'] = members
|
||||||
|
|
||||||
mode = bondethernet.int_to_mode(iface.mode)
|
mode = bondethernet.int_to_mode(bond_iface.mode)
|
||||||
bond['mode'] = mode
|
bond['mode'] = mode
|
||||||
if mode in ['xor', 'lacp']:
|
if mode in ['xor', 'lacp']:
|
||||||
bond['load-balance'] = bondethernet.int_to_lb(iface.lb)
|
bond['load-balance'] = bondethernet.int_to_lb(bond_iface.lb)
|
||||||
|
iface = self.cache['interfaces'][bond_iface.sw_if_index]
|
||||||
|
bond['mac'] = str(iface.l2_address)
|
||||||
config['bondethernets'][iface.interface_name] = bond
|
config['bondethernets'][iface.interface_name] = bond
|
||||||
|
|
||||||
for numtags in [ 0, 1, 2 ]:
|
for numtags in [ 0, 1, 2 ]:
|
||||||
@ -296,6 +298,7 @@ class VPPApiDumper(VPPApi):
|
|||||||
continue
|
continue
|
||||||
loop = {"description": ""}
|
loop = {"description": ""}
|
||||||
loop['mtu'] = iface.mtu[0]
|
loop['mtu'] = iface.mtu[0]
|
||||||
|
loop['mac'] = str(iface.l2_address)
|
||||||
if iface.sw_if_index in self.cache['lcps']:
|
if iface.sw_if_index in self.cache['lcps']:
|
||||||
loop['lcp'] = self.cache['lcps'][iface.sw_if_index].host_if_name
|
loop['lcp'] = self.cache['lcps'][iface.sw_if_index].host_if_name
|
||||||
if iface.sw_if_index in self.cache['interface_addresses']:
|
if iface.sw_if_index in self.cache['interface_addresses']:
|
||||||
@ -315,6 +318,8 @@ class VPPApiDumper(VPPApi):
|
|||||||
if not self.cache['interfaces'][idx].flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
if not self.cache['interfaces'][idx].flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
||||||
i['state'] = 'down'
|
i['state'] = 'down'
|
||||||
|
|
||||||
|
if iface.interface_dev_type == 'dpdk':
|
||||||
|
i['mac'] = str(iface.l2_address)
|
||||||
i['mtu'] = iface.mtu[0]
|
i['mtu'] = iface.mtu[0]
|
||||||
if iface.sub_number_of_tags == 0:
|
if iface.sub_number_of_tags == 0:
|
||||||
config['interfaces'][iface.interface_name] = i
|
config['interfaces'][iface.interface_name] = i
|
||||||
|
Reference in New Issue
Block a user