Skip to content

Commit 56b4df8

Browse files
authored
Merge pull request #2876 from anarkiwi/bgproutevlan
Support router configuration that just connects BGP to a VLAN in anot…
2 parents d0e54e8 + e7af03d commit 56b4df8

File tree

2 files changed

+53
-47
lines changed

2 files changed

+53
-47
lines changed

faucet/dp.py

+51-44
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ def finalize_config(self, dps):
835835

836836
dp_by_name = {}
837837
vlan_by_name = {}
838-
external_ports = False
838+
vlans_with_external_ports = set()
839839

840840
def resolve_ports(port_names):
841841
"""Resolve list of ports, by port by name or number."""
@@ -856,12 +856,21 @@ def resolve_vlan(vlan_name):
856856
return self.vlans[vlan_name]
857857
return None
858858

859+
def resolve_vlans(vlan_names):
860+
"""Resolve a list of VLAN names."""
861+
vlans = []
862+
for vlan_name in vlan_names:
863+
vlan = resolve_vlan(vlan_name)
864+
if vlan:
865+
vlans.append(vlan)
866+
return vlans
867+
859868
def resolve_stack_dps():
860869
"""Resolve DP references in stacking config."""
861870
if self.stack_ports:
862871
if self.stack is None:
863872
self.stack = {}
864-
self.stack['externals'] = external_ports
873+
self.stack['externals'] = bool(vlans_with_external_ports)
865874
port_stack_dp = {}
866875
for port in self.stack_ports:
867876
stack_dp = port.stack['dp']
@@ -1037,70 +1046,68 @@ def resolve_acls():
10371046
for tunnel_acl in self.tunnel_acls.values():
10381047
tunnel_acl.verify_tunnel_compatibility_rules(self)
10391048

1040-
def resolve_vlan_names_in_routers():
1049+
def resolve_routers():
10411050
"""Resolve VLAN references in routers."""
10421051
dp_routers = {}
10431052
for router_name, router in self.routers.items():
10441053
if router.bgp_vlan():
10451054
router.set_bgp_vlan(resolve_vlan(router.bgp_vlan()))
1046-
vlans = []
1047-
for vlan_name in router.vlans:
1048-
vlan = resolve_vlan(vlan_name)
1049-
if vlan is not None:
1050-
vlans.append(vlan)
1051-
if len(vlans):
1055+
vlans = resolve_vlans(router.vlans)
1056+
if vlans or router.bgp_vlan():
10521057
dp_router = copy.copy(router)
10531058
dp_router.vlans = vlans
10541059
dp_routers[router_name] = dp_router
1060+
self.routers = dp_routers
1061+
1062+
if self.global_vlan:
1063+
vids = {vlan.vid for vlan in self.vlans.values()}
1064+
test_config_condition(
1065+
self.global_vlan in vids, 'global_vlan VID %s conflicts with existing VLAN' % self.global_vlan)
1066+
1067+
# Check for overlapping VIP subnets or VLANs.
1068+
all_router_vlans = set()
1069+
for router_name, router in self.routers.items():
10551070
vips = set()
1056-
for vlan in vlans:
1057-
for vip in vlan.faucet_vips:
1058-
if vip.ip.is_link_local:
1059-
continue
1060-
vips.add(vip)
1071+
if router.vlans and len(router.vlans) == 1:
1072+
lone_vlan = router.vlans[0]
1073+
test_config_condition(
1074+
lone_vlan in all_router_vlans, 'single VLAN %s in more than one router' % lone_vlan)
1075+
for vlan in router.vlans:
1076+
vips.update({vip for vip in vlan.faucet_vips if not vip.ip.is_link_local})
1077+
all_router_vlans.update(router.vlans)
10611078
for vip in vips:
10621079
for other_vip in vips - set([vip]):
10631080
test_config_condition(
10641081
vip.ip in other_vip.network,
10651082
'VIPs %s and %s overlap in router %s' % (
10661083
vip, other_vip, router_name))
1067-
self.routers = dp_routers
1084+
bgp_routers = self.bgp_routers()
1085+
if bgp_routers:
1086+
for bgp_router in bgp_routers:
1087+
bgp_vlan = bgp_router.bgp_vlan()
1088+
vlan_dps = [dp for dp in dps if bgp_vlan.vid in dp.vlans]
1089+
test_config_condition(len(vlan_dps) != 1, (
1090+
'DPs %s sharing a BGP speaker VLAN is unsupported'))
1091+
test_config_condition(bgp_router.bgp_server_addresses() != (
1092+
bgp_routers[0].bgp_server_addresses()), (
1093+
'BGP server addresses must all be the same'))
1094+
router_ids = {bgp_router.bgp_routerid() for bgp_router in bgp_routers}
1095+
test_config_condition(len(router_ids) != 1, 'BGP router IDs must all be the same: %s' % router_ids)
1096+
bgp_ports = {bgp_router.bgp_port() for bgp_router in bgp_routers}
1097+
test_config_condition(len(bgp_ports) != 1, 'BGP ports must all be the same: %s' % bgp_ports)
10681098

