CSIT-576 HC Test: Improve SPAN test coverage
[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 HoneycombError: If the provided netmask or prefix is not valid.
487         """
488
489         interface = Topology.convert_interface_reference(
490             node, interface, "name")
491
492         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4")
493         if isinstance(network, basestring):
494             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
495         elif isinstance(network, int) and (0 < network < 33):
496             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
497         else:
498             raise HoneycombError("Value {0} is not a valid netmask or network "
499                                  "prefix length.".format(network))
500         return InterfaceKeywords._set_interface_properties(
501             node, interface, path, address)
502
503     @staticmethod
504     def add_ipv4_address(node, interface, ip_addr, network):
505         """Add IPv4 address.
506
507         :param node: Honeycomb node.
508         :param interface: The name of interface.
509         :param ip_addr: IPv4 address to be set.
510         :param network: Netmask or length of network prefix.
511         :type node: dict
512         :type interface: str
513         :type ip_addr: str
514         :type network: str or int
515         :returns: Content of response.
516         :rtype: bytearray
517         :raises HoneycombError: If the provided netmask or prefix is not valid.
518         """
519
520         interface = Topology.convert_interface_reference(
521             node, interface, "name")
522
523         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
524                 "address")
525         if isinstance(network, basestring):
526             address = [{"ip": ip_addr, "netmask": network}]
527         elif isinstance(network, int) and (0 < network < 33):
528             address = [{"ip": ip_addr, "prefix-length": network}]
529         else:
530             raise HoneycombError("Value {0} is not a valid netmask or network "
531                                  "prefix length.".format(network))
532         return InterfaceKeywords._set_interface_properties(
533             node, interface, path, address)
534
535     @staticmethod
536     def remove_all_ipv4_addresses(node, interface):
537         """Remove all IPv4 addresses from interface.
538
539         :param node: Honeycomb node.
540         :param interface: The name of interface.
541         :type node: dict
542         :type interface: str
543         :returns: Content of response.
544         :rtype: bytearray
545         """
546
547         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
548                 "address")
549         return InterfaceKeywords._set_interface_properties(
550             node, interface, path, None)
551
552     @staticmethod
553     def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address):
554         """Add the IPv4 neighbour.
555
556         :param node: Honeycomb node.
557         :param interface: The name of interface.
558         :param ip_addr: IPv4 address of neighbour to be set.
559         :param link_layer_address: Link layer address.
560         :type node: dict
561         :type interface: str
562         :type ip_addr: str
563         :type link_layer_address: str
564         :returns: Content of response.
565         :rtype: bytearray
566         """
567
568         interface = Topology.convert_interface_reference(
569             node, interface, "name")
570
571         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
572                 "neighbor")
573         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
574         return InterfaceKeywords._set_interface_properties(
575             node, interface, path, neighbor)
576
577     @staticmethod
578     def remove_all_ipv4_neighbors(node, interface):
579         """Remove all IPv4 neighbours.
580
581         :param node: Honeycomb node.
582         :param interface: The name of interface.
583         :type node: dict
584         :type interface: str
585         :returns: Content of response.
586         :rtype: bytearray
587         """
588
589         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
590                 "neighbor")
591         return InterfaceKeywords._set_interface_properties(
592             node, interface, path, None)
593
594     @staticmethod
595     def configure_interface_ipv6(node, interface, param, value):
596         """Configure IPv6 parameters of interface
597
598         :param node: Honeycomb node.
599         :param interface: The name of interface.
600         :param param: Parameter to configure (set, change, remove)
601         :param value: The value of parameter. If None, the parameter will be
602         removed.
603         :type node: dict
604         :type interface: str
605         :type param: str
606         :type value: str
607         :returns: Content of response.
608         :rtype: bytearray
609         :raises HoneycombError: If the parameter is not valid.
610         """
611
612         if param in InterfaceKeywords.IPV6_PARAMS:
613             path = ("interfaces", ("interface", "name", interface),
614                     "ietf-ip:ipv6", param)
615         elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS:
616             path = ("interfaces", ("interface", "name", interface),
617                     "ietf-ip:ipv6", "autoconf", param)
618         else:
619             raise HoneycombError("The parameter {0} is invalid.".format(param))
620
621         return InterfaceKeywords._set_interface_properties(
622             node, interface, path, value)
623
624     @staticmethod
625     def add_first_ipv6_address(node, interface, ip_addr, prefix_len):
626         """Add the first IPv6 address.
627
628         If there are any other addresses configured, they will be removed.
629
630         :param node: Honeycomb node.
631         :param interface: The name of interface.
632         :param ip_addr: IPv6 address to be set.
633         :param prefix_len: Prefix length.
634         :type node: dict
635         :type interface: str
636         :type ip_addr: str
637         :type prefix_len: str
638         :returns: Content of response.
639         :rtype: bytearray
640         """
641
642         interface = Topology.convert_interface_reference(
643             node, interface, "name")
644
645         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6")
646         address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]}
647         return InterfaceKeywords._set_interface_properties(
648             node, interface, path, address)
649
650     @staticmethod
651     def add_ipv6_address(node, interface, ip_addr, prefix_len):
652         """Add IPv6 address.
653
654         :param node: Honeycomb node.
655         :param interface: The name of interface.
656         :param ip_addr: IPv6 address to be set.
657         :param prefix_len: Prefix length.
658         :type node: dict
659         :type interface: str
660         :type ip_addr: str
661         :type prefix_len: str
662         :returns: Content of response.
663         :rtype: bytearray
664         """
665
666         interface = Topology.convert_interface_reference(
667             node, interface, "name")
668
669         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
670                 "address")
671         address = [{"ip": ip_addr, "prefix-length": prefix_len}, ]
672         return InterfaceKeywords._set_interface_properties(
673             node, interface, path, address)
674
675     @staticmethod
676     def remove_all_ipv6_addresses(node, interface):
677         """Remove all IPv6 addresses from interface.
678
679         :param node: Honeycomb node.
680         :param interface: The name of interface.
681         :type node: dict
682         :type interface: str
683         :returns: Content of response.
684         :rtype: bytearray
685         """
686
687         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
688                 "address")
689         return InterfaceKeywords._set_interface_properties(
690             node, interface, path, None)
691
692     @staticmethod
693     def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address):
694         """Add the IPv6 neighbour.
695
696         :param node: Honeycomb node.
697         :param interface: The name of interface.
698         :param ip_addr: IPv6 address of neighbour to be set.
699         :param link_layer_address: Link layer address.
700         :type node: dict
701         :type interface: str
702         :type ip_addr: str
703         :type link_layer_address: str
704         :returns: Content of response.
705         :rtype: bytearray
706         """
707
708         interface = Topology.convert_interface_reference(
709             node, interface, "name")
710
711         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
712                 "neighbor")
713         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
714         return InterfaceKeywords._set_interface_properties(
715             node, interface, path, neighbor)
716
717     @staticmethod
718     def remove_all_ipv6_neighbors(node, interface):
719         """Remove all IPv6 neighbours.
720
721         :param node: Honeycomb node.
722         :param interface: The name of interface.
723         :type node: dict
724         :type interface: str
725         :returns: Content of response.
726         :rtype: bytearray
727         """
728
729         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
730                 "neighbor")
731         return InterfaceKeywords._set_interface_properties(
732             node, interface, path, None)
733
734     @staticmethod
735     def configure_interface_ethernet(node, interface, param, value):
736         """Configure the ethernet parameters of interface.
737
738         :param node: Honeycomb node.
739         :param interface: The name of interface.
740         :param param: Parameter to configure (set, change, remove)
741         :param value: The value of parameter. If None, the parameter will be
742         removed.
743         :type node: dict
744         :type interface: str
745         :type param: str
746         :type value: str
747         :returns: Content of response.
748         :rtype: bytearray
749         :raises HoneycombError: If the parameter is not valid.
750         """
751
752         if param not in InterfaceKeywords.ETH_PARAMS:
753             raise HoneycombError("The parameter {0} is invalid.".format(param))
754         path = ("interfaces", ("interface", "name", interface), "v3po:ethernet",
755                 param)
756         return InterfaceKeywords._set_interface_properties(
757             node, interface, path, value)
758
759     @staticmethod
760     def configure_interface_routing(node, interface, param, value):
761         """Configure the routing parameters of interface.
762
763         :param node: Honeycomb node.
764         :param interface: The name of interface.
765         :param param: Parameter to configure (set, change, remove)
766         :param value: The value of parameter. If None, the parameter will be
767         removed.
768         :type node: dict
769         :type interface: str
770         :type param: str
771         :type value: str
772         :returns: Content of response.
773         :rtype: bytearray
774         :raises HoneycombError: If the parameter is not valid.
775         """
776
777         interface = Topology.convert_interface_reference(
778             node, interface, "name")
779
780         if param not in InterfaceKeywords.ROUTING_PARAMS:
781             raise HoneycombError("The parameter {0} is invalid.".format(param))
782
783         path = ("interfaces", ("interface", "name", interface), "v3po:routing",
784                 param)
785         return InterfaceKeywords._set_interface_properties(
786             node, interface, path, value)
787
788     @staticmethod
789     def create_vxlan_interface(node, interface, **kwargs):
790         """Create a new VxLAN interface.
791
792         :param node: Honeycomb node.
793         :param interface: The name of interface.
794         :param kwargs: Parameters and their values. The accepted parameters are
795         defined in InterfaceKeywords.VXLAN_PARAMS.
796         :type node: dict
797         :type interface: str
798         :type kwargs: dict
799         :returns: Content of response.
800         :rtype: bytearray
801         :raises HoneycombError: If the parameter is not valid.
802         """
803
804         new_vx_lan = {
805             "name": interface,
806             "type": "v3po:vxlan-tunnel",
807             "v3po:vxlan": {}
808         }
809         for param, value in kwargs.items():
810             if param not in InterfaceKeywords.VXLAN_PARAMS:
811                 raise HoneycombError("The parameter {0} is invalid.".
812                                      format(param))
813             new_vx_lan["v3po:vxlan"][param] = value
814
815         path = ("interfaces", "interface")
816         vx_lan_structure = [new_vx_lan, ]
817         return InterfaceKeywords._set_interface_properties(
818             node, interface, path, vx_lan_structure)
819
820     @staticmethod
821     def delete_interface(node, interface):
822         """Delete an interface.
823
824         :param node: Honeycomb node.
825         :param interface: The name of interface.
826         :type node: dict
827         :type interface: str
828         :returns: Content of response.
829         :rtype: bytearray
830         :raises HoneycombError: If it is not possible to get information about
831         interfaces or it is not possible to delete the interface.
832         """
833
834         path = ("interfaces", ("interface", "name", interface))
835
836         status_code, resp = HcUtil.\
837             get_honeycomb_data(node, "config_vpp_interfaces")
838         if status_code != HTTPCodes.OK:
839             raise HoneycombError(
840                 "Not possible to get configuration information about the "
841                 "interfaces. Status code: {0}.".format(status_code))
842
843         new_data = HcUtil.remove_item(resp, path)
844         status_code, resp = HcUtil.\
845             put_honeycomb_data(node, "config_vpp_interfaces", new_data)
846         if status_code != HTTPCodes.OK:
847             raise HoneycombError("Not possible to remove interface {0}. "
848                                  "Status code: {1}.".
849                                  format(interface, status_code))
850         return resp
851
852     @staticmethod
853     def configure_interface_vxlan(node, interface, **kwargs):
854         """Configure VxLAN on the interface.
855
856         The keyword configures VxLAN parameters on the given interface. The type
857         of interface must be set to "v3po:vxlan-tunnel".
858         The new VxLAN parameters overwrite the current configuration. If a
859         parameter in new configuration is missing, it is removed from VxLAN
860         configuration.
861         If the dictionary kwargs is empty, VxLAN configuration is removed.
862
863         :param node: Honeycomb node.
864         :param interface: The name of interface.
865         :param kwargs: Parameters and their values. The accepted parameters are
866         defined in InterfaceKeywords.VXLAN_PARAMS.
867         :type node: dict
868         :type interface: str
869         :type kwargs: dict
870         :returns: Content of response.
871         :rtype: bytearray
872         :raises HoneycombError: If the parameter is not valid.
873         """
874
875         vx_lan_structure = dict()
876         for param, value in kwargs.items():
877             if param not in InterfaceKeywords.VXLAN_PARAMS:
878                 raise HoneycombError("The parameter {0} is invalid.".
879                                      format(param))
880             vx_lan_structure[param] = value
881
882         path = ("interfaces", ("interface", "name", interface), "v3po:vxlan")
883         return InterfaceKeywords._set_interface_properties(
884             node, interface, path, vx_lan_structure)
885
886     @staticmethod
887     def configure_interface_l2(node, interface, param, value):
888         """Configure the L2 parameters of interface.
889
890         :param node: Honeycomb node.
891         :param interface: The name of interface.
892         :param param: Parameter to configure (set, change, remove)
893         :param value: The value of parameter. If None, the parameter will be
894         removed.
895         :type node: dict
896         :type interface: str
897         :type param: str
898         :type value: str
899         :returns: Content of response.
900         :rtype: bytearray
901         :raises HoneycombError: If the parameter is not valid.
902         """
903
904         if param not in InterfaceKeywords.L2_PARAMS:
905             raise HoneycombError("The parameter {0} is invalid.".format(param))
906         path = ("interfaces", ("interface", "name", interface), "v3po:l2",
907                 param)
908         return InterfaceKeywords._set_interface_properties(
909             node, interface, path, value)
910
911     @staticmethod
912     def create_tap_interface(node, interface, **kwargs):
913         """Create a new TAP interface.
914
915         :param node: Honeycomb node.
916         :param interface: The name of interface.
917         :param kwargs: Parameters and their values. The accepted parameters are
918         defined in InterfaceKeywords.TAP_PARAMS.
919         :type node: dict
920         :type interface: str
921         :type kwargs: dict
922         :returns: Content of response.
923         :rtype: bytearray
924         :raises HoneycombError: If the parameter is not valid.
925         """
926
927         new_tap = {
928             "name": interface,
929             "type": "v3po:tap",
930             "v3po:tap": {}
931         }
932         for param, value in kwargs.items():
933             if param not in InterfaceKeywords.TAP_PARAMS:
934                 raise HoneycombError("The parameter {0} is invalid.".
935                                      format(param))
936             new_tap["v3po:tap"][param] = value
937
938         path = ("interfaces", "interface")
939         new_tap_structure = [new_tap, ]
940         return InterfaceKeywords._set_interface_properties(
941             node, interface, path, new_tap_structure)
942
943     @staticmethod
944     def configure_interface_tap(node, interface, **kwargs):
945         """Configure TAP on the interface.
946
947         The keyword configures TAP parameters on the given interface. The type
948         of interface must be set to "v3po:tap".
949         The new TAP parameters overwrite the current configuration. If a
950         parameter in new configuration is missing, it is removed from TAP
951         configuration.
952         If the dictionary kwargs is empty, TAP configuration is removed.
953
954         :param node: Honeycomb node.
955         :param interface: The name of interface.
956         :param kwargs: Parameters and their values. The accepted parameters are
957         defined in InterfaceKeywords.TAP_PARAMS.
958         :type node: dict
959         :type interface: str
960         :type kwargs: dict
961         :returns: Content of response.
962         :rtype: bytearray
963         :raises HoneycombError: If the parameter is not valid.
964         """
965
966         tap_structure = dict()
967         for param, value in kwargs.items():
968             if param not in InterfaceKeywords.TAP_PARAMS:
969                 raise HoneycombError("The parameter {0} is invalid.".
970                                      format(param))
971             tap_structure[param] = value
972
973         path = ("interfaces", ("interface", "name", interface), "v3po:tap")
974         return InterfaceKeywords._set_interface_properties(
975             node, interface, path, tap_structure)
976
977     @staticmethod
978     def configure_interface_vhost_user(node, interface, **kwargs):
979         """Configure vhost-user on the interface.
980
981         The keyword configures vhost-user parameters on the given interface.
982         The type of interface must be set to "v3po:vhost-user".
983         The new vhost-user parameters overwrite the current configuration. If a
984         parameter in new configuration is missing, it is removed from vhost-user
985         configuration.
986         If the dictionary kwargs is empty, vhost-user configuration is removed.
987
988         :param node: Honeycomb node.
989         :param interface: The name of interface.
990         :param kwargs: Parameters and their values. The accepted parameters are
991         defined in InterfaceKeywords.VHOST_USER_PARAMS.
992         :type node: dict
993         :type interface: str
994         :type kwargs: dict
995         :returns: Content of response.
996         :rtype: bytearray
997         :raises HoneycombError: If the parameter is not valid.
998         """
999
1000         vhost_structure = dict()
1001         for param, value in kwargs.items():
1002             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1003                 raise HoneycombError("The parameter {0} is invalid.".
1004                                      format(param))
1005             vhost_structure[param] = value
1006
1007         path = ("interfaces", ("interface", "name", interface),
1008                 "v3po:vhost-user")
1009         return InterfaceKeywords._set_interface_properties(
1010             node, interface, path, vhost_structure)
1011
1012     @staticmethod
1013     def create_vhost_user_interface(node, interface, **kwargs):
1014         """Create a new vhost-user interface.
1015
1016         :param node: Honeycomb node.
1017         :param interface: The name of interface.
1018         :param kwargs: Parameters and their values. The accepted parameters are
1019         defined in InterfaceKeywords.VHOST_USER_PARAMS.
1020         :type node: dict
1021         :type interface: str
1022         :type kwargs: dict
1023         :returns: Content of response.
1024         :rtype: bytearray
1025         :raises HoneycombError: If the parameter is not valid.
1026         """
1027
1028         new_vhost = {
1029             "name": interface,
1030             "type": "v3po:vhost-user",
1031             "v3po:vhost-user": {}
1032         }
1033         for param, value in kwargs.items():
1034             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1035                 raise HoneycombError("The parameter {0} is invalid.".
1036                                      format(param))
1037             new_vhost["v3po:vhost-user"][param] = value
1038
1039         path = ("interfaces", "interface")
1040         new_vhost_structure = [new_vhost, ]
1041         return InterfaceKeywords._set_interface_properties(
1042             node, interface, path, new_vhost_structure)
1043
1044     @staticmethod
1045     def create_sub_interface(node, super_interface, match, tags=None, **kwargs):
1046         """Create a new sub-interface.
1047
1048         :param node: Honeycomb node.
1049         :param super_interface: Super interface.
1050         :param match: Match type. The valid values are defined in
1051         InterfaceKeywords.SUB_IF_MATCH.
1052         :param tags: List of tags.
1053         :param kwargs: Parameters and their values. The accepted parameters are
1054         defined in InterfaceKeywords.SUB_IF_PARAMS.
1055         :type node: dict
1056         :type super_interface: str
1057         :type match: str
1058         :type tags: list
1059         :type kwargs: dict
1060         :returns: Content of response.
1061         :rtype: bytearray
1062         :raises HoneycombError: If the parameter is not valid.
1063         :raises KeyError: If the parameter 'match' is invalid.
1064         """
1065
1066         match_type = {
1067             "default":
1068                 {"default": {}},
1069             "untagged":
1070                 {"untagged": {}},
1071             "vlan-tagged":
1072                 {"vlan-tagged": {"match-exact-tags": "false"}},
1073             "vlan-tagged-exact-match":
1074                 {"vlan-tagged": {"match-exact-tags": "true"}}
1075         }
1076
1077         new_sub_interface = {
1078             "tags": {
1079                 "tag": []
1080             },
1081         }
1082
1083         for param, value in kwargs.items():
1084             if param in InterfaceKeywords.SUB_IF_PARAMS:
1085                 new_sub_interface[param] = value
1086             else:
1087                 raise HoneycombError("The parameter {0} is invalid.".
1088                                      format(param))
1089         try:
1090             new_sub_interface["match"] = match_type[match]
1091         except KeyError:
1092             raise HoneycombError("The value '{0}' of parameter 'match' is "
1093                                  "invalid.".format(match))
1094
1095         if tags:
1096             new_sub_interface["tags"]["tag"].extend(tags)
1097
1098         path = ("interfaces",
1099                 ("interface", "name", super_interface),
1100                 "vpp-vlan:sub-interfaces",
1101                 "sub-interface")
1102         new_sub_interface_structure = [new_sub_interface, ]
1103         return InterfaceKeywords._set_interface_properties(
1104             node, super_interface, path, new_sub_interface_structure)
1105
1106     @staticmethod
1107     def get_sub_interface_oper_data(node, super_interface, identifier):
1108         """Retrieves sub-interface operational data using Honeycomb API.
1109
1110         :param node: Honeycomb node.
1111         :param super_interface: Super interface.
1112         :param identifier: The ID of sub-interface.
1113         :type node: dict
1114         :type super_interface: str
1115         :type identifier: int
1116         :returns: Sub-interface operational data.
1117         :rtype: dict
1118         :raises HoneycombError: If there is no sub-interface with the given ID.
1119         """
1120
1121         if_data = InterfaceKeywords.get_interface_oper_data(node,
1122                                                             super_interface)
1123         for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]:
1124             if str(sub_if["identifier"]) == str(identifier):
1125                 return sub_if
1126
1127         raise HoneycombError("The interface {0} does not have sub-interface "
1128                              "with ID {1}".format(super_interface, identifier))
1129
1130     @staticmethod
1131     def remove_all_sub_interfaces(node, super_interface):
1132         """Remove all sub-interfaces from the given interface.
1133
1134         :param node: Honeycomb node.
1135         :param super_interface: Super interface.
1136         :type node: dict
1137         :type super_interface: str
1138         :returns: Content of response.
1139         :rtype: bytearray
1140         """
1141
1142         path = ("interfaces",
1143                 ("interface", "name", super_interface),
1144                 "vpp-vlan:sub-interfaces")
1145
1146         return InterfaceKeywords._set_interface_properties(
1147             node, super_interface, path, {})
1148
1149     @staticmethod
1150     def set_sub_interface_state(node, super_interface, identifier, state):
1151         """Set the administrative state of sub-interface.
1152
1153         :param node: Honeycomb node.
1154         :param super_interface: Super interface.
1155         :param identifier: The ID of sub-interface.
1156         :param state: Required sub-interface state - up or down.
1157         :type node: dict
1158         :type super_interface: str
1159         :type identifier: int
1160         :type state: str
1161         :returns: Content of response.
1162         :rtype: bytearray
1163         """
1164
1165         super_interface = Topology.convert_interface_reference(
1166             node, super_interface, "name")
1167
1168         intf_state = {"up": "true",
1169                       "down": "false"}
1170
1171         path = ("interfaces",
1172                 ("interface", "name", super_interface),
1173                 "vpp-vlan:sub-interfaces",
1174                 ("sub-interface", "identifier", int(identifier)),
1175                 "enabled")
1176
1177         return InterfaceKeywords._set_interface_properties(
1178             node, super_interface, path, intf_state[state])
1179
1180     @staticmethod
1181     def add_bridge_domain_to_sub_interface(node, super_interface, identifier,
1182                                            config):
1183         """Add a sub-interface to a bridge domain and set its parameters.
1184
1185         :param node: Honeycomb node.
1186         :param super_interface: Super interface.
1187         :param identifier: The ID of sub-interface.
1188         :param config: Bridge domain configuration.
1189         :type node: dict
1190         :type super_interface: str
1191         :type identifier: int
1192         :type config: dict
1193         :returns: Content of response.
1194         :rtype: bytearray
1195         """
1196
1197         path = ("interfaces",
1198                 ("interface", "name", super_interface),
1199                 "vpp-vlan:sub-interfaces",
1200                 ("sub-interface", "identifier", int(identifier)),
1201                 "l2")
1202
1203         return InterfaceKeywords._set_interface_properties(
1204             node, super_interface, path, config)
1205
1206     @staticmethod
1207     def get_bd_data_from_sub_interface(node, super_interface, identifier):
1208         """Get the operational data about the bridge domain from sub-interface.
1209
1210         :param node: Honeycomb node.
1211         :param super_interface: Super interface.
1212         :param identifier: The ID of sub-interface.
1213         :type node: dict
1214         :type super_interface: str
1215         :type identifier: int
1216         :returns: Operational data about the bridge domain.
1217         :rtype: dict
1218         :raises HoneycombError: If there is no sub-interface with the given ID.
1219         """
1220
1221         try:
1222             bd_data = InterfaceKeywords.get_sub_interface_oper_data(
1223                 node, super_interface, identifier)["l2"]
1224             return bd_data
1225         except KeyError:
1226             raise HoneycombError("The operational data does not contain "
1227                                  "information about a bridge domain.")
1228
1229     @staticmethod
1230     def configure_tag_rewrite(node, super_interface, identifier, config):
1231         """Add / change / disable vlan tag rewrite on a sub-interface.
1232
1233         :param node: Honeycomb node.
1234         :param super_interface: Super interface.
1235         :param identifier: The ID of sub-interface.
1236         :param config: Rewrite tag configuration.
1237         :type node: dict
1238         :type super_interface: str
1239         :type identifier: int
1240         :type config: dict
1241         :returns: Content of response.
1242         :rtype: bytearray
1243         """
1244
1245         path = ("interfaces",
1246                 ("interface", "name", super_interface),
1247                 "vpp-vlan:sub-interfaces",
1248                 ("sub-interface", "identifier", int(identifier)),
1249                 "l2",
1250                 "rewrite")
1251
1252         return InterfaceKeywords._set_interface_properties(
1253             node, super_interface, path, config)
1254
1255     @staticmethod
1256     def get_tag_rewrite_oper_data(node, super_interface, identifier):
1257         """Get the operational data about tag rewrite.
1258
1259         :param node: Honeycomb node.
1260         :param super_interface: Super interface.
1261         :param identifier: The ID of sub-interface.
1262         :type node: dict
1263         :type super_interface: str
1264         :type identifier: int
1265         :returns: Operational data about tag rewrite.
1266         :rtype: dict
1267         :raises HoneycombError: If there is no sub-interface with the given ID.
1268         """
1269
1270         try:
1271             tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data(
1272                 node, super_interface, identifier)["l2"]["rewrite"]
1273             return tag_rewrite
1274         except KeyError:
1275             raise HoneycombError("The operational data does not contain "
1276                                  "information about the tag-rewrite.")
1277
1278     @staticmethod
1279     def add_ip_address_to_sub_interface(node, super_interface, identifier,
1280                                         ip_addr, network, ip_version):
1281         """Add an ipv4 address to the specified sub-interface, with the provided
1282         netmask or network prefix length. Any existing ipv4 addresses on the
1283         sub-interface will be replaced.
1284
1285         :param node: Honeycomb node.
1286         :param super_interface: Super interface.
1287         :param identifier: The ID of sub-interface.
1288         :param ip_addr: IPv4 address to be set.
1289         :param network: Network mask or network prefix length.
1290         :param ip_version: ipv4 or ipv6
1291         :type node: dict
1292         :type super_interface: str
1293         :type identifier: int
1294         :type ip_addr: str
1295         :type network: str or int
1296         :type ip_version: string
1297         :returns: Content of response.
1298         :rtype: bytearray
1299         :raises HoneycombError: If the provided netmask or prefix is not valid.
1300         """
1301
1302         path = ("interfaces",
1303                 ("interface", "name", super_interface),
1304                 "vpp-vlan:sub-interfaces",
1305                 ("sub-interface", "identifier", int(identifier)),
1306                 ip_version.lower())
1307
1308         if isinstance(network, basestring) and ip_version.lower() == "ipv4":
1309             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
1310
1311         elif isinstance(network, int) and 0 < network < 33:
1312             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
1313
1314         else:
1315             raise HoneycombError("{0} is not a valid netmask or prefix length."
1316                                  .format(network))
1317
1318         return InterfaceKeywords._set_interface_properties(
1319             node, super_interface, path, address)
1320
1321     @staticmethod
1322     def remove_all_ip_addresses_from_sub_interface(node, super_interface,
1323                                                    identifier, ip_version):
1324         """Remove all ipv4 addresses from the specified sub-interface.
1325
1326         :param node: Honeycomb node.
1327         :param super_interface: Super interface.
1328         :param identifier: The ID of sub-interface.
1329         :param ip_version: ipv4 or ipv6
1330         :type node: dict
1331         :type super_interface: str
1332         :type identifier: int
1333         :type ip_version: string
1334         :returns: Content of response.
1335         :rtype: bytearray
1336         """
1337
1338         path = ("interfaces",
1339                 ("interface", "name", super_interface),
1340                 "vpp-vlan:sub-interfaces",
1341                 ("sub-interface", "identifier", int(identifier)),
1342                 str(ip_version), "address")
1343
1344         return InterfaceKeywords._set_interface_properties(
1345             node, super_interface, path, None)
1346
1347     @staticmethod
1348     def compare_data_structures(data, ref, _path=''):
1349         """Checks if data obtained from UUT is as expected. If it is not,
1350         proceeds down the list/dictionary tree and finds the point of mismatch.
1351
1352         :param data: Data to be checked.
1353         :param ref: Referential data used for comparison.
1354         :param _path: Used in recursive calls, stores the path taken down
1355         the JSON tree.
1356         :type data: dict
1357         :type ref: dict
1358         :type _path: str
1359
1360         :raises HoneycombError: If the data structures do not match in some way,
1361         or if they are not in deserialized JSON format.
1362         """
1363
1364         if data == ref:
1365             return True
1366
1367         elif isinstance(data, dict) and isinstance(ref, dict):
1368             for key in ref:
1369                 if key not in data:
1370                     raise HoneycombError(
1371                         "Key {key} is not present in path {path}. Keys in path:"
1372                         "{data_keys}".format(
1373                             key=key,
1374                             path=_path,
1375                             data_keys=data.keys()))
1376
1377                 if data[key] != ref[key]:
1378                     if isinstance(data[key], list) \
1379                             or isinstance(data[key], dict):
1380                         InterfaceKeywords.compare_data_structures(
1381                             data[key], ref[key],
1382                             _path + '[{0}]'.format(key))
1383                     else:
1384                         raise HoneycombError(
1385                             "Data mismatch, key {key} in path {path} has value"
1386                             " {data}, but should be {ref}".format(
1387                                 key=key,
1388                                 path=_path,
1389                                 data=data[key],
1390                                 ref=ref[key]))
1391
1392         elif isinstance(data, list) and isinstance(ref, list):
1393             for item in ref:
1394                 if item not in data:
1395                     if isinstance(item, dict):
1396                         InterfaceKeywords.compare_data_structures(
1397                             data[0], item,
1398                             _path + '[{0}]'.format(ref.index(item)))
1399                     else:
1400                         raise HoneycombError(
1401                             "Data mismatch, list item {index} in path {path}"
1402                             " has value {data}, but should be {ref}".format(
1403                                 index=ref.index(item),
1404                                 path=_path,
1405                                 data=data[0],
1406                                 ref=item))
1407
1408         else:
1409             raise HoneycombError(
1410                 "Unexpected data type {data_type} in path {path}, reference"
1411                 " type is {ref_type}. Must be list or dictionary.".format(
1412                     data_type=type(data),
1413                     ref_type=type(ref),
1414                     path=_path))
1415
1416     @staticmethod
1417     def compare_interface_lists(list1, list2):
1418         """Compare provided lists of interfaces by name.
1419
1420         :param list1: List of interfaces.
1421         :param list2: List of interfaces.
1422         :type list1: list
1423         :type list2: list
1424         :raises HoneycombError: If an interface exists in only one of the lists.
1425         """
1426
1427         ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"]
1428         # these have no equivalent in config data and no effect on VPP
1429
1430         names1 = [x['name'] for x in list1]
1431         names2 = [x['name'] for x in list2]
1432
1433         for name in names1:
1434             if name not in names2 and name not in ignore:
1435                 raise HoneycombError("Interface {0} not present in list {1}"
1436                                      .format(name, list2))
1437         for name in names2:
1438             if name not in names1 and name not in ignore:
1439                 raise HoneycombError("Interface {0} not present in list {1}"
1440                                      .format(name, list1))
1441
1442     @staticmethod
1443     def create_vxlan_gpe_interface(node, interface, **kwargs):
1444         """Create a new VxLAN GPE interface.
1445
1446         :param node: Honeycomb node.
1447         :param interface: The name of interface to be created.
1448         :param kwargs: Parameters and their values. The accepted parameters are
1449         defined in InterfaceKeywords.VXLAN_GPE_PARAMS.
1450         :type node: dict
1451         :type interface: str
1452         :type kwargs: dict
1453         :returns: Content of response.
1454         :rtype: bytearray
1455         :raises HoneycombError: If a parameter in kwargs is not valid.
1456         """
1457
1458         new_vxlan_gpe = {
1459             "name": interface,
1460             "type": "v3po:vxlan-gpe-tunnel",
1461             "v3po:vxlan-gpe": {}
1462         }
1463         for param, value in kwargs.items():
1464             if param in InterfaceKeywords.INTF_PARAMS:
1465                 new_vxlan_gpe[param] = value
1466             elif param in InterfaceKeywords.VXLAN_GPE_PARAMS:
1467                 new_vxlan_gpe["v3po:vxlan-gpe"][param] = value
1468             else:
1469                 raise HoneycombError("The parameter {0} is invalid.".
1470                                      format(param))
1471         path = ("interfaces", "interface")
1472         vxlan_gpe_structure = [new_vxlan_gpe, ]
1473         return InterfaceKeywords._set_interface_properties(
1474             node, interface, path, vxlan_gpe_structure)
1475
1476     @staticmethod
1477     def enable_acl_on_interface(node, interface, table_name):
1478         """Enable ACL on the given interface.
1479
1480         :param node: Honeycomb node.
1481         :param interface: The interface where the ACL will be enabled.
1482         :param table_name: Name of the classify table.
1483         :type node: dict
1484         :type interface: str
1485         :type table_name: str
1486         :returns: Content of response.
1487         :rtype: bytearray
1488         :raises HoneycombError: If the configuration of interface is not
1489         successful.
1490         """
1491
1492         interface = interface.replace("/", "%2F")
1493
1494         data = {
1495             "vpp-interface-acl:acl": {
1496                 "ingress": {
1497                     "ip4-acl": {
1498                         "classify-table": table_name
1499                     },
1500                     "l2-acl": {
1501                         "classify-table": table_name
1502                     }
1503                 }
1504             }
1505         }
1506
1507         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1508         status_code, resp = HcUtil.\
1509             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1510                                data_representation=DataRepresentation.JSON)
1511         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1512             raise HoneycombError(
1513                 "The configuration of interface '{0}' was not successful. "
1514                 "Status code: {1}.".format(interface, status_code))
1515         return resp
1516
1517     @staticmethod
1518     def enable_policer_on_interface(node, interface, table_name):
1519         """Enable Policer on the given interface.
1520
1521         :param node: Honeycomb node.
1522         :param interface: The interface where policer will be enabled.
1523         :param table_name: Name of the classify table.
1524         :type node: dict
1525         :type interface: str
1526         :type table_name: str
1527         :returns: Content of response.
1528         :rtype: bytearray
1529         :raises HoneycombError: If the configuration of interface is not
1530         successful.
1531         """
1532         interface = Topology.convert_interface_reference(
1533             node, interface, "name")
1534         interface = interface.replace("/", "%2F")
1535
1536         data = {
1537             "interface-policer:policer": {
1538                 "ip4-table": table_name
1539                 }
1540             }
1541
1542         path = "/interface/" + interface + "/interface-policer:policer"
1543         status_code, resp = HcUtil.\
1544             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1545                                data_representation=DataRepresentation.JSON)
1546         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1547             raise HoneycombError(
1548                 "The configuration of interface '{0}' was not successful. "
1549                 "Status code: {1}.".format(interface, status_code))
1550         return resp
1551
1552     @staticmethod
1553     def disable_policer_on_interface(node, interface):
1554         """Disable Policer on the given interface.
1555
1556         :param node: Honeycomb node.
1557         :param interface: The interface where policer will be disabled.
1558         :param table_name: Name of the classify table.
1559         :type node: dict
1560         :type interface: str
1561         :type table_name: str
1562         :returns: Content of response.
1563         :rtype: bytearray
1564         :raises HoneycombError: If the configuration of interface is not
1565         successful.
1566         """
1567         interface = Topology.convert_interface_reference(
1568             node, interface, "name")
1569         interface = interface.replace("/", "%2F")
1570
1571         path = "/interface/" + interface + "/interface-policer:policer"
1572         status_code, resp = HcUtil.\
1573             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1574         if status_code != HTTPCodes.OK:
1575             raise HoneycombError(
1576                 "The configuration of interface '{0}' was not successful. "
1577                 "Status code: {1}.".format(interface, status_code))
1578         return resp
1579
1580     @staticmethod
1581     def disable_acl_on_interface(node, interface):
1582         """Disable ACL on the given interface.
1583
1584         :param node: Honeycomb node.
1585         :param interface: The interface where the ACL will be disabled.
1586         :type node: dict
1587         :type interface: str
1588         :returns: Content of response.
1589         :rtype: bytearray
1590         :raises HoneycombError: If the configuration of interface is not
1591         successful.
1592         """
1593
1594         interface = interface.replace("/", "%2F")
1595
1596         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1597
1598         status_code, resp = HcUtil.\
1599             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1600
1601         if status_code != HTTPCodes.OK:
1602             raise HoneycombError(
1603                 "The configuration of interface '{0}' was not successful. "
1604                 "Status code: {1}.".format(interface, status_code))
1605         return resp
1606
1607     @staticmethod
1608     def create_pbb_sub_interface(node, intf, params):
1609         """Creates a PBB sub-interface on the given interface and sets its
1610         parameters.
1611
1612         :param node: Honeycomb node.
1613         :param intf: The interface where PBB sub-interface will be configured.
1614         :param params: Configuration parameters of the sub-interface to be
1615         created.
1616         :type node: dict
1617         :type intf: str
1618         :type params: dict
1619         :returns: Content of response.
1620         :rtype: bytearray
1621         :raises HoneycombError: If the configuration of sub-interface is not
1622         successful.
1623         """
1624
1625         interface = intf.replace("/", "%2F")
1626         path = "/interface/{0}/pbb-rewrite".format(interface)
1627         status_code, resp = HcUtil. \
1628             put_honeycomb_data(node, "config_vpp_interfaces", params, path,
1629                                data_representation=DataRepresentation.JSON)
1630         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1631             raise HoneycombError(
1632                 "The configuration of PBB sub-interface '{0}' was not "
1633                 "successful. Status code: {1}.".format(intf, status_code))
1634         return resp
1635
1636     @staticmethod
1637     def delete_pbb_sub_interface(node, intf):
1638         """Deletes the given PBB sub-interface.
1639
1640         :param node: Honeycomb node.
1641         :param intf: The interface where PBB sub-interface will be deleted.
1642         :type node: dict
1643         :type intf: str
1644         :returns: Content of response.
1645         :rtype: bytearray
1646         :raises HoneycombError: If the removal of sub-interface is not
1647         successful.
1648         """
1649
1650         interface = intf.replace("/", "%2F")
1651         path = "/interface/{0}/pbb-rewrite".format(interface)
1652
1653         status_code, resp = HcUtil. \
1654             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1655         if status_code != HTTPCodes.OK:
1656             raise HoneycombError(
1657                 "The removal of pbb sub-interface '{0}' was not successful. "
1658                 "Status code: {1}.".format(intf, status_code))
1659         return resp
1660
1661     @staticmethod
1662     def get_pbb_sub_interface_oper_data(node, intf, sub_if_id):
1663         """Retrieves PBB sub-interface operational data from Honeycomb.
1664
1665         :param node: Honeycomb node.
1666         :param intf: The interface where PBB sub-interface is located.
1667         :param sub_if_id: ID of the PBB sub-interface.
1668         :type node: dict
1669         :type intf: str
1670         :type sub_if_id: str or int
1671         :returns: PBB sub-interface operational data.
1672         :rtype: dict
1673         :raises HoneycombError: If the removal of sub-interface is not
1674         successful.
1675         """
1676
1677         raise NotImplementedError
1678
1679     @staticmethod
1680     def check_disabled_interface(node, interface):
1681         """Retrieves list of disabled interface indices from Honeycomb,
1682         and matches with the provided interface by index.
1683
1684         :param node: Honeycomb node.
1685         :param interface: Index number of an interface on the node.
1686         :type node: dict
1687         :type interface: int
1688         :returns: True if the interface exists in disabled interfaces.
1689         :rtype: bool
1690         :raises HoneycombError: If the interface is not present
1691          in retrieved list of disabled interfaces.
1692          """
1693         data = InterfaceKeywords.get_disabled_interfaces_oper_data(node)
1694         # decrement by one = conversion from HC if-index to VPP sw_if_index
1695         interface -= 1
1696
1697         for item in data:
1698             if item["index"] == interface:
1699                 return True
1700         raise HoneycombError("Interface index {0} not present in list"
1701                              " of disabled interfaces.".format(interface))
1702
1703     @staticmethod
1704     def configure_interface_span(node, dst_interface, src_interfaces=None):
1705         """Configure SPAN port mirroring on the specified interfaces. If no
1706          source interface is provided, SPAN will be disabled.
1707
1708         :param node: Honeycomb node.
1709         :param dst_interface: Interface to mirror packets to.
1710         :param src_interfaces: List of interfaces to mirror packets from.
1711         :type node: dict
1712         :type dst_interface: str or int
1713         :type src_interfaces: list of dict
1714         :returns: Content of response.
1715         :rtype: bytearray
1716         :raises HoneycombError: If SPAN could not be configured.
1717         """
1718
1719         interface = Topology.convert_interface_reference(
1720             node, dst_interface, "name")
1721         interface = interface.replace("/", "%2F")
1722         path = "/interface/" + interface + "/span"
1723
1724         if not src_interfaces:
1725             status_code, _ = HcUtil.delete_honeycomb_data(
1726                 node, "config_vpp_interfaces", path)
1727         else:
1728             for src_interface in src_interfaces:
1729                 src_interface["iface-ref"] = Topology.\
1730                     convert_interface_reference(
1731                         node, src_interface["iface-ref"], "name")
1732             data = {
1733                 "span": {
1734                     "mirrored-interfaces": {
1735                         "mirrored-interface": src_interfaces
1736                     }
1737                 }
1738             }
1739
1740             status_code, _ = HcUtil.put_honeycomb_data(
1741                 node, "config_vpp_interfaces", data, path)
1742
1743         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1744             raise HoneycombError(
1745                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1746
1747     @staticmethod
1748     def configure_sub_interface_span(node, super_interface, dst_interface_index,
1749                                      src_interfaces=None):
1750         """Configure SPAN port mirroring on the specified sub-interface. If no
1751          source interface is provided, SPAN will be disabled.
1752
1753         Note: Does not support source sub-interfaces, only destination.
1754
1755         :param node: Honeycomb node.
1756         :param super_interface: Name, link name or sw_if_index
1757         of the destination interface's super-interface.
1758         :param dst_interface_index: Index of sub-interface to mirror packets to.
1759         :param src_interfaces: List of interfaces to mirror packets from.
1760         :type node: dict
1761         :type super_interface: str or int
1762         :type dst_interface_index: int
1763         :type src_interfaces: list of dict
1764         :returns: Content of response.
1765         :rtype: bytearray
1766         :raises HoneycombError: If SPAN could not be configured.
1767         """
1768
1769         super_interface = Topology.convert_interface_reference(
1770             node, super_interface, "name")
1771         super_interface = super_interface.replace("/", "%2F")
1772
1773         path = "/interface/{0}/vpp-vlan:sub-interfaces/sub-interface/{1}/span"\
1774             .format(super_interface, dst_interface_index)
1775
1776         if not src_interfaces:
1777             status_code, _ = HcUtil.delete_honeycomb_data(
1778                 node, "config_vpp_interfaces", path)
1779         else:
1780             for src_interface in src_interfaces:
1781                 src_interface["iface-ref"] = Topology. \
1782                     convert_interface_reference(
1783                     node, src_interface["iface-ref"], "name")
1784             data = {
1785                 "span": {
1786                     "mirrored-interfaces": {
1787                         "mirrored-interface": src_interfaces
1788                     }
1789                 }
1790             }
1791
1792             status_code, _ = HcUtil.put_honeycomb_data(
1793                 node, "config_vpp_interfaces", data, path)
1794
1795         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1796             raise HoneycombError(
1797                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1798
1799     @staticmethod
1800     def add_interface_local0_to_topology(node):
1801         """Use Topology methods to add interface "local0" to working topology,
1802         if not already present.
1803
1804         :param node: DUT node.
1805         :type node: dict
1806         """
1807
1808         if Topology.get_interface_by_sw_index(node, 0) is None:
1809             local0_key = Topology.add_new_port(node, "localzero")
1810             Topology.update_interface_sw_if_index(node, local0_key, 0)
1811             Topology.update_interface_name(node, local0_key, "local0")