diff --git a/doc/source/contributor/internals/openvswitch_firewall.rst b/doc/source/contributor/internals/openvswitch_firewall.rst index 5332986552e..ecf744d3d25 100644 --- a/doc/source/contributor/internals/openvswitch_firewall.rst +++ b/doc/source/contributor/internals/openvswitch_firewall.rst @@ -208,9 +208,11 @@ the second security group. Ports have following attributes: Port 3 - patch bridge port (e.g. patch-tun) in OVS bridge -|table_0| contains a low priority rule to continue packets processing in -|table_60| aka TRANSIENT table. |table_0| is left for use to other -features that take precedence over firewall, e.g. DVR. The only requirement is +|table_0| - |table_59| contain some low priority rules to continue packets +processing in |table_60| aka TRANSIENT table. |table_0| - |table_59| is +left for use to other features that take precedence over firewall, e.g. +DVR, ARP poison/spoofing prevention, MAC spoof filtering and packet rate +limitation etc. The only requirement is that after such a feature is done with its processing, it needs to pass packets for processing to the TRANSIENT table. This TRANSIENT table distinguishes the ingress traffic from the egress traffic and loads into ``register 5`` a value @@ -592,6 +594,7 @@ switched to the OVS driver. not work if one tries to replace openvswitch firewall with iptables. .. |table_0| replace:: ``table 0`` (LOCAL_SWITCHING) +.. |table_59| replace:: ``table 59`` (PACKET_RATE_LIMIT) .. |table_60| replace:: ``table 60`` (TRANSIENT) .. |table_71| replace:: ``table 71`` (BASE_EGRESS) .. |table_72| replace:: ``table 72`` (RULES_EGRESS) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py index 9f9bd4031dc..7fc7a3732cb 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py @@ -60,6 +60,8 @@ MAC_SPOOF_TABLE = 25 LOCAL_EGRESS_TABLE = 30 LOCAL_IP_TABLE = 31 +# packet rate limit table +PACKET_RATE_LIMIT = 59 # Table to decide whether further filtering is needed TRANSIENT_TABLE = 60 LOCAL_MAC_DIRECT = 61 @@ -100,6 +102,7 @@ INT_BR_ALL_TABLES = ( LOCAL_MAC_DIRECT, LOCAL_EGRESS_TABLE, LOCAL_IP_TABLE, + PACKET_RATE_LIMIT, TRANSIENT_TABLE, TRANSIENT_EGRESS_TABLE, BASE_EGRESS_TABLE, diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_dvr_process.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_dvr_process.py index 204fb956f7a..c447be76d61 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_dvr_process.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_dvr_process.py @@ -53,7 +53,7 @@ class OVSDVRInterfaceMixin(object): ] instructions = [ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions), - ofpp.OFPInstructionGotoTable(table_id=constants.TRANSIENT_TABLE)] + ofpp.OFPInstructionGotoTable(table_id=constants.PACKET_RATE_LIMIT)] self.install_instructions(table_id=constants.LOCAL_SWITCHING, priority=99, diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py index 73ada8e40de..6620e2fcf6a 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py @@ -53,7 +53,9 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, enable_dhcpv6=False): (_dp, ofp, ofpp) = self._get_dp() self.setup_canary_table() - self.install_goto(dest_table_id=constants.TRANSIENT_TABLE) + self.install_goto(dest_table_id=constants.PACKET_RATE_LIMIT) + self.install_goto(dest_table_id=constants.TRANSIENT_TABLE, + table_id=constants.PACKET_RATE_LIMIT) self.install_normal(table_id=constants.TRANSIENT_TABLE, priority=3) self.init_dhcp(enable_openflow_dhcp=enable_openflow_dhcp, enable_dhcpv6=enable_dhcpv6) @@ -69,9 +71,9 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, priority=3) # Local IP defaults - self.install_goto(dest_table_id=constants.TRANSIENT_TABLE, + self.install_goto(dest_table_id=constants.PACKET_RATE_LIMIT, table_id=constants.LOCAL_EGRESS_TABLE) - self.install_goto(dest_table_id=constants.TRANSIENT_TABLE, + self.install_goto(dest_table_id=constants.PACKET_RATE_LIMIT, table_id=constants.LOCAL_IP_TABLE) def init_dhcp(self, enable_openflow_dhcp=False, enable_dhcpv6=False): @@ -184,7 +186,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, ] instructions = [ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions), - ofpp.OFPInstructionGotoTable(table_id=constants.TRANSIENT_TABLE), + ofpp.OFPInstructionGotoTable(table_id=constants.PACKET_RATE_LIMIT), ] self.install_instructions( instructions=instructions, @@ -265,7 +267,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, ] instructions = [ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions), - ofpp.OFPInstructionGotoTable(table_id=constants.TRANSIENT_TABLE), + ofpp.OFPInstructionGotoTable(table_id=constants.PACKET_RATE_LIMIT), ] self.install_instructions(table_id=table_id, priority=20, @@ -366,7 +368,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, ip_proto=in_proto.IPPROTO_ICMPV6, icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT, ipv6_nd_target=masked_ip, in_port=port, - dest_table_id=constants.TRANSIENT_TABLE) + dest_table_id=constants.PACKET_RATE_LIMIT) # Now that the rules are ready, direct icmpv6 neighbor advertisement # traffic from the port into the anti-spoof table. @@ -522,7 +524,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, def install_garp_blocker_exception(self, vlan, ip, except_ip, table_id=constants.LOCAL_SWITCHING): match = self._garp_blocker_exception_match(vlan, ip, except_ip) - self.install_goto(dest_table_id=constants.TRANSIENT_TABLE, + self.install_goto(dest_table_id=constants.PACKET_RATE_LIMIT, table_id=table_id, priority=11, match=match) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py index cdd7f162c93..f7e289e0f24 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py @@ -47,12 +47,21 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): call._send_msg(ofpp.OFPFlowMod(dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch(), priority=0, table_id=0), active_bundle=None), + call._send_msg(ofpp.OFPFlowMod(dp, + cookie=self.stamp, + instructions=[ + ofpp.OFPInstructionGotoTable(table_id=60), + ], + match=ofpp.OFPMatch(), + priority=0, + table_id=59), + active_bundle=None), call._send_msg(ofpp.OFPFlowMod(dp, cookie=self.stamp, instructions=[ @@ -130,7 +139,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): call._send_msg(ofpp.OFPFlowMod( dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch(), priority=0, @@ -139,7 +148,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): call._send_msg(ofpp.OFPFlowMod( dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch(), priority=0, @@ -163,7 +172,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ofpp.OFPActionSetField( vlan_vid=lvid | ofp.OFPVID_PRESENT), ]), - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( in_port=port, @@ -190,7 +199,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ofpp.OFPActionSetField( vlan_vid=lvid | ofp.OFPVID_PRESENT), ]), - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( in_port=port, @@ -246,7 +255,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField(eth_src=gateway_mac), ]), - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( eth_dst=dst_mac, @@ -316,7 +325,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField(eth_src=gateway_mac), ]), - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( eth_dst=dst_mac, @@ -359,7 +368,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField(eth_src=gateway_mac), ]), - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( eth_dst=dst_mac, @@ -502,7 +511,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): call._send_msg(ofpp.OFPFlowMod(dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( eth_type=self.ether_types.ETH_TYPE_IPV6, @@ -517,7 +526,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): call._send_msg(ofpp.OFPFlowMod(dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60), + ofpp.OFPInstructionGotoTable(table_id=59), ], match=ofpp.OFPMatch( eth_type=self.ether_types.ETH_TYPE_IPV6, @@ -768,7 +777,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): expected = [ call._send_msg(ofpp.OFPFlowMod(dp, cookie=self.stamp, instructions=[ - ofpp.OFPInstructionGotoTable(table_id=60)], + ofpp.OFPInstructionGotoTable(table_id=59)], match=ofpp.OFPMatch( vlan_vid=vlan | ofp.OFPVID_PRESENT, eth_type=self.ether_types.ETH_TYPE_ARP,