Add ovsdbconfigblaster.py 66/29466/3
authorMarcus Williams <marcus.g.williams@gmail.com>
Mon, 9 Nov 2015 19:18:17 +0000 (11:18 -0800)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 16 Nov 2015 11:41:41 +0000 (11:41 +0000)
Start of ovsdb southbound
performance suite.

Change-Id: I12f6360f343c05d399789b97bbe6a66d7f477469
Signed-off-by: Marcus Williams <marcus.g.williams@gmail.com>
tools/odl-ovsdb-performance-tests/ovsdbconfigblaster.py [new file with mode: 0644]

diff --git a/tools/odl-ovsdb-performance-tests/ovsdbconfigblaster.py b/tools/odl-ovsdb-performance-tests/ovsdbconfigblaster.py
new file mode 100644 (file)
index 0000000..7065909
--- /dev/null
@@ -0,0 +1,317 @@
+"""
+Script to add bridges/ports/termination points to ovsdb config
+"""
+__author__ = 'Marcus Williams'
+__copyright__ = "Copyright (c) 2015, Intel Corp Inc., Cisco Systems Inc. and others"
+__credits__ = ["Jan Medved, Lori Jakab"]
+__license__ = "New-style BSD"
+__email__ = "marcus.williams@intel.com"
+__version__ = "0.0.1"
+
+import argparse
+import logging
+import requests
+
+
+class OvsdbConfigBlaster (object):
+    PUT_HEADERS = {'Content-Type': 'application/json',
+                   'Authorization': 'Basic YWRtaW46YWRtaW4=',
+                   'Accept': 'application/json'}
+    GET_HEADERS = {'Accept': 'application/json',
+                   'Authorization': 'Basic YWRtaW46YWRtaW4='}
+    TIMEOUT = 10
+
+    def __init__(self,
+                 controller_ip,
+                 controller_port,
+                 vswitch_ip,
+                 vswitch_ovsdb_port,
+                 vswitch_remote_ip,
+                 vswitch_remote_ovsdb_port,
+                 vswitch_port_type,
+                 num_instances):
+        """
+        Args:
+            :param controller_ip: The ODL host ip used to send RPCs
+            :param controller_port: The RESTCONF port on the ODL host
+            :param vswitch_ip: The ip of Open vSwitch to use
+            :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
+            :param vswitch_remote_ip: The ip of remote Open vSwitch to use
+            :param vswitch_remote_ovsdb_port: The ovsdb port of remote Open vSwitch to use
+            :param vswitch_port_type: Port type to create
+            :param num_instances: The number of instances (bridges, ports etc) to be added
+        """
+        logging.basicConfig(level=logging.DEBUG)
+        self.session = requests.Session()
+        self.controller_ip = controller_ip
+        self.controller_port = controller_port
+        self.vswitch_dict = dict()
+        self.add_vswitch_to_dict(
+            vswitch_ip,
+            vswitch_remote_ip,
+            vswitch_ovsdb_port, 'ovs-1')
+        if vswitch_remote_ip:
+            self.add_vswitch_to_dict(
+                vswitch_remote_ip,
+                vswitch_ip,
+                vswitch_remote_ovsdb_port, 'ovs-2')
+        self.vswitch_port_type = vswitch_port_type
+        self.num_instances = num_instances
+
+        self.connect_vswitch(self.vswitch_dict['ovs-1'])
+        if self.vswitch_dict.get('ovs-2'):
+            self.connect_vswitch(self.vswitch_dict['ovs-2'])
+
+    @staticmethod
+    def return_ovsdb_url(vswitch_ip, vswitch_ovsdb_port, url_type="config"):
+        """ Return an ovsdb restconf url
+        Args:
+            :param vswitch_ip: The ip of Open vSwitch to use
+            :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
+            :param url_tyep: The type of url 'config' | 'oper'
+        """
+        url_prefix = None
+        if url_type == "config":
+            url_prefix = 'restconf/config/'
+        elif url_type == "oper":
+            url_prefix = 'restconf/operational/'
+        ovsdb_url = url_prefix \
+            + 'network-topology:' \
+            'network-topology/topology/' \
+            'ovsdb:1/node/ovsdb:%2F%2F' \
+            + vswitch_ip\
+            + ':' \
+            + vswitch_ovsdb_port
+        return ovsdb_url
+
+    def add_vswitch_to_dict(self, vswitch_ip, vswitch_remote_ip, vswitch_ovsdb_port, vswitch_name):
+        """ Add details of an Open vSwitch instance to self.vswitch_dict
+        Args:
+            :param vswitch_ip: The ip of Open vSwitch to use
+            :param vswitch_remote_ip: The ip of remote Open vSwitch to use
+            :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
+            :param vswitch_name: The name to label the added Open vSwitch instance
+        """
+        urlprefix = 'http://' \
+                    + self.controller_ip + \
+                    ':' \
+                    + self.controller_port + \
+                    '/'
+        self.vswitch_dict.update({vswitch_name: {
+            'name': vswitch_name,
+            'ip': vswitch_ip,
+            'remote-ip':  vswitch_remote_ip,
+            'ovsdb-port': vswitch_ovsdb_port,
+            'node-id': 'ovsdb://%s:%s'
+            % (vswitch_ip,
+               vswitch_ovsdb_port),
+            'post-url': urlprefix
+            + OvsdbConfigBlaster.return_ovsdb_url(
+                vswitch_ip,
+                vswitch_ovsdb_port),
+            'get-config-url': urlprefix
+            + OvsdbConfigBlaster.return_ovsdb_url(
+                vswitch_ip,
+                vswitch_ovsdb_port),
+            'get-oper-url': urlprefix
+            + OvsdbConfigBlaster.return_ovsdb_url(
+                vswitch_ip,
+                vswitch_ovsdb_port)}})
+
+    def connect_vswitch(self, vswitch_dict):
+        """ Connect ODL to an Open vSwitch instance using restconf
+        Args:
+            :param vswitch_dict: A dictionary detailing
+                                 an instance of Open vSwitch
+        """
+        connect_ovs_body = {
+            u'network-topology:node': [
+                {
+                    u'node-id': unicode(vswitch_dict['node-id']),
+                    u'connection-info': {
+                        u'ovsdb:remote-port': unicode(vswitch_dict['ovsdb-port']),
+                        u'ovsdb:remote-ip': unicode(vswitch_dict['ip'])
+                    }
+                }
+            ]
+        }
+        self.send_rest(self.session,
+                       vswitch_dict['post-url'],
+                       connect_ovs_body)
+
+    def add_bridge(self, num_instances, vswitch_name='ovs-1'):
+        """Add num_instances of bridge to ODL config
+        Args:
+            :param num_instances: Number of bridges to create
+            :param vswitch_name: A name describing
+                                 an instance of Open vSwitch
+        """
+
+        for i in range(num_instances):
+            bridge_name = unicode('br-' + str(i) + '-test')
+            add_bridge_body = {
+                u"network-topology:node": [
+                    {
+                        u"node-id": u"%s/bridge/%s"
+                                    % (unicode(self.vswitch_dict[vswitch_name]
+                                               .get('node-id')),
+                                       unicode(bridge_name)),
+                        u"ovsdb:bridge-name": unicode(bridge_name),
+                        u"ovsdb:datapath-id": u"00:00:b2:bf:48:25:f2:4b",
+                        u"ovsdb:protocol-entry": [
+                            {
+                                u"protocol":
+                                    u"ovsdb:ovsdb-bridge-protocol-openflow-13"
+                            }],
+                        u"ovsdb:controller-entry": [
+                            {
+                                u"target": u"tcp:%s:%s" % (self.controller_ip,
+                                                           self.controller_port)
+                            }],
+                        u"ovsdb:managed-by": u"/network-topology:network-topology/"
+                                             u"network-topology:topology"
+                                             u"[network-topology:topology-id"
+                                             u"='ovsdb:1']/network-topology:node"
+                                             u"[network-topology:node-id="
+                                             u"'%s']"
+                                             % unicode(self.vswitch_dict[vswitch_name]
+                                                       .get('node-id'))
+                    }
+                ]
+            }
+            self.send_rest(self.session,
+                           self.vswitch_dict[vswitch_name]
+                           .get('post-url')
+                           + '%2Fbridge%2F'
+                           + bridge_name,
+                           add_bridge_body)
+        self.session.close()
+
+    def add_port(self, port_type="ovsdb:interface-type-vxlan"):
+        """Add self.num_instances of port to ODL config
+        Args:
+            :param port_type: The type of port to create
+                                default: 'ovsdb:interface-type-vxlan'
+        """
+        bridge_name = 'br-0-test'
+        self.add_bridge(1, 'ovs-1')
+        self.add_bridge(1, 'ovs-2')
+
+        for instance in range(self.num_instances):
+            for vswitch in self.vswitch_dict.itervalues():
+                if port_type == "ovsdb:interface-type-vxlan":
+                    port_prefix = "tp-"
+                    ovsdb_rest_url = vswitch.get('post-url') \
+                        + '%2Fbridge%2F'\
+                        + bridge_name\
+                        + '/termination-point/'
+                    body_name = 'tp-body'
+                else:
+                    port_prefix = "port-"
+                    ovsdb_rest_url = vswitch.get('post-url') \
+                        + '%2Fbridge%2F' \
+                        + bridge_name\
+                        + '/port/'
+                    body_name = 'port-body'
+                port_name = port_prefix + str(instance) + '-test-' + vswitch.get('ip')
+                body = {'tp-body': {
+                    u"network-topology:termination-point": [
+                        {
+                            u"ovsdb:options": [
+                                {
+                                    u"ovsdb:option": u"remote_ip",
+                                    u"ovsdb:value": unicode(vswitch.get('remote-ip'))
+                                }
+                            ],
+                            u"ovsdb:name": unicode(port_name),
+                            u"ovsdb:interface-type": unicode(port_type),
+                            u"tp-id": unicode(port_name),
+                            u"vlan-tag": unicode(instance + 1),
+                            u"trunks": [
+                                {
+                                    u"trunk": u"5"
+                                }
+                            ],
+                            u"vlan-mode": u"access"
+                        }
+                        ]
+                },
+                    # TODO add port-body
+                    'port-body': {}}
+                self.send_rest(self.session,
+                               ovsdb_rest_url + port_name,
+                               body.get(body_name))
+
+        self.session.close()
+
+    def send_rest(self, session, rest_url, json_body):
+        """Send an HTTP PUT to the Rest URL and return the status code
+        Args:
+            :param session: The HTTP session handle
+            :param json_body: the JSON body to be sent
+        Returns:
+            :return int: status_code - HTTP status code
+        """
+        ret = session.put(rest_url,
+                          json=json_body,
+                          headers=self.PUT_HEADERS,
+                          stream=False,
+                          timeout=self.TIMEOUT)
+
+        if ret.status_code is not 200:
+                raise ValueError(ret.text,
+                                 ret.status_code,
+                                 rest_url,
+                                 json_body)
+        return ret.status_code
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Add bridge/port/term-points'
+                                                 ' to OpenDaylight')
+
+    parser.add_argument('--mode', default='bridge',
+                        help='Operating mode, can be "bridge", "port" or "term" \
+                            (default is "bridge")')
+    parser.add_argument('--controller', default='127.0.0.1',
+                        help='IP of running ODL controller (default \
+                            is 127.0.0.1)')
+    parser.add_argument('--controllerport', default='8181',
+                        help='Port of ODL RESTCONF \
+                            (default is 8181)')
+    parser.add_argument('--vswitch', default='127.0.0.1',
+                        help='IP of Open vSwitch \
+                            (default is 127.0.0.1)')
+    parser.add_argument('--vswitchport', default='6640',
+                        help='Port of Open vSwitch OVSDB server \
+                            (default is 6640)')
+    parser.add_argument('--vswitchremote', default=None,
+                        help='IP of remote Open vSwitch \
+                            (default is none)')
+    parser.add_argument('--vswitchremoteport', default=None,
+                        help='Port of remote Open vSwitch OVSDB server \
+                            (default is none)')
+    parser.add_argument('--vswitchporttype', default=None,
+                        help='Port of remote Open vSwitch OVSDB server \
+                            (default is none)')
+    parser.add_argument('--instances', type=int, default=1,
+                        help='Number of instances to add/get (default 1)')
+
+    args = parser.parse_args()
+
+    ovsdb_config_blaster = OvsdbConfigBlaster(args.controller,
+                                              args.controllerport,
+                                              args.vswitch,
+                                              args.vswitchport,
+                                              args.vswitchremote,
+                                              args.vswitchremoteport,
+                                              args.vswitchporttype,
+                                              args.instances)
+
+    if args.mode == "bridge":
+        ovsdb_config_blaster.add_bridge(ovsdb_config_blaster.num_instances)
+    elif args.mode == "term":
+        ovsdb_config_blaster.add_port()
+    elif args.mode == "port" and args.vswitchporttype is not None:
+        ovsdb_config_blaster.add_port(args.vswitchporttype)
+    else:
+        print "Unsupported mode:", args.mode