Add a default goto table=94 for openvswitch fw

If enable explicitly_egress_direct=True and set port as
no security group and port_security=False, the ingress
flood will reappear. The pipleline is:
Ingress
table_0 -> table_60 -> NORMAL -> VM
Egress
table_0 -> ... -> table_94 -> output

Because ingress final action is normal, the br-int will learn the
source MAC, but egress final action is output. So VM's mac will
never be learnt by the br-int. Then ingress flood comes again.

This patch adds a default direct flow to table 94 during the
openflow security group init and explicitly_egress_direct=True, then
the pipleline will be:
Ingress
table_0 -> table_60 -> table_94 -> output VM
Egress
table_0 -> ... -> table_94 -> output

And this patch adds the flows coming from patch port which will
match local vlan then go to table 94 do the same direct actions.

Above flood issue will be addressed by these flows.

Closes-Bug: #2051351
Change-Id: Ia61784174ee610b338f26660b2954330abc131a1
This commit is contained in:
LIU Yulong 2022-01-27 17:01:43 +08:00
parent 484b04cf01
commit d6f56c5f96
6 changed files with 50 additions and 4 deletions

View File

@ -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
-------------------------------

View File

@ -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(

View File

@ -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 = [

View File

@ -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)

View File

@ -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',

View File

@ -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,