Migrate portsec app to new framework

Change-Id: I5c76eabb9e15c628a6ca800123a135b7e1347c3f
Related-Bug: #1738986
Co-Authored-By: Lihi Wishnitzer <lihiwish@gmail.com>
This commit is contained in:
Dima Kuznetsov 2017-12-24 10:53:49 +02:00 committed by Omer Anson
parent b7eda732f5
commit e32364e80d
9 changed files with 88 additions and 68 deletions

View File

@ -18,7 +18,7 @@ OVS_BRANCH=${OVS_BRANCH:-branch-2.6}
EXTERNAL_HOST_IP=${EXTERNAL_HOST_IP:-}
DEFAULT_TUNNEL_TYPES="vxlan,geneve,gre"
DEFAULT_APPS_LIST="portbinding,l2,l3_proactive,dhcp,dnat,sg,portsec,portqos,classifier,tunneling,provider"
DEFAULT_APPS_LIST="portbinding,l2,l3_proactive,dhcp,dnat,sg,portqos,classifier,tunneling,provider"
if [[ $ENABLE_DF_SFC == "True" ]]; then
DEFAULT_APPS_LIST="$DEFAULT_APPS_LIST,fc,sfc"

View File

@ -35,7 +35,7 @@ class ClassifierApp(df_base_app.DFlowApp):
self.add_flow_go_to_table(
table=const.INGRESS_CLASSIFICATION_DISPATCH_TABLE,
priority=const.PRIORITY_DEFAULT,
goto_table_id=const.EGRESS_PORT_SECURITY_TABLE,
goto_table_id=self.dfdp.apps['portsec'].entrypoints.default,
)
@df_base_app.register_event(ovs.OvsPort, model_constants.EVENT_CREATED)

View File