1069-
test_config_condition(not self.vlans, 'no VLANs referenced by interfaces in %s' % self.name)
1070-
1071-
for dp in dps:
1072-
dp_by_name[dp.name] = dp
1073-
for vlan in self.vlans.values():
1074-
vlan_by_name[vlan.name] = vlan
1075-
if self.global_vlan:
1076-
test_config_condition(
1077-
self.global_vlan == vlan.vid, 'VLAN %u is reserved by global_vlan' % vlan.vid)
10781099

1079-
for vlan in vlan_by_name.values():
1080-
if vlan.loop_protect_external_ports():
1081-
external_ports = True
1082-
break
1100+
test_config_condition(not self.vlans, 'no VLANs referenced by interfaces in %s' % self.name)
1101+
dp_by_name = {dp.name: dp for dp in dps}
1102+
vlan_by_name = {vlan.name: vlan for vlan in self.vlans.values()}
1103+
vlans_with_external_ports = {
1104+
vlan for vlan in self.vlans.values() if vlan.loop_protect_external_ports()}
10831105

10841106
resolve_stack_dps()
10851107
resolve_mirror_destinations()
10861108
resolve_override_output_ports()
1087-
resolve_vlan_names_in_routers()
10881109
resolve_acls()
1089-
1090-
bgp_routers = self.bgp_routers()
1091-
if bgp_routers:
1092-
for bgp_router in bgp_routers:
1093-
bgp_vlan = bgp_router.bgp_vlan()
1094-
vlan_dps = [dp for dp in dps if bgp_vlan.vid in dp.vlans]
1095-
test_config_condition(len(vlan_dps) != 1, (
1096-
'DPs %s sharing a BGP speaker VLAN is unsupported'))
1097-
test_config_condition(bgp_router.bgp_server_addresses() != (
1098-
bgp_routers[0].bgp_server_addresses()), (
1099-
'BGP server addresses must all be the same'))
1100-
router_ids = {bgp_router.bgp_routerid() for bgp_router in bgp_routers}
1101-
test_config_condition(len(router_ids) != 1, 'BGP router IDs must all be the same: %s' % router_ids)
1102-
bgp_ports = {bgp_router.bgp_port() for bgp_router in bgp_routers}
1103-
test_config_condition(len(bgp_ports) != 1, 'BGP ports must all be the same: %s' % bgp_ports)
1110+
resolve_routers()
11041111

11051112
self._configure_tables()
11061113

faucet/router.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ def check_config(self):
8888
(self.bgp_neighbor_addresses(), 'neighbor_addresses'),
8989
(self.bgp_neighbor_as(), 'neighbor_as')):
9090
test_config_condition(not accessor_val, 'BGP %s must be specified' % required_field)
91-
test_config_condition(self.bgp_connect_mode() != 'passive', 'BGP connect_mode must be passive')
91+
test_config_condition(
92+
self.bgp_connect_mode() != 'passive', 'BGP connect_mode must be passive')
9293
for ipv in self.bgp_ipvs():
9394
test_config_condition(
9495
len(self.bgp_server_addresses_by_ipv(ipv)) != 1,
@@ -98,8 +99,6 @@ def check_config(self):
9899
len(self.vlans) != 1,
99100
'If routing more than one VLAN, must specify BGP VLAN')
100101
self.set_bgp_vlan(self.vlans[0])
101-
if not self.vlans:
102-
self.vlans = [self.bgp_vlan()]
103102
else:
104103
test_config_condition(
105104
not self.vlans, 'A router must have least one VLAN specified at top level')

0 commit comments

Comments
 (0)