CSIT-811 HC Test: BGP functional tests 99/8999/11
authorselias <samelias@cisco.com>
Mon, 9 Oct 2017 14:36:16 +0000 (16:36 +0200)
committerTibor Frank <tifrank@cisco.com>
Wed, 8 Nov 2017 13:26:45 +0000 (13:26 +0000)
Added traffic tests for Honeycomb's BGP feature.

Change-Id: I5fa99908ab61d8bc9d2975e451917b98571b6aca
Signed-off-by: selias <samelias@cisco.com>
resources/libraries/python/honeycomb/BGP.py
resources/libraries/python/honeycomb/HoneycombSetup.py
resources/libraries/robot/honeycomb/bgp.robot
resources/test_data/honeycomb/bgp.py
resources/traffic_scripts/honeycomb/bgp_open.py [new file with mode: 0755]
tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-apivat-func.robot [deleted file]
tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-func.robot [new file with mode: 0644]

index ca50cc3..75dce76 100644 (file)
@@ -13,6 +13,7 @@
 
 """Keywords to manipulate BGP configuration using Honeycomb REST API."""
 
+from resources.libraries.python.constants import Constants as Const
 from resources.libraries.python.HTTPRequest import HTTPCodes
 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
 from resources.libraries.python.honeycomb.HoneycombUtil \
@@ -27,6 +28,7 @@ class BGPKeywords(object):
     """
 
     def __init__(self):
+        """Initializer."""
         pass
 
     @staticmethod
@@ -41,7 +43,7 @@ class BGPKeywords(object):
         :type data: dict
         :returns: Content of response.
         :rtype: bytearray
-        :raises HoneycombError: If the status code in response on PUT is not
+        :raises HoneycombError: If the status code in response to PUT is not
         200 = OK or 201 = ACCEPTED.
         """
 
@@ -69,7 +71,7 @@ class BGPKeywords(object):
         :type data: dict
         :returns: Content of response.
         :rtype: bytearray
-        :raises HoneycombError: If the status code in response on PUT is not
+        :raises HoneycombError: If the status code in response to PUT is not
         200 = OK or 201 = ACCEPTED.
         """
 
@@ -93,6 +95,7 @@ class BGPKeywords(object):
         :type node: dict
         :returns: BGP configuration data.
         :rtype: dict
+        :raises HoneycombError: If the status code in response is not 200 = OK.
         """
 
         status_code, resp = HcUtil. \
@@ -104,21 +107,29 @@ class BGPKeywords(object):
         return resp
 
     @staticmethod
-    def get_bgp_peer(node, address):
+    def get_bgp_peer(node, address, datastore='config'):
         """Get BGP configuration of the specified peer from the node.
 
         :param node: Honeycomb node.
         :param address: IP address of the peer.
+        :param datastore: Get data from config or operational datastore.
         :type node: dict
         :type address: str
+        :type datastore; str
         :returns: BGP peer configuration data.
         :rtype: dict
+        :raises HoneycombError: If the status code in response is not 200 = OK.
         """
 
         path = "bgp-openconfig-extensions:neighbors/" \
                "neighbor/{0}".format(address)
+        if datastore != "operational":
+            url = "config_bgp_peer"
+        else:
+            url = "oper_bgp"
+            path = "peer/bgp:%2F%2F{0}".format(address)
         status_code, resp = HcUtil. \
