1 # Copyright 2015-2016 Intel Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 """VSPERF Open vSwitch base class
20 from conf import settings
21 from vswitches.vswitch import IVSwitch
22 from src.ovs import OFBridge, flow_key, flow_match
24 _VSWITCHD_CONST_ARGS = []
26 class IVSwitchOvs(IVSwitch):
27 """Open vSwitch base class implementation
29 The method docstrings document only considerations specific to this
30 implementation. For generic information of the nature of the methods,
35 """See IVswitch for general description
38 self._logger = logging.getLogger(__name__)
40 self._vswitchd_args = _VSWITCHD_CONST_ARGS
43 """See IVswitch for general description
45 self._logger.info("Starting vswitchd...")
46 self._vswitchd.start()
47 self._logger.info("Vswitchd...Started.")
50 """See IVswitch for general description
52 self._logger.info("Terminating vswitchd...")
54 self._logger.info("Vswitchd...Terminated.")
56 def add_switch(self, switch_name, params=None):
57 """See IVswitch for general description
59 bridge = OFBridge(switch_name)
61 bridge.set_db_attribute('Open_vSwitch', '.',
62 'other_config:max-idle',
63 settings.getValue('VSWITCH_FLOW_TIMEOUT'))
64 self._bridges[switch_name] = bridge
66 def del_switch(self, switch_name):
67 """See IVswitch for general description
69 bridge = self._bridges[switch_name]
70 self._bridges.pop(switch_name)
73 def add_phy_port(self, switch_name):
74 """See IVswitch for general description
76 raise NotImplementedError
78 def add_vport(self, switch_name):
79 """See IVswitch for general description
81 raise NotImplementedError
83 def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None):
84 """Creates tunneling port
86 bridge = self._bridges[switch_name]
87 pcount = str(self._get_port_count('type=' + tunnel_type))
88 port_name = tunnel_type + pcount
89 local_params = ['--', 'set', 'Interface', port_name,
90 'type=' + tunnel_type,
91 'options:remote_ip=' + remote_ip]
93 if params is not None:
94 local_params = local_params + params
96 of_port = bridge.add_port(port_name, local_params)
97 return (port_name, of_port)
99 def get_ports(self, switch_name):
100 """See IVswitch for general description
102 bridge = self._bridges[switch_name]
103 ports = list(bridge.get_ports().items())
104 return [(name, of_port) for (name, (of_port, _)) in ports]
106 def del_port(self, switch_name, port_name):
107 """See IVswitch for general description
109 bridge = self._bridges[switch_name]
110 bridge.del_port(port_name)
112 def add_flow(self, switch_name, flow, cache='off'):
113 """See IVswitch for general description
115 bridge = self._bridges[switch_name]
116 bridge.add_flow(flow, cache=cache)
118 def del_flow(self, switch_name, flow=None):
119 """See IVswitch for general description
122 bridge = self._bridges[switch_name]
123 bridge.del_flow(flow)
125 def dump_flows(self, switch_name):
126 """See IVswitch for general description
128 bridge = self._bridges[switch_name]
131 def add_route(self, switch_name, network, destination):
132 """See IVswitch for general description
134 bridge = self._bridges[switch_name]
135 bridge.add_route(network, destination)
137 def set_tunnel_arp(self, ip_addr, mac_addr, switch_name):
138 """See IVswitch for general description
140 bridge = self._bridges[switch_name]
141 bridge.set_tunnel_arp(ip_addr, mac_addr, switch_name)
143 def _get_port_count(self, param):
144 """Returns the number of ports having a certain parameter
147 for k in self._bridges:
148 pparams = [c for (_, (_, c)) in list(self._bridges[k].get_ports().items())]
149 phits = [i for i in pparams if param in i]
156 def validate_add_switch(self, result, switch_name, params=None):
157 """Validate - Create a new logical switch with no ports
159 bridge = self._bridges[switch_name]
160 output = bridge.run_vsctl(['show'], check_error=True)
161 assert not output[1] # there shouldn't be any stderr, but in case
162 assert re.search('Bridge ["\']?%s["\']?' % switch_name, output[0]) is not None
165 def validate_del_switch(self, result, switch_name):
166 """Validate removal of switch
168 bridge = OFBridge('tmp')
169 output = bridge.run_vsctl(['show'], check_error=True)
170 assert not output[1] # there shouldn't be any stderr, but in case
171 assert re.search('Bridge ["\']?%s["\']?' % switch_name, output[0]) is None
174 def validate_add_phy_port(self, result, switch_name):
175 """ Validate that physical port was added to bridge.
177 bridge = self._bridges[switch_name]
178 output = bridge.run_vsctl(['show'], check_error=True)
179 assert not output[1] # there shouldn't be any stderr, but in case
180 assert re.search('Port ["\']?%s["\']?' % result[0], output[0]) is not None
181 assert re.search('Interface ["\']?%s["\']?' % result[0], output[0]) is not None
184 def validate_add_vport(self, result, switch_name):
185 """ Validate that virtual port was added to bridge.
187 return self.validate_add_phy_port(result, switch_name)
189 def validate_del_port(self, result, switch_name, port_name):
190 """ Validate that port_name was removed from bridge.
192 bridge = self._bridges[switch_name]
193 output = bridge.run_vsctl(['show'], check_error=True)
194 assert not output[1] # there shouldn't be any stderr, but in case
195 assert 'Port "%s"' % port_name not in output[0]
198 def validate_add_flow(self, result, switch_name, flow, cache='off'):
199 """ Validate insertion of the flow into the switch
201 if 'idle_timeout' in flow:
202 del(flow['idle_timeout'])
204 # Note: it should be possible to call `ovs-ofctl dump-flows switch flow`
205 # to verify flow insertion, but it doesn't accept the same flow syntax
206 # as add-flow, so we have to compare it the hard way
208 # get dump of flows and compare them one by one
209 flow_src = flow_key(flow)
210 bridge = self._bridges[switch_name]
211 output = bridge.run_ofctl(['dump-flows', switch_name], check_error=True)
212 for flow_dump in output[0].split('\n'):
213 if flow_match(flow_dump, flow_src):
214 # flow was added correctly
218 def validate_del_flow(self, result, switch_name, flow=None):
219 """ Validate removal of the flow
222 # what else we can do?
224 return not self.validate_add_flow(result, switch_name, flow)
226 def validate_dump_flows(self, result, switch_name):
227 """ Validate call of flow dump