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/odl-mappingservice:'
34 # Template for adding mappings
35 add_mapping_template = {
39 u'action': u'NoAction',
40 u'authoritative': True,
43 u'ietf-lisp-address-types:ipv4-prefix-afi',
44 u'ipv4-prefix': u'10.0.0.0/32'
48 u'locator-id': u'ipv4:172.16.0.0',
51 u'multicastPriority': 255,
52 u'multicastWeight': 0,
53 u'localLocator': True,
58 u'ietf-lisp-address-types:ipv4-afi',
59 u'ipv4': u'172.16.0.0'
67 # Template for getting mappings
68 get_mapping_template = {
71 u'ipv4-prefix': u'10.0.0.0'
76 def __init__(self, host, port, start_eid, mask, start_rloc, nmappings, v):
79 :param host: The host running ODL where we want to send the RPCs
80 :param port: The RESTCONF port on the ODL host
81 :param start_eid: The starting EID for adding mappings as an IPv4
83 :param mask: The network mask for the EID prefixes to be added
84 :param start_rloc: The starting RLOC for the locators in the
85 mappings as an IPv4 literal
86 :param nmappings: The number of mappings to be generated
87 :param v: Version of the ODL instance (since the RPC URL changed
88 from Lithium to Beryllium
90 self.session = requests.Session()
93 self.start_eid = netaddr.IPAddress(start_eid)
95 self.start_rloc = netaddr.IPAddress(start_rloc)
96 self.nmappings = nmappings
97 if v == "Li" or v == "li":
98 print "Using the Lithium RPC URL"
99 rpc_url = self.RPC_URL_LI
101 print "Using the Beryllium and later RPC URL"
102 rpc_url = self.RPC_URL_BE
104 self.post_url_template = 'http://' + self.host + ':' \
105 + self.port + '/' + rpc_url
107 def mapping_from_tpl(self, eid, mask, rloc):
108 """Create an add-mapping RPC input dictionary from the mapping template
110 :param eid: Replace the default EID in the template with this one
111 :param mask: Replace the default mask in the template with this one
112 :param rloc: Replace the default RLOC in the template with this one
114 :return dict: mapping - template modified with the arguments
116 mapping = copy.deepcopy(
117 self.add_mapping_template['input']['mapping-record'])
118 mapping['eid']['ipv4-prefix'] = str(netaddr.IPAddress(eid)) \
120 mapping['LocatorRecord'][0]['locator-id'] = 'ipv4:' \
121 + str(netaddr.IPAddress(rloc))
122 mapping['LocatorRecord'][0]['rloc']['ipv4'] \
123 = str(netaddr.IPAddress(rloc))
126 def send_rpc(self, session, method, body):
127 """Send an HTTP POST to the RPC URL and return the status code
129 :param session: The HTTP session handle
130 :param method: "add" or "del"ete mapping
131 :param body: the JSON body to be sent
133 :return int: status_code - HTTP status code
135 rpc_url = self.post_url_template + method
136 r = session.post(rpc_url, data=body, headers=self.putheaders,
137 stream=False, auth=('admin', 'admin'),
138 timeout=self.TIMEOUT)
141 def add_n_mappings(self):
142 """Add self.nmappings mappings to ODL"""
143 rpc = dict(self.add_mapping_template)
144 increment = pow(2, 32 - int(self.mask))
145 for i in range(self.nmappings):
146 rpc['input']['mapping-record'] = self.mapping_from_tpl(
147 self.start_eid + i * increment, self.mask,
149 rpc_json = json.dumps(rpc)
150 self.send_rpc(self.session, 'add-mapping', rpc_json)
153 def get_n_mappings(self):
154 """Retrieve self.nmappings mappings from ODL
156 rpc = dict(self.get_mapping_template)
157 increment = pow(2, 32 - int(self.mask))
158 for i in range(self.nmappings):
159 eid = self.start_eid + i * increment
160 rpc['input']['eid']['ipv4-prefix'] = str(netaddr.IPAddress(eid)) \
162 rpc_json = json.dumps(rpc)
163 self.send_rpc(self.session, 'get-mapping', rpc_json)
166 if __name__ == "__main__":
167 parser = argparse.ArgumentParser(description='Add simple IPv4 \
168 prefix-to-IPv4 locator LISP mappings to OpenDaylight')
170 parser.add_argument('--mode', default='add',
171 help='Operating mode, can be "add" or "get" \
173 parser.add_argument('--host', default='127.0.0.1',
174 help='Host where ODL controller is running (default \
176 parser.add_argument('--port', default='8181',
177 help='Port on which ODL\'s RESTCONF is listening \
179 parser.add_argument('--start-eid', default='10.0.0.0',
180 help='Start incrementing EID from this address \
181 (default is 10.0.0.0)')
182 parser.add_argument('--mask', default='32',
183 help='Network mask for the IPv4 EID prefixes \
185 parser.add_argument('--start-rloc', default='172.16.0.0',
186 help='Start incrementing RLOC from this address \
187 (default is 172.16.0.0, ignored for "get")')
188 parser.add_argument('--mappings', type=int, default=1,
189 help='Number of mappings to add/get (default 1)')
190 parser.add_argument('--odl-version', default='Be',
191 help='OpenDaylight version, can be "Li" or "Be" \
194 in_args = parser.parse_args()
196 mapping_rpc_blaster = MappingRPCBlaster(in_args.host, in_args.port,
197 in_args.start_eid, in_args.mask,
202 if in_args.mode == "add":
203 mapping_rpc_blaster.add_n_mappings()
204 elif in_args.mode == "get":
205 mapping_rpc_blaster.get_n_mappings()
207 print "Unsupported mode:", in_args.mode