3 Script to add LISP mappings to ODL. Currently it only supports the
4 RPC interface. Support for RESTCONF is planned in a future release.
6 Use `./mapping_blaster.py --help` to see options
8 Code inspired from `flow_config_blaster.py` by Jan Medved
18 __author__ = "Lori Jakab"
19 __copyright__ = "Copyright (c) 2014, Cisco Systems, Inc."
20 __credits__ = ["Jan Medved"]
21 __license__ = "New-style BSD"
22 __email__ = "lojakab@cisco.com"
26 class MappingRPCBlaster(object):
27 putheaders = {'Content-type': 'application/json'}
28 getheaders = {'Accept': 'application/json'}
30 RPC_URL_LI = 'restconf/operations/lfm-mapping-database:'
31 RPC_URL_BE = 'restconf/operations/mappingservice:'
34 # Template for adding mappings
35 add_mapping_template = {
39 u'authoritative': True,
40 u'action': u'NoAction',
41 u'LispAddressContainer': {
44 u'Ipv4Address': u'10.0.0.0'
49 u'name': u'ipv4:172.16.0.0',
52 u'multicastPriority': 255,
53 u'multicastWeight': 0,
54 u'localLocator': True,
57 u'LispAddressContainer': {
60 u'Ipv4Address': u'172.16.0.0'
68 # Template for getting mappings
69 get_mapping_template = {
71 u'LispAddressContainer': {
74 u'Ipv4Address': u'10.0.0.0'
81 def __init__(self, host, port, start_eid, mask, start_rloc, nmappings, v):
84 :param host: The host running ODL where we want to send the RPCs
85 :param port: The RESTCONF port on the ODL host
86 :param start_eid: The starting EID for adding mappings as an IPv4
88 :param mask: The network mask for the EID prefixes to be added
89 :param start_rloc: The starting RLOC for the locators in the
90 mappings as an IPv4 literal
91 :param nmappings: The number of mappings to be generated
92 :param v: Version of the ODL instance (since the RPC URL changed
93 from Lithium to Beryllium
95 self.session = requests.Session()
98 self.start_eid = netaddr.IPAddress(start_eid)
100 self.start_rloc = netaddr.IPAddress(start_rloc)
101 self.nmappings = nmappings
102 if v == "Li" or v == "li":
103 print "Using the Lithium RPC URL"
104 rpc_url = self.RPC_URL_LI
106 print "Using the Beryllium and later RPC URL"
107 rpc_url = self.RPC_URL_BE
109 self.post_url_template = 'http://' + self.host + ':' \
110 + self.port + '/' + rpc_url
112 def mapping_from_tpl(self, eid, mask, rloc):
113 """Create an add-mapping RPC input dictionary from the mapping template
115 :param eid: Replace the default EID in the template with this one
116 :param mask: Replace the default mask in the template with this one
117 :param rloc: Replace the default RLOC in the template with this one
119 :return dict: mapping - template modified with the arguments
121 mapping = copy.deepcopy(self.add_mapping_template['input'])
122 mapping['maskLength'] = mask
123 mapping['LispAddressContainer']['Ipv4Address']['Ipv4Address'] \
124 = str(netaddr.IPAddress(eid))
125 mapping['LocatorRecord'][0]['name'] = 'ipv4:' \
126 + str(netaddr.IPAddress(rloc))
127 address_container = mapping['LocatorRecord'][0]['LispAddressContainer']
128 address_container['Ipv4Address']['Ipv4Address'] \
129 = str(netaddr.IPAddress(rloc))
132 def send_rpc(self, session, method, body):
133 """Send an HTTP POST to the RPC URL and return the status code
135 :param session: The HTTP session handle
136 :param method: "add" or "del"ete mapping
137 :param body: the JSON body to be sent
139 :return int: status_code - HTTP status code
141 rpc_url = self.post_url_template + method
142 r = session.post(rpc_url, data=body, headers=self.putheaders,
143 stream=False, auth=('admin', 'admin'),
144 timeout=self.TIMEOUT)
147 def add_n_mappings(self):
148 """Add self.nmappings mappings to ODL"""
149 rpc = dict(self.add_mapping_template)
150 increment = pow(2, 32 - int(self.mask))
151 for i in range(self.nmappings):
152 rpc['input'] = self.mapping_from_tpl(self.start_eid + i *
153 increment, self.mask,
155 rpc_json = json.dumps(rpc)
156 self.send_rpc(self.session, 'add-mapping', rpc_json)
159 def get_n_mappings(self):
160 """Retrieve self.nmappings mappings from ODL
162 rpc = dict(self.get_mapping_template)
163 increment = pow(2, 32 - int(self.mask))
164 for i in range(self.nmappings):
165 eid = self.start_eid + i * increment
166 rpc['input']['LispAddressContainer']['Ipv4Address']['Ipv4Address']\
167 = str(netaddr.IPAddress(eid))
168 rpc['input']['mask-length'] = self.mask
169 rpc_json = json.dumps(rpc)
170 self.send_rpc(self.session, 'get-mapping', rpc_json)
173 if __name__ == "__main__":
174 parser = argparse.ArgumentParser(description='Add simple IPv4 \
175 prefix-to-IPv4 locator LISP mappings to OpenDaylight')
177 parser.add_argument('--mode', default='add',
178 help='Operating mode, can be "add" or "get" \
180 parser.add_argument('--host', default='127.0.0.1',
181 help='Host where ODL controller is running (default \
183 parser.add_argument('--port', default='8181',
184 help='Port on which ODL\'s RESTCONF is listening \
186 parser.add_argument('--start-eid', default='10.0.0.0',
187 help='Start incrementing EID from this address \
188 (default is 10.0.0.0)')
189 parser.add_argument('--mask', default='32',
190 help='Network mask for the IPv4 EID prefixes \
192 parser.add_argument('--start-rloc', default='172.16.0.0',
193 help='Start incrementing RLOC from this address \
194 (default is 172.16.0.0, ignored for "get")')
195 parser.add_argument('--mappings', type=int, default=1,
196 help='Number of mappings to add/get (default 1)')
197 parser.add_argument('--odl-version', default='Be',
198 help='OpenDaylight version, can be "Li" or "Be" \
201 in_args = parser.parse_args()
203 mapping_rpc_blaster = MappingRPCBlaster(in_args.host, in_args.port,
204 in_args.start_eid, in_args.mask,
209 if in_args.mode == "add":
210 mapping_rpc_blaster.add_n_mappings()
211 elif in_args.mode == "get":
212 mapping_rpc_blaster.get_n_mappings()
214 print "Unsupported mode:", in_args.mode