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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """Keywords to manipulate interface configuration using Honeycomb REST API.
16 The keywords make possible to put and get configuration data and to get
19 from robot.api import logger
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
30 class InterfaceKeywords(object):
31 """Keywords for Interface manipulation.
33 Implements keywords which get configuration and operational data about
34 vpp interfaces and set the interface's parameters using Honeycomb REST API.
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",
56 SUB_IF_MATCH = ("default",
59 "vlan-tagged-exact-match")
60 BD_PARAMS = ("bridge-domain",
61 "split-horizon-group",
62 "bridged-virtual-interface")
63 VXLAN_GPE_PARAMS = ("local",
74 def _configure_interface(node, interface, data,
75 data_representation=DataRepresentation.JSON):
76 """Send interface configuration data and check the response.
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.
85 :type data_representation: DataRepresentation
86 :returns: Content of response.
88 :raises HoneycombError: If the status code in response on PUT is not
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):
97 "The configuration of interface '{0}' was not successful. "
98 "Status code: {1}.".format(interface, status_code))
102 def get_all_interfaces_cfg_data(node):
103 """Get configuration data about all interfaces from Honeycomb.
105 :param node: Honeycomb node.
107 :returns: Configuration data about all interfaces from Honeycomb.
109 :raises HoneycombError: If it is not possible to get configuration data.
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))
119 return resp["interfaces"]["interface"]
121 except (KeyError, TypeError):
125 def get_interface_cfg_data(node, interface):
126 """Get configuration data about the given interface from Honeycomb.
128 :param node: Honeycomb node.
129 :param interface: The name of interface.
132 :returns: Configuration data about the given interface from Honeycomb.
136 intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node)
138 if intf["name"] == interface:
143 def get_all_interfaces_oper_data(node):
144 """Get operational data about all interfaces from Honeycomb.
146 :param node: Honeycomb node.
148 :returns: Operational data about all interfaces from Honeycomb.
150 :raises HoneycombError: If it is not possible to get operational data.
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))
160 return resp["interfaces-state"]["interface"]
162 except (KeyError, TypeError):
166 def get_disabled_interfaces_oper_data(node):
167 """Get operational data about all disabled interfaces from Honeycomb.
169 :param node: Honeycomb node.
171 :returns: Operational data about disabled interfaces.
173 :raises HoneycombError: If it is not possible to get operational data.
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."
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))
187 return resp["disabled-interfaces"]["disabled-interface-index"]
189 except (KeyError, TypeError):
193 def get_interface_oper_data(node, interface):
194 """Get operational data about the given interface from Honeycomb.
196 :param node: Honeycomb node.
197 :param interface: The name of interface.
200 :returns: Operational data about the given interface from Honeycomb.
205 interface = Topology.convert_interface_reference(
206 node, interface, "name")
208 if isinstance(interface, basestring):
209 # Probably name of a custom interface (TAP, VxLAN, Vhost, ...)
214 intfs = InterfaceKeywords.get_all_interfaces_oper_data(node)
216 if intf["name"] == interface:
221 def _set_interface_properties(node, interface, path, new_value=None):
222 """Set interface properties.
224 This method reads interface configuration data, creates, changes or
225 removes the requested data and puts it back to Honeycomb.
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
235 :type new_value: str, dict or list
236 :returns: Content of response.
238 :raises HoneycombError: If it is not possible to get or set the data.
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))
249 new_data = HcUtil.set_item_value(resp, path, new_value)
251 new_data = HcUtil.remove_item(resp, path)
252 return InterfaceKeywords._configure_interface(node, interface, new_data)
255 def set_interface_state(node, interface, state="up"):
256 """Set VPP interface state.
258 The keyword changes the administration state of interface to up or down
259 depending on the parameter "state".
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
268 :returns: Content of response.
270 :raises KeyError: If the argument "state" is nor "up" or "down".
271 :raises HoneycombError: If the interface is not present on the node.
274 intf_state = {"up": "true",
277 interface = Topology.convert_interface_reference(
278 node, interface, "name")
280 intf = interface.replace("/", "%2F")
281 path = "/interface/{0}".format(intf)
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))
290 resp["interface"][0]["enabled"] = intf_state[state.lower()]
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))
302 def set_interface_up(node, interface):
303 """Set the administration state of VPP interface to up.
305 :param node: Honeycomb node.
306 :param interface: The name of interface.
309 :returns: Content of response
313 return InterfaceKeywords.set_interface_state(node, interface, "up")
316 def set_interface_down(node, interface):
317 """Set the administration state of VPP interface to down.
319 :param node: Honeycomb node.
320 :param interface: The name of interface.
323 :returns: Content of response.
327 return InterfaceKeywords.set_interface_state(node, interface, "down")
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.
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.
342 :type split_horizon_group: str
344 :returns: Content of response.
346 :raises HoneycombError: If the interface is not present on the node.
349 interface = Topology.convert_interface_reference(
350 node, interface, "name")
352 v3po_l2 = {"bridge-domain": str(bd_name)}
353 if split_horizon_group:
354 v3po_l2["split-horizon-group"] = str(split_horizon_group)
356 v3po_l2["bridged-virtual-interface"] = str(bvi)
358 path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2")
360 return InterfaceKeywords._set_interface_properties(
361 node, interface, path, v3po_l2)
364 def remove_bridge_domain_from_interface(node, interface):
365 """Remove bridge domain assignment from interface.
367 :param node: Honeycomb node.
368 :param interface: Interface name, key, link name or sw_if_index.
370 :type interface: str or int
372 :raises HoneycombError: If the operation fails.
375 interface = Topology.convert_interface_reference(
376 node, interface, "name")
378 intf = interface.replace("/", "%2F")
380 path = "/interface/{0}/v3po:l2".format(intf)
382 status_code, response = HcUtil.delete_honeycomb_data(
383 node, "config_vpp_interfaces", path)
385 if status_code != HTTPCodes.OK:
386 if '"error-tag":"data-missing"' in response:
387 logger.debug("Data does not exist in path.")
389 raise HoneycombError(
390 "Could not remove bridge domain assignment from interface "
391 "'{0}'. Status code: {1}.".format(interface, status_code))
394 def get_bd_oper_data_from_interface(node, interface):
395 """Returns operational data about bridge domain settings in the
398 :param node: Honeycomb node.
399 :param interface: The name of interface.
402 :returns: Operational data about bridge domain settings in the
407 if_data = InterfaceKeywords.get_interface_oper_data(node, interface)
411 return if_data["v3po:l2"]
417 def configure_interface_base(node, interface, param, value):
418 """Configure the base parameters of interface.
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
429 :returns: Content of response.
431 :raises HoneycombError: If the parameter is not valid.
434 if param not in InterfaceKeywords.INTF_PARAMS:
435 raise HoneycombError("The parameter {0} is invalid.".format(param))
437 path = ("interfaces", ("interface", "name", interface), param)
438 return InterfaceKeywords._set_interface_properties(
439 node, interface, path, value)
442 def configure_interface_ipv4(node, interface, param, value):
443 """Configure IPv4 parameters of interface.
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
454 :returns: Content of response.
456 :raises HoneycombError: If the parameter is not valid.
459 interface = Topology.convert_interface_reference(
460 node, interface, "name")
462 if param not in InterfaceKeywords.IPV4_PARAMS:
463 raise HoneycombError("The parameter {0} is invalid.".format(param))
465 path = ("interfaces", ("interface", "name", interface),
466 "ietf-ip:ipv4", param)
467 return InterfaceKeywords._set_interface_properties(
468 node, interface, path, value)
471 def add_first_ipv4_address(node, interface, ip_addr, network):
472 """Add the first IPv4 address.
474 If there are any other addresses configured, they will be removed.
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.
483 :type network: str or int
484 :returns: Content of response.
486 :raises HoneycombError: If the provided netmask or prefix is not valid.
489 interface = Topology.convert_interface_reference(
490 node, interface, "name")
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}, ]}
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)
504 def add_ipv4_address(node, interface, ip_addr, network):
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.
514 :type network: str or int
515 :returns: Content of response.
517 :raises HoneycombError: If the provided netmask or prefix is not valid.
520 interface = Topology.convert_interface_reference(
521 node, interface, "name")
523 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
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}]
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)
536 def remove_all_ipv4_addresses(node, interface):
537 """Remove all IPv4 addresses from interface.
539 :param node: Honeycomb node.
540 :param interface: The name of interface.
543 :returns: Content of response.
547 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
549 return InterfaceKeywords._set_interface_properties(
550 node, interface, path, None)
553 def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address):
554 """Add the IPv4 neighbour.
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.
563 :type link_layer_address: str
564 :returns: Content of response.
568 interface = Topology.convert_interface_reference(
569 node, interface, "name")
571 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
573 neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
574 return InterfaceKeywords._set_interface_properties(
575 node, interface, path, neighbor)
578 def remove_all_ipv4_neighbors(node, interface):
579 """Remove all IPv4 neighbours.
581 :param node: Honeycomb node.
582 :param interface: The name of interface.
585 :returns: Content of response.
589 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
591 return InterfaceKeywords._set_interface_properties(
592 node, interface, path, None)
595 def configure_interface_ipv6(node, interface, param, value):
596 """Configure IPv6 parameters of interface
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
607 :returns: Content of response.
609 :raises HoneycombError: If the parameter is not valid.
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)
619 raise HoneycombError("The parameter {0} is invalid.".format(param))
621 return InterfaceKeywords._set_interface_properties(
622 node, interface, path, value)
625 def add_first_ipv6_address(node, interface, ip_addr, prefix_len):
626 """Add the first IPv6 address.
628 If there are any other addresses configured, they will be removed.
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.
637 :type prefix_len: str
638 :returns: Content of response.
642 interface = Topology.convert_interface_reference(
643 node, interface, "name")
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)
651 def add_ipv6_address(node, interface, ip_addr, prefix_len):
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.
661 :type prefix_len: str
662 :returns: Content of response.
666 interface = Topology.convert_interface_reference(
667 node, interface, "name")
669 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
671 address = [{"ip": ip_addr, "prefix-length": prefix_len}, ]
672 return InterfaceKeywords._set_interface_properties(
673 node, interface, path, address)
676 def remove_all_ipv6_addresses(node, interface):
677 """Remove all IPv6 addresses from interface.
679 :param node: Honeycomb node.
680 :param interface: The name of interface.
683 :returns: Content of response.
687 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
689 return InterfaceKeywords._set_interface_properties(
690 node, interface, path, None)
693 def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address):
694 """Add the IPv6 neighbour.
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.
703 :type link_layer_address: str
704 :returns: Content of response.
708 interface = Topology.convert_interface_reference(
709 node, interface, "name")
711 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
713 neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
714 return InterfaceKeywords._set_interface_properties(
715 node, interface, path, neighbor)
718 def remove_all_ipv6_neighbors(node, interface):
719 """Remove all IPv6 neighbours.
721 :param node: Honeycomb node.
722 :param interface: The name of interface.
725 :returns: Content of response.
729 path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
731 return InterfaceKeywords._set_interface_properties(
732 node, interface, path, None)
735 def configure_interface_ethernet(node, interface, param, value):
736 """Configure the ethernet parameters of interface.
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
747 :returns: Content of response.
749 :raises HoneycombError: If the parameter is not valid.
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",
756 return InterfaceKeywords._set_interface_properties(
757 node, interface, path, value)
760 def configure_interface_routing(node, interface, param, value):
761 """Configure the routing parameters of interface.
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
772 :returns: Content of response.
774 :raises HoneycombError: If the parameter is not valid.
777 interface = Topology.convert_interface_reference(
778 node, interface, "name")
780 if param not in InterfaceKeywords.ROUTING_PARAMS:
781 raise HoneycombError("The parameter {0} is invalid.".format(param))
783 path = ("interfaces", ("interface", "name", interface), "v3po:routing",
785 return InterfaceKeywords._set_interface_properties(
786 node, interface, path, value)
789 def create_vxlan_interface(node, interface, **kwargs):
790 """Create a new VxLAN interface.
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.
799 :returns: Content of response.
801 :raises HoneycombError: If the parameter is not valid.
806 "type": "v3po:vxlan-tunnel",
809 for param, value in kwargs.items():
810 if param not in InterfaceKeywords.VXLAN_PARAMS:
811 raise HoneycombError("The parameter {0} is invalid.".
813 new_vx_lan["v3po:vxlan"][param] = value
815 path = ("interfaces", "interface")
816 vx_lan_structure = [new_vx_lan, ]
817 return InterfaceKeywords._set_interface_properties(
818 node, interface, path, vx_lan_structure)
821 def delete_interface(node, interface):
822 """Delete an interface.
824 :param node: Honeycomb node.
825 :param interface: The name of interface.
828 :returns: Content of response.
830 :raises HoneycombError: If it is not possible to get information about
831 interfaces or it is not possible to delete the interface.
834 path = ("interfaces", ("interface", "name", interface))
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))
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}. "
849 format(interface, status_code))
853 def configure_interface_vxlan(node, interface, **kwargs):
854 """Configure VxLAN on the interface.
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
861 If the dictionary kwargs is empty, VxLAN configuration is removed.
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.
870 :returns: Content of response.
872 :raises HoneycombError: If the parameter is not valid.
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.".
880 vx_lan_structure[param] = value
882 path = ("interfaces", ("interface", "name", interface), "v3po:vxlan")
883 return InterfaceKeywords._set_interface_properties(
884 node, interface, path, vx_lan_structure)
887 def configure_interface_l2(node, interface, param, value):
888 """Configure the L2 parameters of interface.
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
899 :returns: Content of response.
901 :raises HoneycombError: If the parameter is not valid.
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",
908 return InterfaceKeywords._set_interface_properties(
909 node, interface, path, value)
912 def create_tap_interface(node, interface, **kwargs):
913 """Create a new TAP interface.
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.
922 :returns: Content of response.
924 :raises HoneycombError: If the parameter is not valid.
932 for param, value in kwargs.items():
933 if param not in InterfaceKeywords.TAP_PARAMS:
934 raise HoneycombError("The parameter {0} is invalid.".
936 new_tap["v3po:tap"][param] = value
938 path = ("interfaces", "interface")
939 new_tap_structure = [new_tap, ]
940 return InterfaceKeywords._set_interface_properties(
941 node, interface, path, new_tap_structure)
944 def configure_interface_tap(node, interface, **kwargs):
945 """Configure TAP on the interface.
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
952 If the dictionary kwargs is empty, TAP configuration is removed.
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.
961 :returns: Content of response.
963 :raises HoneycombError: If the parameter is not valid.
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.".
971 tap_structure[param] = value
973 path = ("interfaces", ("interface", "name", interface), "v3po:tap")
974 return InterfaceKeywords._set_interface_properties(
975 node, interface, path, tap_structure)
978 def configure_interface_vhost_user(node, interface, **kwargs):
979 """Configure vhost-user on the interface.
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
986 If the dictionary kwargs is empty, vhost-user configuration is removed.
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.
995 :returns: Content of response.
997 :raises HoneycombError: If the parameter is not valid.
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.".
1005 vhost_structure[param] = value
1007 path = ("interfaces", ("interface", "name", interface),
1009 return InterfaceKeywords._set_interface_properties(
1010 node, interface, path, vhost_structure)
1013 def create_vhost_user_interface(node, interface, **kwargs):
1014 """Create a new vhost-user interface.
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.
1021 :type interface: str
1023 :returns: Content of response.
1025 :raises HoneycombError: If the parameter is not valid.
1030 "type": "v3po:vhost-user",
1031 "v3po:vhost-user": {}
1033 for param, value in kwargs.items():
1034 if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1035 raise HoneycombError("The parameter {0} is invalid.".
1037 new_vhost["v3po:vhost-user"][param] = value
1039 path = ("interfaces", "interface")
1040 new_vhost_structure = [new_vhost, ]
1041 return InterfaceKeywords._set_interface_properties(
1042 node, interface, path, new_vhost_structure)
1045 def create_sub_interface(node, super_interface, match, tags=None, **kwargs):
1046 """Create a new sub-interface.
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.
1056 :type super_interface: str
1060 :returns: Content of response.
1062 :raises HoneycombError: If the parameter is not valid.
1063 :raises KeyError: If the parameter 'match' is invalid.
1072 {"vlan-tagged": {"match-exact-tags": "false"}},
1073 "vlan-tagged-exact-match":
1074 {"vlan-tagged": {"match-exact-tags": "true"}}
1077 new_sub_interface = {
1083 for param, value in kwargs.items():
1084 if param in InterfaceKeywords.SUB_IF_PARAMS:
1085 new_sub_interface[param] = value
1087 raise HoneycombError("The parameter {0} is invalid.".
1090 new_sub_interface["match"] = match_type[match]
1092 raise HoneycombError("The value '{0}' of parameter 'match' is "
1093 "invalid.".format(match))
1096 new_sub_interface["tags"]["tag"].extend(tags)
1098 path = ("interfaces",
1099 ("interface", "name", super_interface),
1100 "vpp-vlan:sub-interfaces",
1102 new_sub_interface_structure = [new_sub_interface, ]
1103 return InterfaceKeywords._set_interface_properties(
1104 node, super_interface, path, new_sub_interface_structure)
1107 def get_sub_interface_oper_data(node, super_interface, identifier):
1108 """Retrieves sub-interface operational data using Honeycomb API.
1110 :param node: Honeycomb node.
1111 :param super_interface: Super interface.
1112 :param identifier: The ID of sub-interface.
1114 :type super_interface: str
1115 :type identifier: int
1116 :returns: Sub-interface operational data.
1118 :raises HoneycombError: If there is no sub-interface with the given ID.
1121 if_data = InterfaceKeywords.get_interface_oper_data(node,
1123 for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]:
1124 if str(sub_if["identifier"]) == str(identifier):
1127 raise HoneycombError("The interface {0} does not have sub-interface "
1128 "with ID {1}".format(super_interface, identifier))
1131 def remove_all_sub_interfaces(node, super_interface):
1132 """Remove all sub-interfaces from the given interface.
1134 :param node: Honeycomb node.
1135 :param super_interface: Super interface.
1137 :type super_interface: str
1138 :returns: Content of response.
1142 path = ("interfaces",
1143 ("interface", "name", super_interface),
1144 "vpp-vlan:sub-interfaces")
1146 return InterfaceKeywords._set_interface_properties(
1147 node, super_interface, path, {})
1150 def set_sub_interface_state(node, super_interface, identifier, state):
1151 """Set the administrative state of sub-interface.
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.
1158 :type super_interface: str
1159 :type identifier: int
1161 :returns: Content of response.
1165 intf_state = {"up": "true",
1168 path = ("interfaces",
1169 ("interface", "name", super_interface),
1170 "vpp-vlan:sub-interfaces",
1171 ("sub-interface", "identifier", int(identifier)),
1174 return InterfaceKeywords._set_interface_properties(
1175 node, super_interface, path, intf_state[state])
1178 def add_bridge_domain_to_sub_interface(node, super_interface, identifier,
1180 """Add a sub-interface to a bridge domain and set its parameters.
1182 :param node: Honeycomb node.
1183 :param super_interface: Super interface.
1184 :param identifier: The ID of sub-interface.
1185 :param config: Bridge domain configuration.
1187 :type super_interface: str
1188 :type identifier: int
1190 :returns: Content of response.
1194 path = ("interfaces",
1195 ("interface", "name", super_interface),
1196 "vpp-vlan:sub-interfaces",
1197 ("sub-interface", "identifier", int(identifier)),
1200 return InterfaceKeywords._set_interface_properties(
1201 node, super_interface, path, config)
1204 def get_bd_data_from_sub_interface(node, super_interface, identifier):
1205 """Get the operational data about the bridge domain from sub-interface.
1207 :param node: Honeycomb node.
1208 :param super_interface: Super interface.
1209 :param identifier: The ID of sub-interface.
1211 :type super_interface: str
1212 :type identifier: int
1213 :returns: Operational data about the bridge domain.
1215 :raises HoneycombError: If there is no sub-interface with the given ID.
1219 bd_data = InterfaceKeywords.get_sub_interface_oper_data(
1220 node, super_interface, identifier)["l2"]
1223 raise HoneycombError("The operational data does not contain "
1224 "information about a bridge domain.")
1227 def configure_tag_rewrite(node, super_interface, identifier, config):
1228 """Add / change / disable vlan tag rewrite on a sub-interface.
1230 :param node: Honeycomb node.
1231 :param super_interface: Super interface.
1232 :param identifier: The ID of sub-interface.
1233 :param config: Rewrite tag configuration.
1235 :type super_interface: str
1236 :type identifier: int
1238 :returns: Content of response.
1242 path = ("interfaces",
1243 ("interface", "name", super_interface),
1244 "vpp-vlan:sub-interfaces",
1245 ("sub-interface", "identifier", int(identifier)),
1249 return InterfaceKeywords._set_interface_properties(
1250 node, super_interface, path, config)
1253 def get_tag_rewrite_oper_data(node, super_interface, identifier):
1254 """Get the operational data about tag rewrite.
1256 :param node: Honeycomb node.
1257 :param super_interface: Super interface.
1258 :param identifier: The ID of sub-interface.
1260 :type super_interface: str
1261 :type identifier: int
1262 :returns: Operational data about tag rewrite.
1264 :raises HoneycombError: If there is no sub-interface with the given ID.
1268 tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data(
1269 node, super_interface, identifier)["l2"]["rewrite"]
1272 raise HoneycombError("The operational data does not contain "
1273 "information about the tag-rewrite.")
1276 def add_ip_address_to_sub_interface(node, super_interface, identifier,
1277 ip_addr, network, ip_version):
1278 """Add an ipv4 address to the specified sub-interface, with the provided
1279 netmask or network prefix length. Any existing ipv4 addresses on the
1280 sub-interface will be replaced.
1282 :param node: Honeycomb node.
1283 :param super_interface: Super interface.
1284 :param identifier: The ID of sub-interface.
1285 :param ip_addr: IPv4 address to be set.
1286 :param network: Network mask or network prefix length.
1287 :param ip_version: ipv4 or ipv6
1289 :type super_interface: str
1290 :type identifier: int
1292 :type network: str or int
1293 :type ip_version: string
1294 :returns: Content of response.
1296 :raises HoneycombError: If the provided netmask or prefix is not valid.
1299 path = ("interfaces",
1300 ("interface", "name", super_interface),
1301 "vpp-vlan:sub-interfaces",
1302 ("sub-interface", "identifier", int(identifier)),
1305 if isinstance(network, basestring) and ip_version.lower() == "ipv4":
1306 address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
1308 elif isinstance(network, int) and 0 < network < 33:
1309 address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
1312 raise HoneycombError("{0} is not a valid netmask or prefix length."
1315 return InterfaceKeywords._set_interface_properties(
1316 node, super_interface, path, address)
1319 def remove_all_ip_addresses_from_sub_interface(node, super_interface,
1320 identifier, ip_version):
1321 """Remove all ipv4 addresses from the specified sub-interface.
1323 :param node: Honeycomb node.
1324 :param super_interface: Super interface.
1325 :param identifier: The ID of sub-interface.
1326 :param ip_version: ipv4 or ipv6
1328 :type super_interface: str
1329 :type identifier: int
1330 :type ip_version: string
1331 :returns: Content of response.
1335 path = ("interfaces",
1336 ("interface", "name", super_interface),
1337 "vpp-vlan:sub-interfaces",
1338 ("sub-interface", "identifier", int(identifier)),
1339 str(ip_version), "address")
1341 return InterfaceKeywords._set_interface_properties(
1342 node, super_interface, path, None)
1345 def compare_data_structures(data, ref, _path=''):
1346 """Checks if data obtained from UUT is as expected. If it is not,
1347 proceeds down the list/dictionary tree and finds the point of mismatch.
1349 :param data: Data to be checked.
1350 :param ref: Referential data used for comparison.
1351 :param _path: Used in recursive calls, stores the path taken down
1357 :raises HoneycombError: If the data structures do not match in some way,
1358 or if they are not in deserialized JSON format.
1364 elif isinstance(data, dict) and isinstance(ref, dict):
1367 raise HoneycombError(
1368 "Key {key} is not present in path {path}. Keys in path:"
1369 "{data_keys}".format(
1372 data_keys=data.keys()))
1374 if data[key] != ref[key]:
1375 if isinstance(data[key], list) \
1376 or isinstance(data[key], dict):
1377 InterfaceKeywords.compare_data_structures(
1378 data[key], ref[key],
1379 _path + '[{0}]'.format(key))
1381 raise HoneycombError(
1382 "Data mismatch, key {key} in path {path} has value"
1383 " {data}, but should be {ref}".format(
1389 elif isinstance(data, list) and isinstance(ref, list):
1391 if item not in data:
1392 if isinstance(item, dict):
1393 InterfaceKeywords.compare_data_structures(
1395 _path + '[{0}]'.format(ref.index(item)))
1397 raise HoneycombError(
1398 "Data mismatch, list item {index} in path {path}"
1399 " has value {data}, but should be {ref}".format(
1400 index=ref.index(item),
1406 raise HoneycombError(
1407 "Unexpected data type {data_type} in path {path}, reference"
1408 " type is {ref_type}. Must be list or dictionary.".format(
1409 data_type=type(data),
1414 def compare_interface_lists(list1, list2):
1415 """Compare provided lists of interfaces by name.
1417 :param list1: List of interfaces.
1418 :param list2: List of interfaces.
1421 :raises HoneycombError: If an interface exists in only one of the lists.
1424 ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"]
1425 # these have no equivalent in config data and no effect on VPP
1427 names1 = [x['name'] for x in list1]
1428 names2 = [x['name'] for x in list2]
1431 if name not in names2 and name not in ignore:
1432 raise HoneycombError("Interface {0} not present in list {1}"
1433 .format(name, list2))
1435 if name not in names1 and name not in ignore:
1436 raise HoneycombError("Interface {0} not present in list {1}"
1437 .format(name, list1))
1440 def create_vxlan_gpe_interface(node, interface, **kwargs):
1441 """Create a new VxLAN GPE interface.
1443 :param node: Honeycomb node.
1444 :param interface: The name of interface to be created.
1445 :param kwargs: Parameters and their values. The accepted parameters are
1446 defined in InterfaceKeywords.VXLAN_GPE_PARAMS.
1448 :type interface: str
1450 :returns: Content of response.
1452 :raises HoneycombError: If a parameter in kwargs is not valid.
1457 "type": "v3po:vxlan-gpe-tunnel",
1458 "v3po:vxlan-gpe": {}
1460 for param, value in kwargs.items():
1461 if param in InterfaceKeywords.INTF_PARAMS:
1462 new_vxlan_gpe[param] = value
1463 elif param in InterfaceKeywords.VXLAN_GPE_PARAMS:
1464 new_vxlan_gpe["v3po:vxlan-gpe"][param] = value
1466 raise HoneycombError("The parameter {0} is invalid.".
1468 path = ("interfaces", "interface")
1469 vxlan_gpe_structure = [new_vxlan_gpe, ]
1470 return InterfaceKeywords._set_interface_properties(
1471 node, interface, path, vxlan_gpe_structure)
1474 def enable_acl_on_interface(node, interface, table_name):
1475 """Enable ACL on the given interface.
1477 :param node: Honeycomb node.
1478 :param interface: The interface where the ACL will be enabled.
1479 :param table_name: Name of the classify table.
1481 :type interface: str
1482 :type table_name: str
1483 :returns: Content of response.
1485 :raises HoneycombError: If the configuration of interface is not
1489 interface = interface.replace("/", "%2F")
1492 "vpp-interface-acl:acl": {
1495 "classify-table": table_name
1498 "classify-table": table_name
1504 path = "/interface/" + interface + "/vpp-interface-acl:acl"
1505 status_code, resp = HcUtil.\
1506 put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1507 data_representation=DataRepresentation.JSON)
1508 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1509 raise HoneycombError(
1510 "The configuration of interface '{0}' was not successful. "
1511 "Status code: {1}.".format(interface, status_code))
1515 def enable_policer_on_interface(node, interface, table_name):
1516 """Enable Policer on the given interface.
1518 :param node: Honeycomb node.
1519 :param interface: The interface where policer will be enabled.
1520 :param table_name: Name of the classify table.
1522 :type interface: str
1523 :type table_name: str
1524 :returns: Content of response.
1526 :raises HoneycombError: If the configuration of interface is not
1529 interface = Topology.convert_interface_reference(
1530 node, interface, "name")
1531 interface = interface.replace("/", "%2F")
1534 "interface-policer:policer": {
1535 "ip4-table": table_name
1539 path = "/interface/" + interface + "/interface-policer:policer"
1540 status_code, resp = HcUtil.\
1541 put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1542 data_representation=DataRepresentation.JSON)
1543 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1544 raise HoneycombError(
1545 "The configuration of interface '{0}' was not successful. "
1546 "Status code: {1}.".format(interface, status_code))
1550 def disable_policer_on_interface(node, interface):
1551 """Disable Policer on the given interface.
1553 :param node: Honeycomb node.
1554 :param interface: The interface where policer will be disabled.
1555 :param table_name: Name of the classify table.
1557 :type interface: str
1558 :type table_name: str
1559 :returns: Content of response.
1561 :raises HoneycombError: If the configuration of interface is not
1564 interface = Topology.convert_interface_reference(
1565 node, interface, "name")
1566 interface = interface.replace("/", "%2F")
1568 path = "/interface/" + interface + "/interface-policer:policer"
1569 status_code, resp = HcUtil.\
1570 delete_honeycomb_data(node, "config_vpp_interfaces", path)
1571 if status_code != HTTPCodes.OK:
1572 raise HoneycombError(
1573 "The configuration of interface '{0}' was not successful. "
1574 "Status code: {1}.".format(interface, status_code))
1578 def disable_acl_on_interface(node, interface):
1579 """Disable ACL on the given interface.
1581 :param node: Honeycomb node.
1582 :param interface: The interface where the ACL will be disabled.
1584 :type interface: str
1585 :returns: Content of response.
1587 :raises HoneycombError: If the configuration of interface is not
1591 interface = interface.replace("/", "%2F")
1593 path = "/interface/" + interface + "/vpp-interface-acl:acl"
1595 status_code, resp = HcUtil.\
1596 delete_honeycomb_data(node, "config_vpp_interfaces", path)
1598 if status_code != HTTPCodes.OK:
1599 raise HoneycombError(
1600 "The configuration of interface '{0}' was not successful. "
1601 "Status code: {1}.".format(interface, status_code))
1605 def create_pbb_sub_interface(node, intf, params):
1606 """Creates a PBB sub-interface on the given interface and sets its
1609 :param node: Honeycomb node.
1610 :param intf: The interface where PBB sub-interface will be configured.
1611 :param params: Configuration parameters of the sub-interface to be
1616 :returns: Content of response.
1618 :raises HoneycombError: If the configuration of sub-interface is not
1622 interface = intf.replace("/", "%2F")
1623 path = "/interface/{0}/pbb-rewrite".format(interface)
1624 status_code, resp = HcUtil. \
1625 put_honeycomb_data(node, "config_vpp_interfaces", params, path,
1626 data_representation=DataRepresentation.JSON)
1627 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1628 raise HoneycombError(
1629 "The configuration of PBB sub-interface '{0}' was not "
1630 "successful. Status code: {1}.".format(intf, status_code))
1634 def delete_pbb_sub_interface(node, intf):
1635 """Deletes the given PBB sub-interface.
1637 :param node: Honeycomb node.
1638 :param intf: The interface where PBB sub-interface will be deleted.
1641 :returns: Content of response.
1643 :raises HoneycombError: If the removal of sub-interface is not
1647 interface = intf.replace("/", "%2F")
1648 path = "/interface/{0}/pbb-rewrite".format(interface)
1650 status_code, resp = HcUtil. \
1651 delete_honeycomb_data(node, "config_vpp_interfaces", path)
1652 if status_code != HTTPCodes.OK:
1653 raise HoneycombError(
1654 "The removal of pbb sub-interface '{0}' was not successful. "
1655 "Status code: {1}.".format(intf, status_code))
1659 def get_pbb_sub_interface_oper_data(node, intf, sub_if_id):
1660 """Retrieves PBB sub-interface operational data from Honeycomb.
1662 :param node: Honeycomb node.
1663 :param intf: The interface where PBB sub-interface is located.
1664 :param sub_if_id: ID of the PBB sub-interface.
1667 :type sub_if_id: str or int
1668 :returns: PBB sub-interface operational data.
1670 :raises HoneycombError: If the removal of sub-interface is not
1674 raise NotImplementedError
1677 def check_disabled_interface(node, interface):
1678 """Retrieves list of disabled interface indices from Honeycomb,
1679 and matches with the provided interface by index.
1681 :param node: Honeycomb node.
1682 :param interface: Index number of an interface on the node.
1684 :type interface: int
1685 :returns: True if the interface exists in disabled interfaces.
1687 :raises HoneycombError: If the interface is not present
1688 in retrieved list of disabled interfaces.
1690 data = InterfaceKeywords.get_disabled_interfaces_oper_data(node)
1691 # decrement by one = conversion from HC if-index to VPP sw_if_index
1695 if item["index"] == interface:
1697 raise HoneycombError("Interface index {0} not present in list"
1698 " of disabled interfaces.".format(interface))
1701 def configure_interface_span(node, dst_interface, src_interfaces=None):
1702 """Configure SPAN port mirroring on the specified interfaces. If no
1703 source interface is provided, SPAN will be disabled.
1705 :param node: Honeycomb node.
1706 :param dst_interface: Interface to mirror packets to.
1707 :param src_interfaces: List of interfaces to mirror packets from.
1709 :type dst_interface: str
1710 :type src_interfaces: list of dict
1711 :returns: Content of response.
1713 :raises HoneycombError: If SPAN could not be configured.
1716 interface = Topology.convert_interface_reference(
1717 node, dst_interface, "name")
1718 interface = interface.replace("/", "%2F")
1719 path = "/interface/" + interface + "/span"
1721 if not src_interfaces:
1722 status_code, _ = HcUtil.delete_honeycomb_data(
1723 node, "config_vpp_interfaces", path)
1725 for src_interface in src_interfaces:
1726 src_interface["iface-ref"] = Topology.\
1727 convert_interface_reference(
1728 node, src_interface["iface-ref"], "name")
1731 "mirrored-interfaces": {
1732 "mirrored-interface": src_interfaces
1737 status_code, _ = HcUtil.put_honeycomb_data(
1738 node, "config_vpp_interfaces", data, path)
1740 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1741 raise HoneycombError(
1742 "Configuring SPAN failed. Status code:{0}".format(status_code))
1745 def add_interface_local0_to_topology(node):
1746 """Use Topology methods to add interface "local0" to working topology,
1747 if not already present.
1749 :param node: DUT node.
1753 if Topology.get_interface_by_sw_index(node, 0) is None:
1754 local0_key = Topology.add_new_port(node, "localzero")
1755 Topology.update_interface_sw_if_index(node, local0_key, 0)
1756 Topology.update_interface_name(node, local0_key, "local0")