2 Script to add bridges/ports/termination points to ovsdb config
8 __author__ = 'Marcus Williams'
9 __copyright__ = "Copyright (c) 2015, Intel Corp Inc., Cisco Systems Inc. and others"
10 __credits__ = ["Jan Medved, Lori Jakab"]
11 __license__ = "New-style BSD"
12 __email__ = "marcus.williams@intel.com"
16 class OvsdbConfigBlaster (object):
17 PUT_HEADERS = {'Content-Type': 'application/json',
18 'Authorization': 'Basic YWRtaW46YWRtaW4=',
19 'Accept': 'application/json'}
20 GET_HEADERS = {'Accept': 'application/json',
21 'Authorization': 'Basic YWRtaW46YWRtaW4='}
22 DELETE_HEADERS = {'Accept': 'application/json',
23 'Authorization': 'Basic YWRtaW46YWRtaW4='}
32 vswitch_remote_ovsdb_port,
39 :param controller_ip: The ODL host ip used to send RPCs
40 :param controller_port: The RESTCONF port on the ODL host
41 :param vswitch_ip: The ip of OpenvSwitch to use
42 :param vswitch_ovsdb_port: The ovsdb port of OpenvSwitch to use
43 :param vswitch_remote_ip: The ip of remote OpenvSwitch to use
44 :param vswitch_remote_ovsdb_port: The ovsdb port of remote OpenvSwitch to use
45 :param vswitch_port_type: Port type to create
46 :param vswitch_lst_del_br: string containing a list of ovs switches on which BR'S should be deleted.
47 :param num_instances: The number of instances (bridges, ports etc)to be added
48 :param delete_ports: The number of ports to be deleted from a bridge
50 logging.basicConfig(level=logging.DEBUG)
51 self.session = requests.Session()
52 self.controller_ip = controller_ip
53 self.controller_port = controller_port
54 self.vswitch_dict = dict()
55 self.add_vswitch_to_dict(
58 vswitch_ovsdb_port, 'ovs-1')
60 self.add_vswitch_to_dict(
63 vswitch_remote_ovsdb_port, 'ovs-2')
64 self.vswitch_port_type = vswitch_port_type
65 self.vswitch_lst_del_br = vswitch_lst_del_br
66 self.num_instances = num_instances
67 self.delete_ports = delete_ports
68 self.connect_vswitch(self.vswitch_dict['ovs-1'])
69 if self.vswitch_dict.get('ovs-2'):
70 self.connect_vswitch(self.vswitch_dict['ovs-2'])
73 def return_ovsdb_url(vswitch_ip, vswitch_ovsdb_port, url_type="config"):
74 """ Return an ovsdb restconf url
76 :param vswitch_ip: The ip of Open vSwitch to use
77 :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
78 :param url_tyep: The type of url 'config' | 'oper'
81 if url_type == "config":
82 url_prefix = 'restconf/config/'
83 elif url_type == "oper":
84 url_prefix = 'restconf/operational/'
85 ovsdb_url = url_prefix \
86 + 'network-topology:' \
87 'network-topology/topology/' \
88 'ovsdb:1/node/ovsdb:%2F%2F' \
94 def add_vswitch_to_dict(self, vswitch_ip, vswitch_remote_ip, vswitch_ovsdb_port, vswitch_name):
95 """ Add details of an Open vSwitch instance to self.vswitch_dict
97 :param vswitch_ip: The ip of Open vSwitch to use
98 :param vswitch_remote_ip: The ip of remote Open vSwitch to use
99 :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
100 :param vswitch_name: The name to label the added Open vSwitch instance
102 urlprefix = 'http://' \
103 + self.controller_ip + \
105 + self.controller_port + \
107 self.vswitch_dict.update({
109 'name': vswitch_name,
111 'remote-ip': vswitch_remote_ip,
112 'ovsdb-port': vswitch_ovsdb_port,
113 'node-id': 'ovsdb://%s:%s'
116 'post-url': urlprefix +
117 OvsdbConfigBlaster.return_ovsdb_url(
120 'get-config-url': urlprefix +
121 OvsdbConfigBlaster.return_ovsdb_url(
124 'get-oper-url': urlprefix +
125 OvsdbConfigBlaster.return_ovsdb_url(
127 vswitch_ovsdb_port)}})
129 def connect_vswitch(self, vswitch_dict):
130 """ Connect ODL to an Open vSwitch instance using restconf
132 :param vswitch_dict: A dictionary detailing
133 an instance of Open vSwitch
136 u'network-topology:node': [
138 u'node-id': unicode(vswitch_dict['node-id']),
139 u'connection-info': {
140 u'ovsdb:remote-port': unicode(vswitch_dict['ovsdb-port']),
141 u'ovsdb:remote-ip': unicode(vswitch_dict['ip'])
146 self.send_rest(self.session,
147 vswitch_dict['post-url'],
150 def add_bridge(self, num_instances, vswitch_name='ovs-1'):
151 """Add num_instances of bridge to ODL config
153 :param num_instances: Number of bridges to create
154 :param vswitch_name: A name describing
155 an instance of Open vSwitch
158 for i in range(num_instances):
159 bridge_name = unicode('br-' + str(i) + '-test')
161 u"network-topology:node": [
163 u"node-id": u"%s/bridge/%s"
164 % (unicode(self.vswitch_dict[vswitch_name]
166 unicode(bridge_name)),
167 u"ovsdb:bridge-name": unicode(bridge_name),
168 u"ovsdb:datapath-id": u"00:00:b2:bf:48:25:f2:4b",
169 u"ovsdb:protocol-entry": [
172 u"ovsdb:ovsdb-bridge-protocol-openflow-13"
174 u"ovsdb:controller-entry": [
176 u"target": u"tcp:%s:%s" % (self.controller_ip, self.controller_port)
178 u"ovsdb:managed-by": u"/network-topology:network-topology/"
179 u"network-topology:topology"
180 u"[network-topology:topology-id"
181 u"='ovsdb:1']/network-topology:node"
182 u"[network-topology:node-id="
184 % unicode(self.vswitch_dict[vswitch_name]
189 self.send_rest(self.session,
190 self.vswitch_dict[vswitch_name]
197 def add_port(self, port_type="ovsdb:interface-type-vxlan"):
198 """Add self.num_instances of port to ODL config
200 :param port_type: The type of port to create
201 default: 'ovsdb:interface-type-vxlan'
203 bridge_name = 'br-0-test'
204 self.add_bridge(1, 'ovs-1')
205 # self.add_bridge(1, 'ovs-2')
207 for instance in range(self.num_instances):
208 for vswitch in self.vswitch_dict.itervalues():
209 if port_type == "ovsdb:interface-type-vxlan":
211 ovsdb_rest_url = vswitch.get('post-url') \
214 + '/termination-point/'
215 body_name = 'tp-body'
217 port_prefix = "port-"
218 ovsdb_rest_url = vswitch.get('post-url') \
222 body_name = 'port-body'
223 port_name = port_prefix + str(instance) + '-test-' + vswitch.get('ip')
225 u"network-topology:termination-point": [
229 u"ovsdb:option": u"remote_ip",
230 u"ovsdb:value": unicode(vswitch.get('remote-ip'))
233 u"ovsdb:name": unicode(port_name),
234 u"ovsdb:interface-type": unicode(port_type),
235 u"tp-id": unicode(port_name),
236 u"vlan-tag": unicode(instance + 1),
242 u"vlan-mode": u"access"
248 self.send_rest(self.session,
249 ovsdb_rest_url + port_name,
254 def delete_bridge(self, vswitch_lst_del_br, num_bridges):
255 """Delete num_instances of bridge in ODL config
257 :param num_bridges: Number of bridges to delete
258 :param vswitch_lst_del_br: A list containing instances of Open vSwitch on which bridges should be deleted.
260 for vswitch_names in vswitch_lst_del_br:
261 for br_num in range(num_bridges):
262 bridge_name = unicode('br-' + str(br_num) + '-test')
263 self.send_rest_del(self.session,
264 self.vswitch_dict[vswitch_names]
270 def delete_port(self, num_ports):
271 """Delete ports from ODL config
273 :param num_ports: Number of ports to delete
275 for port in range(num_ports):
276 bridge_name = 'br-0-test'
277 for vswitch in self.vswitch_dict.itervalues():
279 ovsdb_rest_url = vswitch.get('post-url') \
282 + '/termination-point/'
283 port_name = port_prefix + str(port) + '-test-' + vswitch.get('ip')
284 self.send_rest_del(self.session,
285 ovsdb_rest_url + port_name)
288 def send_rest_del(self, session, rest_url):
289 """Send an HTTP DELETE to the Rest URL and return the status code
291 :param session: The HTTP session handle
292 :return int: status_code - HTTP status code
294 ret = session.delete(rest_url,
295 headers=self.DELETE_HEADERS,
297 timeout=self.TIMEOUT)
299 if ret.status_code is not 200:
300 raise ValueError(ret.text,
303 return ret.status_code
305 def send_rest(self, session, rest_url, json_body):
306 """Send an HTTP PUT to the Rest URL and return the status code
308 :param session: The HTTP session handle
309 :param json_body: the JSON body to be sent
311 :return int: status_code - HTTP status code
313 ret = session.put(rest_url,
315 headers=self.PUT_HEADERS,
317 timeout=self.TIMEOUT)
319 if ret.status_code is not 200:
320 raise ValueError(ret.text,
324 return ret.status_code
327 if __name__ == "__main__":
328 parser = argparse.ArgumentParser(description='Add:delete bridge/port/term-points to OpenDaylight')
330 parser.add_argument('--mode', default='None',
331 help='Operating mode, can be "bridge", "port" or "term" \
332 (default is "bridge")')
333 parser.add_argument('--controller', default='127.0.0.1',
334 help='IP of running ODL controller \
335 (default is 127.0.0.1)')
336 parser.add_argument('--controllerport', default='8181',
337 help='Port of ODL RESTCONF \
339 parser.add_argument('--vswitch', default='127.0.0.1',
340 help='IP of Open vSwitch \
341 (default is 127.0.0.1)')
342 parser.add_argument('--vswitchport', default='6640',
343 help='Port of Open vSwitch OVSDB server \
345 parser.add_argument('--vswitchremote', default=None,
346 help='IP of remote Open vSwitch \
348 parser.add_argument('--vswitchremoteport', default=None,
349 help='Port of remote Open vSwitch OVSDB server \
351 parser.add_argument('--vswitchporttype', default=None,
352 help='Port of remote Open vSwitch OVSDB server \
354 parser.add_argument('--deletebridges', nargs='*', type=str, default=None,
355 help='A list of switches on which to delete bridges, '
356 'uses instances for number of bridges. \
357 Example: "ovs-1 ovs2" \
359 parser.add_argument('--deleteports', type=int, default=1,
360 help='delete ports of remote open vswitch ovsdb server (default 1)')
361 parser.add_argument('--instances', type=int, default=1,
362 help='Number of instances to add/get (default 1)')
364 args = parser.parse_args()
366 ovsdb_config_blaster = OvsdbConfigBlaster(args.controller,
371 args.vswitchremoteport,
372 args.vswitchporttype,
376 if args.mode == "bridge":
377 if args.deletebridges is not None:
378 ovsdb_config_blaster.delete_bridge(ovsdb_config_blaster.
380 ovsdb_config_blaster.
383 ovsdb_config_blaster.add_bridge(ovsdb_config_blaster.num_instances)
384 elif args.mode == "term":
385 if args.deleteports is not None:
386 ovsdb_config_blaster.delete_port(ovsdb_config_blaster.delete_ports)
388 ovsdb_config_blaster.add_port()
390 print "please use: python ovsdbconfigblaster.py --help " \
391 "\nUnsupported mode: ", args.mode