From: peusterm Date: Wed, 20 Feb 2019 14:11:40 +0000 (+0100) Subject: Merge "Support (simple) classifiers" X-Git-Tag: v6.0.0~23 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2Fvim-emu.git;a=commitdiff_plain;h=c2741f9919ccb9559d63ff00effa0664605997f6;hp=4c50ae39537f45285e3463e93fd0221135c1b109 Merge "Support (simple) classifiers" --- diff --git a/src/emuvim/api/openstack/resources/flow_classifier.py b/src/emuvim/api/openstack/resources/flow_classifier.py index 284fee8..4d50eca 100644 --- a/src/emuvim/api/openstack/resources/flow_classifier.py +++ b/src/emuvim/api/openstack/resources/flow_classifier.py @@ -34,10 +34,10 @@ class FlowClassifier(object): self.description = "" self.ethertype = "IPv4" self.protocol = None - self.source_port_range_min = 0 - self.source_port_range_max = 0 - self.destination_port_range_min = 0 - self.destination_port_range_max = 0 + self.source_port_range_min = None + self.source_port_range_max = None + self.destination_port_range_min = None + self.destination_port_range_max = None self.source_ip_prefix = None self.destination_ip_prefix = None self.logical_source_port = "" @@ -75,3 +75,30 @@ class FlowClassifier(object): representation["l7_parameters"] = self.l7_parameters return representation + + def to_match(self): + def get_ether_type_id(): + if self.ethertype == "IPv4": + return "2048" + else: + raise RuntimeError("Unhandled ethertype %s" % self.ethertype) + + def get_ip_protocol_id(): + id = { + "icmp": 1, + "tcp": 6, + }.get("tcp") + if not id: + raise RuntimeError("Unhandled ip protocol %s" % self.protocol) + return id + + match = ["dl_type=%s" % get_ether_type_id()] + if self.protocol: + match.append("nw_proto=%s" % get_ip_protocol_id()) + if self.source_ip_prefix: + match.append("nw_src=%s" % self.source_ip_prefix) + if self.destination_ip_prefix: + match.append("nw_dst=%s" % self.destination_ip_prefix) + if self.destination_port_range_min: + match.append("tp_dst=%s" % self.destination_port_range_min) + return ",".join(match) diff --git a/src/emuvim/api/openstack/resources/port_chain.py b/src/emuvim/api/openstack/resources/port_chain.py index e9ce057..e1b3cbc 100644 --- a/src/emuvim/api/openstack/resources/port_chain.py +++ b/src/emuvim/api/openstack/resources/port_chain.py @@ -68,38 +68,39 @@ class PortChain(object): chain_start = ingress_ports[0] chain_rest = ingress_ports[1:] - source_port_to_chain_start = [] for flow_classifier_id in self.flow_classifiers: flow_classifier = compute.find_flow_classifier_by_name_or_id(flow_classifier_id) - if flow_classifier: - port = compute.find_port_by_name_or_id(flow_classifier.logical_source_port) - source_port_to_chain_start.append((port, chain_start)) + if not flow_classifier: + raise RuntimeError("Unable to find flow_classifier %s" % flow_classifier_id) - chain = source_port_to_chain_start + zip(egress_ports, chain_rest) + port = compute.find_port_by_name_or_id(flow_classifier.logical_source_port) - for (egress_port, ingress_port) in chain: - server_egress = None - server_ingress = None - for server in compute.computeUnits.values(): - if egress_port.name in server.port_names or egress_port.id in server.port_names: - server_egress = server - if ingress_port.name in server.port_names or ingress_port.id in server.port_names: - server_ingress = server + chain = [(port, chain_start)] + zip(egress_ports, chain_rest) - if not server_egress: - raise RuntimeError("Neutron SFC: egress port %s not connected to any server." % - egress_port.name) - if not server_ingress: - raise RuntimeError("Neutron SFC: ingress port %s not connected to any server." % - ingress_port.name) + for (egress_port, ingress_port) in chain: + server_egress = None + server_ingress = None + for server in compute.computeUnits.values(): + if egress_port.name in server.port_names or egress_port.id in server.port_names: + server_egress = server + if ingress_port.name in server.port_names or ingress_port.id in server.port_names: + server_ingress = server - compute.dc.net.setChain( - server_egress.name, server_ingress.name, - egress_port.intf_name, ingress_port.intf_name, - mod_dl_dst=ingress_port.mac_address, - cmd="add-flow", cookie=self.cookie, priority=10, bidirectional=False, - monitor=False, skip_vlan_tag=True - ) + if not server_egress: + raise RuntimeError("Neutron SFC: egress port %s not connected to any server." % + egress_port.name) + if not server_ingress: + raise RuntimeError("Neutron SFC: ingress port %s not connected to any server." % + ingress_port.name) + + compute.dc.net.setChain( + server_egress.name, server_ingress.name, + egress_port.intf_name, ingress_port.intf_name, + match=flow_classifier.to_match(), + mod_dl_dst=ingress_port.mac_address, + cmd="add-flow", cookie=self.cookie, priority=10, bidirectional=False, + monitor=False, skip_vlan_tag=True + ) def uninstall(self, compute): # TODO: implement diff --git a/src/emuvim/test/unittests/test_flow_classifier.py b/src/emuvim/test/unittests/test_flow_classifier.py new file mode 100644 index 0000000..78d8963 --- /dev/null +++ b/src/emuvim/test/unittests/test_flow_classifier.py @@ -0,0 +1,43 @@ +# Copyright (c) 2018 SONATA-NFV and Paderborn University +# ALL RIGHTS RESERVED. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Neither the name of the SONATA-NFV, Paderborn University +# nor the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# This work has been performed in the framework of the SONATA project, +# funded by the European Commission under Grant number 671517 through +# the Horizon 2020 and 5G-PPP programmes. The authors would like to +# acknowledge the contributions of their colleagues of the SONATA +# partner consortium (www.sonata-nfv.eu). +import unittest + +from emuvim.api.openstack.resources.flow_classifier import FlowClassifier + + +class FlowClassifierTest(unittest.TestCase): + def test_empty_flow_classifier_to_match_conversion(self): + c = FlowClassifier("test") + self.assertEqual("dl_type=2048", c.to_match()) + + def test_tcp_ip_flow_classifier_to_match_conversion(self): + c = FlowClassifier("test") + c.protocol = "tcp" + c.source_ip_prefix = "10.0.0.10/32" + c.destination_ip_prefix = "10.0.0.12/32" + c.destination_port_range_min = 80 + c.destination_port_range_max = 80 + self.assertEqual("dl_type=2048,nw_proto=6,nw_src=10.0.0.10/32,nw_dst=10.0.0.12/32,tp_dst=80", c.to_match())