From fd029f985d913ae33290ae3c1bc8474a2aac1d1a Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Wed, 20 Nov 2024 16:06:18 +0100 Subject: [PATCH] Ensure that ARP/NDP is enabled for vlan devices In case VLAN networks are being used in neutron for providing external connectivity they will be assinged an IP address as well in order to get ARP/NDP proxying to work. With that VRF exposure method was relying on broken behaviour, as it never needed/expected ARP/NDP to be enabled var a vlan rather then bridge as well as vlan device to exist at all. So skipping vlan_id for evpn makes sense in this case, as only offload is important. Closes-Bug: #2088558 Change-Id: Ibffda84801150a18ee8c441b4396afc900d8bc36 --- .../drivers/openstack/ovn_bgp_driver.py | 7 ++-- ovn_bgp_agent/drivers/openstack/utils/evpn.py | 2 +- ovn_bgp_agent/drivers/openstack/utils/wire.py | 8 +++-- .../openstack/test_nb_ovn_bgp_driver.py | 6 ++-- .../drivers/openstack/test_ovn_bgp_driver.py | 6 ++-- .../unit/drivers/openstack/utils/test_evpn.py | 2 +- .../tests/unit/utils/test_linux_net.py | 16 +++++----- ovn_bgp_agent/utils/linux_net.py | 32 +++++++++++++------ ...le_arp_ndp_for_vlans-6c306601aba68cb4.yaml | 10 ++++++ 9 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 releasenotes/notes/enable_arp_ndp_for_vlans-6c306601aba68cb4.yaml diff --git a/ovn_bgp_agent/drivers/openstack/ovn_bgp_driver.py b/ovn_bgp_agent/drivers/openstack/ovn_bgp_driver.py index c329d4e8..3055212c 100644 --- a/ovn_bgp_agent/drivers/openstack/ovn_bgp_driver.py +++ b/ovn_bgp_agent/drivers/openstack/ovn_bgp_driver.py @@ -169,9 +169,12 @@ class OVNBGPDriver(driver_api.AgentDriverBase): linux_net.ensure_vlan_device_for_network(bridge, vlan_tag) + linux_net.ensure_arp_ndp_enabled_for_bridge(bridge, + bridge_index, + vlan_tag) + linux_net.ensure_arp_ndp_enabled_for_bridge(bridge, - bridge_index, - vlan_tags) + bridge_index) if self.ovs_flows.get(bridge): continue diff --git a/ovn_bgp_agent/drivers/openstack/utils/evpn.py b/ovn_bgp_agent/drivers/openstack/utils/evpn.py index 7ba06b9a..8efbf521 100644 --- a/ovn_bgp_agent/drivers/openstack/utils/evpn.py +++ b/ovn_bgp_agent/drivers/openstack/utils/evpn.py @@ -232,7 +232,7 @@ class VlanDev: # Add 169.254.x.x address to veth_vrf for ipv4 and ipv6 linux_net.ensure_arp_ndp_enabled_for_bridge( - self.veth_vrf, offset=int(self.vlan_tag), vlan_tag=self.vlan_tag + self.veth_vrf, offset=int(self.vlan_tag) ) # Configure mac on the veth interface to be the same on all hosts diff --git a/ovn_bgp_agent/drivers/openstack/utils/wire.py b/ovn_bgp_agent/drivers/openstack/utils/wire.py index 8c0724cc..76711a89 100644 --- a/ovn_bgp_agent/drivers/openstack/utils/wire.py +++ b/ovn_bgp_agent/drivers/openstack/utils/wire.py @@ -65,9 +65,13 @@ def _ensure_base_wiring_config_underlay(idl, ovs_idl, routing_tables): linux_net.ensure_vlan_device_for_network(bridge, vlan_tag) + linux_net.ensure_arp_ndp_enabled_for_bridge(bridge, + bridge_index, + vlan_tag) + linux_net.ensure_arp_ndp_enabled_for_bridge(bridge, - bridge_index, - vlan_tags) + bridge_index) + if not flows_info.get(bridge): mac = linux_net.get_interface_address(bridge) flows_info[bridge] = {'mac': mac, 'in_port': set()} diff --git a/ovn_bgp_agent/tests/unit/drivers/openstack/test_nb_ovn_bgp_driver.py b/ovn_bgp_agent/tests/unit/drivers/openstack/test_nb_ovn_bgp_driver.py index 88fec848..29b98d77 100644 --- a/ovn_bgp_agent/tests/unit/drivers/openstack/test_nb_ovn_bgp_driver.py +++ b/ovn_bgp_agent/tests/unit/drivers/openstack/test_nb_ovn_bgp_driver.py @@ -208,8 +208,10 @@ class TestNBOVNBGPDriver(test_base.TestCase): mock_ensure_br.assert_has_calls(expected_calls) expected_calls = [mock.call('bridge0', 10), mock.call('bridge1', 11)] mock_ensure_vlan_network.assert_has_calls(expected_calls) - expected_calls = [mock.call('bridge0', 1, [10]), - mock.call('bridge1', 2, [11])] + expected_calls = [mock.call('bridge0', 1, 10), + mock.call('bridge0', 1), + mock.call('bridge1', 2, 11), + mock.call('bridge1', 2)] mock_ensure_arp.assert_has_calls(expected_calls) expected_calls = [ mock.call('bridge0'), mock.call('bridge1')] diff --git a/ovn_bgp_agent/tests/unit/drivers/openstack/test_ovn_bgp_driver.py b/ovn_bgp_agent/tests/unit/drivers/openstack/test_ovn_bgp_driver.py index 6d739062..cdaef6e5 100644 --- a/ovn_bgp_agent/tests/unit/drivers/openstack/test_ovn_bgp_driver.py +++ b/ovn_bgp_agent/tests/unit/drivers/openstack/test_ovn_bgp_driver.py @@ -145,8 +145,10 @@ class TestOVNBGPDriver(test_base.TestCase): self.bgp_driver.sync() - expected_calls = [mock.call('bridge0', 1, [10]), - mock.call('bridge1', 2, [11])] + expected_calls = [mock.call('bridge0', 1, 10), + mock.call('bridge0', 1), + mock.call('bridge1', 2, 11), + mock.call('bridge1', 2)] mock_ensure_arp.assert_has_calls(expected_calls) expected_calls = [mock.call('bridge0'), mock.call('bridge1')] diff --git a/ovn_bgp_agent/tests/unit/drivers/openstack/utils/test_evpn.py b/ovn_bgp_agent/tests/unit/drivers/openstack/utils/test_evpn.py index 5df3d993..7d90d7b0 100644 --- a/ovn_bgp_agent/tests/unit/drivers/openstack/utils/test_evpn.py +++ b/ovn_bgp_agent/tests/unit/drivers/openstack/utils/test_evpn.py @@ -302,7 +302,7 @@ class TestEVPN(test_base.TestCase): linux_net.set_master_for_device.assert_called_once_with(self.veth_vrf, self.vrf_name) linux_net.ensure_arp_ndp_enabled_for_bridge.assert_called_once_with( - self.veth_vrf, offset=vlan_tag, vlan_tag=vlan_tag_str) + self.veth_vrf, offset=vlan_tag) linux_net.enable_routing_for_interfaces.assert_called_once_with( self.veth_vrf, 'br-100') diff --git a/ovn_bgp_agent/tests/unit/utils/test_linux_net.py b/ovn_bgp_agent/tests/unit/utils/test_linux_net.py index d9951988..1e31380e 100644 --- a/ovn_bgp_agent/tests/unit/utils/test_linux_net.py +++ b/ovn_bgp_agent/tests/unit/utils/test_linux_net.py @@ -160,8 +160,8 @@ class TestLinuxNet(test_base.TestCase): linux_net.ensure_arp_ndp_enabled_for_bridge('fake-bridge', 511) # NOTE(ltomasbo): hardoced starting ipv4 is 192.168.0.0, and ipv6 is # fd53:d91e:400:7f17::0 - ipv4 = '169.254.1.255' # base + 511 offset - ipv6 = 'fd53:d91e:400:7f17::1ff' # base + 5122 offset (to hex) + ipv4 = '169.254.255.255' # base + 511 offset + ipv6 = 'fd53:d91e:400:7f17::1ff:1ff' # base + 5122 offset (to hex) calls = [mock.call(ipv4, 'fake-bridge'), mock.call(ipv6, 'fake-bridge')] mock_add_ip_to_dev.assert_has_calls(calls) @@ -176,13 +176,13 @@ class TestLinuxNet(test_base.TestCase): linux_net.ensure_arp_ndp_enabled_for_bridge('fake-bridge', 511, 11) # NOTE(ltomasbo): hardoced starting ipv4 is 192.168.0.0, and ipv6 is # fd53:d91e:400:7f17::0 - ipv4 = '169.254.1.255' # base + 511 offset - ipv6 = 'fd53:d91e:400:7f17::1ff' # base + 5122 offset (to hex) - calls = [mock.call(ipv4, 'fake-bridge'), - mock.call(ipv6, 'fake-bridge')] + ipv4 = '169.254.255.11' # base + 511 offset + ipv6 = 'fd53:d91e:400:7f17::1ff:b' # base + 5122 offset (to hex) + calls = [mock.call(ipv4, 'fake-bridg.11'), + mock.call(ipv6, 'fake-bridg.11')] mock_add_ip_to_dev.assert_has_calls(calls) - mock_ndp.assert_called_once_with('fake-bridge') - mock_arp.assert_called_once_with('fake-bridge') + mock_ndp.assert_called_once_with('fake-bridg/11') + mock_arp.assert_called_once_with('fake-bridg/11') @mock.patch.object(linux_net, 'enable_proxy_arp') @mock.patch.object(linux_net, 'enable_proxy_ndp') diff --git a/ovn_bgp_agent/utils/linux_net.py b/ovn_bgp_agent/utils/linux_net.py index 0694b074..204eacb4 100644 --- a/ovn_bgp_agent/utils/linux_net.py +++ b/ovn_bgp_agent/utils/linux_net.py @@ -136,25 +136,37 @@ def delete_device(device): def ensure_arp_ndp_enabled_for_bridge(bridge, offset, vlan_tag=None): + + if vlan_tag: + device_name = '{}.{}'.format( + bridge[:constants.OVN_VLAN_DEVICE_MAX_LENGTH], + vlan_tag + ) + device_index = vlan_tag % constants.IPV4_OCTET_RANGE + + else: + device_name = bridge[:n_const.DEVICE_NAME_MAX_LEN] + device_index = offset + ipv4 = "%s%d.%s" % ( - constants.ARP_IPV4_PREFIX, offset / constants.IPV4_OCTET_RANGE, - offset % constants.IPV4_OCTET_RANGE) - ipv6 = "%s%x" % (constants.NDP_IPV6_PREFIX, offset) + constants.ARP_IPV4_PREFIX, offset % constants.IPV4_OCTET_RANGE, + device_index % constants.IPV4_OCTET_RANGE) + ipv6 = "%s%x:%x" % (constants.NDP_IPV6_PREFIX, offset, device_index) for ip in (ipv4, ipv6): try: - ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ip, bridge) + ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ip, device_name) except agent_exc.IpAddressAlreadyExists: - LOG.debug("IP %s already added on bridge %s", ip, bridge) + LOG.debug("IP %s already added on device %s", ip, device_name) except KeyError as e: if "object exists" not in str(e): - LOG.error("Unable to add IP on bridge %s to enable arp/ndp. " - "Exception: %s", bridge, e) + LOG.error("Unable to add IP on device %s to enable arp/ndp. " + "Exception: %s", device_name, e) raise - # also enable the arp/ndp on the bridge in case there are flat networks - enable_proxy_arp(bridge) - enable_proxy_ndp(bridge) + # also enable the arp/ndp on the device + enable_proxy_arp(device_name.replace('.', '/')) + enable_proxy_ndp(device_name.replace('.', '/')) def ensure_anycast_mac_for_interface(intf, offset): diff --git a/releasenotes/notes/enable_arp_ndp_for_vlans-6c306601aba68cb4.yaml b/releasenotes/notes/enable_arp_ndp_for_vlans-6c306601aba68cb4.yaml new file mode 100644 index 00000000..6ce04e3c --- /dev/null +++ b/releasenotes/notes/enable_arp_ndp_for_vlans-6c306601aba68cb4.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + Loopback IP addresses for provider bridge interfaces will be changed + with upgrade. This should have no impact on environments. +fixes: + - | + ARP/NDP are now will be enabled not only for the provider bridge itself, + but also for VLAN interfaces in case VLANs are being used as provider + networks instead of FLAT.