Add SXP performance measuring suite
[integration/test.git] / csit / libraries / Sxp.py
1 import json
2 from netaddr import IPAddress
3 from string import Template
4
5
6 def mod(num, base):
7     """Gets modulo of number
8
9     :param num: Number to be used
10     :type num: string
11     :param base: Base used
12     :type base: string
13     :returns: Int representing modulo of specified numbers.
14
15     """
16     return int(num) % int(base)
17
18
19 def get_average_of_items(items):
20     """Gets average of items in provided list
21
22     :param items: To be proceed
23     :return: Average value
24
25     """
26     return sum(items) / len(items)
27
28
29 def get_opposing_mode(mode):
30     """Generate string representing opposing SXP peer mode
31
32         :param mode: SXP peer mode
33         :type mode: str
34         :returns: String with opposing SXP peer mode.
35
36         """
37     if 'speaker' == mode:
38         return 'listener'
39     elif 'listener' == mode:
40         return 'speaker'
41     return 'both'
42
43
44 def get_ip_from_number(n, base=2130706432):
45     """Generate string representing Ipv4 from specified number plus base value
46
47     :param n: Number to be converted
48     :type n: int
49     :param base: Starting index
50     :type base: int
51     :returns: String containing Ipv4.
52
53     """
54     ip = IPAddress(int(base) + n)
55     return str(ip)
56
57
58 def get_ip_from_number_and_ip(n, ip_address):
59     """Generate string representing Ipv4 from specified number and IPAddress
60
61     :param n: Number to be converted
62     :type n: int
63     :param ip_address: Base address
64     :type ip_address: string
65     :returns: String containing Ipv4.
66
67     """
68     ip = IPAddress(int(IPAddress(ip_address)) + n)
69     return str(ip)
70
71
72 def lower_version(ver1, ver2):
73     """Generate xml containing SGT mach data
74
75     :param ver1: Version of SXP protocol for compare
76     :type ver1: string
77     :param ver2: Version of SXP protocol for compare
78     :type ver2: string
79     :returns: String containing lower from those two specified versions.
80
81     """
82     v1 = int(ver1[-1:])
83     v2 = int(ver2[-1:])
84     if v1 <= v2:
85         return ver1
86     else:
87         return ver2
88
89
90 def get_filter_entry(seq, entry_type, sgt="", esgt="", acl="", eacl="", pl="", epl="", ps=""):
91     """Generate xml containing FilterEntry data
92
93     :param seq: Sequence of entry
94     :type seq: string
95     :param entry_type: Type of entry (permit/deny)
96     :type entry_type: string
97     :param sgt: SGT matches to be added to entry
98     :type sgt: string
99     :param esgt: SGT ranges match to be added to entry
100     :type esgt: string
101     :param acl: ACL matches to be added to entry
102     :type acl: string
103     :param eacl: EACL matches to be added to entry
104     :type eacl: string
105     :param pl: PrefixList matches to be added to entry
106     :type pl: string
107     :param epl: ExtendedPrefixList matches to be added to entry
108     :type epl: string
109     :param ps: PeerSequence matches to be added to entry
110     :type ps: string
111     :returns: String containing xml data for request
112
113     """
114     entries = ""
115     # Generate XML request containing combination of Matches of different types
116     if sgt:
117         args = sgt.split(',')
118         entries += add_sgt_matches_xml(args)
119     elif esgt:
120         args = esgt.split(',')
121         entries += add_sgt_range_xml(args[0], args[1])
122     if pl:
123         entries += add_pl_entry_xml(pl)
124     elif epl:
125         args = epl.split(',')
126         entries += add_epl_entry_xml(args[0], args[1], args[2])
127     if acl:
128         args = acl.split(',')
129         entries += add_acl_entry_xml(args[0], args[1])
130     elif eacl:
131         args = eacl.split(',')
132         entries += add_eacl_entry_xml(args[0], args[1], args[2], args[3])
133     if ps:
134         args = ps.split(',')
135         entries += add_ps_entry_xml(args[0], args[1])
136     # Wrap entries in ACL/PrefixList according to specified values
137     if pl or epl:
138         return add_pl_entry_default_xml(seq, entry_type, entries)
139     elif ps:
140         return add_ps_entry_default_xml(seq, entry_type, entries)
141     return add_acl_entry_default_xml(seq, entry_type, entries)
142
143
144 def add_peers(*args):
145     """Generate xml containing Peer mach data
146
147     :param args: Peers data
148     :type args: dict
149     :returns: String containing xml data for request
150
151     """
152     templ = Template('''
153         <sxp-peer>
154             <peer-address>$ip</peer-address>
155         </sxp-peer>''')
156     peers = ""
157     for count, value in enumerate(args):
158         peers += templ.substitute({'ip': value})
159     return peers
160
161
162 def add_domains(*args):
163     """Generate xml containing Domain mach data
164
165     :param args: Domain data
166     :type args: dict
167     :returns: String containing xml data for request
168
169     """
170     templ = Template('''
171         <domain>
172             <name>$name</name>
173         </domain>''')
174     peers = ""
175     for count, value in enumerate(args):
176         peers += templ.substitute({'name': value})
177     return peers
178
179
180 def add_sgt_matches_xml(sgt_entries):
181     """Generate xml containing SGT mach data
182
183     :param sgt_entries: SGT matches
184     :type sgt_entries: string
185     :returns: String containing xml data for request
186
187     """
188     templ = Template('''
189         <matches>$sgt</matches>''')
190     matches = ""
191     for sgt in sgt_entries:
192         matches += templ.substitute({'sgt': sgt})
193     return matches
194
195
196 def add_sgt_range_xml(start, end):
197     """Generate xml containing SGT RangeMach data
198
199     :param start: Start range of SGT
200     :type start: string
201     :param end: End range of SGT
202     :type end: string
203     :returns: String containing xml data for request
204
205     """
206     templ = Template('''
207         <sgt-start>$start</sgt-start>
208         <sgt-end>$end</sgt-end>''')
209     match = templ.substitute({'start': start, 'end': end})
210     return match
211
212
213 def add_acl_entry_default_xml(seq, entry_type, acl_entries):
214     """Generate xml containing AccessList data
215
216     :param seq: Sequence of PrefixList entry
217     :type seq: string
218     :param entry_type: Entry type (permit/deny)
219     :type entry_type: string
220     :param acl_entries: XML data containing AccessList entries
221     :type acl_entries: string
222     :returns: String containing xml data for request
223
224     """
225     templ = Template('''
226         <acl-entry>
227             <entry-type>$entry_type</entry-type>
228             <entry-seq>$seq</entry-seq>$acl_entries
229         </acl-entry>''')
230     matches = templ.substitute(
231         {'seq': seq, 'entry_type': entry_type, 'acl_entries': acl_entries})
232     return matches
233
234
235 def add_acl_entry_xml(ip, mask):
236     """Generate xml containing AccessList data
237
238     :param ip: Ipv4/6 address
239     :type ip: string
240     :param mask: Ipv4/6 wildcard mask
241     :type mask: string
242     :returns: String containing xml data for request
243
244     """
245     templ = Template('''
246         <acl-match>
247             <ip-address>$ip</ip-address>
248             <wildcard-mask>$mask</wildcard-mask>
249         </acl-match>''')
250     return templ.substitute({'ip': ip, 'mask': mask})
251
252
253 def add_eacl_entry_xml(ip, mask, amask, wmask):
254     """Generate xml containing ExtendedAccessList data
255
256     :param ip: Ipv4/6 address
257     :type ip: string
258     :param mask: Ipv4/6 wildcard mask
259     :type mask: string
260     :param amask: Ipv4/6 address mask
261     :type amask: string
262     :param wmask: Ipv4/6 address wildcard mask
263     :type wmask: string
264     :returns: String containing xml data for request
265
266     """
267     templ = Template('''
268         <acl-match>
269             <ip-address>$ip</ip-address>
270             <wildcard-mask>$mask</wildcard-mask>
271             <mask>
272               <address-mask>$amask</address-mask>
273               <wildcard-mask>$wmask</wildcard-mask>
274             </mask>
275         </acl-match>''')
276     return templ.substitute({'ip': ip, 'mask': mask, 'amask': amask, 'wmask': wmask})
277
278
279 def add_ps_entry_default_xml(seq, entry_type, ps_entries):
280     """Generate xml containing PeerSequence data
281
282     :param seq: Sequence of PrefixList entry
283     :type seq: string
284     :param entry_type: Entry type (permit/deny)
285     :type entry_type: string
286     :param ps_entries: XML data containing PeerSequence entries
287     :type ps_entries: string
288     :returns: String containing xml data for request
289
290     """
291     templ = Template('''
292     <peer-sequence-entry xmlns="urn:opendaylight:sxp:controller">
293           <entry-type>$entry_type</entry-type>
294           <entry-seq>$seq</entry-seq>$ps_entries
295     </peer-sequence-entry>''')
296     return templ.substitute({'seq': seq, 'entry_type': entry_type, 'ps_entries': ps_entries})
297
298
299 def add_pl_entry_default_xml(seq, entry_type, pl_entries):
300     """Generate xml containing PrefixList data
301
302     :param seq: Sequence of PrefixList entry
303     :type seq: string
304     :param entry_type: Entry type (permit/deny)
305     :type entry_type: string
306     :param pl_entries: XML data containing PrefixList entries
307     :type pl_entries: string
308     :returns: String containing xml data for request
309
310     """
311     templ = Template('''
312     <prefix-list-entry xmlns="urn:opendaylight:sxp:controller">
313           <entry-type>$entry_type</entry-type>
314           <entry-seq>$seq</entry-seq>$pl_entries
315     </prefix-list-entry>''')
316     return templ.substitute({'seq': seq, 'entry_type': entry_type, 'pl_entries': pl_entries})
317
318
319 def add_pl_entry_xml(prefix):
320     """Generate xml containing PrefixList data
321
322     :param prefix: Ipv4/6 prefix
323     :type prefix: string
324     :returns: String containing xml data for request
325
326     """
327     templ = Template('''
328         <prefix-list-match>
329             <ip-prefix>$prefix</ip-prefix>
330         </prefix-list-match>''')
331     return templ.substitute({'prefix': prefix})
332
333
334 def add_epl_entry_xml(prefix, op, mask):
335     """Generate xml containing Extended PrefixList data
336
337     :param prefix: Ipv4/6 prefix
338     :type prefix: string
339     :param op: PrefixList option (ge/le/eq)
340     :type op: string
341     :param mask: Ipv4/6 Mask
342     :type mask: string
343     :returns: String containing xml data for request
344
345     """
346     templ = Template('''
347         <prefix-list-match>
348             <ip-prefix>$prefix</ip-prefix>
349             <mask>
350                 <mask-range>$op</mask-range>
351                 <mask-value>$mask</mask-value>
352             </mask>
353         </prefix-list-match>''')
354     return templ.substitute({'prefix': prefix, 'mask': mask, 'op': op})
355
356
357 def add_ps_entry_xml(op, length):
358     """Generate xml containing Extended PrefixList data
359
360     :param op: PrefixList option (ge/le/eq)
361     :type op: string
362     :param length: PeerSequence length
363     :type length: string
364     :returns: String containing xml data for request
365
366     """
367     templ = Template('''
368         <peer-sequence-length>$length</peer-sequence-length>
369         <peer-sequence-range>$op</peer-sequence-range>
370         ''')
371     return templ.substitute({'length': length, 'op': op})
372
373
374 def parse_peer_groups(groups_json):
375     """Parse JSON string into Array of PeerGroups
376
377     :param groups_json: JSON containing PeerGroups
378     :type groups_json: string
379     :returns: Array containing PeerGroups.
380
381     """
382     data = json.loads(groups_json)
383     groups = data['output']
384     output = []
385     for group in groups.values():
386         output += group
387     return output
388
389
390 def parse_connections(connections_json):
391     """Parse JSON string into Array of Connections
392
393     :param connections_json: JSON containing Connections
394     :type connections_json: string
395     :returns: Array containing Connections.
396
397     """
398     data = json.loads(connections_json)
399     connections = data['output']['connections']
400     output = []
401     for connection in connections.values():
402         output += connection
403     return output
404
405
406 def find_connection(connections_json, version, mode, ip, port, state):
407     """Test if Connection with specified values is contained in JSON
408
409     :param connections_json: JSON containing Connections
410     :type connections_json: string
411     :param version: Version of SXP protocol (version1/2/3/4)
412     :type version: string
413     :param mode: Mode of SXP peer (speaker/listener/both)
414     :type mode: string
415     :param ip: Ipv4/6 address of remote peer
416     :type ip: string
417     :param port: Port on with remote peer listens
418     :type port: string
419     :param state: State of connection (on/off/pendingOn/deleteHoldDown)
420     :type state: string
421     :returns: True if Connection with specified params was found, otherwise False.
422
423     """
424     for connection in parse_connections(connections_json):
425         if (connection['peer-address'] == ip and connection['tcp-port'] == int(port) and (
426                         mode.strip() == 'any' or connection['mode'] == mode) and connection['version'] == version):
427             if state == 'none':
428                 return True
429             elif connection['state'] == state:
430                 return True
431     return False
432
433
434 def parse_bindings(bindings_json):
435     """Parse JSON string into Array of Bindings
436
437     :param bindings_json: JSON containing Bindings
438     :type bindings_json: string
439     :returns: Array containing Bindings.
440
441     """
442     data = json.loads(bindings_json)
443     output = []
444     for bindings_json in data['output'].values():
445         for binding in bindings_json:
446             output.append(binding)
447     return output
448
449
450 def find_binding(bindings, sgt, prefix):
451     """Test if Binding with specified values is contained in JSON
452
453     :param bindings: JSON containing Bindings
454     :type bindings: string
455     :param sgt: Source Group Tag
456     :type sgt: string
457     :param prefix: Ipv4/6 prefix
458     :type prefix: string
459     :returns: True if Binding with specified params was found, otherwise False.
460
461     """
462     for binding in parse_bindings(bindings):
463         if binding['sgt'] == int(sgt):
464             for ip_prefix in binding['ip-prefix']:
465                 if ip_prefix == prefix:
466                     return True
467     return False
468
469
470 def parse_prefix_groups(prefix_groups_json, source_):
471     """Parse JSON string into Array of PrefixGroups
472
473     :param prefix_groups_json: JSON containing PrefixGroups
474     :type prefix_groups_json: string
475     :param source_: Source of PrefixGroups (sxp/local)
476     :type source_: string
477     :returns: Array containing PrefixGroups.
478
479     """
480     data = json.loads(prefix_groups_json)
481     bindings = data['sxp-node:master-database']
482     output = []
483     for binding in bindings.values():
484         for binding_source in binding:
485             if source_ == "any" or binding_source['binding-source'] == source_:
486                 for prefix_group in binding_source['prefix-group']:
487                     output.append(prefix_group)
488     return output
489
490
491 def find_binding_legacy(prefix_groups_json, sgt, prefix, source_, action):
492     """Test if Binding with specified values is contained in JSON
493
494     :param prefix_groups_json: JSON containing Bindings and PrefixGroups
495     :type prefix_groups_json: string
496     :param sgt: Source Group Tag
497     :type sgt: string
498     :param prefix: Ipv4/6 prefix
499     :type prefix: string
500     :param source_: Source of binding (local/sxp)
501     :type source_: string
502     :param action: Action for binding (add/delete)
503     :type action: string
504     :returns: True if Binding with specified params was found, otherwise False.
505
506     """
507     found = False
508     for prefixgroup in parse_prefix_groups(prefix_groups_json, source_):
509         if prefixgroup['sgt'] == int(sgt):
510             for binding in prefixgroup['binding']:
511                 if binding['ip-prefix'] == prefix and binding['action'] == action:
512                     found = True
513     return found
514
515
516 def add_entry_xml(sgt, prefix, ip, domain_name):
517     """Generate xml for Add Bindings request
518
519     :param sgt: Source Group Tag
520     :type sgt: string
521     :param prefix: Ipv4/6 prefix
522     :type prefix: string
523     :param ip: Ipv4 address of node
524     :type ip: string
525     :param domain_name: Name of Domain
526     :type domain_name: string
527     :returns: String containing xml data for request
528
529     """
530     templ = Template('''<input>
531   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
532   $domain
533   <sgt xmlns="urn:opendaylight:sxp:controller">$sgt</sgt>
534   <ip-prefix xmlns="urn:opendaylight:sxp:controller">$prefix</ip-prefix>
535 </input>''')
536     data = templ.substitute({'sgt': sgt, 'prefix': prefix, 'ip': ip, 'domain': get_domain_name(domain_name)})
537     return data
538
539
540 def add_connection_xml(version, mode, ip, port, node, password_, domain_name, bindings_timeout=0):
541     """Generate xml for Add Connection request
542
543     :param version: Version of SXP protocol (version1/2/3/4)
544     :type version: string
545     :param mode: Mode of SXP peer (speaker/listener/both)
546     :type mode: string
547     :param ip: Ipv4/6 address of remote peer
548     :type ip: string
549     :param port: Port on with remote peer listens
550     :type port: string
551     :param node: Ipv4 address of node
552     :type node: string
553     :param password_: Password type (none/default)
554     :type password_: string
555     :param domain_name: Name of Domain
556     :type domain_name: string
557     :param bindings_timeout: Specifies DHD and Reconciliation timers
558     :type bindings_timeout: int
559     :returns: String containing xml data for request
560
561     """
562     templ = Template('''<input>
563    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
564    $domain
565    <connections xmlns="urn:opendaylight:sxp:controller">
566       <connection>
567          <peer-address>$ip</peer-address>
568          <tcp-port>$port</tcp-port>
569          <password>$password_</password>
570          <mode>$mode</mode>
571          <version>$version</version>
572          <description>Connection to ISR-G2</description>
573          <connection-timers>
574             <hold-time-min-acceptable>45</hold-time-min-acceptable>
575             <keep-alive-time>30</keep-alive-time>
576             <reconciliation-time>$timeout</reconciliation-time>
577             <delete-hold-down-time>$timeout</delete-hold-down-time>
578          </connection-timers>
579       </connection>
580    </connections>
581 </input>
582 ''')
583     data = templ.substitute(
584         {'ip': ip, 'port': port, 'mode': mode, 'version': version, 'node': node,
585          'password_': password_, 'domain': get_domain_name(domain_name), 'timeout': bindings_timeout})
586     return data
587
588
589 def delete_connections_xml(address, port, node, domain_name):
590     """Generate xml for Delete Connection request
591
592     :param address: Ipv4/6 address of remote peer
593     :type address: string
594     :param port: Port on with remote peer listens
595     :type port: string
596     :param node: Ipv4 address of node
597     :type node: string
598     :param domain_name: Name of Domain
599     :type domain_name: string
600     :returns: String containing xml data for request
601
602     """
603     templ = Template('''<input>
604    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
605    $domain
606    <peer-address xmlns="urn:opendaylight:sxp:controller">$address</peer-address>
607    <tcp-port xmlns="urn:opendaylight:sxp:controller">$port</tcp-port>
608 </input>''')
609     data = templ.substitute({'address': address, 'port': port, 'node': node, 'domain': get_domain_name(domain_name)})
610     return data
611
612
613 def update_binding_xml(sgt0, prefix0, sgt1, prefix1, ip, domain_name):
614     """Generate xml for Update Binding request
615
616     :param sgt0: Original Source Group Tag
617     :type sgt0: string
618     :param prefix0: Original Ipv4/6 prefix
619     :type prefix0: string
620     :param sgt1: New Source Group Tag
621     :type sgt1: string
622     :param prefix1: New Ipv4/6 prefix
623     :type prefix1: string
624     :param ip: Ipv4 address of node
625     :type ip: string
626     :param domain_name: Name of Domain
627     :type domain_name: string
628     :returns: String containing xml data for request
629
630     """
631     templ = Template('''<input>
632   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
633   $domain
634   <original-binding xmlns="urn:opendaylight:sxp:controller">
635     <sgt>$sgt0</sgt>
636     <ip-prefix>$prefix0</ip-prefix>
637   </original-binding>
638   <new-binding xmlns="urn:opendaylight:sxp:controller">
639     <sgt>$sgt1</sgt>
640     <ip-prefix>$prefix1</ip-prefix>
641   </new-binding>
642 </input>''')
643     data = templ.substitute(
644         {'sgt0': sgt0, 'sgt1': sgt1, 'prefix0': prefix0, 'prefix1': prefix1, 'ip': ip,
645          'domain': get_domain_name(domain_name)})
646     return data
647
648
649 def delete_binding_xml(sgt, prefix, ip, domain_name):
650     """Generate xml for Delete Binding request
651
652     :param sgt: Source Group Tag
653     :type sgt: string
654     :param prefix: Ipv4/6 prefix
655     :type prefix: string
656     :param ip: Ipv4 address of node
657     :type ip: string
658     :param domain_name: Name of Domain
659     :type domain_name: string
660     :returns: String containing xml data for request
661
662     """
663     templ = Template('''<input>
664   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
665   <sgt xmlns="urn:opendaylight:sxp:controller">$sgt</sgt>
666   <ip-prefix xmlns="urn:opendaylight:sxp:controller">$prefix</ip-prefix>
667   $domain
668 </input>''')
669     data = templ.substitute({'sgt': sgt, 'prefix': prefix, 'ip': ip, 'domain': get_domain_name(domain_name)})
670     return data
671
672
673 def add_peer_group_xml(name, peers, ip):
674     """Generate xml for Add PeerGroups request
675
676     :param name: Name of PeerGroup
677     :type name: string
678     :param peers: XML formatted peers that will be added to group
679     :type peers: string
680     :param ip: Ipv4 address of node
681     :type ip: string
682     :returns: String containing xml data for request
683
684     """
685     templ = Template('''<input>
686   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
687   <sxp-peer-group xmlns="urn:opendaylight:sxp:controller">
688     <name xmlns="urn:opendaylight:sxp:controller">$name</name>
689     <sxp-peers xmlns="urn:opendaylight:sxp:controller">$peers</sxp-peers>
690     </sxp-peer-group>
691 </input>''')
692     data = templ.substitute({'name': name, 'peers': peers, 'ip': ip})
693     return data
694
695
696 def delete_peer_group_xml(name, ip):
697     """Generate xml for Delete PeerGroup request
698
699     :param name: Name of PeerGroup
700     :type name: string
701     :param ip: Ipv4 address of node
702     :type ip: string
703     :returns: String containing xml data for request
704
705     """
706     templ = Template('''<input>
707   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
708   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$name</peer-group-name>
709 </input>''')
710     data = templ.substitute({'name': name, 'ip': ip})
711     return data
712
713
714 def get_peer_groups_from_node_xml(ip):
715     """Generate xml for Get PeerGroups request
716
717     :param ip: Ipv4 address of node
718     :type ip: string
719     :returns: String containing xml data for request
720
721     """
722     templ = Template('''<input>
723    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
724 </input>''')
725     data = templ.substitute({'ip': ip})
726     return data
727
728
729 def add_filter_xml(group, filter_type, entries, ip):
730     """Generate xml for Add Filter request
731
732     :param group: Name of group containing filter
733     :type group: string
734     :param filter_type: Type of filter
735     :type filter_type: string
736     :param entries: XML formatted entries that will be added in filter
737     :type entries: string
738     :param ip: Ipv4 address of node
739     :type ip: string
740     :returns: String containing xml data for request
741
742     """
743     templ = Template('''<input>
744   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
745   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
746   <sxp-filter xmlns="urn:opendaylight:sxp:controller">
747     <filter-type>$filter_type</filter-type>$entries
748   </sxp-filter>
749 </input>''')
750     data = templ.substitute(
751         {'group': group, 'filter_type': filter_type, 'ip': ip, 'entries': entries})
752     return data
753
754
755 def add_domain_filter_xml(domain, domains, entries, ip, filter_name=None):
756     """Generate xml for Add Domain Filter request
757
758     :param domain: Name of Domain containing filter
759     :type domain: string
760     :param domains: Domains on which filter will be applied
761     :type domains: string
762     :param entries: XML formatted entries that will be added in filter
763     :type entries: string
764     :param ip: Ipv4 address of node
765     :type ip: string
766     :param filter_name: Name of filter
767     :type filter_name: string
768     :returns: String containing xml data for request
769
770     """
771     if filter_name:
772         filter_name = "<filter-name>" + filter_name + "</filter-name>"
773     templ = Template('''<input>
774   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
775   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
776   <sxp-domain-filter xmlns="urn:opendaylight:sxp:controller">
777     $filter_name
778     <domains>$domains</domains>
779     $entries
780   </sxp-domain-filter>
781 </input>''')
782     data = templ.substitute(
783         {'domain': domain, 'domains': domains, 'ip': ip, 'entries': entries, 'filter_name': filter_name})
784     return data
785
786
787 def delete_filter_xml(group, filter_type, ip):
788     """Generate xml for Delete Filter request
789
790     :param group: Name of group containing filter
791     :type group: string
792     :param filter_type: Type of filter
793     :type filter_type: string
794     :param ip: Ipv4 address of node
795     :type ip: string
796     :returns: String containing xml data for request
797
798     """
799     templ = Template('''<input>
800   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
801   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
802   <filter-type xmlns="urn:opendaylight:sxp:controller">$filter_type</filter-type>
803 </input>''')
804     data = templ.substitute(
805         {'group': group, 'filter_type': filter_type, 'ip': ip})
806     return data
807
808
809 def delete_domain_filter_xml(domain, ip, filter_name=None):
810     """Generate xml for Delete Filter request
811
812     :param domain: Name of Domain containing filter
813     :type domain: string
814     :param ip: Ipv4 address of node
815     :type ip: string
816     :param filter_name: Name of filter
817     :type filter_name: string
818     :returns: String containing xml data for request
819
820     """
821     if filter_name:
822         filter_name = '<filter-name xmlns="urn:opendaylight:sxp:controller">' + filter_name + "</filter-name>"
823     templ = Template('''<input>
824   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
825   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
826   $filter_name
827 </input>''')
828     data = templ.substitute(
829         {'domain': domain, 'ip': ip, 'filter_name': filter_name})
830     return data
831
832
833 def get_connections_from_node_xml(ip, domain_name):
834     """Generate xml for Get Connections request
835
836     :param ip: Ipv4 address of node
837     :type ip: string
838     :param domain_name: Name of Domain
839     :type domain_name: string
840     :returns: String containing xml data for request
841
842     """
843     templ = Template('''<input>
844    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
845    $domain
846 </input>''')
847     data = templ.substitute({'ip': ip, 'domain': get_domain_name(domain_name)})
848     return data
849
850
851 def get_bindings_from_node_xml(ip, binding_range, domain_name):
852     """Generate xml for Get Bindings request
853
854     :param binding_range: All or only Local bindings
855     :type binding_range: string
856     :param ip: Ipv4 address of node
857     :type ip: string
858     :param domain_name: Name of Domain
859     :type domain_name: string
860     :returns: String containing xml data for request
861
862     """
863     templ = Template('''<input>
864   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
865   <bindings-range xmlns="urn:opendaylight:sxp:controller">$range</bindings-range>
866   $domain
867 </input>''')
868     data = templ.substitute({'ip': ip, 'range': binding_range, 'domain': get_domain_name(domain_name)})
869     return data
870
871
872 def add_node_xml(node_id, port, password, version, node_ip=None, expansion=0, bindings_timeout=0):
873     """Generate xml for Add Node request
874
875     :param node_id: Ipv4 address formatted node id
876     :type node_id: string
877     :param node_ip: Ipv4 address of node
878     :type node_ip: string
879     :param port: Node port number
880     :type port: int
881     :param password: TCP-MD5 password
882     :type password: string
883     :param version: Sxp device version
884     :type version: string
885     :param expansion: Bindings expansion
886     :type expansion: int
887     :param bindings_timeout: Specifies DHD and Reconciliation timers
888     :type bindings_timeout: int
889     :returns: String containing xml data for request
890
891     """
892     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
893     <node-id>$id</node-id>
894     <timers>
895         <retry-open-time>1</retry-open-time>
896         <hold-time-min-acceptable>120</hold-time-min-acceptable>
897         <delete-hold-down-time>$timeout</delete-hold-down-time>
898         <hold-time-min>90</hold-time-min>
899         <reconciliation-time>$timeout</reconciliation-time>
900         <hold-time>90</hold-time>
901         <hold-time-max>180</hold-time-max>
902         <keep-alive-time>30</keep-alive-time>
903     </timers>
904     <mapping-expanded>$expansion</mapping-expanded>
905     <security>
906         <password>$password</password>
907     </security>
908     <tcp-port>$port</tcp-port>
909     <version>$version</version>
910     <description>ODL SXP Controller</description>
911     <source-ip>$ip</source-ip>
912     <master-database></master-database>
913 </input>''')
914     data = templ.substitute(
915         {'ip': node_id if not node_ip else node_ip, 'id': node_id, 'port': port, 'password': password,
916          'version': version, 'expansion': expansion, 'timeout': bindings_timeout})
917     return data
918
919
920 def delete_node_xml(node_id):
921     """Generate xml for Delete node request
922
923     :param node_id: Ipv4 address formatted node id
924     :type node_id: string
925     :returns: String containing xml data for request
926
927     """
928     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
929   <node-id>$id</node-id>
930 </input>''')
931     data = templ.substitute({'id': node_id})
932     return data
933
934
935 def add_domain_xml(node_id, name):
936     """Generate xml for Add Domain request
937
938     :param node_id: Id of node
939     :type node_id: string
940     :param name: Name of Domain
941     :type name: string
942     :returns: String containing xml data for request
943
944     """
945     templ = Template('''<input>
946   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
947   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
948 </input>''')
949     data = templ.substitute({'name': name, 'id': node_id})
950     return data
951
952
953 def delete_domain_xml(node_id, name):
954     """Generate xml for Remove Domain request
955
956     :param node_id: Id of node
957     :type node_id: string
958     :param name: Name of Domain
959     :type name: string
960     :returns: String containing xml data for request
961
962     """
963     return add_domain_xml(node_id, name)
964
965
966 def get_domain_name(domain_name):
967     """Generate xml for Get Bindings request
968
969     :param domain_name: Name of Domain
970     :type domain_name: string
971     :returns: String containing xml data for request
972
973     """
974     if domain_name == 'global':
975         return ''
976     else:
977         return '<domain-name xmlns="urn:opendaylight:sxp:controller">' + domain_name + '</domain-name>'
978
979
980 def add_bindings_xml(node_id, domain, sgt, prefixes):
981     """Generate xml for Add Bindings request
982
983     :param node_id: Id of node
984     :type node_id: string
985     :param domain: Name of Domain
986     :type domain: string
987     :param sgt: Security group
988     :type sgt: int
989     :param prefixes: List of ip-prefixes
990     :type prefixes: string
991     :returns: String containing xml data for request
992
993     """
994     bindings = ''
995     for prefix in prefixes.split(','):
996         bindings += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
997     templ = Template('''<input>
998   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
999   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
1000   <binding xmlns="urn:opendaylight:sxp:controller">
1001       <sgt>$sgt</sgt>
1002       $bindings
1003   </binding>
1004 </input>''')
1005     data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'bindings': bindings})
1006     return data
1007
1008
1009 def delete_bindings_xml(node_id, domain, sgt, prefixes):
1010     """Generate xml for Remove Bindings request
1011
1012     :param node_id: Id of node
1013     :type node_id: string
1014     :param domain: Name of Domain
1015     :type domain: string
1016     :param sgt: Security group
1017     :type sgt: int
1018     :param prefixes: List of ip-prefixes
1019     :type prefixes: string
1020     :returns: String containing xml data for request
1021
1022     """
1023     return add_bindings_xml(node_id, domain, sgt, prefixes)
1024
1025
1026 def prefix_range(start, end):
1027     """Generate and concatenate ip-prefixes
1028
1029     :param start: Start index
1030     :type start: string
1031     :param end: End index
1032     :type end: string
1033     :returns: String containing concatenated ip-prefixes
1034
1035     """
1036     start = int(start)
1037     end = int(end)
1038     index = 0
1039     prefixes = ''
1040     while index < end:
1041         prefixes += get_ip_from_number(index, start) + '/32'
1042         index += 1
1043         if index < end:
1044             prefixes += ','
1045     return prefixes