-            get_honeycomb_data(node, "config_bgp_peer", path)
+            get_honeycomb_data(node, url, path)
         if status_code != HTTPCodes.OK:
             raise HoneycombError(
                 "Not possible to get configuration information about the BGP"
@@ -211,7 +222,7 @@ class BGPKeywords(object):
         :type ip_version: str
         :returns: Content of response.
         :rtype: bytearray
-        :raises HoneycombError: If the operation fails.
+        :raises HoneycombError: If the status code in response is not 200 = OK.
         """
 
         route_address = route_address.replace("/", "%2F")
@@ -239,7 +250,7 @@ class BGPKeywords(object):
     def get_all_peer_routes(node, peer_address, ip_version):
         """Get all configured routes for the given BGP peer.
 
-        :param node: HOneycomb node.
+        :param node: Honeycomb node.
         :param peer_address: IP address of the peer.
         :param ip_version: IP protocol version. ipv4 or ipv6
         :type node: dict
@@ -247,7 +258,7 @@ class BGPKeywords(object):
         :type ip_version: str
         :returns: Content of response.
         :rtype: bytearray
-        :raises HoneycombError: If the operation fails.
+        :raises HoneycombError: If the status code in response is not 200 = OK.
         """
 
         if ip_version.lower() == "ipv4":
@@ -299,3 +310,85 @@ class BGPKeywords(object):
                 .format(peer_address, route_address, index)
 
         return BGPKeywords._configure_bgp_route(node, path)
+
+    @staticmethod
+    def get_bgp_local_rib(node):
+        """Get local RIB table from the Honeycomb node.
+
+        :param node: Honeycomb node.
+        :type node: dict
+        :returns: RIB operational data.
+        :rtype: dict
+        :raises HoneycombError: If the status code in response is not 200 = OK.
+        """
+
+        path = "loc-rib"
+
+        status_code, resp = HcUtil. \
+            get_honeycomb_data(node, "oper_bgp", path)
+
+        if status_code != HTTPCodes.OK:
+            raise HoneycombError(
+                "Not possible to get operational data from BGP local RIB."
+                " Status code: {0}.".format(status_code))
+
+        return resp
+
+    @staticmethod
+    def configure_bgp_base(node, ip_address, port, as_number):
+        """Modify BGP config file. Requires a restart of Honeycomb to take
+        effect.
+
+        :param node: Honeycomb node.
+        :param ip_address: BGP peer identifier/binding address.
+        :param port: BGP binding port.
+        :param as_number: Autonomous System ID number.
+        :type node: dict
+        :type ip_address: str
+        :type port: int
+        :type as_number: int
+        :raises HoneycombError: If modifying the configuration fails.
+        """
+
+        from resources.libraries.python.ssh import SSH
+
+        config = {
+            '\\"bgp-binding-address\\"': '\\"{0}\\"'.format(ip_address),
+            '\\"bgp-port\\"': port,
+            '\\"bgp-as-number\\"': as_number}
+
+        path = "{0}/config/bgp.json".format(Const.REMOTE_HC_DIR)
+
+        for key, value in config.items():
+            find = key
+            replace = '"{0}": "{1}",'.format(key, value)
+
+            argument = '"/{0}/c\\ {1}"'.format(find, replace)
+            command = "sed -i {0} {1}".format(argument, path)
+
+            ssh = SSH()
+            ssh.connect(node)
+            (ret_code, _, stderr) = ssh.exec_command_sudo(command)
+            if ret_code != 0:
+                raise HoneycombError("Failed to modify configuration on "
+                                     "node {0}, {1}".format(node, stderr))
+
+    @staticmethod
+    def compare_rib_tables(data, ref):
+        """Compare provided RIB table with reference. All reference entries must
+        be present in data. Data entries not present in reference are ignored.
+
+        :param data: Data from Honeycomb node.
+        :param ref: Reference data to compare against.
+        :type data: dict
+        :type ref: dict
+        :raises HoneycombError: If the tables do not match."""
+
+        # Remove runtime attributes from data
+        for item in data:
+            item.pop("attributes", "")
+
+        for item in ref:
+            if item not in data:
+                raise HoneycombError(
+                    "RIB entry {0} not found in operational data.")
index 7c3831c..d4175b1 100644 (file)
@@ -61,12 +61,13 @@ class HoneycombSetup(object):
 
         HoneycombSetup.print_environment(nodes)
 
-        logger.console("\n(re)Starting Honeycomb service ...")
-
         cmd = "sudo service honeycomb start"
 
         for node in nodes:
             if node['type'] == NodeType.DUT:
+                logger.console(
+                    "\n(re)Starting Honeycomb service on node {0}".format(
+                        node["host"]))
                 ssh = SSH()
                 ssh.connect(node)
                 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
@@ -89,13 +90,15 @@ class HoneycombSetup(object):
         :type nodes: list
         :raises HoneycombError: If Honeycomb failed to stop.
         """
-        logger.console("\nShutting down Honeycomb service ...")
 
         cmd = "sudo service honeycomb stop"
         errors = []
 
         for node in nodes:
             if node['type'] == NodeType.DUT:
+                logger.console(
+                    "\nShutting down Honeycomb service on node {0}".format(
+                        node["host"]))
                 ssh = SSH()
                 ssh.connect(node)
                 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
@@ -121,7 +124,8 @@ class HoneycombSetup(object):
         :raises HoneycombError: If Honeycomb fails to start.
         """
 
-        logger.console("\n(re)Starting Honeycomb service ...")
+        logger.console(
+            "\n(re)Starting Honeycomb service on node {0}".format(node["host"]))
 
         cmd = "sudo service honeycomb restart"
 
@@ -650,6 +654,26 @@ class HoneycombSetup(object):
 
         logger.info("ODL client service stopped.")
 
+    @staticmethod
+    def set_static_arp(node, ip_address, mac_address):
+        """Configure a static ARP entry using arp.
+
+        :param node: Node in topology.
+        :param ip_address: IP address for the entry.
+        :param mac_address: MAC adddress for the entry.
+        :type node: dict
+        :type ip_address: str
+        :type mac_address: str
+        :raises RuntimeError: If the operation fails.
+        """
+
+        ssh = SSH()
+        ssh.connect(node)
+        ret_code, _, _ = ssh.exec_command_sudo("arp -s {0} {1}".format(
+            ip_address, mac_address))
+
+        if ret_code != 0:
+            raise RuntimeError("Failed to configure static ARP adddress.")
 
 
 class HoneycombStartupConfig(object):
index d4c2d6b..aa96cc6 100644 (file)
 | Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords
 
 *** Keywords ***
+| Configure BGP module
+| | [Documentation] | Edit Honeycomb's configuration file for the BGP feature.\
+| | ... | Honeycomb needs to be restarted for the changes to take effect.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - information about a DUT node. Type: dictionary
+| | ... | - ip_address - IP address to bind BGP listener to. Type: string
+| | ... | - port - Port number to bind BGP listener to. Type: integer
+| | ... | - as_number - Autonomous System (AS) ID number. Type: integer
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| Configure BGP module \| ${nodes['DUT1']} \| 192.168.0.1 \| ${179} \
+| | ... | \| ${65000} \|
+| | ...
+| | [Arguments] | ${node} | ${ip_address} | ${port} | ${as_number}
+| | Configure BGP base | ${node} | ${ip_address} | ${port} | ${as_number}
+
 | No BGP peers should be configured
 | | [Documentation] | Uses Honeycomb API to read BGP configuration and checks
 | | ... | if there ary BGP peers conffigured.
@@ -50,7 +68,7 @@
 | | Add BGP Peer | ${node} | ${address} | ${data}
 
 | BGP Peer From Honeycomb Should be
-| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data.
+| | [Documentation] | Uses Honeycomb API to verify BGP peer config data.
 | | ...
 | | ... | *Arguments:*
 | | ... | - node - Information about a DUT node. Type: dictionary
 | | ${oper_data}= | Get BGP Peer | ${node} | ${address}
 | | Compare Data Structures | ${oper_data} | ${data}
 
+| Peer Operational Data From Honeycomb Should be
+| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - Information about a DUT node. Type: dictionary
+| | ... | - address - IP address of the peer. Type: string
+| | ... | - data - Peer configuration data. Type: dictionary
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| BGP Peer From Honeycomb Should be \
+| | ... | \| ${nodes['DUT1']} \| 192.168.0.1 \| ${data} \|
+| | ...
+| | [Arguments] | ${node} | ${address}
+| | ...
+| | ${oper_data}= | Get BGP Peer | ${node} | ${address} | operational
+| | Should be Equal | ${oper_data['peer'][0]['peer-id']} | bgp://${address}
+
 | Honeycomb removes BGP peer
 | | [Documentation] | Uses Honeycomb API to add a BGP peer.
 | | ...
 | | ${oper_data}= | Get All Peer Routes
 | | ... | ${node} | ${peer_address} | ${ip_version}
 | | Should be Empty | ${oper_data['bgp-inet:${ip_version}-routes']}
+
+| BGP Loc-RIB table should include
+| | [Documentation] | Uses Honeycomb API to retrieve local BGP RIB table\
+| | ... | And verifies that it contains the specified entry.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - Information about a DUT node. Type: dictionary
+| | ... | - data - RIB that should be present in operational data.\
+| | ... | Type: dictionary
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| BGP Loc-RIB table should include \| ${nodes['DUT1']} \| ${data} \|
+| | ...
+| | [Arguments] | ${node} | ${data}
+| | ...
+| | ${oper_data}= | Get BGP Local RIB | ${node}
+| | ${oper_data}= | Set Variable | ${oper_data['loc-rib']['tables']}
+| | ${data}= | Set Variable | ${data['loc-rib']['tables']}
+| | Compare RIB Tables | ${oper_data} | ${data}
+
+| Receive BGP OPEN message
+| | [Documentation] | Open a TCP listener on BGP port(179) and listen\
+| | ... | for BGP OPEN message. Verify ID and holdtime fields.
+| | ...
+| | ... | *Arguments:*
+| | ... | - tg_node - Information about the TG node. Type: dictionary
+| | ... | - rx_ip - IP address to listen on. Type: string
+| | ... | - src_ip - IP address of the BGP speaker. Also acts as BGP peer ID.\
+| | ... | Type: string
+| | ... | - holdtime - Expected value of HOLD_TIME field in received message.\
+| | ... | Type: integer
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| Receive BGP OPEN message \| ${node['TG']} \
+| | ... | \| 192.168.0.1 \| 192.168.0.2 \| ${0}
+| | ...
+| | [Arguments] | ${tg_node} | ${rx_ip} | ${src_ip} | ${port} | ${as_number}
+| | ... | ${holdtime}
+| | ...
+| | ${args}= | Catenate | --rx_ip | ${rx_ip}
+| | ...                 | --src_ip | ${src_ip}
+| | ...                 | --rx_port | ${port}
+| | ...                 | --as_number | ${as_number}
+| | ...                 | --holdtime | ${holdtime}
+| | Run Traffic Script On Node | honeycomb/bgp_open.py
+| | ... | ${tg_node} | ${args}
index f9dc4ab..84c9431 100644 (file)
@@ -18,6 +18,7 @@ from copy import deepcopy
 # Internal BGP peers for CRUD tests
 address_internal = "192.168.0.2"
 address_internal2 = "192.168.0.3"
+holdtime_internal = 60
 peer_internal = {
     "bgp-openconfig-extensions:neighbor": [{
         "neighbor-address": address_internal,
@@ -26,13 +27,13 @@ peer_internal = {
         },
         "timers": {
             "config": {
-                "connect-retry": 10,
-                "hold-time": 60
+                "connect-retry": 3,
+                "hold-time": holdtime_internal
             }
         },
         "transport": {
             "config": {
-                "remote-port": 17900,
+                "remote-port": 179,
                 "passive-mode": False
             }
         },
@@ -55,12 +56,12 @@ peer_internal_update = {
         "timers": {
             "config": {
                 "connect-retry": 5,
-                "hold-time": 120
+                "hold-time": holdtime_internal*2
             }
         },
         "transport": {
             "config": {
-                "remote-port": 17901,
+                "remote-port": 180,
                 "passive-mode": True
             }
         },
@@ -78,7 +79,7 @@ peer_internal2 = deepcopy(peer_internal)
 peer_internal2["bgp-openconfig-extensions:neighbor"][0]["neighbor-address"] = \
     address_internal2
 
-# Application BGP peer for CRUD tests
+# Application BGP peer for CRUD test
 address_application = "192.168.0.4"
 peer_application = {
     "bgp-openconfig-extensions:neighbor": [{
@@ -103,6 +104,7 @@ peer_application = {
         }]
     }
 
+# IPv4 route for CRUD test
 route_address_ipv4 = "192.168.0.5/32"
 route_id_ipv4 = 0
 route_data_ipv4 = {
@@ -124,6 +126,7 @@ route_data_ipv4 = {
     }]
 }
 
+# IPv4 route for testing Update operation
 route_data_ipv4_update = {
     "bgp-inet:ipv4-route": [{
         "path-id": route_id_ipv4,
@@ -143,6 +146,7 @@ route_data_ipv4_update = {
     }]
 }
 
+# IPv4 route for testing multiple routes
 route_address_ipv4_2 = "192.168.0.6/32"
 route_id_ipv4_2 = 1
 route_data_ipv4_2 = {
@@ -164,6 +168,7 @@ route_data_ipv4_2 = {
     }]
 }
 
+# IPv6 route for CRUD test
 route_address_ipv6 = "3ffe:62::1/64"
 route_id_ipv6 = 0
 route_data_ipv6 = {
@@ -185,8 +190,164 @@ route_data_ipv6 = {
     }]
 }
 
+# IPv4 route operational data in routing table
 table1_oper = {
     "destination-prefix": route_address_ipv4,
     "next-hop": "192.168.1.1",
     "vpp-ipv4-route-state": {}
-}
\ No newline at end of file
+}
+
+# Peer configurations for traffic test
+dut1_peer = {
+    "bgp-openconfig-extensions:neighbor": [{
+        "neighbor-address": "192.168.1.1",
+        "config": {
+            "peer-type": "INTERNAL"
+        },
+        "timers": {
+            "config": {
+                "connect-retry": 3,
+                "hold-time": 60
+            }
+        },
+        "transport": {
+            "config": {
+                "remote-port": 179,
+                "passive-mode": False
+            }
+        },
+        "afi-safis": {
+            "afi-safi": [
+                {
+                    "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+                    "receive": True,
+                    "send-max": 0},
+                {
+                    "afi-safi-name": "openconfig-bgp-types:IPV6-UNICAST",
+                    "receive": True,
+                    "send-max": 0},
+                {
+                    "afi-safi-name": "LINKSTATE"
+                }
+            ]
+        }
+    }]
+}
+
+dut2_peer = {
+    "bgp-openconfig-extensions:neighbor": [{
+        "neighbor-address": "192.168.1.2",
+        "config": {
+            "peer-type": "INTERNAL"
+        },
+        "timers": {
+            "config": {
+                "connect-retry": 3,
+                "hold-time": 60
+            }
+        },
+        "transport": {
+            "config": {
+                "remote-port": 179,
+                "passive-mode": True
+            }
+        },
+        "afi-safis": {
+            "afi-safi": [
+                {
+                    "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+                    "receive": True,
+                    "send-max": 0},
+                {
+                    "afi-safi-name": "openconfig-bgp-types:IPV6-UNICAST",
+                    "receive": True,
+                    "send-max": 0},
+                {
+                    "afi-safi-name": "LINKSTATE"
+                }
+            ]
+        }
+    }]
+}
+
+# IPv4 route for traffic test
+dut1_route_address = "192.168.0.5/32"
+dut1_route_id = 1
+dut1_route = {
+    "bgp-inet:ipv4-route": [{
+        "path-id": dut1_route_id,
+        "prefix": dut1_route_address,
+        "attributes": {
+            "as-path": {},
+            "origin": {
+                "value": "igp"
+            },
+            "local-pref": {
+                "pref": 100
+            },
+            "ipv4-next-hop": {
+                "global": "192.168.1.3"
+            }
+        }
+    }]
+}
+
+# IPv4 route in peer operational data
+rib_operational = {
+    "loc-rib": {"tables": [
+        {
+            "afi": "bgp-types:ipv4-address-family",
+            "safi": "bgp-types:unicast-subsequent-address-family",
+            "bgp-inet:ipv4-routes": {
+                "ipv4-route": dut1_route["bgp-inet:ipv4-route"]
+            }
+        }
+    ]}
+}
+
+route_operational = {
+    "vpp-ipv4-route-state": {},
+    "next-hop": "192.168.1.3",
+    "destination-prefix": dut1_route_address
+}
+
+# IPv6 route for traffic test
+dut1_route_ip6_address = "3ffe:62::1/64"
+dut1_route_ip6_id = 1
+dut1_route_ip6 = {
+    "bgp-inet:ipv6-route": [{
+        "path-id": dut1_route_ip6_id,
+        "prefix": dut1_route_ip6_address,
+        "attributes": {
+            "as-path": {},
+            "origin": {
+                "value": "igp"
+            },
+            "local-pref": {
+                "pref": 100
+            },
+            "ipv6-next-hop": {
+                "global": "3ffe:63::1"
+            }
+        }
+    }]
+}
+
+# IPv6 route in peer operational data
+rib_ip6_operational = {
+    "loc-rib": {"tables": [
+        {
+            "afi": "bgp-types:ipv6-address-family",
+            "safi": "bgp-types:unicast-subsequent-address-family",
+            "bgp-inet:ipv6-routes": {
+                "ipv6-route": dut1_route_ip6["bgp-inet:ipv6-route"]
+            }
+        }
+    ]}
+}
+
+route_ip6_operational = {
+    "vpp-ipv6-route-state": {},
+    "next-hop": "3ffe:63::1",
+    "destination-prefix": dut1_route_ip6_address
+}
diff --git a/resources/traffic_scripts/honeycomb/bgp_open.py b/resources/traffic_scripts/honeycomb/bgp_open.py
new file mode 100755 (executable)
index 0000000..e7bb7d8
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Traffic script that listens for incoming BGP connections and verifies
+received GBP Open message."""
+
+import sys
+import socket
+
+from scapy.main import load_contrib
+from scapy.layers.inet import Raw
+from scapy.contrib.bgp import BGPHeader, BGPOpen
+
+from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
+
+
+def main():
+    """Open a TCP listener socket on the default BGP port. Accept an incoming
+    connection, receive data and verify if data is a valid BGP Open message."""
+    args = TrafficScriptArg(['rx_ip', 'src_ip', 'rx_port', 'as_number',
+                             'holdtime'])
+
+    rx_ip = args.get_arg('rx_ip')
+    src_ip = args.get_arg('src_ip')
+    rx_port = int(args.get_arg('rx_port'))
+    as_number = int(args.get_arg('as_number'))
+    holdtime = int(args.get_arg('holdtime'))
+
+    load_contrib("bgp")
+
+    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    soc.bind((rx_ip, rx_port))
+    soc.listen(1)
+
+    print "Listener active, awaiting connection..."
+    soc.settimeout(8)
+    conn, addr = soc.accept()
+    print 'Connection established with peer:', addr
+
+    data = conn.recv(256)
+    conn.close()
+    soc.close()
+
+    bgp_layer = (BGPHeader(Raw(data).load))
+    bgp_layer.show()
+
+    if not bgp_layer.haslayer(BGPOpen):
+        raise RuntimeError("Received data is not a BGP OPEN message.")
+    bgp_open = bgp_layer.getlayer(BGPOpen)
+    if bgp_open.bgp_id != src_ip:
+        raise RuntimeError(
+            "BGP ID mismatch. Received {0} but should be {1}".
+            format(bgp_open.bgp_id, src_ip))
+    else:
+        print "BGP ID matched."
+
+    if bgp_open.AS != as_number:
+        raise RuntimeError(
+            "BGP AS number mismatch. Received {0} but should be {1}".
+            format(bgp_open.AS, as_number))
+    else:
+        print "BGP AS number matched."
+
+    if bgp_open.hold_time != holdtime:
+        raise RuntimeError(
+            "Hold Time parameter mismatch. Received {0} but should be {1}.".
+            format(bgp_layer.getlayer(BGPOpen).holdtime, holdtime))
+    else:
+        print "BGP Hold Time parameter matched."
+
+    sys.exit(0)
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-apivat-func.robot b/tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-apivat-func.robot
deleted file mode 100644 (file)
index 290725e..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright (c) 2017 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-*** Variables ***
-# Interface to run tests on.
-| ${interface}= | ${node['interfaces']['port1']['name']}
-
-*** Settings ***
-| Resource | resources/libraries/robot/shared/default.robot
-| Resource | resources/libraries/robot/honeycomb/honeycomb.robot
-| Resource | resources/libraries/robot/honeycomb/interfaces.robot
-| Resource | resources/libraries/robot/honeycomb/bgp.robot
-| Resource | resources/libraries/robot/honeycomb/routing.robot
-| Variables | resources/test_data/honeycomb/bgp.py
-| ...
-| Suite Setup | Run Keywords
-| ... | Enable Honeycomb Feature | ${node} | BGP | AND
-| ... | Set Up Honeycomb Functional Test Suite | ${node}
-| ...
-| Suite Teardown | Run Keywords
-| ... | Tear Down Honeycomb Functional Test Suite | ${node} | AND
-| ... | Disable Honeycomb Feature | ${node} | BGP
-| ...
-# HONEYCOMB-409: ODL client fails to parse requests to BGP instance node
-| Force Tags | HC_FUNC | EXPECTED_FAILING
-| ...
-| Documentation | *Honeycomb BGP management test suite.*
-
-*** Test Cases ***
-| TC01: Honeycomb configures BGP peer - Internal
-| | [Documentation] | Check if Honeycomb can configure an internal BGP peer.
-| | ...
-| | When Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | Then BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-
-| TC03: Honeycomb removes peer configuration
-| | [Documentation] | Check if Honeycomb can remove a configured BGP peer.
-| | ...
-| | Given BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | When Honeycomb removes BGP peer | ${node} | ${address_internal}
-| | Then No BGP peers should be configured | ${node}
-
-| TC02: Honeycomb updates existing BGP peer - Internal
-| | [Documentation] | Check if Honeycomb can update an existing BGP peer.
-| | ...
-| | [Teardown] | Honeycomb removes BGP peer | ${node} | ${address_internal}
-| | ...
-| | Given No BGP peers should be configured | ${node}
-| | When Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | And Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal} | ${peer_internal_update}
-| | Then BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal_update}
-
-| TC04: Honeycomb configures BGP peer - Application
-| | [Documentation] | Check if Honeycomb can configure an application BGP peer.
-| | ...
-| | [Teardown] | Honeycomb removes BGP peer | ${node} | ${address_application}
-| | ...
-| | Given No BGP peers should be configured | ${node}
-| | When Honeycomb adds BGP peer
-| | ... | ${node} | ${address_application} | ${peer_application}
-| | Then BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_application} | ${peer_application}
-
-| TC05: Honeycomb configures a second BGP peer
-| | [Documentation] | Check if Honeycomb can configure more than one BGP peer.
-| | ...
-| | [Teardown] | Run Keywords
-| | ... | Honeycomb removes BGP peer | ${node} | ${address_internal} | AND
-| | ... | Honeycomb removes BGP peer | ${node} | ${address_internal2}
-| | ...
-| | Given No BGP peers should be configured | ${node}
-| | When Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | And Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal2} | ${peer_internal2}
-| | Then BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | And BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal2} | ${peer_internal2}
-
-| TC06: Honeycomb configures IPv4 route using BGP
-| | [Documentation] | Check if Honeycomb can configure a BGP route under a peer.
-| | ...
-| | Given Honeycomb adds BGP peer
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | When Honeycomb configures BGP route
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | Then BGP Route from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-
-| TC08: Honeycomb removes IPv4 route configuration
-| | [Documentation] | Check if Honeycomb can remove a configured BGP route.
-| | ...
-| | Given BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | And BGP Route from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | When Honeycomb removes BGP route | ${node} | ${address_internal}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | Then No BGP Routes Should be Configured
-| | ... | ${node} | ${address_internal} | ipv4
-
-| TC07: Honeycomb updates existing IPv4 route using BGP
-| | [Documentation] | Check if Honeycomb can update an existing BGP route.
-| | ...
-| | [Teardown] | Honeycomb removes BGP route | ${node} | ${address_internal}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | ...
-| | Given BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | And No BGP Routes Should be Configured
-| | ... | ${node} | ${address_internal} | ipv4
-| | When Honeycomb configures BGP route
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | And Honeycomb configures BGP route
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4_update}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | Then BGP Route from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4_update}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-
-| TC09: Honeycomb configures a second IPv4 route
-| | [Documentation] | Check if Honeycomb can configure more than one BGP route.
-| | ...
-| | [Teardown] | Run Keywords
-| | ... | Honeycomb removes BGP route | ${node} | ${address_internal}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4 | AND
-| | ... | Honeycomb removes BGP route | ${node} | ${address_internal}
-| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4
-| | ...
-| | Given BGP peer from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${peer_internal}
-| | When Honeycomb configures BGP route
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | And Honeycomb configures BGP route
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4_2}
-| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4
-| | Then BGP Route from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
-| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
-| | And BGP Route from Honeycomb should be
-| | ... | ${node} | ${address_internal} | ${route_data_ipv4_2}
-| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4
diff --git a/tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-func.robot b/tests/vpp/func/honeycomb/mgmt-cfg-bgp-apihc-func.robot
new file mode 100644 (file)
index 0000000..8f74280
--- /dev/null
@@ -0,0 +1,365 @@
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+*** Variables ***
+# Interface to run tests on.
+| ${interface}= | ${node['interfaces']['port1']['name']}
+| ${dut1_to_tg_ip}= | 192.168.0.1
+| ${tg_to_dut1_ip}= | 192.168.0.2
+| ${dut1_to_dut2_ip}= | 192.168.1.1
+| ${dut2_to_dut1_ip}= | 192.168.1.2
+| ${bgp_port}= | ${179}
+| ${bgp_as_number}= | ${37}
+| ${prefix}= | ${24}
+
+*** Settings ***
+| Library | resources.libraries.python.honeycomb.IPv6Management
+| Resource | resources/libraries/robot/shared/default.robot
+| Resource | resources/libraries/robot/honeycomb/honeycomb.robot
+| Resource | resources/libraries/robot/honeycomb/interfaces.robot
+| Resource | resources/libraries/robot/honeycomb/bgp.robot
+| Resource | resources/libraries/robot/honeycomb/routing.robot
+| Resource | resources/libraries/robot/shared/testing_path.robot
+| Resource | resources/libraries/robot/honeycomb/ipv6_control.robot
+| Variables | resources/test_data/honeycomb/bgp.py
+| ...
+| Suite Setup | Run Keywords
+| ... | Enable Honeycomb Feature | ${node} | BGP | AND
+| ... | Configure BGP Module | ${node} | ${dut1_to_tg_ip}
+| ... | ${bgp_port} | ${bgp_as_number} | AND
+| ... | Set Up Honeycomb Functional Test Suite | ${node}
+| ...
+| Suite Teardown | Run Keywords
+| ... | Tear Down Honeycomb Functional Test Suite | ${nodes['DUT1']} | AND
+| ... | Stop Honeycomb service on DUTs | ${nodes['DUT2']} | AND
+| ... | Unconfigure IPv4 Management Interfaces | AND
+| ... | Disable Honeycomb Feature | ${node} | BGP | AND
+| ... | Disable Honeycomb Feature | ${nodes['DUT2']} | BGP
+| ...
+| Force Tags | HC_FUNC
+| ...
+| Documentation | *Honeycomb BGP management test suite.*
+
+*** Test Cases ***
+| TC01: Honeycomb configures BGP peer - Internal
+| | [Documentation] | Check if Honeycomb can configure an internal BGP peer.
+| | ...
+| | When Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | Then BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+
+| TC02: Honeycomb removes peer configuration
+| | [Documentation] | Check if Honeycomb can remove a configured BGP peer.
+| | ...
+| | Given BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | When Honeycomb removes BGP peer | ${node} | ${address_internal}
+| | Then No BGP peers should be configured | ${node}
+
+| TC03: Honeycomb updates existing BGP peer - Internal
+| | [Documentation] | Check if Honeycomb can update an existing BGP peer.
+| | ...
+| | [Teardown] | Honeycomb removes BGP peer | ${node} | ${address_internal}
+| | ...
+| | Given No BGP peers should be configured | ${node}
+| | When Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | And Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal} | ${peer_internal_update}
+| | Then BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal_update}
+
+| TC04: Honeycomb configures BGP peer - Application
+| | [Documentation] | Check if Honeycomb can configure an application BGP peer.
+| | ...
+| | [Teardown] | Honeycomb removes BGP peer | ${node} | ${address_application}
+| | ...
+| | Given No BGP peers should be configured | ${node}
+| | When Honeycomb adds BGP peer
+| | ... | ${node} | ${address_application} | ${peer_application}
+| | Then BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_application} | ${peer_application}
+
+| TC05: Honeycomb configures a second BGP peer
+| | [Documentation] | Check if Honeycomb can configure more than one BGP peer.
+| | ...
+| | [Teardown] | Run Keywords
+| | ... | Honeycomb removes BGP peer | ${node} | ${address_internal} | AND
+| | ... | Honeycomb removes BGP peer | ${node} | ${address_internal2}
+| | ...
+| | Given No BGP peers should be configured | ${node}
+| | When Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | And Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal2} | ${peer_internal2}
+| | Then BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | And BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal2} | ${peer_internal2}
+
+| TC06: Honeycomb configures IPv4 route using BGP
+| | [Documentation] | Check if Honeycomb can configure a BGP route under a peer.
+| | ...
+| | Given Honeycomb adds BGP peer
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | When Honeycomb configures BGP route
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | Then BGP Route from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+
+| TC07: Honeycomb removes IPv4 route configuration
+| | [Documentation] | Check if Honeycomb can remove a configured BGP route.
+| | ...
+| | Given BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | And BGP Route from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | When Honeycomb removes BGP route | ${node} | ${address_internal}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | Then No BGP Routes Should be Configured
+| | ... | ${node} | ${address_internal} | ipv4
+
+| TC08: Honeycomb updates existing IPv4 route using BGP
+| | [Documentation] | Check if Honeycomb can update an existing BGP route.
+| | ...
+| | [Teardown] | Honeycomb removes BGP route | ${node} | ${address_internal}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | ...
+| | Given BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | And No BGP Routes Should be Configured
+| | ... | ${node} | ${address_internal} | ipv4
+| | When Honeycomb configures BGP route
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | And Honeycomb configures BGP route
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4_update}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | Then BGP Route from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4_update}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+
+| TC09: Honeycomb configures a second IPv4 route
+| | [Documentation] | Check if Honeycomb can configure more than one BGP route.
+| | ...
+| | [Teardown] | Run Keywords
+| | ... | Honeycomb removes BGP route | ${node} | ${address_internal}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4 | AND
+| | ... | Honeycomb removes BGP route | ${node} | ${address_internal}
+| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4 | AND
+| | ... | Honeycomb removes BGP peer | ${node} | ${address_internal}
+| | ...
+| | Given BGP peer from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${peer_internal}
+| | When Honeycomb configures BGP route
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | And Honeycomb configures BGP route
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4_2}
+| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4
+| | Then BGP Route from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4}
+| | ... | ${route_address_ipv4} | ${route_id_ipv4} | ipv4
+| | And BGP Route from Honeycomb should be
+| | ... | ${node} | ${address_internal} | ${route_data_ipv4_2}
+| | ... | ${route_address_ipv4_2} | ${route_id_ipv4_2} | ipv4
+
+| TC10: Honeycomb sends BGP OPEN messages to configured peer
+| | [Documentation]
+| | ... | [top] TG-DUT1-TG.
+| | ... | [enc] Eth-IPv4-TCP-BGP.
+| | ... | [cfg] On DUT1 give Honeycomb control over the data-plane interface
+| | ... | connected to TG. Configure a BGP peer with the address of TG.
+| | ... | [ver] Open a TCP listener on TG on the BGP port and listen for BGP
+| | ... | OPEN message. On receive, verify message fields.
+| | ...
+| | [Setup] | Run Keywords
+| | ... | Configure BGP Module | ${node} | ${dut1_to_dut2_ip}
+| | ... | ${bgp_port} | ${bgp_as_number} | AND
+| | ... | Configure IPv4 Management Interface
+| | [Teardown] | Honeycomb removes BGP peer | ${dut1_node} | ${address_internal}
+| | When Honeycomb adds BGP peer
+| | ... | ${dut1_node} | ${address_internal} | ${peer_internal}
+| | Then Receive BGP OPEN message
+| | ... | ${tg_node} | ${tg_to_dut1_ip} | ${dut1_to_dut2_ip}
+| | ... | ${bgp_port} | ${bgp_as_number} | ${holdtime_internal}
+
+| TC11: Honeycomb shows connected peer in operational data
+| | [Documentation]
+| | ... | [top] TG-DUT1-DUT2-TG.
+| | ... | [enc] Eth-IPv4-TCP-BGP.
+| | ... | [cfg] On DUT1 and DUT2 give Honeycomb control over the data-plane
+| | ... | interfaces connecting DUT1 ad DUT2. Configure BGP peers on DUT1
+| | ... | and DUT2 with each other's IP address.
+| | ... | [ver] Using Restconf, verify that Honeycomb on each DUT has the
+| | ... | other DUT's entry in operational data.
+| | ...
+| | When Honeycomb adds BGP peer
+| | ... | ${dut1_node} | ${dut2_to_dut1_ip} | ${dut2_peer}
+| | And Honeycomb adds BGP peer
+| | ... | ${dut2_node} | ${dut1_to_dut2_ip} | ${dut1_peer}
+| | Sleep | 5s | Wait for BGP connection. Retry timer is 5 seconds.
+| | Then Peer operational data from Honeycomb should be
+| | ... | ${dut1_node} | ${dut2_to_dut1_ip}
+| | And Peer operational data from Honeycomb should be
+| | ... | ${dut2_node} | ${dut1_to_dut2_ip}
+
+| TC12: Honeycomb sends IPv4 BGP route to connected peer
+| | [Documentation]
+| | ... | [top] TG-DUT1-DUT2-TG.
+| | ... | [enc] Eth-IPv4-TCP-BGP.
+| | ... | [cfg] On DUT1 and DUT2 give Honeycomb control over the data-plane
+| | ... | interfaces connecting DUT1 ad DUT2. Configure BGP peers on DUT1
+| | ... | and DUT2 with each other's IP address. On DUT2 configure a static
+| | ... | IPv4 route using Honeycomb's BGP module.
+| | ... | [ver] Verify that the route is present in BGP
+| | ... | local RIB and VPP's routing table on each DUT.
+| | ...
+| | Given Peer operational data from Honeycomb should be
+| | ... | ${dut1_node} | ${dut2_to_dut1_ip}
+| | And Peer operational data from Honeycomb should be
+| | ... | ${dut2_node} | ${dut1_to_dut2_ip}
+| | When Honeycomb adds BGP peer
+| | ... | ${dut2_node} | ${address_application} | ${peer_application}
+| | And Honeycomb configures BGP route
+| | ... | ${dut2_node} | ${address_application} | ${dut1_route}
+| | ... | ${dut1_route_address} | ${dut1_route_id} | ipv4
+| | And Sleep | 5s | Wait for route advertisement. Retry timer is 5 seconds.
+| | Then Routing data from Honeycomb should contain
+| | ... | ${dut1_node} | learned-protocol-0 | ipv4 | ${route_operational}
+| | And Routing data from Honeycomb should contain
+| | ... | ${dut2_node} | learned-protocol-0 | ipv4 | ${route_operational}
+| | And BGP Loc-RIB table should include | ${dut1_node} | ${rib_operational}
+| | And BGP Loc-RIB table should include | ${dut2_node} | ${rib_operational}
+
+| TC13: Honeycomb sends IPv6 BGP route to connected peer
+| | [Documentation]
+| | ... | [top] TG-DUT1-DUT2-TG.
+| | ... | [enc] Eth-IPv4-TCP-BGP.
+| | ... | [cfg] On DUT1 and DUT2 give Honeycomb control over the data-plane
+| | ... | interfaces connecting DUT1 ad DUT2. Configure BGP peers on DUT1
+| | ... | and DUT2 with each other's IP address. On DUT2 configure a static
+| | ... | IPv6 route using Honeycomb's BGP module.
+| | ... | [ver] Verify that the route is present in BGP
+| | ... | local RIB and VPP's routing table on each DUT.
+| | ...
+# HONEYCOMB-403: Missing writers for IPv6 BGP route
+| | [Tags] | EXPECTED_FAILING
+| | Given Peer operational data from Honeycomb should be
+| | ... | ${dut1_node} | ${dut2_to_dut1_ip}
+| | And Peer operational data from Honeycomb should be
+| | ... | ${dut2_node} | ${dut1_to_dut2_ip}
+| | And Honeycomb adds BGP peer
+| | ... | ${dut2_node} | ${address_application} | ${peer_application}
+| | And Honeycomb configures BGP route
+| | ... | ${dut2_node} | ${address_application} | ${dut1_route_ip6}
+| | ... | ${dut1_route_ip6_address} | ${dut1_route_ip6_id} | ipv6
+| | And Sleep | 5s | Wait for route advertisement. Retry timer is 5 seconds.
+| | Then Routing data from Honeycomb should contain
+| | ... | ${dut1_node} | learned-protocol-0 | ipv6 | ${route_ip6_operational}
+| | And Routing data from Honeycomb should contain
+| | ... | ${dut2_node} | learned-protocol-0 | ipv6 | ${route_ip6_operational}
+| | And BGP Loc-RIB table should include | ${dut1_node} | ${rib_ip6_operational}
+| | And BGP Loc-RIB table should include | ${dut2_node} | ${rib_ip6_operational}
+
+#TODO: Add tests once implemented in HC:
+# IPv6 neighbor, L2VPN, L3VPN, linkstate, route reflector, and more
+
+*** Keywords ***
+| Configure IPv4 Management Interface
+| | [Documentation] | Change one of VPP's data-plane interfaces on DUT into\
+| | ... | a control-plane interface that Honeycomb can listen on. Setup IP\
+| | ... | addresses on the link, create suite variables for traffic trests, set
+| | ... | static ARP entries, then restart VPP and Honeycomb to apply changes.
+| | ...
+| | Configure path in 3-node circular topology
+| | ... | ${nodes['TG']} | ${nodes['DUT1']} | ${nodes['DUT2']} | ${nodes['TG']}
+| | ${interface}= | Get Interface Name | ${dut1_node} | ${dut1_to_tg}
+| | Set Suite Variable | ${interface}
+| | Set Suite Variable | ${tg_node}
+| | Set Suite Variable | ${dut1_node}
+| | Set Suite Variable | ${dut2_node}
+| | Set Suite Variable | ${dut1_to_tg}
+| | Stop VPP service on DUT | ${dut1_node}
+| | Stop VPP service on DUT | ${dut2_node}
+| | Stop Honeycomb Service on DUTs | ${dut1_node}
+| | Stop Honeycomb Service on DUTs | ${dut2_node}
+| | Convert data-plane interface to control-plane
+| | ... | ${dut1_node} | ${dut1_to_tg}
+| | Convert data-plane interface to control-plane
+| | ... | ${dut1_node} | ${dut1_to_dut2}
+| | Convert data-plane interface to control-plane
+| | ... | ${dut2_node} | ${dut2_to_dut1}
+| | Sleep | 5sec | Wait until OS reclaims the interfaces.
+| | ${tg_to_dut1_name}= | Get Interface Name by MAC
+| | ... | ${tg_node} | ${tg_to_dut1_mac}
+| | ${dut1_to_tg_name}= | Get Interface Name by MAC
+| | ... | ${dut1_node} | ${dut1_to_tg_mac}
+| | ${dut1_to_dut2_name}= | Get Interface Name by MAC
+| | ... | ${dut1_node} | ${dut1_to_dut2_mac}
+| | ${dut2_to_dut1_name}= | Get Interface Name by MAC
+| | ... | ${dut2_node} | ${dut2_to_dut1_mac}
+| | Set Suite Variable | ${dut1_to_tg_name}
+| | Set Suite Variable | ${tg_to_dut1_name}
+| | Set Suite Variable | ${dut1_to_dut2_name}
+| | Set Suite Variable | ${dut2_to_dut1_name}
+| | Set management interface address
+| | ... | ${tg_node} | ${tg_to_dut1_name}
+| | ... | ${tg_to_dut1_ip} | ${prefix}
+| | Set management interface address
+| | ... | ${dut1_node} | ${dut1_to_tg_name}
+| | ... | ${dut1_to_tg_ip} | ${prefix}
+| | Set management interface address
+| | ... | ${dut1_node} | ${dut1_to_dut2_name}
+| | ... | ${dut1_to_dut2_ip} | ${prefix}
+| | Set management interface address
+| | ... | ${dut2_node} | ${dut2_to_dut1_name}
+| | ... | ${dut2_to_dut1_ip} | ${prefix}
+| | Set Static ARP | ${tg_node} | ${dut1_to_tg_ip} | ${dut1_to_tg_mac}
+| | Set Static ARP | ${dut1_node} | ${tg_to_dut1_ip} | ${tg_to_dut1_mac}
+| | Set Static ARP | ${dut1_node} | ${dut2_to_dut1_ip} | ${dut2_to_dut1_mac}
+| | Set Static ARP | ${dut2_node} | ${dut1_to_dut2_ip} | ${dut1_to_dut2_mac}
+| | Enable Honeycomb Feature | ${dut2_node} | BGP
+| | Configure BGP Module | ${dut1_node} | ${dut1_to_dut2_ip}
+| | ... | ${bgp_port} | ${bgp_as_number}
+| | Configure BGP Module | ${dut2_node} | ${dut2_to_dut1_ip}
+| | ... | ${bgp_port} | ${bgp_as_number}
+| | Start VPP service on DUT | ${dut1_node}
+| | Start VPP service on DUT | ${dut2_node}
+| | Configure Honeycomb service on DUTs | ${dut1_node}
+| | Set Up Honeycomb Functional Test Suite | ${dut2_node}
+
+| Unconfigure IPv4 Management Interfaces
+| | [Documentation] | Remove all IP addresses from the interface.
+| | ...
+| | Clear Interface Configuration | ${tg_node} | ${tg_to_dut1_name}
+| | Clear Interface Configuration | ${dut1_node} | ${dut1_to_tg_name}
+| | Clear Interface Configuration | ${dut1_node} | ${dut1_to_dut2_name}
+| | Clear Interface Configuration | ${dut2_node} | ${dut2_to_dut1_name}
+
+| Set BGP Suite Variables
+| | Configure path in 3-node circular topology
+| | ... | ${nodes['TG']} | ${nodes['DUT1']} | ${nodes['DUT2']} | ${nodes['TG']}
+| | Set Suite Variable | ${interface}
+| | Set Suite Variable | ${tg_node}
+| | Set Suite Variable | ${dut1_node}
+| | Set Suite Variable | ${dut2_node}
+| | Set Suite Variable | ${dut1_to_tg}
+| | Set Suite Variable | ${dut1_to_tg_name}
+| | Set Suite Variable | ${tg_to_dut1_name}
+| | Set Suite Variable | ${dut1_to_dut2_name}
+| | Set Suite Variable | ${dut2_to_dut1_name}