1 # Copyright (c) 2015 SONATA-NFV and Paderborn University
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # Neither the name of the SONATA-NFV, Paderborn University
17 # nor the names of its contributors may be used to endorse or promote
18 # products derived from this software without specific prior written
21 # This work has been performed in the framework of the SONATA project,
22 # funded by the European Commission under Grant number 671517 through
23 # the Horizon 2020 and 5G-PPP programmes. The authors would like to
24 # acknowledge the contributions of their colleagues of the SONATA
25 # partner consortium (www.sonata-nfv.eu).
31 class PortChain(object):
32 def __init__(self
, name
):
33 self
.id = str(uuid
.uuid4())
34 self
.tenant_id
= "abcdefghijklmnopqrstuvwxyz123456"
37 self
.port_pair_groups
= list()
38 self
.flow_classifiers
= list()
39 self
.chain_parameters
= dict()
41 # Cookie for internal identification of installed flows (e.g. to delete
43 self
.cookie
= random
.randint(1, 0xffffffff)
45 def create_dict(self
, compute
):
48 "tenant_id": self
.tenant_id
,
49 "description": self
.description
,
50 "flow_classifiers": self
.flow_classifiers
,
51 "port_pair_groups": self
.port_pair_groups
,
56 def _get_port_pair(self
, port_pair_group_id
, compute
):
57 port_pair_group
= compute
.find_port_pair_group_by_name_or_id(port_pair_group_id
)
58 if len(port_pair_group
.port_pairs
) != 1:
59 raise RuntimeError("Only port pair groups with a single port pair are supported!")
60 return compute
.find_port_pair_by_name_or_id(port_pair_group
.port_pairs
[0])
62 def install(self
, compute
):
64 port_pair_chain
= map(lambda port_pair_group_id
: self
._get
_port
_pair
(port_pair_group_id
, compute
),
65 self
.port_pair_groups
)
66 ingress_ports
= map(lambda port_pair
: port_pair
.ingress
, port_pair_chain
)
67 egress_ports
= map(lambda port_pair
: port_pair
.ingress
, port_pair_chain
)
68 chain_start
= ingress_ports
[0]
69 chain_rest
= ingress_ports
[1:]
71 for flow_classifier_id
in self
.flow_classifiers
:
72 flow_classifier
= compute
.find_flow_classifier_by_name_or_id(flow_classifier_id
)
73 if not flow_classifier
:
74 raise RuntimeError("Unable to find flow_classifier %s" % flow_classifier_id
)
76 port
= compute
.find_port_by_name_or_id(flow_classifier
.logical_source_port
)
78 chain
= [(port
, chain_start
)] + zip(egress_ports
, chain_rest
)
80 for (egress_port
, ingress_port
) in chain
:
83 for server
in compute
.computeUnits
.values():
84 if egress_port
.name
in server
.port_names
or egress_port
.id in server
.port_names
:
85 server_egress
= server
86 if ingress_port
.name
in server
.port_names
or ingress_port
.id in server
.port_names
:
87 server_ingress
= server
90 raise RuntimeError("Neutron SFC: egress port %s not connected to any server." %
92 if not server_ingress
:
93 raise RuntimeError("Neutron SFC: ingress port %s not connected to any server." %
96 compute
.dc
.net
.setChain(
97 server_egress
.name
, server_ingress
.name
,
98 egress_port
.intf_name
, ingress_port
.intf_name
,
99 match
=flow_classifier
.to_match(),
100 mod_dl_dst
=ingress_port
.mac_address
,
101 cmd
="add-flow", cookie
=self
.cookie
, priority
=10, bidirectional
=False,
102 monitor
=False, skip_vlan_tag
=True
105 def uninstall(self
, compute
):
107 logging
.warn("Removing flows is currently not implemented.")
111 logging
.warn("Updating flows is currently not implemented.")