CSIT-610 HC Test: add test cases for unnumbered interface
[csit.git] / resources / libraries / python / honeycomb / HcAPIKwInterfaces.py
1 # Copyright (c) 2017 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Keywords to manipulate interface configuration using Honeycomb REST API.
15
16 The keywords make possible to put and get configuration data and to get
17 operational data.
18 """
19 from robot.api import logger
20
21 from resources.libraries.python.topology import Topology
22 from resources.libraries.python.HTTPRequest import HTTPCodes
23 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
24 from resources.libraries.python.honeycomb.HoneycombUtil \
25     import DataRepresentation
26 from resources.libraries.python.honeycomb.HoneycombUtil \
27     import HoneycombUtil as HcUtil
28
29
30 class InterfaceKeywords(object):
31     """Keywords for Interface manipulation.
32
33     Implements keywords which get configuration and operational data about
34     vpp interfaces and set the interface's parameters using Honeycomb REST API.
35     """
36
37     INTF_PARAMS = ("name", "description", "type", "enabled",
38                    "link-up-down-trap-enable", "v3po:l2", "v3po:vxlan-gpe",
39                    "vpp-vlan:sub-interfaces")
40     IPV4_PARAMS = ("enabled", "forwarding", "mtu")
41     IPV6_PARAMS = ("enabled", "forwarding", "mtu", "dup-addr-detect-transmits")
42     IPV6_AUTOCONF_PARAMS = ("create-global-addresses",
43                             "create-temporary-addresses",
44                             "temporary-valid-lifetime",
45                             "temporary-preferred-lifetime")
46     ETH_PARAMS = ("mtu", )
47     ROUTING_PARAMS = ("ipv4-vrf-id", "ipv6-vrf-id")
48     VXLAN_PARAMS = ("src", "dst", "vni", "encap-vrf-id")
49     L2_PARAMS = ("bridge-domain", "split-horizon-group",
50                  "bridged-virtual-interface")
51     TAP_PARAMS = ("tap-name", "mac", "device-instance")
52     VHOST_USER_PARAMS = ("socket", "role")
53     SUB_IF_PARAMS = ("identifier",
54                      "vlan-type",
55                      "enabled")
56     SUB_IF_MATCH = ("default",
57                     "untagged",
58                     "vlan-tagged",
59                     "vlan-tagged-exact-match")
60     BD_PARAMS = ("bridge-domain",
61                  "split-horizon-group",
62                  "bridged-virtual-interface")
63     VXLAN_GPE_PARAMS = ("local",
64                         "remote",
65                         "vni",
66                         "next-protocol",
67                         "encap-vrf-id",
68                         "decap-vrf-id")
69
70     def __init__(self):
71         pass
72
73     @staticmethod
74     def _configure_interface(node, interface, data,
75                              data_representation=DataRepresentation.JSON):
76         """Send interface configuration data and check the response.
77
78         :param node: Honeycomb node.
79         :param interface: The name of interface.
80         :param data: Configuration data to be sent in PUT request.
81         :param data_representation: How the data is represented.
82         :type node: dict
83         :type interface: str
84         :type data: dict
85         :type data_representation: DataRepresentation
86         :returns: Content of response.
87         :rtype: bytearray
88         :raises HoneycombError: If the status code in response on PUT is not
89         200 = OK.
90         """
91
92         status_code, resp = HcUtil.\
93             put_honeycomb_data(node, "config_vpp_interfaces", data,
94                                data_representation=data_representation)
95         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
96             raise HoneycombError(
97                 "The configuration of interface '{0}' was not successful. "
98                 "Status code: {1}.".format(interface, status_code))
99         return resp
100
101     @staticmethod
102     def get_all_interfaces_cfg_data(node):
103         """Get configuration data about all interfaces from Honeycomb.
104
105         :param node: Honeycomb node.
106         :type node: dict
107         :returns: Configuration data about all interfaces from Honeycomb.
108         :rtype: list
109         :raises HoneycombError: If it is not possible to get configuration data.
110         """
111
112         status_code, resp = HcUtil.\
113             get_honeycomb_data(node, "config_vpp_interfaces")
114         if status_code != HTTPCodes.OK:
115             raise HoneycombError(
116                 "Not possible to get configuration information about the "
117                 "interfaces. Status code: {0}.".format(status_code))
118         try:
119             return resp["interfaces"]["interface"]
120
121         except (KeyError, TypeError):
122             return []
123
124     @staticmethod
125     def get_interface_cfg_data(node, interface):
126         """Get configuration data about the given interface from Honeycomb.
127
128         :param node: Honeycomb node.
129         :param interface: The name of interface.
130         :type node: dict
131         :type interface: str
132         :returns: Configuration data about the given interface from Honeycomb.
133         :rtype: dict
134         """
135
136         intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node)
137         for intf in intfs:
138             if intf["name"] == interface:
139                 return intf
140         return {}
141
142     @staticmethod
143     def get_all_interfaces_oper_data(node):
144         """Get operational data about all interfaces from Honeycomb.
145
146         :param node: Honeycomb node.
147         :type node: dict
148         :returns: Operational data about all interfaces from Honeycomb.
149         :rtype: list
150         :raises HoneycombError: If it is not possible to get operational data.
151         """
152
153         status_code, resp = HcUtil.\
154             get_honeycomb_data(node, "oper_vpp_interfaces")
155         if status_code != HTTPCodes.OK:
156             raise HoneycombError(
157                 "Not possible to get operational information about the "
158                 "interfaces. Status code: {0}.".format(status_code))
159         try:
160             return resp["interfaces-state"]["interface"]
161
162         except (KeyError, TypeError):
163             return []
164
165     @staticmethod
166     def get_disabled_interfaces_oper_data(node):
167         """Get operational data about all disabled interfaces from Honeycomb.
168
169         :param node: Honeycomb node.
170         :type node: dict
171         :returns: Operational data about disabled interfaces.
172         :rtype: list
173         :raises HoneycombError: If it is not possible to get operational data.
174         """
175
176         status_code, resp = HcUtil. \
177             get_honeycomb_data(node, "oper_disabled_interfaces")
178         if status_code == HTTPCodes.NOT_FOUND:
179             raise HoneycombError(
180                 "No disabled interfaces present on node."
181             )
182         if status_code != HTTPCodes.OK:
183             raise HoneycombError(
184                 "Not possible to get operational information about the "
185                 "interfaces. Status code: {0}.".format(status_code))
186         try:
187             return resp["disabled-interfaces"]["disabled-interface-index"]
188
189         except (KeyError, TypeError):
190             return []
191
192     @staticmethod
193     def get_interface_oper_data(node, interface):
194         """Get operational data about the given interface from Honeycomb.
195
196         :param node: Honeycomb node.
197         :param interface: The name of interface.
198         :type node: dict
199         :type interface: str
200         :returns: Operational data about the given interface from Honeycomb.
201         :rtype: dict
202         """
203
204         try:
205             interface = Topology.convert_interface_reference(
206                 node, interface, "name")
207         except RuntimeError:
208             if isinstance(interface, basestring):
209                 # Probably name of a custom interface (TAP, VxLAN, Vhost, ...)
210                 pass
211             else:
212                 raise
213
214         intfs = InterfaceKeywords.get_all_interfaces_oper_data(node)
215         for intf in intfs:
216             if intf["name"] == interface:
217                 return intf
218         return {}
219
220     @staticmethod
221     def _set_interface_properties(node, interface, path, new_value=None):
222         """Set interface properties.
223
224         This method reads interface configuration data, creates, changes or
225         removes the requested data and puts it back to Honeycomb.
226
227         :param node: Honeycomb node.
228         :param interface: The name of interface.
229         :param path:  Path to data we want to change / create / remove.
230         :param new_value: The new value to be set. If None, the item will be
231         removed.
232         :type node: dict
233         :type interface: str
234         :type path: tuple
235         :type new_value: str, dict or list
236         :returns: Content of response.
237         :rtype: bytearray
238         :raises HoneycombError: If it is not possible to get or set the data.
239         """
240
241         status_code, resp = HcUtil.\
242             get_honeycomb_data(node, "config_vpp_interfaces")
243         if status_code != HTTPCodes.OK:
244             raise HoneycombError(
245                 "Not possible to get configuration information about the "
246                 "interfaces. Status code: {0}.".format(status_code))
247
248         if new_value:
249             new_data = HcUtil.set_item_value(resp, path, new_value)
250         else:
251             new_data = HcUtil.remove_item(resp, path)
252         return InterfaceKeywords._configure_interface(node, interface, new_data)
253
254     @staticmethod
255     def set_interface_state(node, interface, state="up"):
256         """Set VPP interface state.
257
258         The keyword changes the administration state of interface to up or down
259         depending on the parameter "state".
260
261         :param node: Honeycomb node.
262         :param interface: Interface name, key, link name or sw_if_index.
263         :param state: The requested state, only "up" and "down" are valid
264         values.
265         :type node: dict
266         :type interface: str
267         :type state: str
268         :returns: Content of response.
269         :rtype: bytearray
270         :raises KeyError: If the argument "state" is nor "up" or "down".
271         :raises HoneycombError: If the interface is not present on the node.
272         """
273
274         intf_state = {"up": "true",
275                       "down": "false"}
276
277         interface = Topology.convert_interface_reference(
278             node, interface, "name")
279
280         intf = interface.replace("/", "%2F")
281         path = "/interface/{0}".format(intf)
282
283         status_code, resp = HcUtil.\
284             get_honeycomb_data(node, "config_vpp_interfaces", path)
285         if status_code != HTTPCodes.OK:
286             raise HoneycombError(
287                 "Not possible to get configuration information about the "
288                 "interfaces. Status code: {0}.".format(status_code))
289
290         resp["interface"][0]["enabled"] = intf_state[state.lower()]
291
292         status_code, resp = HcUtil. \
293             put_honeycomb_data(node, "config_vpp_interfaces", resp, path,
294                                data_representation=DataRepresentation.JSON)
295         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
296             raise HoneycombError(
297                 "The configuration of interface '{0}' was not successful. "
298                 "Status code: {1}.".format(interface, status_code))
299         return resp
300
301     @staticmethod
302     def set_interface_up(node, interface):
303         """Set the administration state of VPP interface to up.
304
305         :param node: Honeycomb node.
306         :param interface: The name of interface.
307         :type node: dict
308         :type interface: str
309         :returns: Content of response
310         :rtype: bytearray
311         """
312
313         return InterfaceKeywords.set_interface_state(node, interface, "up")
314
315     @staticmethod
316     def set_interface_down(node, interface):
317         """Set the administration state of VPP interface to down.
318
319         :param node: Honeycomb node.
320         :param interface: The name of interface.
321         :type node: dict
322         :type interface: str
323         :returns: Content of response.
324         :rtype: bytearray
325         """
326
327         return InterfaceKeywords.set_interface_state(node, interface, "down")
328
329     @staticmethod
330     def add_bridge_domain_to_interface(node, interface, bd_name,
331                                        split_horizon_group=None, bvi=None):
332         """Add a new bridge domain to an interface and set its parameters.
333
334         :param node: Honeycomb node.
335         :param interface: Interface name, key, link name or sw_if_index.
336         :param bd_name: Bridge domain name.
337         :param split_horizon_group: Split-horizon group name.
338         :param bvi: The bridged virtual interface.
339         :type node: dict
340         :type interface: str
341         :type bd_name: str
342         :type split_horizon_group: str
343         :type bvi: str
344         :returns: Content of response.
345         :rtype: bytearray
346         :raises HoneycombError: If the interface is not present on the node.
347         """
348
349         interface = Topology.convert_interface_reference(
350             node, interface, "name")
351
352         v3po_l2 = {"bridge-domain": str(bd_name)}
353         if split_horizon_group:
354             v3po_l2["split-horizon-group"] = str(split_horizon_group)
355         if bvi:
356             v3po_l2["bridged-virtual-interface"] = str(bvi)
357
358         path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2")
359
360         return InterfaceKeywords._set_interface_properties(
361             node, interface, path, v3po_l2)
362
363     @staticmethod
364     def remove_bridge_domain_from_interface(node, interface):
365         """Remove bridge domain assignment from interface.
366
367         :param node: Honeycomb node.
368         :param interface: Interface name, key, link name or sw_if_index.
369         :type node: dict
370         :type interface: str or int
371
372         :raises HoneycombError: If the operation fails.
373         """
374
375         interface = Topology.convert_interface_reference(
376             node, interface, "name")
377
378         intf = interface.replace("/", "%2F")
379
380         path = "/interface/{0}/v3po:l2".format(intf)
381
382         status_code, response = HcUtil.delete_honeycomb_data(
383             node, "config_vpp_interfaces", path)
384
385         if status_code != HTTPCodes.OK:
386             if '"error-tag":"data-missing"' in response:
387                 logger.debug("Data does not exist in path.")
388             else:
389                 raise HoneycombError(
390                     "Could not remove bridge domain assignment from interface "
391                     "'{0}'. Status code: {1}.".format(interface, status_code))
392
393     @staticmethod
394     def get_bd_oper_data_from_interface(node, interface):
395         """Returns operational data about bridge domain settings in the
396         interface.
397
398         :param node: Honeycomb node.
399         :param interface: The name of interface.
400         :type node: dict
401         :type interface: str
402         :returns: Operational data about bridge domain settings in the
403         interface.
404         :rtype: dict
405         """
406
407         if_data = InterfaceKeywords.get_interface_oper_data(node, interface)
408
409         if if_data:
410             try:
411                 return if_data["v3po:l2"]
412             except KeyError:
413                 return {}
414         return {}
415
416     @staticmethod
417     def configure_interface_base(node, interface, param, value):
418         """Configure the base parameters of interface.
419
420         :param node: Honeycomb node.
421         :param interface: The name of interface.
422         :param param: Parameter to configure (set, change, remove)
423         :param value: The value of parameter. If None, the parameter will be
424         removed.
425         :type node: dict
426         :type interface: str
427         :type param: str
428         :type value: str
429         :returns: Content of response.
430         :rtype: bytearray
431         :raises HoneycombError: If the parameter is not valid.
432         """
433
434         if param not in InterfaceKeywords.INTF_PARAMS:
435             raise HoneycombError("The parameter {0} is invalid.".format(param))
436
437         path = ("interfaces", ("interface", "name", interface), param)
438         return InterfaceKeywords._set_interface_properties(
439             node, interface, path, value)
440
441     @staticmethod
442     def configure_interface_ipv4(node, interface, param, value):
443         """Configure IPv4 parameters of interface.
444
445         :param node: Honeycomb node.
446         :param interface: The name of interface.
447         :param param: Parameter to configure (set, change, remove)
448         :param value: The value of parameter. If None, the parameter will be
449         removed.
450         :type node: dict
451         :type interface: str
452         :type param: str
453         :type value: str
454         :returns: Content of response.
455         :rtype: bytearray
456         :raises HoneycombError: If the parameter is not valid.
457         """
458
459         interface = Topology.convert_interface_reference(
460             node, interface, "name")
461
462         if param not in InterfaceKeywords.IPV4_PARAMS:
463             raise HoneycombError("The parameter {0} is invalid.".format(param))
464
465         path = ("interfaces", ("interface", "name", interface),
466                 "ietf-ip:ipv4", param)
467         return InterfaceKeywords._set_interface_properties(
468             node, interface, path, value)
469
470     @staticmethod
471     def add_first_ipv4_address(node, interface, ip_addr, network):
472         """Add the first IPv4 address.
473
474         If there are any other addresses configured, they will be removed.
475
476         :param node: Honeycomb node.
477         :param interface: The name of interface.
478         :param ip_addr: IPv4 address to be set.
479         :param network: Netmask or length of network prefix.
480         :type node: dict
481         :type interface: str
482         :type ip_addr: str
483         :type network: str or int
484         :returns: Content of response.
485         :rtype: bytearray
486         :raises ValueError: If the provided netmask or prefix is not valid.
487         :raises HoneycombError: If the operation fails.
488         """
489
490         interface = InterfaceKeywords.handle_interface_reference(
491             node, interface)
492
493         path = "/interface/{0}/ietf-ip:ipv4".format(interface)
494         if isinstance(network, basestring):
495             data = {
496                 "ietf-ip:ipv4": {
497                     "address": [{"ip": ip_addr, "netmask": network}, ]}}
498         elif isinstance(network, int) and (0 < network < 33):
499             data = {
500                 "ietf-ip:ipv4": {
501                     "address": [{"ip": ip_addr, "prefix-length": network}, ]}}
502         else:
503             raise ValueError("Value {0} is not a valid netmask or network "
504                              "prefix length.".format(network))
505         status_code, _ = HcUtil.put_honeycomb_data(
506             node, "config_vpp_interfaces", data, path)
507
508         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
509             raise HoneycombError(
510                 "Configuring IPv4 address failed. "
511                 "Status code:{0}".format(status_code))
512
513     @staticmethod
514     def add_ipv4_address(node, interface, ip_addr, network):
515         """Add IPv4 address.
516
517         :param node: Honeycomb node.
518         :param interface: The name of interface.
519         :param ip_addr: IPv4 address to be set.
520         :param network: Netmask or length of network prefix.
521         :type node: dict
522         :type interface: str
523         :type ip_addr: str
524         :type network: str or int
525         :returns: Content of response.
526         :rtype: bytearray
527         :raises HoneycombError: If the provided netmask or prefix is not valid.
528         """
529
530         interface = Topology.convert_interface_reference(
531             node, interface, "name")
532
533         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
534                 "address")
535         if isinstance(network, basestring):
536             address = [{"ip": ip_addr, "netmask": network}]
537         elif isinstance(network, int) and (0 < network < 33):
538             address = [{"ip": ip_addr, "prefix-length": network}]
539         else:
540             raise HoneycombError("Value {0} is not a valid netmask or network "
541                                  "prefix length.".format(network))
542         return InterfaceKeywords._set_interface_properties(
543             node, interface, path, address)
544
545     @staticmethod
546     def remove_all_ipv4_addresses(node, interface):
547         """Remove all IPv4 addresses from interface.
548
549         :param node: Honeycomb node.
550         :param interface: The name of interface.
551         :type node: dict
552         :type interface: str
553         :returns: Content of response.
554         :rtype: bytearray
555         """
556
557         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
558                 "address")
559         return InterfaceKeywords._set_interface_properties(
560             node, interface, path, None)
561
562     @staticmethod
563     def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address):
564         """Add the IPv4 neighbour.
565
566         :param node: Honeycomb node.
567         :param interface: The name of interface.
568         :param ip_addr: IPv4 address of neighbour to be set.
569         :param link_layer_address: Link layer address.
570         :type node: dict
571         :type interface: str
572         :type ip_addr: str
573         :type link_layer_address: str
574         :returns: Content of response.
575         :rtype: bytearray
576         """
577
578         interface = Topology.convert_interface_reference(
579             node, interface, "name")
580
581         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
582                 "neighbor")
583         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
584         return InterfaceKeywords._set_interface_properties(
585             node, interface, path, neighbor)
586
587     @staticmethod
588     def remove_all_ipv4_neighbors(node, interface):
589         """Remove all IPv4 neighbours.
590
591         :param node: Honeycomb node.
592         :param interface: The name of interface.
593         :type node: dict
594         :type interface: str
595         :returns: Content of response.
596         :rtype: bytearray
597         """
598
599         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
600                 "neighbor")
601         return InterfaceKeywords._set_interface_properties(
602             node, interface, path, None)
603
604     @staticmethod
605     def configure_interface_ipv6(node, interface, param, value):
606         """Configure IPv6 parameters of interface
607
608         :param node: Honeycomb node.
609         :param interface: The name of interface.
610         :param param: Parameter to configure (set, change, remove)
611         :param value: The value of parameter. If None, the parameter will be
612         removed.
613         :type node: dict
614         :type interface: str
615         :type param: str
616         :type value: str
617         :returns: Content of response.
618         :rtype: bytearray
619         :raises HoneycombError: If the parameter is not valid.
620         """
621
622         if param in InterfaceKeywords.IPV6_PARAMS:
623             path = ("interfaces", ("interface", "name", interface),
624                     "ietf-ip:ipv6", param)
625         elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS:
626             path = ("interfaces", ("interface", "name", interface),
627                     "ietf-ip:ipv6", "autoconf", param)
628         else:
629             raise HoneycombError("The parameter {0} is invalid.".format(param))
630
631         return InterfaceKeywords._set_interface_properties(
632             node, interface, path, value)
633
634     @staticmethod
635     def add_first_ipv6_address(node, interface, ip_addr, prefix_len):
636         """Add the first IPv6 address.
637
638         If there are any other addresses configured, they will be removed.
639
640         :param node: Honeycomb node.
641         :param interface: The name of interface.
642         :param ip_addr: IPv6 address to be set.
643         :param prefix_len: Prefix length.
644         :type node: dict
645         :type interface: str
646         :type ip_addr: str
647         :type prefix_len: str
648         :returns: Content of response.
649         :rtype: bytearray
650         """
651
652         interface = Topology.convert_interface_reference(
653             node, interface, "name")
654
655         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6")
656         address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]}
657         return InterfaceKeywords._set_interface_properties(
658             node, interface, path, address)
659
660     @staticmethod
661     def add_ipv6_address(node, interface, ip_addr, prefix_len):
662         """Add IPv6 address.
663
664         :param node: Honeycomb node.
665         :param interface: The name of interface.
666         :param ip_addr: IPv6 address to be set.
667         :param prefix_len: Prefix length.
668         :type node: dict
669         :type interface: str
670         :type ip_addr: str
671         :type prefix_len: str
672         :returns: Content of response.
673         :rtype: bytearray
674         """
675
676         interface = Topology.convert_interface_reference(
677             node, interface, "name")
678
679         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
680                 "address")
681         address = [{"ip": ip_addr, "prefix-length": prefix_len}, ]
682         return InterfaceKeywords._set_interface_properties(
683             node, interface, path, address)
684
685     @staticmethod
686     def remove_all_ipv6_addresses(node, interface):
687         """Remove all IPv6 addresses from interface.
688
689         :param node: Honeycomb node.
690         :param interface: The name of interface.
691         :type node: dict
692         :type interface: str
693         :returns: Content of response.
694         :rtype: bytearray
695         """
696
697         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
698                 "address")
699         return InterfaceKeywords._set_interface_properties(
700             node, interface, path, None)
701
702     @staticmethod
703     def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address):
704         """Add the IPv6 neighbour.
705
706         :param node: Honeycomb node.
707         :param interface: The name of interface.
708         :param ip_addr: IPv6 address of neighbour to be set.
709         :param link_layer_address: Link layer address.
710         :type node: dict
711         :type interface: str
712         :type ip_addr: str
713         :type link_layer_address: str
714         :returns: Content of response.
715         :rtype: bytearray
716         """
717
718         interface = Topology.convert_interface_reference(
719             node, interface, "name")
720
721         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
722                 "neighbor")
723         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
724         return InterfaceKeywords._set_interface_properties(
725             node, interface, path, neighbor)
726
727     @staticmethod
728     def remove_all_ipv6_neighbors(node, interface):
729         """Remove all IPv6 neighbours.
730
731         :param node: Honeycomb node.
732         :param interface: The name of interface.
733         :type node: dict
734         :type interface: str
735         :returns: Content of response.
736         :rtype: bytearray
737         """
738
739         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
740                 "neighbor")
741         return InterfaceKeywords._set_interface_properties(
742             node, interface, path, None)
743
744     @staticmethod
745     def configure_interface_ethernet(node, interface, param, value):
746         """Configure the ethernet parameters of interface.
747
748         :param node: Honeycomb node.
749         :param interface: The name of interface.
750         :param param: Parameter to configure (set, change, remove)
751         :param value: The value of parameter. If None, the parameter will be
752         removed.
753         :type node: dict
754         :type interface: str
755         :type param: str
756         :type value: str
757         :returns: Content of response.
758         :rtype: bytearray
759         :raises HoneycombError: If the parameter is not valid.
760         """
761
762         if param not in InterfaceKeywords.ETH_PARAMS:
763             raise HoneycombError("The parameter {0} is invalid.".format(param))
764         path = ("interfaces", ("interface", "name", interface), "v3po:ethernet",
765                 param)
766         return InterfaceKeywords._set_interface_properties(
767             node, interface, path, value)
768
769     @staticmethod
770     def configure_interface_routing(node, interface, param, value):
771         """Configure the routing parameters of interface.
772
773         :param node: Honeycomb node.
774         :param interface: The name of interface.
775         :param param: Parameter to configure (set, change, remove)
776         :param value: The value of parameter. If None, the parameter will be
777         removed.
778         :type node: dict
779         :type interface: str
780         :type param: str
781         :type value: str
782         :returns: Content of response.
783         :rtype: bytearray
784         :raises HoneycombError: If the parameter is not valid.
785         """
786
787         interface = Topology.convert_interface_reference(
788             node, interface, "name")
789
790         if param not in InterfaceKeywords.ROUTING_PARAMS:
791             raise HoneycombError("The parameter {0} is invalid.".format(param))
792
793         path = ("interfaces", ("interface", "name", interface), "v3po:routing",
794                 param)
795         return InterfaceKeywords._set_interface_properties(
796             node, interface, path, value)
797
798     @staticmethod
799     def create_vxlan_interface(node, interface, **kwargs):
800         """Create a new VxLAN interface.
801
802         :param node: Honeycomb node.
803         :param interface: The name of interface.
804         :param kwargs: Parameters and their values. The accepted parameters are
805         defined in InterfaceKeywords.VXLAN_PARAMS.
806         :type node: dict
807         :type interface: str
808         :type kwargs: dict
809         :returns: Content of response.
810         :rtype: bytearray
811         :raises HoneycombError: If the parameter is not valid.
812         """
813
814         new_vx_lan = {
815             "name": interface,
816             "type": "v3po:vxlan-tunnel",
817             "v3po:vxlan": {}
818         }
819         for param, value in kwargs.items():
820             if param not in InterfaceKeywords.VXLAN_PARAMS:
821                 raise HoneycombError("The parameter {0} is invalid.".
822                                      format(param))
823             new_vx_lan["v3po:vxlan"][param] = value
824
825         path = ("interfaces", "interface")
826         vx_lan_structure = [new_vx_lan, ]
827         return InterfaceKeywords._set_interface_properties(
828             node, interface, path, vx_lan_structure)
829
830     @staticmethod
831     def delete_interface(node, interface):
832         """Delete an interface.
833
834         :param node: Honeycomb node.
835         :param interface: The name of interface.
836         :type node: dict
837         :type interface: str
838         :returns: Content of response.
839         :rtype: bytearray
840         :raises HoneycombError: If it is not possible to get information about
841         interfaces or it is not possible to delete the interface.
842         """
843
844         path = ("interfaces", ("interface", "name", interface))
845
846         status_code, resp = HcUtil.\
847             get_honeycomb_data(node, "config_vpp_interfaces")
848         if status_code != HTTPCodes.OK:
849             raise HoneycombError(
850                 "Not possible to get configuration information about the "
851                 "interfaces. Status code: {0}.".format(status_code))
852
853         new_data = HcUtil.remove_item(resp, path)
854         status_code, resp = HcUtil.\
855             put_honeycomb_data(node, "config_vpp_interfaces", new_data)
856         if status_code != HTTPCodes.OK:
857             raise HoneycombError("Not possible to remove interface {0}. "
858                                  "Status code: {1}.".
859                                  format(interface, status_code))
860         return resp
861
862     @staticmethod
863     def configure_interface_vxlan(node, interface, **kwargs):
864         """Configure VxLAN on the interface.
865
866         The keyword configures VxLAN parameters on the given interface. The type
867         of interface must be set to "v3po:vxlan-tunnel".
868         The new VxLAN parameters overwrite the current configuration. If a
869         parameter in new configuration is missing, it is removed from VxLAN
870         configuration.
871         If the dictionary kwargs is empty, VxLAN configuration is removed.
872
873         :param node: Honeycomb node.
874         :param interface: The name of interface.
875         :param kwargs: Parameters and their values. The accepted parameters are
876         defined in InterfaceKeywords.VXLAN_PARAMS.
877         :type node: dict
878         :type interface: str
879         :type kwargs: dict
880         :returns: Content of response.
881         :rtype: bytearray
882         :raises HoneycombError: If the parameter is not valid.
883         """
884
885         vx_lan_structure = dict()
886         for param, value in kwargs.items():
887             if param not in InterfaceKeywords.VXLAN_PARAMS:
888                 raise HoneycombError("The parameter {0} is invalid.".
889                                      format(param))
890             vx_lan_structure[param] = value
891
892         path = ("interfaces", ("interface", "name", interface), "v3po:vxlan")
893         return InterfaceKeywords._set_interface_properties(
894             node, interface, path, vx_lan_structure)
895
896     @staticmethod
897     def configure_interface_l2(node, interface, param, value):
898         """Configure the L2 parameters of interface.
899
900         :param node: Honeycomb node.
901         :param interface: The name of interface.
902         :param param: Parameter to configure (set, change, remove)
903         :param value: The value of parameter. If None, the parameter will be
904         removed.
905         :type node: dict
906         :type interface: str
907         :type param: str
908         :type value: str
909         :returns: Content of response.
910         :rtype: bytearray
911         :raises HoneycombError: If the parameter is not valid.
912         """
913
914         if param not in InterfaceKeywords.L2_PARAMS:
915             raise HoneycombError("The parameter {0} is invalid.".format(param))
916         path = ("interfaces", ("interface", "name", interface), "v3po:l2",
917                 param)
918         return InterfaceKeywords._set_interface_properties(
919             node, interface, path, value)
920
921     @staticmethod
922     def create_tap_interface(node, interface, **kwargs):
923         """Create a new TAP interface.
924
925         :param node: Honeycomb node.
926         :param interface: The name of interface.
927         :param kwargs: Parameters and their values. The accepted parameters are
928         defined in InterfaceKeywords.TAP_PARAMS.
929         :type node: dict
930         :type interface: str
931         :type kwargs: dict
932         :returns: Content of response.
933         :rtype: bytearray
934         :raises HoneycombError: If the parameter is not valid.
935         """
936
937         new_tap = {
938             "name": interface,
939             "type": "v3po:tap",
940             "v3po:tap": {}
941         }
942         for param, value in kwargs.items():
943             if param not in InterfaceKeywords.TAP_PARAMS:
944                 raise HoneycombError("The parameter {0} is invalid.".
945                                      format(param))
946             new_tap["v3po:tap"][param] = value
947
948         path = ("interfaces", "interface")
949         new_tap_structure = [new_tap, ]
950         return InterfaceKeywords._set_interface_properties(
951             node, interface, path, new_tap_structure)
952
953     @staticmethod
954     def configure_interface_tap(node, interface, **kwargs):
955         """Configure TAP on the interface.
956
957         The keyword configures TAP parameters on the given interface. The type
958         of interface must be set to "v3po:tap".
959         The new TAP parameters overwrite the current configuration. If a
960         parameter in new configuration is missing, it is removed from TAP
961         configuration.
962         If the dictionary kwargs is empty, TAP configuration is removed.
963
964         :param node: Honeycomb node.
965         :param interface: The name of interface.
966         :param kwargs: Parameters and their values. The accepted parameters are
967         defined in InterfaceKeywords.TAP_PARAMS.
968         :type node: dict
969         :type interface: str
970         :type kwargs: dict
971         :returns: Content of response.
972         :rtype: bytearray
973         :raises HoneycombError: If the parameter is not valid.
974         """
975
976         tap_structure = dict()
977         for param, value in kwargs.items():
978             if param not in InterfaceKeywords.TAP_PARAMS:
979                 raise HoneycombError("The parameter {0} is invalid.".
980                                      format(param))
981             tap_structure[param] = value
982
983         path = ("interfaces", ("interface", "name", interface), "v3po:tap")
984         return InterfaceKeywords._set_interface_properties(
985             node, interface, path, tap_structure)
986
987     @staticmethod
988     def configure_interface_vhost_user(node, interface, **kwargs):
989         """Configure vhost-user on the interface.
990
991         The keyword configures vhost-user parameters on the given interface.
992         The type of interface must be set to "v3po:vhost-user".
993         The new vhost-user parameters overwrite the current configuration. If a
994         parameter in new configuration is missing, it is removed from vhost-user
995         configuration.
996         If the dictionary kwargs is empty, vhost-user configuration is removed.
997
998         :param node: Honeycomb node.
999         :param interface: The name of interface.
1000         :param kwargs: Parameters and their values. The accepted parameters are
1001         defined in InterfaceKeywords.VHOST_USER_PARAMS.
1002         :type node: dict
1003         :type interface: str
1004         :type kwargs: dict
1005         :returns: Content of response.
1006         :rtype: bytearray
1007         :raises HoneycombError: If the parameter is not valid.
1008         """
1009
1010         vhost_structure = dict()
1011         for param, value in kwargs.items():
1012             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1013                 raise HoneycombError("The parameter {0} is invalid.".
1014                                      format(param))
1015             vhost_structure[param] = value
1016
1017         path = ("interfaces", ("interface", "name", interface),
1018                 "v3po:vhost-user")
1019         return InterfaceKeywords._set_interface_properties(
1020             node, interface, path, vhost_structure)
1021
1022     @staticmethod
1023     def create_vhost_user_interface(node, interface, **kwargs):
1024         """Create a new vhost-user interface.
1025
1026         :param node: Honeycomb node.
1027         :param interface: The name of interface.
1028         :param kwargs: Parameters and their values. The accepted parameters are
1029         defined in InterfaceKeywords.VHOST_USER_PARAMS.
1030         :type node: dict
1031         :type interface: str
1032         :type kwargs: dict
1033         :returns: Content of response.
1034         :rtype: bytearray
1035         :raises HoneycombError: If the parameter is not valid.
1036         """
1037
1038         new_vhost = {
1039             "name": interface,
1040             "type": "v3po:vhost-user",
1041             "v3po:vhost-user": {}
1042         }
1043         for param, value in kwargs.items():
1044             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1045                 raise HoneycombError("The parameter {0} is invalid.".
1046                                      format(param))
1047             new_vhost["v3po:vhost-user"][param] = value
1048
1049         path = ("interfaces", "interface")
1050         new_vhost_structure = [new_vhost, ]
1051         return InterfaceKeywords._set_interface_properties(
1052             node, interface, path, new_vhost_structure)
1053
1054     @staticmethod
1055     def create_sub_interface(node, super_interface, match, tags=None, **kwargs):
1056         """Create a new sub-interface.
1057
1058         :param node: Honeycomb node.
1059         :param super_interface: Super interface.
1060         :param match: Match type. The valid values are defined in
1061         InterfaceKeywords.SUB_IF_MATCH.
1062         :param tags: List of tags.
1063         :param kwargs: Parameters and their values. The accepted parameters are
1064         defined in InterfaceKeywords.SUB_IF_PARAMS.
1065         :type node: dict
1066         :type super_interface: str
1067         :type match: str
1068         :type tags: list
1069         :type kwargs: dict
1070         :returns: Content of response.
1071         :rtype: bytearray
1072         :raises HoneycombError: If the parameter is not valid.
1073         :raises KeyError: If the parameter 'match' is invalid.
1074         """
1075
1076         match_type = {
1077             "default":
1078                 {"default": {}},
1079             "untagged":
1080                 {"untagged": {}},
1081             "vlan-tagged":
1082                 {"vlan-tagged": {"match-exact-tags": "false"}},
1083             "vlan-tagged-exact-match":
1084                 {"vlan-tagged": {"match-exact-tags": "true"}}
1085         }
1086
1087         new_sub_interface = {
1088             "tags": {
1089                 "tag": []
1090             },
1091         }
1092
1093         for param, value in kwargs.items():
1094             if param in InterfaceKeywords.SUB_IF_PARAMS:
1095                 new_sub_interface[param] = value
1096             else:
1097                 raise HoneycombError("The parameter {0} is invalid.".
1098                                      format(param))
1099         try:
1100             new_sub_interface["match"] = match_type[match]
1101         except KeyError:
1102             raise HoneycombError("The value '{0}' of parameter 'match' is "
1103                                  "invalid.".format(match))
1104
1105         if tags:
1106             new_sub_interface["tags"]["tag"].extend(tags)
1107
1108         path = ("interfaces",
1109                 ("interface", "name", super_interface),
1110                 "vpp-vlan:sub-interfaces",
1111                 "sub-interface")
1112         new_sub_interface_structure = [new_sub_interface, ]
1113         return InterfaceKeywords._set_interface_properties(
1114             node, super_interface, path, new_sub_interface_structure)
1115
1116     @staticmethod
1117     def get_sub_interface_oper_data(node, super_interface, identifier):
1118         """Retrieves sub-interface operational data using Honeycomb API.
1119
1120         :param node: Honeycomb node.
1121         :param super_interface: Super interface.
1122         :param identifier: The ID of sub-interface.
1123         :type node: dict
1124         :type super_interface: str
1125         :type identifier: int
1126         :returns: Sub-interface operational data.
1127         :rtype: dict
1128         :raises HoneycombError: If there is no sub-interface with the given ID.
1129         """
1130
1131         if_data = InterfaceKeywords.get_interface_oper_data(node,
1132                                                             super_interface)
1133         for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]:
1134             if str(sub_if["identifier"]) == str(identifier):
1135                 return sub_if
1136
1137         raise HoneycombError("The interface {0} does not have sub-interface "
1138                              "with ID {1}".format(super_interface, identifier))
1139
1140     @staticmethod
1141     def remove_all_sub_interfaces(node, super_interface):
1142         """Remove all sub-interfaces from the given interface.
1143
1144         :param node: Honeycomb node.
1145         :param super_interface: Super interface.
1146         :type node: dict
1147         :type super_interface: str
1148         :returns: Content of response.
1149         :rtype: bytearray
1150         """
1151
1152         path = ("interfaces",
1153                 ("interface", "name", super_interface),
1154                 "vpp-vlan:sub-interfaces")
1155
1156         return InterfaceKeywords._set_interface_properties(
1157             node, super_interface, path, {})
1158
1159     @staticmethod
1160     def set_sub_interface_state(node, super_interface, identifier, state):
1161         """Set the administrative state of sub-interface.
1162
1163         :param node: Honeycomb node.
1164         :param super_interface: Super interface.
1165         :param identifier: The ID of sub-interface.
1166         :param state: Required sub-interface state - up or down.
1167         :type node: dict
1168         :type super_interface: str
1169         :type identifier: int
1170         :type state: str
1171         :returns: Content of response.
1172         :rtype: bytearray
1173         """
1174
1175         super_interface = Topology.convert_interface_reference(
1176             node, super_interface, "name")
1177
1178         intf_state = {"up": "true",
1179                       "down": "false"}
1180
1181         path = ("interfaces",
1182                 ("interface", "name", super_interface),
1183                 "vpp-vlan:sub-interfaces",
1184                 ("sub-interface", "identifier", int(identifier)),
1185                 "enabled")
1186
1187         return InterfaceKeywords._set_interface_properties(
1188             node, super_interface, path, intf_state[state])
1189
1190     @staticmethod
1191     def add_bridge_domain_to_sub_interface(node, super_interface, identifier,
1192                                            config):
1193         """Add a sub-interface to a bridge domain and set its parameters.
1194
1195         :param node: Honeycomb node.
1196         :param super_interface: Super interface.
1197         :param identifier: The ID of sub-interface.
1198         :param config: Bridge domain configuration.
1199         :type node: dict
1200         :type super_interface: str
1201         :type identifier: int
1202         :type config: dict
1203         :returns: Content of response.
1204         :rtype: bytearray
1205         """
1206
1207         path = ("interfaces",
1208                 ("interface", "name", super_interface),
1209                 "vpp-vlan:sub-interfaces",
1210                 ("sub-interface", "identifier", int(identifier)),
1211                 "l2")
1212
1213         return InterfaceKeywords._set_interface_properties(
1214             node, super_interface, path, config)
1215
1216     @staticmethod
1217     def get_bd_data_from_sub_interface(node, super_interface, identifier):
1218         """Get the operational data about the bridge domain from sub-interface.
1219
1220         :param node: Honeycomb node.
1221         :param super_interface: Super interface.
1222         :param identifier: The ID of sub-interface.
1223         :type node: dict
1224         :type super_interface: str
1225         :type identifier: int
1226         :returns: Operational data about the bridge domain.
1227         :rtype: dict
1228         :raises HoneycombError: If there is no sub-interface with the given ID.
1229         """
1230
1231         try:
1232             bd_data = InterfaceKeywords.get_sub_interface_oper_data(
1233                 node, super_interface, identifier)["l2"]
1234             return bd_data
1235         except KeyError:
1236             raise HoneycombError("The operational data does not contain "
1237                                  "information about a bridge domain.")
1238
1239     @staticmethod
1240     def configure_tag_rewrite(node, super_interface, identifier, config):
1241         """Add / change / disable vlan tag rewrite on a sub-interface.
1242
1243         :param node: Honeycomb node.
1244         :param super_interface: Super interface.
1245         :param identifier: The ID of sub-interface.
1246         :param config: Rewrite tag configuration.
1247         :type node: dict
1248         :type super_interface: str
1249         :type identifier: int
1250         :type config: dict
1251         :returns: Content of response.
1252         :rtype: bytearray
1253         """
1254
1255         path = ("interfaces",
1256                 ("interface", "name", super_interface),
1257                 "vpp-vlan:sub-interfaces",
1258                 ("sub-interface", "identifier", int(identifier)),
1259                 "l2",
1260                 "rewrite")
1261
1262         return InterfaceKeywords._set_interface_properties(
1263             node, super_interface, path, config)
1264
1265     @staticmethod
1266     def get_tag_rewrite_oper_data(node, super_interface, identifier):
1267         """Get the operational data about tag rewrite.
1268
1269         :param node: Honeycomb node.
1270         :param super_interface: Super interface.
1271         :param identifier: The ID of sub-interface.
1272         :type node: dict
1273         :type super_interface: str
1274         :type identifier: int
1275         :returns: Operational data about tag rewrite.
1276         :rtype: dict
1277         :raises HoneycombError: If there is no sub-interface with the given ID.
1278         """
1279
1280         try:
1281             tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data(
1282                 node, super_interface, identifier)["l2"]["rewrite"]
1283             return tag_rewrite
1284         except KeyError:
1285             raise HoneycombError("The operational data does not contain "
1286                                  "information about the tag-rewrite.")
1287
1288     @staticmethod
1289     def add_ip_address_to_sub_interface(node, super_interface, identifier,
1290                                         ip_addr, network, ip_version):
1291         """Add an ipv4 address to the specified sub-interface, with the provided
1292         netmask or network prefix length. Any existing ipv4 addresses on the
1293         sub-interface will be replaced.
1294
1295         :param node: Honeycomb node.
1296         :param super_interface: Super interface.
1297         :param identifier: The ID of sub-interface.
1298         :param ip_addr: IPv4 address to be set.
1299         :param network: Network mask or network prefix length.
1300         :param ip_version: ipv4 or ipv6
1301         :type node: dict
1302         :type super_interface: str
1303         :type identifier: int
1304         :type ip_addr: str
1305         :type network: str or int
1306         :type ip_version: string
1307         :returns: Content of response.
1308         :rtype: bytearray
1309         :raises HoneycombError: If the provided netmask or prefix is not valid.
1310         """
1311
1312         path = ("interfaces",
1313                 ("interface", "name", super_interface),
1314                 "vpp-vlan:sub-interfaces",
1315                 ("sub-interface", "identifier", int(identifier)),
1316                 ip_version.lower())
1317
1318         if isinstance(network, basestring) and ip_version.lower() == "ipv4":
1319             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
1320
1321         elif isinstance(network, int) and 0 < network < 33:
1322             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
1323
1324         else:
1325             raise HoneycombError("{0} is not a valid netmask or prefix length."
1326                                  .format(network))
1327
1328         return InterfaceKeywords._set_interface_properties(
1329             node, super_interface, path, address)
1330
1331     @staticmethod
1332     def remove_all_ip_addresses_from_sub_interface(node, super_interface,
1333                                                    identifier, ip_version):
1334         """Remove all ipv4 addresses from the specified sub-interface.
1335
1336         :param node: Honeycomb node.
1337         :param super_interface: Super interface.
1338         :param identifier: The ID of sub-interface.
1339         :param ip_version: ipv4 or ipv6
1340         :type node: dict
1341         :type super_interface: str
1342         :type identifier: int
1343         :type ip_version: string
1344         :returns: Content of response.
1345         :rtype: bytearray
1346         """
1347
1348         path = ("interfaces",
1349                 ("interface", "name", super_interface),
1350                 "vpp-vlan:sub-interfaces",
1351                 ("sub-interface", "identifier", int(identifier)),
1352                 str(ip_version), "address")
1353
1354         return InterfaceKeywords._set_interface_properties(
1355             node, super_interface, path, None)
1356
1357     @staticmethod
1358     def compare_data_structures(data, ref, _path=''):
1359         """Checks if data obtained from UUT is as expected. If it is not,
1360         proceeds down the list/dictionary tree and finds the point of mismatch.
1361
1362         :param data: Data to be checked.
1363         :param ref: Referential data used for comparison.
1364         :param _path: Used in recursive calls, stores the path taken down
1365         the JSON tree.
1366         :type data: dict
1367         :type ref: dict
1368         :type _path: str
1369
1370         :raises HoneycombError: If the data structures do not match in some way,
1371         or if they are not in deserialized JSON format.
1372         """
1373
1374         if data == ref:
1375             return True
1376
1377         elif isinstance(data, dict) and isinstance(ref, dict):
1378             for key in ref:
1379                 if key not in data:
1380                     raise HoneycombError(
1381                         "Key {key} is not present in path {path}. Keys in path:"
1382                         "{data_keys}".format(
1383                             key=key,
1384                             path=_path,
1385                             data_keys=data.keys()))
1386
1387                 if data[key] != ref[key]:
1388                     if isinstance(data[key], list) \
1389                             or isinstance(data[key], dict):
1390                         InterfaceKeywords.compare_data_structures(
1391                             data[key], ref[key],
1392                             _path + '[{0}]'.format(key))
1393                     else:
1394                         raise HoneycombError(
1395                             "Data mismatch, key {key} in path {path} has value"
1396                             " {data}, but should be {ref}".format(
1397                                 key=key,
1398                                 path=_path,
1399                                 data=data[key],
1400                                 ref=ref[key]))
1401
1402         elif isinstance(data, list) and isinstance(ref, list):
1403             for item in ref:
1404                 if item not in data:
1405                     if isinstance(item, dict):
1406                         InterfaceKeywords.compare_data_structures(
1407                             data[0], item,
1408                             _path + '[{0}]'.format(ref.index(item)))
1409                     else:
1410                         raise HoneycombError(
1411                             "Data mismatch, list item {index} in path {path}"
1412                             " has value {data}, but should be {ref}".format(
1413                                 index=ref.index(item),
1414                                 path=_path,
1415                                 data=data[0],
1416                                 ref=item))
1417
1418         else:
1419             raise HoneycombError(
1420                 "Unexpected data type {data_type} in path {path}, reference"
1421                 " type is {ref_type}. Must be list or dictionary.".format(
1422                     data_type=type(data),
1423                     ref_type=type(ref),
1424                     path=_path))
1425
1426     @staticmethod
1427     def compare_interface_lists(list1, list2):
1428         """Compare provided lists of interfaces by name.
1429
1430         :param list1: List of interfaces.
1431         :param list2: List of interfaces.
1432         :type list1: list
1433         :type list2: list
1434         :raises HoneycombError: If an interface exists in only one of the lists.
1435         """
1436
1437         ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"]
1438         # these have no equivalent in config data and no effect on VPP
1439
1440         names1 = [x['name'] for x in list1]
1441         names2 = [x['name'] for x in list2]
1442
1443         for name in names1:
1444             if name not in names2 and name not in ignore:
1445                 raise HoneycombError("Interface {0} not present in list {1}"
1446                                      .format(name, list2))
1447         for name in names2:
1448             if name not in names1 and name not in ignore:
1449                 raise HoneycombError("Interface {0} not present in list {1}"
1450                                      .format(name, list1))
1451
1452     @staticmethod
1453     def create_vxlan_gpe_interface(node, interface, **kwargs):
1454         """Create a new VxLAN GPE interface.
1455
1456         :param node: Honeycomb node.
1457         :param interface: The name of interface to be created.
1458         :param kwargs: Parameters and their values. The accepted parameters are
1459         defined in InterfaceKeywords.VXLAN_GPE_PARAMS.
1460         :type node: dict
1461         :type interface: str
1462         :type kwargs: dict
1463         :returns: Content of response.
1464         :rtype: bytearray
1465         :raises HoneycombError: If a parameter in kwargs is not valid.
1466         """
1467
1468         new_vxlan_gpe = {
1469             "name": interface,
1470             "type": "v3po:vxlan-gpe-tunnel",
1471             "v3po:vxlan-gpe": {}
1472         }
1473         for param, value in kwargs.items():
1474             if param in InterfaceKeywords.INTF_PARAMS:
1475                 new_vxlan_gpe[param] = value
1476             elif param in InterfaceKeywords.VXLAN_GPE_PARAMS:
1477                 new_vxlan_gpe["v3po:vxlan-gpe"][param] = value
1478             else:
1479                 raise HoneycombError("The parameter {0} is invalid.".
1480                                      format(param))
1481         path = ("interfaces", "interface")
1482         vxlan_gpe_structure = [new_vxlan_gpe, ]
1483         return InterfaceKeywords._set_interface_properties(
1484             node, interface, path, vxlan_gpe_structure)
1485
1486     @staticmethod
1487     def enable_acl_on_interface(node, interface, table_name):
1488         """Enable ACL on the given interface.
1489
1490         :param node: Honeycomb node.
1491         :param interface: The interface where the ACL will be enabled.
1492         :param table_name: Name of the classify table.
1493         :type node: dict
1494         :type interface: str
1495         :type table_name: str
1496         :returns: Content of response.
1497         :rtype: bytearray
1498         :raises HoneycombError: If the configuration of interface is not
1499         successful.
1500         """
1501
1502         interface = interface.replace("/", "%2F")
1503
1504         data = {
1505             "vpp-interface-acl:acl": {
1506                 "ingress": {
1507                     "ip4-acl": {
1508                         "classify-table": table_name
1509                     },
1510                     "l2-acl": {
1511                         "classify-table": table_name
1512                     }
1513                 }
1514             }
1515         }
1516
1517         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1518         status_code, resp = HcUtil.\
1519             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1520                                data_representation=DataRepresentation.JSON)
1521         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1522             raise HoneycombError(
1523                 "The configuration of interface '{0}' was not successful. "
1524                 "Status code: {1}.".format(interface, status_code))
1525         return resp
1526
1527     @staticmethod
1528     def enable_policer_on_interface(node, interface, table_name):
1529         """Enable Policer on the given interface.
1530
1531         :param node: Honeycomb node.
1532         :param interface: The interface where policer will be enabled.
1533         :param table_name: Name of the classify table.
1534         :type node: dict
1535         :type interface: str
1536         :type table_name: str
1537         :returns: Content of response.
1538         :rtype: bytearray
1539         :raises HoneycombError: If the configuration of interface is not
1540         successful.
1541         """
1542         interface = Topology.convert_interface_reference(
1543             node, interface, "name")
1544         interface = interface.replace("/", "%2F")
1545
1546         data = {
1547             "interface-policer:policer": {
1548                 "ip4-table": table_name
1549                 }
1550             }
1551
1552         path = "/interface/" + interface + "/interface-policer:policer"
1553         status_code, resp = HcUtil.\
1554             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1555                                data_representation=DataRepresentation.JSON)
1556         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1557             raise HoneycombError(
1558                 "The configuration of interface '{0}' was not successful. "
1559                 "Status code: {1}.".format(interface, status_code))
1560         return resp
1561
1562     @staticmethod
1563     def disable_policer_on_interface(node, interface):
1564         """Disable Policer on the given interface.
1565
1566         :param node: Honeycomb node.
1567         :param interface: The interface where policer will be disabled.
1568         :type node: dict
1569         :type interface: str
1570         :returns: Content of response.
1571         :rtype: bytearray
1572         :raises HoneycombError: If the configuration of interface is not
1573         successful.
1574         """
1575         interface = Topology.convert_interface_reference(
1576             node, interface, "name")
1577         interface = interface.replace("/", "%2F")
1578
1579         path = "/interface/" + interface + "/interface-policer:policer"
1580         status_code, resp = HcUtil.\
1581             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1582         if status_code != HTTPCodes.OK:
1583             raise HoneycombError(
1584                 "The configuration of interface '{0}' was not successful. "
1585                 "Status code: {1}.".format(interface, status_code))
1586         return resp
1587
1588     @staticmethod
1589     def disable_acl_on_interface(node, interface):
1590         """Disable ACL on the given interface.
1591
1592         :param node: Honeycomb node.
1593         :param interface: The interface where the ACL will be disabled.
1594         :type node: dict
1595         :type interface: str
1596         :returns: Content of response.
1597         :rtype: bytearray
1598         :raises HoneycombError: If the configuration of interface is not
1599         successful.
1600         """
1601
1602         interface = interface.replace("/", "%2F")
1603
1604         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1605
1606         status_code, resp = HcUtil.\
1607             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1608
1609         if status_code != HTTPCodes.OK:
1610             raise HoneycombError(
1611                 "The configuration of interface '{0}' was not successful. "
1612                 "Status code: {1}.".format(interface, status_code))
1613         return resp
1614
1615     @staticmethod
1616     def create_pbb_sub_interface(node, intf, params):
1617         """Creates a PBB sub-interface on the given interface and sets its
1618         parameters.
1619
1620         :param node: Honeycomb node.
1621         :param intf: The interface where PBB sub-interface will be configured.
1622         :param params: Configuration parameters of the sub-interface to be
1623         created.
1624         :type node: dict
1625         :type intf: str
1626         :type params: dict
1627         :returns: Content of response.
1628         :rtype: bytearray
1629         :raises HoneycombError: If the configuration of sub-interface is not
1630         successful.
1631         """
1632
1633         interface = intf.replace("/", "%2F")
1634         path = "/interface/{0}/pbb-rewrite".format(interface)
1635         status_code, resp = HcUtil. \
1636             put_honeycomb_data(node, "config_vpp_interfaces", params, path,
1637                                data_representation=DataRepresentation.JSON)
1638         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1639             raise HoneycombError(
1640                 "The configuration of PBB sub-interface '{0}' was not "
1641                 "successful. Status code: {1}.".format(intf, status_code))
1642         return resp
1643
1644     @staticmethod
1645     def delete_pbb_sub_interface(node, intf):
1646         """Deletes the given PBB sub-interface.
1647
1648         :param node: Honeycomb node.
1649         :param intf: The interface where PBB sub-interface will be deleted.
1650         :type node: dict
1651         :type intf: str
1652         :returns: Content of response.
1653         :rtype: bytearray
1654         :raises HoneycombError: If the removal of sub-interface is not
1655         successful.
1656         """
1657
1658         interface = intf.replace("/", "%2F")
1659         path = "/interface/{0}/pbb-rewrite".format(interface)
1660
1661         status_code, resp = HcUtil. \
1662             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1663         if status_code != HTTPCodes.OK:
1664             raise HoneycombError(
1665                 "The removal of pbb sub-interface '{0}' was not successful. "
1666                 "Status code: {1}.".format(intf, status_code))
1667         return resp
1668
1669     @staticmethod
1670     def get_pbb_sub_interface_oper_data(node, intf, sub_if_id):
1671         """Retrieves PBB sub-interface operational data from Honeycomb.
1672
1673         :param node: Honeycomb node.
1674         :param intf: The interface where PBB sub-interface is located.
1675         :param sub_if_id: ID of the PBB sub-interface.
1676         :type node: dict
1677         :type intf: str
1678         :type sub_if_id: str or int
1679         :returns: PBB sub-interface operational data.
1680         :rtype: dict
1681         :raises HoneycombError: If the removal of sub-interface is not
1682         successful.
1683         """
1684
1685         raise NotImplementedError
1686
1687     @staticmethod
1688     def check_disabled_interface(node, interface):
1689         """Retrieves list of disabled interface indices from Honeycomb,
1690         and matches with the provided interface by index.
1691
1692         :param node: Honeycomb node.
1693         :param interface: Index number of an interface on the node.
1694         :type node: dict
1695         :type interface: int
1696         :returns: True if the interface exists in disabled interfaces.
1697         :rtype: bool
1698         :raises HoneycombError: If the interface is not present
1699          in retrieved list of disabled interfaces.
1700          """
1701         data = InterfaceKeywords.get_disabled_interfaces_oper_data(node)
1702         # decrement by one = conversion from HC if-index to VPP sw_if_index
1703         interface -= 1
1704
1705         for item in data:
1706             if item["index"] == interface:
1707                 return True
1708         raise HoneycombError("Interface index {0} not present in list"
1709                              " of disabled interfaces.".format(interface))
1710
1711     @staticmethod
1712     def configure_interface_span(node, dst_interface, src_interfaces=None):
1713         """Configure SPAN port mirroring on the specified interfaces. If no
1714          source interface is provided, SPAN will be disabled.
1715
1716         :param node: Honeycomb node.
1717         :param dst_interface: Interface to mirror packets to.
1718         :param src_interfaces: List of interfaces to mirror packets from.
1719         :type node: dict
1720         :type dst_interface: str or int
1721         :type src_interfaces: list of dict
1722         :returns: Content of response.
1723         :rtype: bytearray
1724         :raises HoneycombError: If SPAN could not be configured.
1725         """
1726
1727         interface = Topology.convert_interface_reference(
1728             node, dst_interface, "name")
1729         interface = interface.replace("/", "%2F")
1730         path = "/interface/" + interface + "/span"
1731
1732         if not src_interfaces:
1733             status_code, _ = HcUtil.delete_honeycomb_data(
1734                 node, "config_vpp_interfaces", path)
1735         else:
1736             for src_interface in src_interfaces:
1737                 src_interface["iface-ref"] = Topology.\
1738                     convert_interface_reference(
1739                         node, src_interface["iface-ref"], "name")
1740             data = {
1741                 "span": {
1742                     "mirrored-interfaces": {
1743                         "mirrored-interface": src_interfaces
1744                     }
1745                 }
1746             }
1747
1748             status_code, _ = HcUtil.put_honeycomb_data(
1749                 node, "config_vpp_interfaces", data, path)
1750
1751         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1752             raise HoneycombError(
1753                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1754
1755     @staticmethod
1756     def configure_sub_interface_span(node, super_interface, dst_interface_index,
1757                                      src_interfaces=None):
1758         """Configure SPAN port mirroring on the specified sub-interface. If no
1759          source interface is provided, SPAN will be disabled.
1760
1761         Note: Does not support source sub-interfaces, only destination.
1762
1763         :param node: Honeycomb node.
1764         :param super_interface: Name, link name or sw_if_index
1765         of the destination interface's super-interface.
1766         :param dst_interface_index: Index of sub-interface to mirror packets to.
1767         :param src_interfaces: List of interfaces to mirror packets from.
1768         :type node: dict
1769         :type super_interface: str or int
1770         :type dst_interface_index: int
1771         :type src_interfaces: list of dict
1772         :returns: Content of response.
1773         :rtype: bytearray
1774         :raises HoneycombError: If SPAN could not be configured.
1775         """
1776
1777         super_interface = Topology.convert_interface_reference(
1778             node, super_interface, "name")
1779         super_interface = super_interface.replace("/", "%2F")
1780
1781         path = "/interface/{0}/vpp-vlan:sub-interfaces/sub-interface/{1}/span"\
1782             .format(super_interface, dst_interface_index)
1783
1784         if not src_interfaces:
1785             status_code, _ = HcUtil.delete_honeycomb_data(
1786                 node, "config_vpp_interfaces", path)
1787         else:
1788             for src_interface in src_interfaces:
1789                 src_interface["iface-ref"] = Topology. \
1790                     convert_interface_reference(
1791                         node, src_interface["iface-ref"], "name")
1792             data = {
1793                 "span": {
1794                     "mirrored-interfaces": {
1795                         "mirrored-interface": src_interfaces
1796                     }
1797                 }
1798             }
1799
1800             status_code, _ = HcUtil.put_honeycomb_data(
1801                 node, "config_vpp_interfaces", data, path)
1802
1803         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1804             raise HoneycombError(
1805                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1806
1807     @staticmethod
1808     def add_interface_local0_to_topology(node):
1809         """Use Topology methods to add interface "local0" to working topology,
1810         if not already present.
1811
1812         :param node: DUT node.
1813         :type node: dict
1814         """
1815
1816         if Topology.get_interface_by_sw_index(node, 0) is None:
1817             local0_key = Topology.add_new_port(node, "localzero")
1818             Topology.update_interface_sw_if_index(node, local0_key, 0)
1819             Topology.update_interface_name(node, local0_key, "local0")
1820
1821     @staticmethod
1822     def configure_interface_unnumbered(node, interface, interface_src=None):
1823         """Configure the specified interface as unnumbered. The interface
1824         borrows IP address from the specified source interface. If not source
1825         interface is provided, unnumbered configuration will be removed.
1826
1827         :param node: Honeycomb node.
1828         :param interface: Name, link name or sw_if_index of an interface.
1829         :param interface_src: Name of source interface.
1830         :type node: dict
1831         :type interface: str or int
1832         :type interface_src: str
1833         :raises HoneycombError: If the configuration fails.
1834         """
1835
1836         interface = InterfaceKeywords.handle_interface_reference(
1837             node, interface)
1838
1839         path = "/interface/{0}/unnumbered-interfaces:unnumbered"\
1840             .format(interface)
1841
1842         if interface_src:
1843             data = {
1844                 "unnumbered": {
1845                     "use": interface_src
1846                 }
1847             }
1848             status_code, _ = HcUtil.put_honeycomb_data(
1849                 node, "config_vpp_interfaces", data, path)
1850         else:
1851             status_code, _ = HcUtil.delete_honeycomb_data(
1852                 node, "config_vpp_interfaces", path)
1853
1854         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1855             raise HoneycombError(
1856                 "Configuring unnumbered interface failed. "
1857                 "Status code:{0}".format(status_code))
1858
1859     @staticmethod
1860     def handle_interface_reference(node, interface):
1861         """Convert any interface reference to interface name used by Honeycomb.
1862
1863         :param node: Honeycomb node.
1864         :param interface: Name, link name or sw_if_index of an interface,
1865         name of a custom interface or name of a sub-interface.
1866         :type node: Honeycomb node.
1867         :type interface: str or int
1868         :returns: Name of interface that can be used in Honeycomb requests.
1869         :rtype: str
1870         """
1871
1872         try:
1873             interface = Topology.convert_interface_reference(
1874                 node, interface, "name")
1875             interface = interface.replace("/", "%2F")
1876         except RuntimeError:
1877             # interface is not in topology
1878             if "." in interface:
1879                 # Assume it's the name of a sub-interface
1880                 interface, index = interface.split(".")
1881                 interface = interface.replace("/", "%2F")
1882                 interface = "{0}/vpp-vlan:sub-interfaces/sub-interface/{1}".\
1883                     format(interface, index)
1884             else:
1885                 # Assume it's the name of a custom interface (pbb, vxlan, etc.)
1886                 interface = interface.replace("/", "%2F")
1887
1888         return interface