@ -73,11 +73,6 @@ class L2App(df_base_app.DFlowApp):
const.PRIORITY_MEDIUM,
const.IPV6_ND_TABLE, match=match)
# Default: traffic => send to connection track table
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
const.PRIORITY_DEFAULT,
const.EGRESS_CONNTRACK_TABLE)
# Default: traffic => send to service classification table
self.add_flow_go_to_table(const.EGRESS_CONNTRACK_TABLE,
const.PRIORITY_DEFAULT,

View File

@ -203,15 +203,17 @@ class MetadataServiceApp(df_base_app.DFlowApp):
ip_proto=ipv4.inet.IPPROTO_TCP,
tcp_dst=const.METADATA_HTTP_PORT,
)
inst = [parser.OFPInstructionGotoTable(
const.SERVICES_CLASSIFICATION_TABLE)]
actions = [
parser.NXActionResubmitTable(
table_id=self.dfdp.apps['portsec'].exitpoints.services),
]
# Bypass the security group check for metadata request.
self.mod_flow(
table_id=const.EGRESS_PORT_SECURITY_TABLE,
table_id=self.dfdp.apps['portsec'].states.main,
command=ofproto.OFPFC_ADD,
priority=const.PRIORITY_VERY_HIGH,
match=match,
inst=inst)
actions=actions)
inst = self._get_incoming_flow_instructions(ofproto, parser)
self.mod_flow(

View File

@ -21,6 +21,7 @@ from ryu.lib.packet import arp
from ryu.lib.packet import in_proto
from ryu.ofproto import ether
from dragonflow.controller import app_base
from dragonflow.controller.common import constants as const
from dragonflow.controller.common import utils
from dragonflow.controller import df_base_app
@ -32,13 +33,42 @@ IPV4_SRC_MATCH_ITEM = 'ipv4_src'
IPV6_SRC_MATCH_ITEM = 'ipv6_src'
class PortSecApp(df_base_app.DFlowApp):
@app_base.define_specification(
states=('main',),
public_mapping=app_base.VariableMapping(
source_port_key='reg6',
),
entrypoints=(
app_base.Entrypoint(
name='default',
target='main',
consumes=(
'source_port_key',
),
),
),
exitpoints=(
app_base.Exitpoint(
name='default',
provides=(
'source_port_key',
),
),
app_base.Exitpoint(
name='services',
provides=(
'source_port_key',
),
),
),
)
class PortSecApp(app_base.Base):
def _add_flow_drop(self, priority, match):
drop_inst = None
self.mod_flow(
inst=drop_inst,
table_id=const.EGRESS_PORT_SECURITY_TABLE,
table_id=self.states.main,
priority=priority,
match=match)
@ -125,9 +155,9 @@ class PortSecApp(df_base_app.DFlowApp):
def _install_flows_check_valid_ip_and_mac(self, unique_key, ip, mac):
match = self._get_ip_match_obj(unique_key, mac, ip)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.EGRESS_CONNTRACK_TABLE,
self.exitpoints.default,
match=match)
ip_version = netaddr.IPAddress(ip).version
@ -136,9 +166,9 @@ class PortSecApp(df_base_app.DFlowApp):
match = self._get_arp_match_obj(unique_key, mac, ip)
else:
match = self._get_nd_match_object(unique_key, mac, ip)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.SERVICES_CLASSIFICATION_TABLE,
self.exitpoints.services,
match=match)
def _uninstall_flows_check_valid_ip_and_mac(self, unique_key, ip, mac):
@ -160,9 +190,9 @@ class PortSecApp(df_base_app.DFlowApp):
# Other packets with valid source mac pass
match = parser.OFPMatch(reg6=unique_key,
eth_src=mac)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_LOW,
const.SERVICES_CLASSIFICATION_TABLE,
self.exitpoints.services,
match=match)
def _uninstall_flows_check_valid_mac(self, unique_key, mac):
@ -184,9 +214,9 @@ class PortSecApp(df_base_app.DFlowApp):
udp_src=const.DHCP_CLIENT_PORT,
udp_dst=const.DHCP_SERVER_PORT)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.EGRESS_CONNTRACK_TABLE,
self.exitpoints.default,
match=match)
# DHCPv6 packets with the vm mac pass
@ -198,24 +228,24 @@ class PortSecApp(df_base_app.DFlowApp):
udp_src=const.DHCPV6_CLIENT_PORT,
udp_dst=const.DHCPV6_SERVER_PORT)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.EGRESS_CONNTRACK_TABLE,
self.exitpoints.default,
match=match)
# Arp probe packets with the vm mac pass
match = self._get_arp_match_obj(unique_key=unique_key,
mac=vm_mac,
arp_op=arp.ARP_REQUEST)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.SERVICES_CLASSIFICATION_TABLE,
self.exitpoints.services,
match=match)
match = self._get_nd_match_object(unique_key, vm_mac)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.SERVICES_CLASSIFICATION_TABLE,
self.exitpoints.services,
match=match)
def _uninstall_flows_check_only_vm_mac(self, unique_key, vm_mac):
@ -302,7 +332,7 @@ class PortSecApp(df_base_app.DFlowApp):
def _remove_one_port_security_flow(self, priority, match):
ofproto = self.ofproto
self.mod_flow(table_id=const.EGRESS_PORT_SECURITY_TABLE,
self.mod_flow(table_id=self.states.main,
priority=priority,
match=match,
command=ofproto.OFPFC_DELETE_STRICT)
@ -335,9 +365,9 @@ class PortSecApp(df_base_app.DFlowApp):
# Send packets to next table directly
match = parser.OFPMatch(reg6=unique_key)
self.add_flow_go_to_table(const.EGRESS_PORT_SECURITY_TABLE,
self.add_flow_go_to_table(self.states.main,
const.PRIORITY_HIGH,
const.EGRESS_CONNTRACK_TABLE,
self.exitpoints.default,
match=match)
def _uninstall_disable_flow(self, lport):
@ -370,7 +400,8 @@ class PortSecApp(df_base_app.DFlowApp):
self._subtract_lists(new_valid_macs, old_valid_macs)
return added_valid_macs, removed_valid_macs
def switch_features_handler(self, ev):
def initialize(self):
super(PortSecApp, self).initialize()
parser = self.parser
# Ip default drop

View File

@ -419,7 +419,7 @@ class MplsDriver(_SimpleMplsLabelAllocator, sfc_driver_base.SfcBaseDriver):
port_pair):
for flow_classifier in port_chain.flow_classifiers:
self.app.mod_flow(
table_id=constants.EGRESS_PORT_SECURITY_TABLE,
table_id=self.app.dfdp.apps['portsec'].states.main,
priority=constants.PRIORITY_VERY_HIGH,
match=self.app.parser.OFPMatch(
reg6=port_pair.egress_port.unique_key,
@ -430,22 +430,16 @@ class MplsDriver(_SimpleMplsLabelAllocator, sfc_driver_base.SfcBaseDriver):
port_pair_group,
),
),
inst=[
self.app.parser.OFPInstructionActions(
self.app.ofproto.OFPIT_APPLY_ACTIONS,
[
self.app.parser.OFPActionSetField(
mpls_label=self._get_egress_label(
port_chain,
flow_classifier,
port_pair_group
),
),
],
),
self.app.parser.OFPInstructionGotoTable(
constants.SFC_MPLS_DISPATCH_TABLE,
actions=[
self.app.parser.OFPActionSetField(
mpls_label=self._get_egress_label(
port_chain,
flow_classifier,
port_pair_group
),
),
self.app.parser.NXActionResubmitTable(
table_id=constants.SFC_MPLS_DISPATCH_TABLE),
],
)
@ -460,7 +454,7 @@ class MplsDriver(_SimpleMplsLabelAllocator, sfc_driver_base.SfcBaseDriver):
for eth_type in self._ETH_TYPE_TO_TC:
self.app.mod_flow(
table_id=constants.EGRESS_PORT_SECURITY_TABLE,
table_id=self.app.dfdp.apps['portsec'].states.main,
priority=constants.PRIORITY_VERY_HIGH,
match=self.app.parser.OFPMatch(
reg6=port_pair.egress_port.unique_key,
@ -501,7 +495,7 @@ class MplsDriver(_SimpleMplsLabelAllocator, sfc_driver_base.SfcBaseDriver):
for flow_classifier in port_chain.flow_classifiers:
self.app.mod_flow(
command=self.app.ofproto.OFPFC_DELETE_STRICT,
table_id=constants.EGRESS_PORT_SECURITY_TABLE,
table_id=self.app.dfdp.apps['portsec'].states.main,
priority=constants.PRIORITY_VERY_HIGH,
match=self.app.parser.OFPMatch(
reg6=port_pair.egress_port.unique_key,
@ -519,7 +513,7 @@ class MplsDriver(_SimpleMplsLabelAllocator, sfc_driver_base.SfcBaseDriver):
self.app.mod_flow(
command=self.app.ofproto.OFPFC_DELETE_STRICT,
priority=constants.PRIORITY_VERY_HIGH,
table_id=constants.EGRESS_PORT_SECURITY_TABLE,
table_id=self.app.dfdp.apps['portsec'].states.main,
match=self.app.parser.OFPMatch(
reg6=port_pair.egress_port.unique_key,
eth_type=eth_type,

View File

@ -19,7 +19,7 @@
# First table in the pipeline. All packets are landed here.
# In case packet is originated from local port, it is forwarded
# to EGRESS_PORT_SECURITY_TABLE.
# to the port sec application.
# In case packet is coming from outside with a fip, it is
# forwarded to table INGRESS_NAT_TABLE for translation.
# In case the packet is coming with a tunnel id, it is
@ -28,9 +28,6 @@
INGRESS_CLASSIFICATION_DISPATCH_TABLE = 0
# Detect reg6 (provider network and dNAT)
EXTERNAL_INGRESS_DETECT_SOURCE_TABLE = 2
# All packets from unknown ovs ports are dropped here. Other packets
# are forwarded to table EGRESS_CONNTRACK_TABLE.
EGRESS_PORT_SECURITY_TABLE = 5
# Next 2 tables are related to connection tracking and packet filtering.
# Used for SG.
EGRESS_CONNTRACK_TABLE = 10

View File

@ -11,6 +11,7 @@
# under the License.
import netaddr
import six
import time
from neutron_lib import constants as n_const
@ -25,7 +26,8 @@ from dragonflow.tests.fullstack import test_objects as objects
class TestOVSFlowsForPortSecurity(test_base.DFTestBase):
def _is_expected_flow(self, flow, expected_list):
if flow['table'] != str(const.EGRESS_PORT_SECURITY_TABLE):
table_id_u = six.text_type(self.dfdp.apps['portsec'].states.main)
if flow['table'] != table_id_u:
return False
priority = expected_list['priority']
@ -63,10 +65,10 @@ class TestOVSFlowsForPortSecurity(test_base.DFTestBase):
unique_key_match = "reg6=" + hex(unique_key)
dl_src_match = "dl_src=" + mac
goto_conntrack_table_action = \
"goto_table:" + str(const.EGRESS_CONNTRACK_TABLE)
goto_classification_table_action = \
"goto_table:" + str(const.SERVICES_CLASSIFICATION_TABLE)
exitpoints = self.dfdp.apps['portsec'].exitpoints
goto_conntrack_table_action = "goto_table:" + str(exitpoints.default)
goto_classification_table_action = ("goto_table:" +
str(exitpoints.services))
# priority: High, match: reg6=unique_key, dl_src=$vm_mac,
# dl_dst=ff:ff:ff:ff:ff:ff, udp, tp_src=68, tp_dst=67,
@ -205,13 +207,6 @@ class TestOVSFlowsForPortSecurity(test_base.DFTestBase):
"actions": "drop"
})
# priority: default, goto const.EGRESS_CONNTRACK_TABLE
expected_flow_list.append({
"priority": str(const.PRIORITY_DEFAULT),
"match_list": [],
"actions": "goto_table:" + str(const.EGRESS_CONNTRACK_TABLE)
})
self._check_all_flows_existed(expected_flow_list)
def _test_anti_spoof_flows(self, subnet_info):

View File

@ -1,2 +1,8 @@
vertices: {}
edges: {}
vertices:
portsec:
type: portsec
edges:
dragonflow-legacy.out.5: portsec.in.default
portsec.out.default: dragonflow-legacy.in.10
portsec.out.services: dragonflow-legacy.in.20