diff --git a/doc/source/contributor/internals/openvswitch_firewall.rst b/doc/source/contributor/internals/openvswitch_firewall.rst index e98c10bc096..44b03dab2bc 100644 --- a/doc/source/contributor/internals/openvswitch_firewall.rst +++ b/doc/source/contributor/internals/openvswitch_firewall.rst @@ -525,6 +525,19 @@ will be: table=94, priority=10,reg6=0x284,dl_src=fa:16:3e:24:57:c7,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=push_vlan:0x8100,set_field:0x1->vlan_vid,output:3 table=94, priority=1 actions=NORMAL +The OVS firewall will initialize a default goto table 94 flow +on TRANSIENT_TABLE |table_60|, if ``explicitly_egress_direct`` +is set to True, which is mainly for ports without security groups +and disabled port_security. For instance: + +:: + table=60, priority=2 actions=resubmit(,94) + +Then for packets from the outside to VM without security functionalities +(--disable-port-security --no-security-group) +will go to table 94 and do the same direct actions. + + OVS firewall integration points ------------------------------- diff --git a/neutron/agent/linux/openvswitch_firewall/firewall.py b/neutron/agent/linux/openvswitch_firewall/firewall.py index 4bc8fe9c39d..8e7c3f5df8e 100644 --- a/neutron/agent/linux/openvswitch_firewall/firewall.py +++ b/neutron/agent/linux/openvswitch_firewall/firewall.py @@ -646,6 +646,14 @@ class OVSFirewallDriver(firewall.FirewallDriver): 'resubmit(,%d)' % ovs_consts.BASE_EGRESS_TABLE, ) + if cfg.CONF.AGENT.explicitly_egress_direct: + self._add_flow( + table=ovs_consts.TRANSIENT_TABLE, + priority=2, + actions='resubmit(,%d)' % ( + ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE) + ) + def _initialize_third_party_tables(self): self.int_br.br.add_flow( table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, @@ -1255,6 +1263,7 @@ class OVSFirewallDriver(firewall.FirewallDriver): return # Prevent flood for accepted egress traffic + # For packets from internal ports or VM ports. self._add_flow( flow_group_id=dst_port, table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, @@ -1263,6 +1272,15 @@ class OVSFirewallDriver(firewall.FirewallDriver): reg_net=vlan_tag, actions='output:{:d}'.format(dst_port) ) + # For packets from patch ports. + self._add_flow( + flow_group_id=dst_port, + table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, + priority=12, + dl_dst=mac, + dl_vlan=vlan_tag, + actions='strip_vlan,output:{:d}'.format(dst_port) + ) # The former flow may not match, that means the destination port is # not in this host. So, we direct the packet to mapped bridge(s). @@ -1311,6 +1329,12 @@ class OVSFirewallDriver(firewall.FirewallDriver): dl_src=mac, reg_net=vlan_tag) + self._delete_flows( + table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, + dl_dst=mac, + dl_vlan=vlan_tag + ) + def _initialize_tracked_egress(self, port): # Drop invalid packets self._add_flow( diff --git a/neutron/conf/plugins/ml2/drivers/ovs_conf.py b/neutron/conf/plugins/ml2/drivers/ovs_conf.py index c05a895b38f..8cf3075d3aa 100644 --- a/neutron/conf/plugins/ml2/drivers/ovs_conf.py +++ b/neutron/conf/plugins/ml2/drivers/ovs_conf.py @@ -222,12 +222,16 @@ agent_opts = [ "outgoing IP packet carrying GRE/VXLAN tunnel.")), cfg.BoolOpt('baremetal_smartnic', default=False, help=_("Enable the agent to process Smart NIC ports.")), + # TODO(liuyulong): consider adding a new configuration + # item to control ingress behavior. cfg.BoolOpt('explicitly_egress_direct', default=False, help=_("When set to True, the accepted egress unicast " "traffic will not use action NORMAL. The accepted " "egress packets will be taken care of in the final " "egress tables direct output flows for unicast " - "traffic.")), + "traffic. This will aslo change the pipleline for " + "ingress traffic to ports without security, the final " + "output action will be hit in table 94. ")), ] dhcp_opts = [ 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 181ae62d3c8..550c5a1c05e 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 @@ -64,7 +64,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge, self.install_goto(dest_table_id=PACKET_RATE_LIMIT) self.install_goto(dest_table_id=constants.TRANSIENT_TABLE, table_id=PACKET_RATE_LIMIT) - self.install_normal(table_id=constants.TRANSIENT_TABLE, priority=3) + self.install_normal(table_id=constants.TRANSIENT_TABLE, priority=1) self.init_dhcp(enable_openflow_dhcp=enable_openflow_dhcp, enable_dhcpv6=enable_dhcpv6) self.install_drop(table_id=constants.ARP_SPOOF_TABLE) diff --git a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py index af1fbe69b2e..ee3359e98be 100644 --- a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py +++ b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py @@ -919,8 +919,13 @@ class TestOVSFirewallDriver(base.BaseTestCase): "reg6": port.vlan_tag} flow7 = mock.call(**call_args7) + call_args8 = {"table": ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, + "dl_dst": port.mac, + "dl_vlan": port.vlan_tag} + flow8 = mock.call(**call_args8) + self.mock_bridge.br.delete_flows.assert_has_calls( - [flow1, flow2, flow3, flow6, flow7, flow4, flow5]) + [flow1, flow2, flow3, flow6, flow7, flow8, flow4, flow5]) def test_prepare_port_filter_initialized_port(self): port_dict = {'device': 'port-id', 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 5c4be724397..400895ea359 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 @@ -75,7 +75,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): ]), ], match=ofpp.OFPMatch(), - priority=3, + priority=1, table_id=ovs_constants.TRANSIENT_TABLE), active_bundle=None), call._send_msg(ofpp.OFPFlowMod(dp,