Merge "makefile: Remove obsolete copy operations"
[vswitchperf.git] / vswitches / ovs.py
1 # Copyright 2015-2016 Intel Corporation.
2 #
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
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 """VSPERF Open vSwitch base class
16 """
17
18 import logging
19 import re
20 from conf import settings
21 from vswitches.vswitch import IVSwitch
22 from src.ovs import OFBridge, flow_key, flow_match
23
24 _VSWITCHD_CONST_ARGS = []
25
26 class IVSwitchOvs(IVSwitch):
27     """Open vSwitch base class implementation
28
29     The method docstrings document only considerations specific to this
30     implementation. For generic information of the nature of the methods,
31     see the interface.
32     """
33
34     def __init__(self):
35         """See IVswitch for general description
36         """
37         self._vswitchd = None
38         self._logger = logging.getLogger(__name__)
39         self._bridges = {}
40         self._vswitchd_args = _VSWITCHD_CONST_ARGS
41
42     def start(self):
43         """See IVswitch for general description
44         """
45         self._logger.info("Starting vswitchd...")
46         self._vswitchd.start()
47         self._logger.info("Vswitchd...Started.")
48
49     def stop(self):
50         """See IVswitch for general description
51         """
52         self._logger.info("Terminating vswitchd...")
53         self._vswitchd.kill()
54         self._logger.info("Vswitchd...Terminated.")
55
56     def add_switch(self, switch_name, params=None):
57         """See IVswitch for general description
58         """
59         bridge = OFBridge(switch_name)
60         bridge.create(params)
61         bridge.set_db_attribute('Open_vSwitch', '.',
62                                 'other_config:max-idle',
63                                 settings.getValue('VSWITCH_FLOW_TIMEOUT'))
64         self._bridges[switch_name] = bridge
65
66     def del_switch(self, switch_name):
67         """See IVswitch for general description
68         """
69         bridge = self._bridges[switch_name]
70         self._bridges.pop(switch_name)
71         bridge.destroy()
72
73     def add_phy_port(self, switch_name):
74         """See IVswitch for general description
75         """
76         raise NotImplementedError
77
78     def add_vport(self, switch_name):
79         """See IVswitch for general description
80         """
81         raise NotImplementedError
82
83     def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None):
84         """Creates tunneling port
85         """
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]
92
93         if params is not None:
94             local_params = local_params + params
95
96         of_port = bridge.add_port(port_name, local_params)
97         return (port_name, of_port)
98
99     def get_ports(self, switch_name):
100         """See IVswitch for general description
101         """
102         bridge = self._bridges[switch_name]
103         ports = list(bridge.get_ports().items())
104         return [(name, of_port) for (name, (of_port, _)) in ports]
105
106     def del_port(self, switch_name, port_name):
107         """See IVswitch for general description
108         """
109         bridge = self._bridges[switch_name]
110         bridge.del_port(port_name)
111
112     def add_flow(self, switch_name, flow, cache='off'):
113         """See IVswitch for general description
114         """
115         bridge = self._bridges[switch_name]
116         bridge.add_flow(flow, cache=cache)
117
118     def del_flow(self, switch_name, flow=None):
119         """See IVswitch for general description
120         """
121         flow = flow or {}
122         bridge = self._bridges[switch_name]
123         bridge.del_flow(flow)
124
125     def dump_flows(self, switch_name):
126         """See IVswitch for general description
127         """
128         bridge = self._bridges[switch_name]
129         bridge.dump_flows()
130
131     def add_route(self, switch_name, network, destination):
132         """See IVswitch for general description
133         """
134         bridge = self._bridges[switch_name]
135         bridge.add_route(network, destination)
136
137     def set_tunnel_arp(self, ip_addr, mac_addr, switch_name):
138         """See IVswitch for general description
139         """
140         bridge = self._bridges[switch_name]
141         bridge.set_tunnel_arp(ip_addr, mac_addr, switch_name)
142
143     def _get_port_count(self, param):
144         """Returns the number of ports having a certain parameter
145         """
146         cnt = 0
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]
150             cnt += len(phits)
151
152         if cnt is None:
153             cnt = 0
154         return cnt
155
156     def validate_add_switch(self, result, switch_name, params=None):
157         """Validate - Create a new logical switch with no ports
158         """
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
163         return True
164
165     def validate_del_switch(self, result, switch_name):
166         """Validate removal of switch
167         """
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
172         return True
173
174     def validate_add_phy_port(self, result, switch_name):
175         """ Validate that physical port was added to bridge.
176         """
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
182         return True
183
184     def validate_add_vport(self, result, switch_name):
185         """ Validate that virtual port was added to bridge.
186         """
187         return self.validate_add_phy_port(result, switch_name)
188
189     def validate_del_port(self, result, switch_name, port_name):
190         """ Validate that port_name was removed from bridge.
191         """
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]
196         return True
197
198     def validate_add_flow(self, result, switch_name, flow, cache='off'):
199         """ Validate insertion of the flow into the switch
200         """
201         if 'idle_timeout' in flow:
202             del(flow['idle_timeout'])
203
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
207
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
215                 return True
216         return False
217
218     def validate_del_flow(self, result, switch_name, flow=None):
219         """ Validate removal of the flow
220         """
221         if not flow:
222             # what else we can do?
223             return True
224         return not self.validate_add_flow(result, switch_name, flow)
225
226     def validate_dump_flows(self, result, switch_name):
227         """ Validate call of flow dump
228         """
229         return True