Add lispflowmapping performance tests
[integration/test.git] / tools / odl-lispflowmapping-performance-tests / mapping_blaster.py
diff --git a/tools/odl-lispflowmapping-performance-tests/mapping_blaster.py b/tools/odl-lispflowmapping-performance-tests/mapping_blaster.py
new file mode 100755 (executable)
index 0000000..15fc642
--- /dev/null
@@ -0,0 +1,214 @@
+#!/usr/bin/python
+"""
+Script to add LISP mappings to ODL.  Currently it only supports the
+RPC interface.  Support for RESTCONF is planned in a future release.
+
+Use `./mapping_blaster.py --help` to see options
+
+Code inspired from `flow_config_blaster.py` by Jan Medved
+"""
+
+import argparse
+import copy
+import json
+
+import netaddr
+import requests
+
+__author__ = "Lori Jakab"
+__copyright__ = "Copyright (c) 2014, Cisco Systems, Inc."
+__credits__ = ["Jan Medved"]
+__license__ = "New-style BSD"
+__email__ = "lojakab@cisco.com"
+__version__ = "0.0.3"
+
+
+class MappingRPCBlaster(object):
+    putheaders = {'Content-type': 'application/json'}
+    getheaders = {'Accept': 'application/json'}
+
+    RPC_URL_LI = 'restconf/operations/lfm-mapping-database:'
+    RPC_URL_BE = 'restconf/operations/mappingservice:'
+    TIMEOUT = 10
+
+    # Template for adding mappings
+    add_mapping_template = {
+        u'input': {
+            u'recordTtl': 60,
+            u'maskLength': 32,
+            u'authoritative': True,
+            u'action': u'NoAction',
+            u'LispAddressContainer': {
+                u'Ipv4Address': {
+                    u'afi': 1,
+                    u'Ipv4Address': u'10.0.0.0'
+                }
+            },
+            u'LocatorRecord': [
+                {
+                    u'name': u'ipv4:172.16.0.0',
+                    u'priority': 1,
+                    u'weight': 1,
+                    u'multicastPriority': 255,
+                    u'multicastWeight': 0,
+                    u'localLocator': True,
+                    u'rlocProbed': False,
+                    u'routed': True,
+                    u'LispAddressContainer': {
+                        u'Ipv4Address': {
+                            u'afi': 1,
+                            u'Ipv4Address': u'172.16.0.0'
+                        }
+                    }
+                }
+            ]
+        }
+    }
+
+    # Template for getting mappings
+    get_mapping_template = {
+        u'input': {
+            u'LispAddressContainer': {
+                u'Ipv4Address': {
+                    u'afi': 1,
+                    u'Ipv4Address': u'10.0.0.0'
+                }
+            },
+            u'mask-length': 32
+        }
+    }
+
+    def __init__(self, host, port, start_eid, mask, start_rloc, nmappings, v):
+        """
+        Args:
+            :param host: The host running ODL where we want to send the RPCs
+            :param port: The RESTCONF port on the ODL host
+            :param start_eid: The starting EID for adding mappings as an IPv4
+                literal
+            :param mask: The network mask for the EID prefixes to be added
+            :param start_rloc: The starting RLOC for the locators in the
+                mappings as an IPv4 literal
+            :param nmappings: The number of mappings to be generated
+            :param v: Version of the ODL instance (since the RPC URL changed
+                from Lithium to Beryllium
+        """
+        self.session = requests.Session()
+        self.host = host
+        self.port = port
+        self.start_eid = netaddr.IPAddress(start_eid)
+        self.mask = mask
+        self.start_rloc = netaddr.IPAddress(start_rloc)
+        self.nmappings = nmappings
+        if v == "Li" or v == "li":
+            print "Using the Lithium RPC URL"
+            rpc_url = self.RPC_URL_LI
+        else:
+            print "Using the Beryllium and later RPC URL"
+            rpc_url = self.RPC_URL_BE
+
+        self.post_url_template = 'http://' + self.host + ':' \
+            + self.port + '/' + rpc_url
+
+    def mapping_from_tpl(self, eid, mask, rloc):
+        """Create an add-mapping RPC input dictionary from the mapping template
+        Args:
+            :param eid: Replace the default EID in the template with this one
+            :param mask: Replace the default mask in the template with this one
+            :param rloc: Replace the default RLOC in the template with this one
+        Returns:
+            :return dict: mapping - template modified with the arguments
+        """
+        mapping = copy.deepcopy(self.add_mapping_template['input'])
+        mapping['maskLength'] = mask
+        mapping['LispAddressContainer']['Ipv4Address']['Ipv4Address'] \
+            = str(netaddr.IPAddress(eid))
+        mapping['LocatorRecord'][0]['name'] = 'ipv4:' \
+            + str(netaddr.IPAddress(rloc))
+        address_container = mapping['LocatorRecord'][0]['LispAddressContainer']
+        address_container['Ipv4Address']['Ipv4Address'] \
+            = str(netaddr.IPAddress(rloc))
+        return mapping
+
+    def send_rpc(self, session, method, body):
+        """Send an HTTP POST to the RPC URL and return the status code
+        Args:
+            :param session: The HTTP session handle
+            :param method: "add" or "del"ete mapping
+            :param body: the JSON body to be sent
+        Returns:
+            :return int: status_code - HTTP status code
+        """
+        rpc_url = self.post_url_template + method
+        r = session.post(rpc_url, data=body, headers=self.putheaders,
+                         stream=False, auth=('admin', 'admin'),
+                         timeout=self.TIMEOUT)
+        return r.status_code
+
+    def add_n_mappings(self):
+        """Add self.nmappings mappings to ODL"""
+        rpc = dict(self.add_mapping_template)
+        increment = pow(2, 32 - int(self.mask))
+        for i in range(self.nmappings):
+            rpc['input'] = self.mapping_from_tpl(self.start_eid + i *
+                                                 increment, self.mask,
+                                                 self.start_rloc + i)
+            rpc_json = json.dumps(rpc)
+            self.send_rpc(self.session, 'add-mapping', rpc_json)
+        self.session.close()
+
+    def get_n_mappings(self):
+        """Retrieve self.nmappings mappings from ODL
+        """
+        rpc = dict(self.get_mapping_template)
+        increment = pow(2, 32 - int(self.mask))
+        for i in range(self.nmappings):
+            eid = self.start_eid + i * increment
+            rpc['input']['LispAddressContainer']['Ipv4Address']['Ipv4Address']\
+                = str(netaddr.IPAddress(eid))
+            rpc['input']['mask-length'] = self.mask
+            rpc_json = json.dumps(rpc)
+            self.send_rpc(self.session, 'get-mapping', rpc_json)
+        self.session.close()
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Add simple IPv4 \
+        prefix-to-IPv4 locator LISP mappings to OpenDaylight')
+
+    parser.add_argument('--mode', default='add',
+                        help='Operating mode, can be "add" or "get" \
+                            (default is "add")')
+    parser.add_argument('--host', default='127.0.0.1',
+                        help='Host where ODL controller is running (default \
+                            is 127.0.0.1)')
+    parser.add_argument('--port', default='8181',
+                        help='Port on which ODL\'s RESTCONF is listening \
+                            (default is 8181)')
+    parser.add_argument('--start-eid', default='10.0.0.0',
+                        help='Start incrementing EID from this address \
+                            (default is 10.0.0.0)')
+    parser.add_argument('--mask', default='32',
+                        help='Network mask for the IPv4 EID prefixes \
+                            (default is 32)')
+    parser.add_argument('--start-rloc', default='172.16.0.0',
+                        help='Start incrementing RLOC from this address \
+                            (default is 172.16.0.0, ignored for "get")')
+    parser.add_argument('--mappings', type=int, default=1,
+                        help='Number of mappings to add/get (default 1)')
+    parser.add_argument('--odl-version', default='Be',
+                        help='OpenDaylight version, can be "Li" or "Be" \
+                            (default is "Be")')
+
+    in_args = parser.parse_args()
+
+    mapping_rpc_blaster = MappingRPCBlaster(in_args.host, in_args.port,
+                                            in_args.start_eid, in_args.mask,
+                                            in_args.start_rloc,
+                                            in_args.mappings,
+                                            in_args.odl_version)
+
+    if in_args.mode == "add":
+        mapping_rpc_blaster.add_n_mappings()
+    elif in_args.mode == "get":
+        mapping_rpc_blaster.get_n_mappings()
+    else:
+        print "Unsupported mode:", in_args.mode