Add bridgedomain settings.
Bridges can be created with default settings, with specific settings, and they can be sync'd at runtime with all of the settings in this change. Notably missing are two features: - unknown unicast flooding into specific interfaces (as opposed to on/off on the bridge) - learn-limit, which does not have an API getter, only a setter.
This commit is contained in:
@ -81,6 +81,38 @@ def bvi_unique(yaml, bviname):
|
|||||||
return n<2
|
return n<2
|
||||||
|
|
||||||
|
|
||||||
|
def get_settings(yaml, ifname):
|
||||||
|
ifname, iface = get_by_name(yaml, ifname)
|
||||||
|
if not iface:
|
||||||
|
return None
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
'learn': True,
|
||||||
|
'unicast-flood': True,
|
||||||
|
'unknown-unicast-flood': True,
|
||||||
|
'unicast-forward': True,
|
||||||
|
'arp-termination': False,
|
||||||
|
'arp-unicast-forward': False,
|
||||||
|
'mac-age-minutes': 0, ## 0 means disabled
|
||||||
|
}
|
||||||
|
if 'settings' in iface:
|
||||||
|
if 'learn' in iface['settings']:
|
||||||
|
settings['learn'] = iface['settings']['learn']
|
||||||
|
if 'unicast-flood' in iface['settings']:
|
||||||
|
settings['unicast-flood'] = iface['settings']['unicast-flood']
|
||||||
|
if 'unknown-unicast-flood' in iface['settings']:
|
||||||
|
settings['unknown-unicast-flood'] = iface['settings']['unknown-unicast-flood']
|
||||||
|
if 'unicast-forward' in iface['settings']:
|
||||||
|
settings['unicast-forward'] = iface['settings']['unicast-forward']
|
||||||
|
if 'arp-termination' in iface['settings']:
|
||||||
|
settings['arp-termination'] = iface['settings']['arp-termination']
|
||||||
|
if 'arp-unicast-forward' in iface['settings']:
|
||||||
|
settings['arp-unicast-forward'] = iface['settings']['arp-unicast-forward']
|
||||||
|
if 'mac-age-minutes' in iface['settings']:
|
||||||
|
settings['mac-age-minutes'] = int(iface['settings']['mac-age-minutes'])
|
||||||
|
return settings
|
||||||
|
|
||||||
|
|
||||||
def validate_bridgedomains(yaml):
|
def validate_bridgedomains(yaml):
|
||||||
result = True
|
result = True
|
||||||
msgs = []
|
msgs = []
|
||||||
|
@ -32,6 +32,16 @@ bridgedomain:
|
|||||||
mtu: int(min=128,max=9216,required=False)
|
mtu: int(min=128,max=9216,required=False)
|
||||||
bvi: str(matches='loop[0-9]+',required=False)
|
bvi: str(matches='loop[0-9]+',required=False)
|
||||||
interfaces: list(str(),required=False)
|
interfaces: list(str(),required=False)
|
||||||
|
settings: include('bridgedomain-settings',required=False)
|
||||||
|
---
|
||||||
|
bridgedomain-settings:
|
||||||
|
learn: bool(required=False)
|
||||||
|
unicast-flood: bool(required=False)
|
||||||
|
unknown-unicast-flood: bool(required=False)
|
||||||
|
unicast-forward: bool(required=False)
|
||||||
|
arp-termination: bool(required=False)
|
||||||
|
arp-unicast-forward: bool(required=False)
|
||||||
|
mac-age-minutes: int(min=0,max=255,required=False)
|
||||||
---
|
---
|
||||||
loopback:
|
loopback:
|
||||||
description: str(exclude='\'"',len=64,required=False)
|
description: str(exclude='\'"',len=64,required=False)
|
||||||
|
@ -49,3 +49,19 @@ class TestBridgeDomainMethods(unittest.TestCase):
|
|||||||
def test_get_bridgedomains(self):
|
def test_get_bridgedomains(self):
|
||||||
ifs = bridgedomain.get_bridgedomains(self.cfg)
|
ifs = bridgedomain.get_bridgedomains(self.cfg)
|
||||||
self.assertEqual(len(ifs), 6)
|
self.assertEqual(len(ifs), 6)
|
||||||
|
|
||||||
|
def test_get_settings(self):
|
||||||
|
settings = bridgedomain.get_settings(self.cfg, "bd1")
|
||||||
|
self.assertIsNone(settings)
|
||||||
|
|
||||||
|
settings = bridgedomain.get_settings(self.cfg, "bd10")
|
||||||
|
self.assertTrue(settings['learn'])
|
||||||
|
self.assertTrue(settings['unknown-unicast-flood'])
|
||||||
|
self.assertTrue(settings['unicast-flood'])
|
||||||
|
self.assertEqual(settings['mac-age-minutes'], 0)
|
||||||
|
|
||||||
|
settings = bridgedomain.get_settings(self.cfg, "bd11")
|
||||||
|
self.assertTrue(settings['learn'])
|
||||||
|
self.assertFalse(settings['unknown-unicast-flood'])
|
||||||
|
self.assertFalse(settings['unicast-flood'])
|
||||||
|
self.assertEqual(settings['mac-age-minutes'], 10)
|
||||||
|
@ -105,17 +105,24 @@ BridgeDomains are required to be named `bdN` where N in [1, 16777216). Note that
|
|||||||
* ***interfaces***: A list of zero or more interfaces or sub-interfaces that are bridge
|
* ***interfaces***: A list of zero or more interfaces or sub-interfaces that are bridge
|
||||||
members. If the bridge has a `BVI`, it MUST NOT appear in this list. Bridges are allowed to
|
members. If the bridge has a `BVI`, it MUST NOT appear in this list. Bridges are allowed to
|
||||||
exist with no member interfaces.
|
exist with no member interfaces.
|
||||||
|
* ***settings***: A map of bridge-domain settings to further manipulate its behavior:
|
||||||
|
* ***learn***: A boolean that turns learning on/off. Default True.
|
||||||
|
* ***unicast-flood***: A boolean that turns unicast flooding on/off. Default True.
|
||||||
|
* ***unknown-unicast-flood***: A boolean that turns unknown unicast flooding on/off.
|
||||||
|
Default True.
|
||||||
|
* ***unicast-forward***: A boolean that turns unicast forwarding on/off. Default True.
|
||||||
|
* ***arp-termination***: A boolean that turns termination and response of ARP Requests
|
||||||
|
on/off. Default False.
|
||||||
|
* ***arp-unicast-forward***: A boolean that turns L2 arp-unicast forwarding on/off.
|
||||||
|
Default False.
|
||||||
|
* ***mac-age-minutes***: An integer between [0,256) that drives the ARP timeout on the
|
||||||
|
bridge in minutes, where 0 means do not age out, which is the default.
|
||||||
|
|
||||||
Any member sub-interfaces that are added, will automatically be configured to tag-rewrite the
|
Any member sub-interfaces that are added, will automatically be configured to tag-rewrite the
|
||||||
number of tags they have, so a simple dot1q sub-interface will be configured as `pop 1`, while
|
number of tags they have, so a simple dot1q sub-interface will be configured as `pop 1`, while
|
||||||
a QinQ or QinAD sub-interface will be configured as `pop 2`. Conversely, when interfaces are
|
a QinQ or QinAD sub-interface will be configured as `pop 2`. Conversely, when interfaces are
|
||||||
removed from the bridge, their tag-rewriting will be disabled.
|
removed from the bridge, their tag-rewriting will be disabled.
|
||||||
|
|
||||||
*Caveat*: Currently, bridgedomains are always created with their default attributes in VPP, that
|
|
||||||
is to say with learning and unicast forwarding turned on, unknown-unicast flooding enabled,
|
|
||||||
and ARP terminating and aging turned off. In a future release, `vppcfg` will give more
|
|
||||||
configuration options.
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
```
|
```
|
||||||
bridgedomains:
|
bridgedomains:
|
||||||
@ -124,9 +131,20 @@ bridgedomains:
|
|||||||
bvi: loop1
|
bvi: loop1
|
||||||
interfaces: [ BondEthernet0.500, HundredGigabitEthernet12/0/1, vxlan_tunnel1 ]
|
interfaces: [ BondEthernet0.500, HundredGigabitEthernet12/0/1, vxlan_tunnel1 ]
|
||||||
bd11:
|
bd11:
|
||||||
description: "No member interfaces, default 1500 byte MTU"
|
description: "No members, default 1500 byte MTU, with (default) settings"
|
||||||
|
settings:
|
||||||
|
learn: True
|
||||||
|
unicast-flood: True
|
||||||
|
unknown-unicast-flood: True
|
||||||
|
unicast-forward: True
|
||||||
|
arp-termination: False
|
||||||
|
arp-unicast-forward: False
|
||||||
|
mac-age-minutes: 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*Caveat*: The flooding of unknown-unicast can be turned on or off, but flooding to a specific interface
|
||||||
|
(as opposed to all interfaces which is the default), is not supported.
|
||||||
|
|
||||||
### BondEthernets
|
### BondEthernets
|
||||||
|
|
||||||
BondEthernets are required to be named `BondEthernetN` (note the camelcase) where N in
|
BondEthernets are required to be named `BondEthernetN` (note the camelcase) where N in
|
||||||
|
@ -75,6 +75,9 @@ bridgedomains:
|
|||||||
mtu: 2000
|
mtu: 2000
|
||||||
bvi: loop2
|
bvi: loop2
|
||||||
interfaces: [ BondEthernet0.500, BondEthernet0.501 ]
|
interfaces: [ BondEthernet0.500, BondEthernet0.501 ]
|
||||||
|
settings:
|
||||||
|
mac-age-minutes: 10
|
||||||
|
learn: False
|
||||||
bd11:
|
bd11:
|
||||||
mtu: 1500
|
mtu: 1500
|
||||||
|
|
||||||
|
10
schema.yaml
10
schema.yaml
@ -18,6 +18,16 @@ bridgedomain:
|
|||||||
mtu: int(min=128,max=9216,required=False)
|
mtu: int(min=128,max=9216,required=False)
|
||||||
bvi: str(matches='loop[0-9]+',required=False)
|
bvi: str(matches='loop[0-9]+',required=False)
|
||||||
interfaces: list(str(),required=False)
|
interfaces: list(str(),required=False)
|
||||||
|
settings: include('bridgedomain-settings',required=False)
|
||||||
|
---
|
||||||
|
bridgedomain-settings:
|
||||||
|
learn: bool(required=False)
|
||||||
|
unicast-flood: bool(required=False)
|
||||||
|
unknown-unicast-flood: bool(required=False)
|
||||||
|
unicast-forward: bool(required=False)
|
||||||
|
arp-termination: bool(required=False)
|
||||||
|
arp-unicast-forward: bool(required=False)
|
||||||
|
mac-age-minutes: int(min=0,max=255,required=False)
|
||||||
---
|
---
|
||||||
loopback:
|
loopback:
|
||||||
description: str(exclude='\'"',len=64,required=False)
|
description: str(exclude='\'"',len=64,required=False)
|
||||||
|
@ -51,9 +51,13 @@ bridgedomains:
|
|||||||
bvi: loop0
|
bvi: loop0
|
||||||
interfaces: [ GigabitEthernet1/0/0, GigabitEthernet1/0/1, BondEthernet0 ]
|
interfaces: [ GigabitEthernet1/0/0, GigabitEthernet1/0/1, BondEthernet0 ]
|
||||||
bd11:
|
bd11:
|
||||||
description: "Bridge Domain 11, with sub-interfaces"
|
description: "Bridge Domain 11, with sub-interfaces and settings"
|
||||||
mtu: 2000
|
mtu: 2000
|
||||||
interfaces: [ GigabitEthernet2/0/0.100, GigabitEthernet2/0/1.100, BondEthernet0.100 ]
|
interfaces: [ GigabitEthernet2/0/0.100, GigabitEthernet2/0/1.100, BondEthernet0.100 ]
|
||||||
|
settings:
|
||||||
|
mac-age-minutes: 10
|
||||||
|
unicast-flood: False
|
||||||
|
unknown-unicast-flood: False
|
||||||
bd12:
|
bd12:
|
||||||
description: "Bridge Domain 12, invalid because it has Gi1/0/0 as well"
|
description: "Bridge Domain 12, invalid because it has Gi1/0/0 as well"
|
||||||
mtu: 9000
|
mtu: 9000
|
||||||
|
@ -623,9 +623,24 @@ class Reconciler():
|
|||||||
for ifname in bridgedomain.get_bridgedomains(self.cfg):
|
for ifname in bridgedomain.get_bridgedomains(self.cfg):
|
||||||
ifname, iface = bridgedomain.get_by_name(self.cfg, ifname)
|
ifname, iface = bridgedomain.get_by_name(self.cfg, ifname)
|
||||||
instance = int(ifname[2:])
|
instance = int(ifname[2:])
|
||||||
|
settings = bridgedomain.get_settings(self.cfg, ifname)
|
||||||
if instance in self.vpp.cache['bridgedomains']:
|
if instance in self.vpp.cache['bridgedomains']:
|
||||||
continue
|
continue
|
||||||
cli="create bridge-domain %s" % (instance)
|
cli="create bridge-domain %s" % (instance)
|
||||||
|
if not settings['learn']:
|
||||||
|
cli += " learn 0"
|
||||||
|
if not settings['unicast-flood']:
|
||||||
|
cli += " flood 0"
|
||||||
|
if not settings['unknown-unicast-flood']:
|
||||||
|
cli += " uu-flood 0"
|
||||||
|
if not settings['unicast-forward']:
|
||||||
|
cli += " forward 0"
|
||||||
|
if settings['arp-termination']:
|
||||||
|
cli += " arp-term 1"
|
||||||
|
if settings['arp-unicast-forward']:
|
||||||
|
cli += " arp-ufwd 1"
|
||||||
|
if settings['mac-age-minutes'] > 0:
|
||||||
|
cli += " mac-age %d" % settings['mac-age-minutes']
|
||||||
self.cli['create'].append(cli);
|
self.cli['create'].append(cli);
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -727,12 +742,48 @@ class Reconciler():
|
|||||||
bridge_members = [self.vpp.cache['interfaces'][x].interface_name for x in bridge_sw_if_index_list if x in self.vpp.cache['interfaces']]
|
bridge_members = [self.vpp.cache['interfaces'][x].interface_name for x in bridge_sw_if_index_list if x in self.vpp.cache['interfaces']]
|
||||||
else:
|
else:
|
||||||
## New BridgeDomain
|
## New BridgeDomain
|
||||||
|
vpp_bridge = None
|
||||||
bvi_sw_if_index = -1
|
bvi_sw_if_index = -1
|
||||||
bridge_members = []
|
bridge_members = []
|
||||||
|
|
||||||
config_bridge_ifname, config_bridge_iface = bridgedomain.get_by_name(self.cfg, "bd%d"%instance)
|
config_bridge_ifname, config_bridge_iface = bridgedomain.get_by_name(self.cfg, "bd%d"%instance)
|
||||||
if not 'interfaces' in config_bridge_iface:
|
if vpp_bridge:
|
||||||
continue
|
# Sync settings on existing bridge. create_bridgedomain() will have set them for new bridges.
|
||||||
|
settings = bridgedomain.get_settings(self.cfg, config_bridge_ifname)
|
||||||
|
if settings['learn'] != vpp_bridge.learn:
|
||||||
|
cli="set bridge-domain learn %d" % (instance)
|
||||||
|
if not settings['learn']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['unicast-forward'] != vpp_bridge.forward:
|
||||||
|
cli="set bridge-domain forward %d" % (instance)
|
||||||
|
if not settings['unicast-forward']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['unicast-flood'] != vpp_bridge.flood:
|
||||||
|
cli="set bridge-domain flood %d" % (instance)
|
||||||
|
if not settings['unicast-flood']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['unknown-unicast-flood'] != vpp_bridge.uu_flood:
|
||||||
|
cli="set bridge-domain uu-flood %d" % (instance)
|
||||||
|
if not settings['unknown-unicast-flood']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['arp-termination'] != vpp_bridge.arp_term:
|
||||||
|
cli="set bridge-domain arp term %d" % (instance)
|
||||||
|
if not settings['arp-termination']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['arp-unicast-forward'] != vpp_bridge.arp_ufwd:
|
||||||
|
cli="set bridge-domain arp-ufwd %d" % (instance)
|
||||||
|
if not settings['arp-unicast-forward']:
|
||||||
|
cli += " disable"
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
if settings['mac-age-minutes'] != vpp_bridge.mac_age:
|
||||||
|
cli="set bridge-domain mac-age %d %d" % (instance, settings['mac-age-minutes'])
|
||||||
|
self.cli['sync'].append(cli);
|
||||||
|
|
||||||
if 'bvi' in config_bridge_iface:
|
if 'bvi' in config_bridge_iface:
|
||||||
bviname = config_bridge_iface['bvi']
|
bviname = config_bridge_iface['bvi']
|
||||||
if bviname in self.vpp.cache['interface_names'] and self.vpp.cache['interface_names'][bviname].sw_if_index == bvi_sw_if_index:
|
if bviname in self.vpp.cache['interface_names'] and self.vpp.cache['interface_names'][bviname].sw_if_index == bvi_sw_if_index:
|
||||||
@ -740,6 +791,8 @@ class Reconciler():
|
|||||||
cli="set interface l2 bridge %s %d bvi" % (bviname, instance)
|
cli="set interface l2 bridge %s %d bvi" % (bviname, instance)
|
||||||
self.cli['sync'].append(cli);
|
self.cli['sync'].append(cli);
|
||||||
|
|
||||||
|
if not 'interfaces' in config_bridge_iface:
|
||||||
|
continue
|
||||||
for member_ifname in config_bridge_iface['interfaces']:
|
for member_ifname in config_bridge_iface['interfaces']:
|
||||||
member_ifname, member_iface = interface.get_by_name(self.cfg, member_ifname)
|
member_ifname, member_iface = interface.get_by_name(self.cfg, member_ifname)
|
||||||
if not member_ifname in bridge_members:
|
if not member_ifname in bridge_members:
|
||||||
|
Reference in New Issue
Block a user