Merge "Change PTL informatin in INFO"
[bottlenecks.git] / testsuites / vstf / vstf_scripts / vstf / agent / env / vswitch_plugins / ovs_plugin.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import os
11 import shutil
12 import logging
13 import time
14 import re
15
16 from vstf.agent.env.vswitch_plugins import model
17 from vstf.common.utils import check_and_kill, check_and_rmmod, check_call, check_output, \
18     get_eth_by_bdf, my_mkdir, call
19
20 LOG = logging.getLogger(__name__)
21
22
23 class OvsPlugin(model.VswitchPlugin):
24
25     def __init__(self):
26         self.daemons = ['ovs-vswitchd', 'ovsdb-server']
27         self.mods = ['openvswitch']
28         self.dirs = {'db': "/usr/local/etc/openvswitch"}
29         self.cmds = []
30         self.cmds.append("mkdir -p /usr/local/etc/openvswitch")
31         self.cmds.append(
32             "ovsdb-tool create /usr/local/etc/openvswitch/conf.db")
33         self.cmds.append("ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \
34              --remote=db:Open_vSwitch,Open_vSwitch,manager_options \
35              --private-key=db:Open_vSwitch,SSL,private_key \
36              --certificate=db:Open_vSwitch,SSL,certificate \
37              --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
38              --pidfile --detach")
39         self.cmds.append("ovs-vsctl --no-wait init")
40         self.cmds.append("ovs-vswitchd --pidfile --detach")
41         self.initialized = False
42
43     def init(self):
44         if not self.initialized:
45             self._start_servers()
46             self.initialized = True
47
48     def clean(self):
49         """clean for ovs. Rmmod openvswitch.ko, kill openvswitch daemon process.
50
51         """
52         for process in self.daemons:
53             check_and_kill(process)
54         for mod in self.mods:
55             check_and_rmmod(mod)
56         for _, directory in self.dirs.items():
57             if os.path.isdir(directory):
58                 LOG.info('rm -rf %s', directory)
59                 shutil.rmtree(directory, ignore_errors=True)
60         self.initialized = False
61         return True
62
63     def create_br(self, br_cfg):
64         """Create a bridge(virtual switch). Return True for success, return False for failure.
65
66         :param dict    br_cfg: configuration for bridge creation like
67                 {
68                     "type": "ovs",
69                     "name": "ovs1",
70                     "uplinks": [
71                         {
72                             "bdf": "04:00.0",
73                             "vlan_mode": "access",
74                             "vlan_id": "1"
75                         }
76                     ],
77                     "vtep": {},
78                 }
79
80         """
81         self.init()
82         name, uplinks = br_cfg['name'], br_cfg['uplinks']
83
84         check_call("ovs-vsctl add-br %s" % (name), shell=True)
85         if br_cfg['vtep']:  # vxlan supports
86             local_ip, remote_ip = br_cfg['vtep'][
87                 'local_ip'], br_cfg['vtep']['remote_ip']
88             assert len(uplinks) == 1
89             uplink = uplinks[0]
90             device = get_eth_by_bdf(uplink['bdf'])
91             time.sleep(0.5)
92             vtep = 'vx1'
93             check_call("ifconfig %s %s up" % (device, local_ip), shell=True)
94             check_call("ovs-vsctl add-port %s %s" % (name, vtep), shell=True)
95             check_call(
96                 "ovs-vsctl set interface %s type=vxlan options:remote_ip=%s" %
97                 (vtep, remote_ip), shell=True)
98         for uplink in uplinks:
99             device = get_eth_by_bdf(uplink['bdf'])
100             vlan_mode = uplink['vlan_mode']
101             vlan_id = uplink['vlan_id']
102             check_call("ip link set dev %s up" % device, shell=True)
103             call("ethtool -A %s rx off tx off " % device, shell=True)
104             check_call("ovs-vsctl add-port %s %s" % (name, device), shell=True)
105             if vlan_mode == 'trunk':
106                 check_call(
107                     "ovs-vsctl set port %s trunks=%s" %
108                     (device, vlan_id), shell=True)
109             elif vlan_mode == 'access':
110                 check_call(
111                     "ovs-vsctl set port %s tag=%s" %
112                     (device, vlan_id), shell=True)
113             else:
114                 raise Exception("unreconized vlan_mode:%s" % vlan_mode)
115         return True
116
117     def set_tap_vid(self, tap_cfg):
118         """set vlan id or vxlan id for tap device(virtual nic for vm).
119         return True for success, return False for failure.
120
121         :param dict    tap_cfg: dictionary config for tap device like
122                         {
123                             "tap_name": "tap_in",
124                             "vlan_mode": "access",
125                             "vlan_id": "1"
126                         }
127
128         """
129         port, vlan_mode, vlan = tap_cfg['tap_name'], tap_cfg[
130             'vlan_mode'], tap_cfg['vlan_id']
131         assert vlan_mode in ('access', 'vxlan')
132         if int(vlan) > '4095':
133             # vxlan setting
134             self.__set_tap_vid(port, "vxlan", vlan)
135         else:
136             # vlan setting
137             self.__set_tap_vid(port, vlan_mode, vlan)
138         return True
139
140     def set_fastlink(self, br_cfg):
141         """connect two ports directly, so that packets comes from any one port be forwarded to the other.
142         return True for success, return False for failure.
143
144         :param dict    br_cfg: dictionary configuration for linking ports.
145                 {
146                     "name": "ovs1",
147                     "fastlink": [
148                         {
149                             "inport": "04:00.0",
150                             "outport": "tap_in"
151                         }
152                     ]
153                 }
154         """
155         br_name = br_cfg['name']
156         for fast_cfg in br_cfg['fastlink']:
157             p1, p2 = fast_cfg['inport'], fast_cfg['outport']
158         self.__fastlink(br_name, p1, p2)
159         return True
160
161     def _start_servers(self):
162         for _, directory in self.dirs.items():
163             my_mkdir(directory)
164         for mod in self.mods:
165             check_call("modprobe %s" % mod, shell=True)
166         for cmd in self.cmds:
167             check_call(cmd, shell=True)
168         return True
169
170     def __set_tap_vid(self, port, vlan_mode, vlan_id):
171         if vlan_mode == 'vxlan':
172             raise Exception("don't support vxlan setting right now.")
173         elif vlan_mode == 'trunk':
174             check_call(
175                 "ovs-vsctl set port %s trunks=%s" %
176                 (port, vlan_id), shell=True)
177         else:
178             check_call(
179                 "ovs-vsctl set port %s tag=%s" %
180                 (port, vlan_id), shell=True)
181
182     def __fastlink(self, br, p1, p2):
183         LOG.info("_fastlink(%s,%s,%s)", br, p1, p2)
184         p1 = p1.replace(' ', '')
185         p2 = p2.replace(' ', '')
186         bdfs = check_output(
187             "lspci |grep Eth | awk '{print $1}'",
188             shell=True).splitlines()
189         if p1 in bdfs:
190             p1 = get_eth_by_bdf(p1)
191         if p2 in bdfs:
192             p2 = get_eth_by_bdf(p2)
193         ovs_port = {}
194         buf = check_output("ovs-ofctl show %s" % br, shell=True)
195         port_info = re.compile(r"[0-9]+\(.*\)", re.IGNORECASE | re.MULTILINE)
196         for s in port_info.findall(buf):
197             port_num, interface = s.replace('(', ' ').replace(')', ' ').split()
198             ovs_port[interface] = port_num
199         pn1, pn2 = ovs_port[p1], ovs_port[p2]
200         check_call(
201             "ovs-ofctl add-flow %s in_port=%s,priority=100,action=output:%s" %
202             (br, pn1, pn2), shell=True)
203         check_call(
204             "ovs-ofctl add-flow %s in_port=%s,priority=100,action=output:%s" %
205             (br, pn2, pn1), shell=True)
206         return True