Library SSHLibrary
Library String
Library DateTime
+Library Process
Library ./UtilLibrary.py
Resource KarafKeywords.robot
Variables ../variables/Variables.py
${body} OperatingSystem.Get File ${data_file}
${resp} RequestsLibrary.Post session ${dest_uri} data=${body} headers=${headers}
Should Be Equal As Strings ${resp.status_code} 200
+
+Run Process With Logging And Status Check
+ [Arguments] @{proc_args}
+ [Documentation] Execute an OS command, log STDOUT and STDERR output and check exit code to be 0
+ ${result}= Run Process @{proc_args}
+ Log ${result.stdout}
+ Log ${result.stderr}
+ Should Be Equal As Integers ${result.rc} 0
+ [Return] ${result}
--- /dev/null
+*** Settings ***
+Documentation Test suite to determine the southbound Map-Request serving rate
+Suite Setup Prepare Environment
+Suite Teardown Destroy Environment
+Library Collections
+Library OperatingSystem
+Library RequestsLibrary
+Library String
+Resource ../../../libraries/Utils.robot
+Variables ../../../variables/Variables.py
+
+*** Variables ***
+${MAPPINGS}= 10000
+${LISP_SCAPY} https://raw.githubusercontent.com/intouch/py-lispnetworking/master/lisp.py
+${TOOLS_DIR} ${CURDIR}/../../../../tools/odl-lispflowmapping-performance-tests/
+${PCAP_CREATOR} ${TOOLS_DIR}/create_map_request_pcap.py
+${MAPPING_BLASTER} ${TOOLS_DIR}/mapping_blaster.py
+${REPLAY_PPS} 100000
+${REPLAY_CNT} 1000
+${REPLAY_FILE} ${CURDIR}/encapsulated-map-requests-sequential.pcap
+${RESULTS_FILE} pps.csv
+
+*** Test Cases ***
+Add Simple IPv4 Mappings
+ Run Process With Logging And Status Check ${MAPPING_BLASTER} --host ${CONTROLLER} --mappings ${MAPPINGS}
+
+Generate Test Traffic
+ Reset Stats
+ ${result}= Run Process With Logging And Status Check /usr/local/bin/udpreplay --pps ${REPLAY_PPS} --repeat ${REPLAY_CNT} --port 4342 ${REPLAY_FILE}
+ ${partial}= Fetch From Left ${result.stdout} s =
+ Log ${partial}
+ ${seconds}= Fetch From Right ${partial} ${SPACE}
+ ${seconds}= Convert To Number ${seconds}
+ Log ${seconds}
+ Set Suite Variable ${seconds}
+
+Compute And Export MapReply Rate
+ ${txmrep}= Get Transmitted Map-Requests Stats
+ ${pps}= Evaluate ${txmrep}/${seconds}
+ Log ${pps}
+ Create File ${RESULTS_FILE} replies/s\n
+ Append To File ${RESULTS_FILE} ${pps}\n
+
+*** Keywords ***
+Reset Stats
+ ${resp}= RequestsLibrary.Post session ${LFM_SB_RPC_API}:reset-stats
+ Log ${resp.content}
+ Should Be Equal As Strings ${resp.status_code} 200
+
+Get Transmitted Map-Requests Stats
+ ${resp}= RequestsLibrary.Post session ${LFM_SB_RPC_API}:get-stats
+ Log ${resp.content}
+ ${output}= Get From Dictionary ${resp.json()} output
+ ${stats}= Get From Dictionary ${output} control-message-stats
+ ${ctrlmsg}= Get From Dictionary ${stats} control-message
+ ${replies}= Get From List ${ctrlmsg} 2
+ ${txmrep}= Get From Dictionary ${replies} tx-count
+ ${txmrep}= Convert To Integer ${txmrep}
+ Log ${txmrep}
+ [Return] ${txmrep}
+
+Prepare Environment
+ Create Session session http://${CONTROLLER}:${RESTCONFPORT} auth=${AUTH} headers=${HEADERS}
+ Run Process With Logging And Status Check wget -P ${TOOLS_DIR} ${LISP_SCAPY}
+ Run Process With Logging And Status Check ${PCAP_CREATOR} --requests ${MAPPINGS}
+
+Destroy Environment
+ Delete All Sessions
+ Remove File ${TOOLS_DIR}/lisp.py*
+ Remove File ${REPLAY_FILE}
# LISP Flow Mapping variables
LFM_RPC_API = "/restconf/operations/mappingservice"
LFM_RPC_API_LI = "/restconf/operations/lfm-mapping-database"
+LFM_SB_RPC_API = "/restconf/operations/lisp-sb"
--- /dev/null
+#!/usr/bin/env python
+"""
+Script to generate a pcap file with n Map-Request packets with EID records
+increasing sequentially and (optionally) another pcap file with n Map-Request
+packets that have random EIDs
+
+Use `./create_map_request_pcap.py --help` to see options
+"""
+
+import argparse
+import netaddr
+import lisp
+import random
+
+__author__ = "Lori Jakab"
+__copyright__ = "Copyright (c) 2015, Cisco Systems, Inc."
+__license__ = "New-style BSD"
+__email__ = "lojakab@cisco.com"
+__version__ = "0.0.2"
+
+
+def generate_eids_random(base, n):
+ """Generate n number of EIDs in random order starting from base
+ Args:
+ :param base: A string used as the first EID
+ :param n: An integer, number of EIDs to generate
+ Returns:
+ :return : returns list containing string EIDs
+ """
+ eids = []
+ for i in range(0, n):
+ eids.append(str(netaddr.IPAddress(base) +
+ random.randint(0, (n-1)*increment)))
+ return eids
+
+
+def generate_eids_sequential(base, n):
+ """Generate n number of EIDs in sequential order starting from base
+ Args:
+ :param base: A string used as the first EID
+ :param n: An integer, number of EIDs to generate
+ Returns:
+ :return : returns list containing string EIDs
+ """
+ eids = []
+ for i in range(0, n):
+ eids.append(str(netaddr.IPAddress(base) + i*increment))
+ return eids
+
+
+def generate_map_request(eid):
+ """Create a LISP Map-Request packet as a Scapy object
+ Args:
+ :param eid: A string used as the EID record
+ Returns:
+ :return : returns a Scapy Map-Request packet object
+ """
+ sport1 = random.randint(60000, 65000)
+ sport2 = random.randint(60000, 65000)
+ rnonce = random.randint(0, 2**63)
+
+ itr_rloc = [lisp.LISP_AFI_Address(address=src_rloc, afi=1)]
+ record = [lisp.LISP_MapRequestRecord(request_address=eid,
+ request_afi=1,
+ eid_mask_len=32)]
+
+ packet = lisp.Ether(dst=dst_mac, src=src_mac)
+ packet /= lisp.IP(dst=dst_rloc, src=src_rloc)
+ packet /= lisp.UDP(sport=sport1, dport=4342)
+ packet /= lisp.LISP_Encapsulated_Control_Message(ptype=8)
+ packet /= lisp.IP(dst=eid, src=src_eid)
+ packet /= lisp.UDP(sport=sport2, dport=4342)
+ packet /= lisp.LISP_MapRequest(nonce=rnonce, request_afi=1,
+ address=src_eid, ptype=1,
+ itr_rloc_records=itr_rloc,
+ request_records=record)
+ return packet
+
+parser = argparse.ArgumentParser(description='Create a Map-Request trace file')
+
+parser.add_argument('--dst-mac', default='00:00:00:00:00:00',
+ help='Map-Request destination MAC address \
+ (default is 00:00:00:00:00:00)')
+parser.add_argument('--src-mac', default='00:00:00:00:00:00',
+ help='Map-Request source MAC address \
+ (default is 00:00:00:00:00:00)')
+parser.add_argument('--dst-rloc', default='127.0.0.1',
+ help='Send Map-Request to the Map-Server with this RLOC \
+ (default is 127.0.0.1)')
+parser.add_argument('--src-rloc', default='127.0.0.1',
+ help='Send Map-Request with this source RLOC \
+ (default is 127.0.0.1)')
+parser.add_argument('--src-eid', default='192.0.2.1',
+ help='Send Map-Request with this source EID \
+ (default is 192.0.2.1)')
+parser.add_argument('--base-eid', default='10.0.0.0',
+ help='Start incrementing EID from this address \
+ (default is 10.0.0.0)')
+parser.add_argument('--requests', type=int, default=1,
+ help='Number of requests to create (default 1)')
+parser.add_argument('--increment', type=int, default=1,
+ help='Increment EID requests (default 1)')
+parser.add_argument('--random', type=bool, default=False,
+ help='Create random EID requests (default False)')
+
+in_args = parser.parse_args()
+dst_mac = in_args.dst_mac
+src_mac = in_args.src_mac
+dst_rloc = in_args.dst_rloc
+src_rloc = in_args.src_rloc
+src_eid = in_args.src_eid
+increment = in_args.increment
+
+seq_eids = generate_eids_sequential(in_args.base_eid, in_args.requests)
+seq_pkts = []
+
+for eid in seq_eids:
+ seq_pkts.append(generate_map_request(eid))
+
+lisp.wrpcap("encapsulated-map-requests-sequential.pcap", seq_pkts)
+
+if in_args.random is True:
+ rand_eids = generate_eids_random(in_args.base_eid, in_args.requests)
+ rand_pkts = []
+
+ for eid in rand_eids:
+ rand_pkts.append(generate_map_request(eid))
+
+ lisp.wrpcap("encapsulated-map-requests-random.pcap", rand_pkts)
--- /dev/null
+#!/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