Skip to content

Commit

Permalink
Support untagged infra networks
Browse files Browse the repository at this point in the history
We now support the already present untagged flag for infra networks.
Only one network can be set as untagged for each hostgroup. As we want
to make sure servers stay deployable via OpenStack, the OpenStack
network will take precedence over an untagged infra network for all
direct mode bindings. Due to this quirk, we also cannot properly sync
the native vlan via the sync_infra_networks API call, so this will have
to be done via a full switch sync.
  • Loading branch information
sebageek committed Apr 26, 2024
1 parent fc1c5cc commit 25474e2
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 9 deletions.
15 changes: 15 additions & 0 deletions networking_ccloud/common/config/config_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ class InfraNetwork(pydantic.BaseModel):
networks: List[str] = []
aggregates: List[str] = []
vni: pydantic.conint(gt=0, lt=2**24)

# note that untagged OpenStack network will take precedence over untagged infra networks
untagged: bool = False
dhcp_relays: List[str] = []

Expand Down Expand Up @@ -327,6 +329,19 @@ def ensure_at_least_one_member(cls, v):
raise ValueError("Hostgroup needs to have at least one member")
return v

@pydantic.validator('infra_networks')
def ensure_only_one_untagged_infra_network(cls, v):
untagged_net = None
for infra_net in v or []:
if not infra_net.untagged:
continue
if untagged_net is None:
untagged_net = infra_net.name
else:
raise ValueError("Found two untagged InfraNetworks on same hostgroup: "
f"{untagged_net} and {infra_net.name}")
return v

@pydantic.root_validator()
def ensure_hostgroups_with_role_are_not_a_metagroup(cls, values):
# FIXME: constants? enum? what do we do here
Expand Down
4 changes: 3 additions & 1 deletion networking_ccloud/extensions/fabricoperations.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ def sync_infra_networks(self, request, **kwargs):
scul = agent_msg.SwitchConfigUpdateList(agent_msg.OperationEnum.replace, self.drv_conf)
for hg in self.drv_conf.get_hostgroups_by_switches([switch.name]):
if hg.infra_networks:
scul.add_infra_networks_from_hostgroup(hg, sg)
# as we don't know if a direct-binding deployment is on a port we cannot
# process native vlans here --> needs to be done in a full switch sync
scul.add_infra_networks_from_hostgroup(hg, sg, process_untagged=False)
if hg.extra_vlans:
scul.add_extra_vlans(hg)
scul.clean_switches(switch.name)
Expand Down
18 changes: 11 additions & 7 deletions networking_ccloud/ml2/agent/common/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,8 @@ def get_or_create_switch(self, switch_name):
return self.switch_config_updates[switch_name]

def add_binding_host_to_config(self, hg_config, network_id, seg_vni, seg_vlan, trunk_vlan=None,
keep_mapping=False, exclude_hosts=None, is_bgw=False, gateways=None):
keep_mapping=False, exclude_hosts=None, is_bgw=False, gateways=None,
override_native=False):
"""Add binding host config to all required switches
Given a hostgroup config this method generates and adds config to this
Expand Down Expand Up @@ -422,10 +423,13 @@ def add_binding_host_to_config(self, hg_config, network_id, seg_vni, seg_vlan, t
iface = scu.get_or_create_iface_from_switchport(sp)
iface.add_trunk_vlan(seg_vlan)

if hg_config.direct_binding and not hg_config.role:
if trunk_vlan:
iface.add_vlan_translation(seg_vlan, trunk_vlan)
elif not hg_config.allow_multiple_trunk_ports:
if not hg_config.role:
if hg_config.direct_binding:
if trunk_vlan:
iface.add_vlan_translation(seg_vlan, trunk_vlan)
elif not hg_config.allow_multiple_trunk_ports:
iface.native_vlan = seg_vlan
elif not hg_config.direct_binding and override_native:
iface.native_vlan = seg_vlan

def add_vrf_bgp_config(self, switch_names, vrf_name, vrf_networks, vrf_aggregates):
Expand All @@ -447,15 +451,15 @@ def add_vrf_bgp_config(self, switch_names, vrf_name, vrf_networks, vrf_aggregate
aggregates.append(BGPVRFAggregate(network=network, az_local=az_local))
vrf.add_aggregates(aggregates)

def add_infra_networks_from_hostgroup(self, hg_config, sg):
def add_infra_networks_from_hostgroup(self, hg_config, sg, process_untagged=False):
for inet in hg_config.infra_networks or []:
# FIXME: exclude hosts
gateways = None
if inet.vrf:
gateways = {'vrf': inet.vrf, 'ips': inet.networks}

self.add_binding_host_to_config(hg_config, inet.name, inet.vni, inet.vlan,
gateways=gateways)
gateways=gateways, override_native=inet.untagged and process_untagged)

if inet.vrf:
# get network address from network (clear host bits); they are az-local and non-ext-announcable
Expand Down
2 changes: 1 addition & 1 deletion networking_ccloud/ml2/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def make_switchgroup_config(self, context, sg):
# add interconnects, infra networks and extra vlans
for hg in self.drv_conf.get_hostgroups_by_switches([sw.name for sw in sg.members]):
if hg.infra_networks:
scul.add_infra_networks_from_hostgroup(hg, sg)
scul.add_infra_networks_from_hostgroup(hg, sg, process_untagged=True)
if hg.extra_vlans:
scul.add_extra_vlans(hg)
if hg.role:
Expand Down
10 changes: 10 additions & 0 deletions networking_ccloud/tests/unit/common/test_driver_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ def test_infra_network_vrf_presence(self):
config.DriverConfig, switchgroups=[switchgroup], hostgroups=hostgroups,
global_config=global_config)

def test_hostgroup_no_two_untagged_networks(self):
sg = cfix.make_switchgroup("seagull", availability_zone="qa-de-1a"),
untagged_1 = config.InfraNetwork(name="mew-gull", vlan=23, vni=100023, untagged=True)
untagged_2 = config.InfraNetwork(name="herring-gull", vlan=42, vni=100042, untagged=True)
regular_1 = config.InfraNetwork(name="sparrow", vlan=2, vni=2)
cfix.make_hostgroups(sg, infra_networks=[untagged_1])
cfix.make_hostgroups(sg, infra_networks=[untagged_1, regular_1])
self.assertRaisesRegex(ValueError, "on same hostgroup: mew-gull and herring-gull",
cfix.make_hostgroups, sg, infra_networks=[untagged_1, regular_1, untagged_2])

def test_duplicate_vrf_name(self):
vrfs = cfix.make_vrfs(['ROUTE-ME', 'ROUTE-ME'])

Expand Down

0 comments on commit 25474e2

Please sign in to comment.