[ML2/OVS] Maintain learning OF rules for GARP/ND in br-tun
This patch adds 3 new OF rules in the br-tun bridge to learn with higher priority GARP/ND packets which are sent during e.g. failover. With those rules, packets will not be send to the old VXLAN tunnels after failover as GARP/ND packets sent will force to learn new tunnels for the MAC address. Closes-bug: #2123911 Change-Id: I6e74214908e70e3a35af266dee524d6cf90bad42 Signed-off-by: Slawek Kaplonski <skaplons@redhat.com>
This commit is contained in:
@@ -15,8 +15,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from neutron_lib import constants as lib_constants
|
||||||
from neutron_lib.plugins.ml2 import ovs_constants as constants
|
from neutron_lib.plugins.ml2 import ovs_constants as constants
|
||||||
from os_ken.lib.packet import ether_types
|
from os_ken.lib.packet import ether_types
|
||||||
|
from os_ken.lib.packet import icmpv6
|
||||||
|
from os_ken.lib.packet import in_proto
|
||||||
|
|
||||||
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
|
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
|
||||||
import br_dvr_process
|
import br_dvr_process
|
||||||
@@ -33,6 +36,62 @@ class OVSTunnelBridge(ovs_bridge.OVSAgentBridge,
|
|||||||
dvr_process_next_table_id = constants.PATCH_LV_TO_TUN
|
dvr_process_next_table_id = constants.PATCH_LV_TO_TUN
|
||||||
of_tables = constants.TUN_BR_ALL_TABLES
|
of_tables = constants.TUN_BR_ALL_TABLES
|
||||||
|
|
||||||
|
def _setup_learn_flows(self, ofpp, patch_int_ofport):
|
||||||
|
flow_specs = [
|
||||||
|
ofpp.NXFlowSpecMatch(src=('vlan_tci', 0),
|
||||||
|
dst=('vlan_tci', 0),
|
||||||
|
n_bits=12),
|
||||||
|
ofpp.NXFlowSpecMatch(src=('eth_src', 0),
|
||||||
|
dst=('eth_dst', 0),
|
||||||
|
n_bits=48),
|
||||||
|
ofpp.NXFlowSpecLoad(src=0,
|
||||||
|
dst=('vlan_tci', 0),
|
||||||
|
n_bits=16),
|
||||||
|
ofpp.NXFlowSpecLoad(src=('tunnel_id', 0),
|
||||||
|
dst=('tunnel_id', 0),
|
||||||
|
n_bits=64),
|
||||||
|
ofpp.NXFlowSpecOutput(src=('in_port', 0),
|
||||||
|
dst='',
|
||||||
|
n_bits=32),
|
||||||
|
]
|
||||||
|
actions = [
|
||||||
|
ofpp.NXActionLearn(table_id=constants.UCAST_TO_TUN,
|
||||||
|
cookie=self.default_cookie,
|
||||||
|
priority=1,
|
||||||
|
hard_timeout=300,
|
||||||
|
specs=flow_specs),
|
||||||
|
ofpp.OFPActionOutput(patch_int_ofport, 0),
|
||||||
|
]
|
||||||
|
|
||||||
|
arp_match = ofpp.OFPMatch(
|
||||||
|
eth_type=ether_types.ETH_TYPE_ARP,
|
||||||
|
arp_tha=lib_constants.BROADCAST_MAC
|
||||||
|
)
|
||||||
|
ipv6_ra_match = ofpp.OFPMatch(
|
||||||
|
eth_type=ether_types.ETH_TYPE_IPV6,
|
||||||
|
ip_proto=in_proto.IPPROTO_ICMPV6,
|
||||||
|
icmpv6_type=icmpv6.ND_ROUTER_ADVERT) # icmp_type=134
|
||||||
|
ipv6_na_match = ofpp.OFPMatch(
|
||||||
|
eth_type=ether_types.ETH_TYPE_IPV6,
|
||||||
|
ip_proto=in_proto.IPPROTO_ICMPV6,
|
||||||
|
icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT) # icmp_type=136
|
||||||
|
|
||||||
|
self.install_apply_actions(table_id=constants.LEARN_FROM_TUN,
|
||||||
|
priority=2,
|
||||||
|
match=arp_match,
|
||||||
|
actions=actions)
|
||||||
|
self.install_apply_actions(table_id=constants.LEARN_FROM_TUN,
|
||||||
|
priority=2,
|
||||||
|
match=ipv6_ra_match,
|
||||||
|
actions=actions)
|
||||||
|
self.install_apply_actions(table_id=constants.LEARN_FROM_TUN,
|
||||||
|
priority=2,
|
||||||
|
match=ipv6_na_match,
|
||||||
|
actions=actions)
|
||||||
|
self.install_apply_actions(table_id=constants.LEARN_FROM_TUN,
|
||||||
|
priority=1,
|
||||||
|
actions=actions)
|
||||||
|
|
||||||
def setup_default_table(
|
def setup_default_table(
|
||||||
self, patch_int_ofport, arp_responder_enabled, dvr_enabled):
|
self, patch_int_ofport, arp_responder_enabled, dvr_enabled):
|
||||||
(dp, ofp, ofpp) = self._get_dp()
|
(dp, ofp, ofpp) = self._get_dp()
|
||||||
@@ -81,34 +140,7 @@ class OVSTunnelBridge(ovs_bridge.OVSAgentBridge,
|
|||||||
# dynamically set-up flows in UCAST_TO_TUN corresponding to remote mac
|
# dynamically set-up flows in UCAST_TO_TUN corresponding to remote mac
|
||||||
# addresses (assumes that lvid has already been set by a previous flow)
|
# addresses (assumes that lvid has already been set by a previous flow)
|
||||||
# Once remote mac addresses are learnt, output packet to patch_int
|
# Once remote mac addresses are learnt, output packet to patch_int
|
||||||
flow_specs = [
|
self._setup_learn_flows(ofpp, patch_int_ofport)
|
||||||
ofpp.NXFlowSpecMatch(src=('vlan_tci', 0),
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=12),
|
|
||||||
ofpp.NXFlowSpecMatch(src=('eth_src', 0),
|
|
||||||
dst=('eth_dst', 0),
|
|
||||||
n_bits=48),
|
|
||||||
ofpp.NXFlowSpecLoad(src=0,
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=16),
|
|
||||||
ofpp.NXFlowSpecLoad(src=('tunnel_id', 0),
|
|
||||||
dst=('tunnel_id', 0),
|
|
||||||
n_bits=64),
|
|
||||||
ofpp.NXFlowSpecOutput(src=('in_port', 0),
|
|
||||||
dst='',
|
|
||||||
n_bits=32),
|
|
||||||
]
|
|
||||||
actions = [
|
|
||||||
ofpp.NXActionLearn(table_id=constants.UCAST_TO_TUN,
|
|
||||||
cookie=self.default_cookie,
|
|
||||||
priority=1,
|
|
||||||
hard_timeout=300,
|
|
||||||
specs=flow_specs),
|
|
||||||
ofpp.OFPActionOutput(patch_int_ofport, 0),
|
|
||||||
]
|
|
||||||
self.install_apply_actions(table_id=constants.LEARN_FROM_TUN,
|
|
||||||
priority=1,
|
|
||||||
actions=actions)
|
|
||||||
|
|
||||||
# Egress unicast will be handled in table UCAST_TO_TUN, where remote
|
# Egress unicast will be handled in table UCAST_TO_TUN, where remote
|
||||||
# mac addresses will be learned. For now, just add a default flow that
|
# mac addresses will be learned. For now, just add a default flow that
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from neutron_lib import constants as lib_constants
|
||||||
from neutron_lib.plugins.ml2 import ovs_constants as ovs_const
|
from neutron_lib.plugins.ml2 import ovs_constants as ovs_const
|
||||||
|
|
||||||
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.openflow.native \
|
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.openflow.native \
|
||||||
@@ -48,6 +49,73 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||||||
self.setup_bridge_mock('br-tun', self.br_tun_cls)
|
self.setup_bridge_mock('br-tun', self.br_tun_cls)
|
||||||
self.stamp = self.br.default_cookie
|
self.stamp = self.br.default_cookie
|
||||||
|
|
||||||
|
def _get_learn_flows(self, ofpp, patch_int_ofport):
|
||||||
|
(dp, ofp, ofpp) = self._get_dp()
|
||||||
|
# flows_data is list of tuples (priority, match)
|
||||||
|
flows_data = [
|
||||||
|
(2, ofpp.OFPMatch(
|
||||||
|
eth_type=self.ether_types.ETH_TYPE_ARP,
|
||||||
|
arp_tha=lib_constants.BROADCAST_MAC
|
||||||
|
)),
|
||||||
|
(2, ofpp.OFPMatch(
|
||||||
|
eth_type=self.ether_types.ETH_TYPE_IPV6,
|
||||||
|
ip_proto=self.in_proto.IPPROTO_ICMPV6,
|
||||||
|
icmpv6_type=self.icmpv6.ND_ROUTER_ADVERT
|
||||||
|
)),
|
||||||
|
(2, ofpp.OFPMatch(
|
||||||
|
eth_type=self.ether_types.ETH_TYPE_IPV6,
|
||||||
|
ip_proto=self.in_proto.IPPROTO_ICMPV6,
|
||||||
|
icmpv6_type=self.icmpv6.ND_NEIGHBOR_ADVERT
|
||||||
|
)),
|
||||||
|
(1, ofpp.OFPMatch())
|
||||||
|
]
|
||||||
|
learn_flows = []
|
||||||
|
for priority, match in flows_data:
|
||||||
|
learn_flows.append(
|
||||||
|
call._send_msg(
|
||||||
|
ofpp.OFPFlowMod(
|
||||||
|
dp,
|
||||||
|
cookie=self.stamp,
|
||||||
|
instructions=[
|
||||||
|
ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
|
||||||
|
ofpp.NXActionLearn(
|
||||||
|
cookie=self.stamp,
|
||||||
|
hard_timeout=300,
|
||||||
|
priority=1,
|
||||||
|
specs=[
|
||||||
|
ofpp.NXFlowSpecMatch(
|
||||||
|
dst=('vlan_tci', 0),
|
||||||
|
n_bits=12,
|
||||||
|
src=('vlan_tci', 0)),
|
||||||
|
ofpp.NXFlowSpecMatch(
|
||||||
|
dst=('eth_dst', 0),
|
||||||
|
n_bits=48,
|
||||||
|
src=('eth_src', 0)),
|
||||||
|
ofpp.NXFlowSpecLoad(
|
||||||
|
dst=('vlan_tci', 0),
|
||||||
|
n_bits=16,
|
||||||
|
src=0),
|
||||||
|
ofpp.NXFlowSpecLoad(
|
||||||
|
dst=('tunnel_id', 0),
|
||||||
|
n_bits=64,
|
||||||
|
src=('tunnel_id', 0)),
|
||||||
|
ofpp.NXFlowSpecOutput(
|
||||||
|
dst='',
|
||||||
|
n_bits=32,
|
||||||
|
src=('in_port', 0)),
|
||||||
|
],
|
||||||
|
table_id=20),
|
||||||
|
ofpp.OFPActionOutput(patch_int_ofport, 0),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
match=match,
|
||||||
|
priority=priority,
|
||||||
|
table_id=10),
|
||||||
|
active_bundle=None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return learn_flows
|
||||||
|
|
||||||
def test_setup_default_table(self):
|
def test_setup_default_table(self):
|
||||||
patch_int_ofport = 5555
|
patch_int_ofport = 5555
|
||||||
arp_responder_enabled = False
|
arp_responder_enabled = False
|
||||||
@@ -110,47 +178,9 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||||||
instructions=[],
|
instructions=[],
|
||||||
match=ofpp.OFPMatch(),
|
match=ofpp.OFPMatch(),
|
||||||
priority=0, table_id=6),
|
priority=0, table_id=6),
|
||||||
active_bundle=None),
|
active_bundle=None)]
|
||||||
call._send_msg(
|
expected += self._get_learn_flows(ofpp, patch_int_ofport)
|
||||||
ofpp.OFPFlowMod(
|
expected += [
|
||||||
dp,
|
|
||||||
cookie=self.stamp,
|
|
||||||
instructions=[
|
|
||||||
ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
|
|
||||||
ofpp.NXActionLearn(
|
|
||||||
cookie=self.stamp,
|
|
||||||
hard_timeout=300,
|
|
||||||
priority=1,
|
|
||||||
specs=[
|
|
||||||
ofpp.NXFlowSpecMatch(
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=12,
|
|
||||||
src=('vlan_tci', 0)),
|
|
||||||
ofpp.NXFlowSpecMatch(
|
|
||||||
dst=('eth_dst', 0),
|
|
||||||
n_bits=48,
|
|
||||||
src=('eth_src', 0)),
|
|
||||||
ofpp.NXFlowSpecLoad(
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=16,
|
|
||||||
src=0),
|
|
||||||
ofpp.NXFlowSpecLoad(
|
|
||||||
dst=('tunnel_id', 0),
|
|
||||||
n_bits=64,
|
|
||||||
src=('tunnel_id', 0)),
|
|
||||||
ofpp.NXFlowSpecOutput(
|
|
||||||
dst='',
|
|
||||||
n_bits=32,
|
|
||||||
src=('in_port', 0)),
|
|
||||||
],
|
|
||||||
table_id=20),
|
|
||||||
ofpp.OFPActionOutput(patch_int_ofport, 0),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
match=ofpp.OFPMatch(),
|
|
||||||
priority=1,
|
|
||||||
table_id=10),
|
|
||||||
active_bundle=None),
|
|
||||||
call._send_msg(
|
call._send_msg(
|
||||||
ofpp.OFPFlowMod(dp,
|
ofpp.OFPFlowMod(dp,
|
||||||
cookie=self.stamp,
|
cookie=self.stamp,
|
||||||
@@ -243,47 +273,9 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||||||
instructions=[],
|
instructions=[],
|
||||||
match=ofpp.OFPMatch(),
|
match=ofpp.OFPMatch(),
|
||||||
priority=0, table_id=6),
|
priority=0, table_id=6),
|
||||||
active_bundle=None),
|
active_bundle=None)]
|
||||||
call._send_msg(
|
expected += self._get_learn_flows(ofpp, patch_int_ofport)
|
||||||
ofpp.OFPFlowMod(
|
expected += [
|
||||||
dp,
|
|
||||||
cookie=self.stamp,
|
|
||||||
instructions=[
|
|
||||||
ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
|
|
||||||
ofpp.NXActionLearn(
|
|
||||||
cookie=self.stamp,
|
|
||||||
hard_timeout=300,
|
|
||||||
priority=1,
|
|
||||||
specs=[
|
|
||||||
ofpp.NXFlowSpecMatch(
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=12,
|
|
||||||
src=('vlan_tci', 0)),
|
|
||||||
ofpp.NXFlowSpecMatch(
|
|
||||||
dst=('eth_dst', 0),
|
|
||||||
n_bits=48,
|
|
||||||
src=('eth_src', 0)),
|
|
||||||
ofpp.NXFlowSpecLoad(
|
|
||||||
dst=('vlan_tci', 0),
|
|
||||||
n_bits=16,
|
|
||||||
src=0),
|
|
||||||
ofpp.NXFlowSpecLoad(
|
|
||||||
dst=('tunnel_id', 0),
|
|
||||||
n_bits=64,
|
|
||||||
src=('tunnel_id', 0)),
|
|
||||||
ofpp.NXFlowSpecOutput(
|
|
||||||
dst='',
|
|
||||||
n_bits=32,
|
|
||||||
src=('in_port', 0)),
|
|
||||||
],
|
|
||||||
table_id=20),
|
|
||||||
ofpp.OFPActionOutput(patch_int_ofport, 0),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
match=ofpp.OFPMatch(),
|
|
||||||
priority=1,
|
|
||||||
table_id=10),
|
|
||||||
active_bundle=None),
|
|
||||||
call._send_msg(
|
call._send_msg(
|
||||||
ofpp.OFPFlowMod(dp,
|
ofpp.OFPFlowMod(dp,
|
||||||
cookie=self.stamp,
|
cookie=self.stamp,
|
||||||
|
|||||||
Reference in New Issue
Block a user