aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--resources/libraries/python/IPUtil.py68
-rw-r--r--resources/libraries/python/IPv4Util.py26
-rw-r--r--resources/libraries/python/InterfaceUtil.py22
-rw-r--r--resources/libraries/python/L2Util.py29
-rw-r--r--resources/libraries/python/LispSetup.py44
-rw-r--r--resources/libraries/python/LispUtil.py17
-rw-r--r--resources/libraries/robot/lisp/lisp_api.robot35
-rw-r--r--resources/libraries/robot/lisp/lispgpe.robot118
-rw-r--r--resources/templates/vat/lisp/lisp_gpe_status.vat1
-rw-r--r--resources/templates/vat/lisp/show_lisp_gpe_tunnel.vat1
-rw-r--r--resources/templates/vat/lisp/show_lisp_locator_set.vat2
-rw-r--r--resources/test_data/lisp/ipv4_lispgpe_ipv4/ipv4_lispgpe_ipv4.py54
-rw-r--r--tests/func/lisp/lisp_ipv4_lispgpe_ipv4.robot179
13 files changed, 530 insertions, 66 deletions
diff --git a/resources/libraries/python/IPUtil.py b/resources/libraries/python/IPUtil.py
index 5011708c39..ed38272645 100644
--- a/resources/libraries/python/IPUtil.py
+++ b/resources/libraries/python/IPUtil.py
@@ -17,7 +17,7 @@ from ipaddress import IPv4Network, ip_address
from resources.libraries.python.ssh import SSH
from resources.libraries.python.constants import Constants
-
+from resources.libraries.python.ssh import exec_cmd_no_error, exec_cmd
from resources.libraries.python.topology import Topology
@@ -73,6 +73,72 @@ class IPUtil(object):
raise AssertionError('IP addresses are not equal: {0} != {1}'.
format(ip1, ip2))
+ @staticmethod
+ def setup_network_namespace(node, namespace_name, interface_name,
+ ip_address, prefix):
+ """Setup namespace on given node and attach interface and IP to
+ this namespace. Applicable also on TG node.
+
+ :param node: Node to set namespace on.
+ :param namespace_name: Namespace name.
+ :param interface_name: Interface name.
+ :param ip_address: IP address of namespace's interface.
+ :param prefix: IP address prefix length.
+ :type node: dict
+ :type namespace_name: str
+ :type vhost_if: str
+ :type ip_address: str
+ :type prefix: int
+ """
+ cmd = ('ip netns add {0}'.format(namespace_name))
+ exec_cmd_no_error(node, cmd, sudo=True)
+
+ cmd = ('ip link set dev {0} up netns {1}'.format(interface_name,
+ namespace_name))
+ exec_cmd_no_error(node, cmd, sudo=True)
+
+ cmd = ('ip netns exec {0} ip addr add {1}/{2} dev {3}'.format(
+ namespace_name, ip_address, prefix, interface_name))
+ exec_cmd_no_error(node, cmd, sudo=True)
+
+ @staticmethod
+ def linux_enable_forwarding(node, ip_ver='ipv4'):
+ """Enable forwarding on a Linux node, e.g. VM.
+
+ :param node: Node to enable forwarding on.
+ :param ip_ver: IP version, 'ipv4' or 'ipv6'.
+ :type node: dict
+ :type ip_ver: str
+ """
+ cmd = 'sysctl -w net.{0}.ip_forward=1'.format(ip_ver)
+ exec_cmd_no_error(node, cmd, sudo=True)
+
+ @staticmethod
+ def set_linux_interface_ip(node, interface, ip, prefix, namespace=None):
+ """Set IP address to interface in linux.
+
+ :param node: Node where to execute command.
+ :param interface: Interface in namespace.
+ :param ip: IP to be set on interface.
+ :param prefix: IP prefix.
+ :param namespace: Execute command in namespace. Optional
+ :type node: dict
+ :type interface: str
+ :type ip: str
+ :type prefix: int
+ :type namespace: str
+ :raises RuntimeError: IP could not be set.
+ """
+ if namespace is not None:
+ cmd = 'ip netns exec {} ip addr add {}/{} dev {}'.format(
+ namespace, ip, prefix, interface)
+ else:
+ cmd = 'ip addr add {}/{} dev {}'.format(ip, prefix, interface)
+ (rc, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
+ if rc != 0:
+ raise RuntimeError(
+ 'Could not set IP for interface, reason:{}'.format(stderr))
+
def convert_ipv4_netmask_prefix(network):
"""Convert network mask to equivalent network prefix length or vice versa.
diff --git a/resources/libraries/python/IPv4Util.py b/resources/libraries/python/IPv4Util.py
index 3043f230c2..ca5a1b571f 100644
--- a/resources/libraries/python/IPv4Util.py
+++ b/resources/libraries/python/IPv4Util.py
@@ -218,29 +218,3 @@ class IPv4Util(object):
if rc != 0:
raise RuntimeError("Arp set not successful, reason:{}".
format(stderr))
-
- @staticmethod
- def set_linux_interface_ip(node, interface, ip, prefix, namespace=None):
- """Set IP address to interface in linux.
-
- :param node: Node where to execute command.
- :param interface: Interface in namespace.
- :param ip: IP to be set on interface.
- :param prefix: IP prefix.
- :param namespace: Execute command in namespace. Optional
- :type node: dict
- :type interface: str
- :type ip: str
- :type prefix: int
- :type namespace: str
- :raises RuntimeError: IP could not be set.
- """
- if namespace is not None:
- cmd = 'ip netns exec {} ip addr add {}/{} dev {}'.format(
- namespace, ip, prefix, interface)
- else:
- cmd = 'ip addr add {}/{} dev {}'.format(ip, prefix, interface)
- (rc, _, stderr) = exec_cmd(node, cmd, timeout=5, sudo=True)
- if rc != 0:
- raise RuntimeError(
- 'Could not set IP for interface, reason:{}'.format(stderr))
diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py
index f5f1ce314e..11600a1d47 100644
--- a/resources/libraries/python/InterfaceUtil.py
+++ b/resources/libraries/python/InterfaceUtil.py
@@ -213,6 +213,28 @@ class InterfaceUtil(object):
return data
@staticmethod
+ def vpp_get_interface_mac(node, interface=None):
+ """Get MAC address for the given interface from actual interface dump.
+
+ :param node: VPP node to get interface data from.
+ :param interface: Numeric index or name string of a specific interface.
+ :type node: dict
+ :type interface: int or str
+ :return: MAC address.
+ :rtype: str
+ """
+
+ if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
+ mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
+ mac_data_nice = []
+ for item in mac_data:
+ if len(item) == 1:
+ item = '0' + item
+ mac_data_nice.append(item)
+ mac = ":".join(mac_data_nice)
+ return mac
+
+ @staticmethod
def vpp_get_interface_ip_addresses(node, interface, ip_version):
"""Get list of IP addresses from an interface on a VPP node.
diff --git a/resources/libraries/python/L2Util.py b/resources/libraries/python/L2Util.py
index 566b69bf1c..a909e8611b 100644
--- a/resources/libraries/python/L2Util.py
+++ b/resources/libraries/python/L2Util.py
@@ -218,35 +218,6 @@ class L2Util(object):
exec_cmd_no_error(node, cmd, sudo=True)
@staticmethod
- def setup_network_namespace(node, namespace_name, interface_name,
- ip_address, prefix):
- """Setup namespace on given node and attach interface and IP to
- this namespace. Applicable also on TG node.
-
- :param node: Node to set namespace on.
- :param namespace_name: Namespace name.
- :param interface_name: Interface name.
- :param ip_address: IP address of namespace's interface.
- :param prefix: IP address prefix length.
- :type node: dict
- :type namespace_name: str
- :type vhost_if: str
- :type ip_address: str
- :type prefix: int
-
- """
- cmd = ('ip netns add {0}'.format(namespace_name))
- exec_cmd_no_error(node, cmd, sudo=True)
-
- cmd = ('ip link set dev {0} up netns {1}'.format(interface_name,
- namespace_name))
- exec_cmd_no_error(node, cmd, sudo=True)
-
- cmd = ('ip netns exec {0} ip addr add {1}/{2} dev {3}'.format(
- namespace_name, ip_address, prefix, interface_name))
- exec_cmd_no_error(node, cmd, sudo=True)
-
- @staticmethod
def linux_del_bridge(node, br_name, set_down=True):
"""Delete bridge from linux node.
diff --git a/resources/libraries/python/LispSetup.py b/resources/libraries/python/LispSetup.py
index 531510198c..ee2ae5d8a3 100644
--- a/resources/libraries/python/LispSetup.py
+++ b/resources/libraries/python/LispSetup.py
@@ -164,6 +164,26 @@ class LispAdjacency(object):
seid_prefix=seid_prefix)
+class LispGpeStatus(object):
+ """Clas for LISP GPE status manipulation."""
+
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def vpp_lisp_gpe_enable_disable(node, state):
+ """Change the state of LISP GPE - enable or disable.
+
+ :param node: VPP node.
+ :param state: Requested state - enable or disable.
+ :type node: dict
+ :type state: str
+ """
+
+ VatExecutor.cmd_from_template(node, 'lisp/lisp_gpe_status.vat',
+ state=state)
+
+
class LispGpeIface(object):
"""Class for Lisp gpe interface API."""
@@ -180,11 +200,31 @@ class LispGpeIface(object):
:type state: str
"""
- VatExecutor.cmd_from_template(node,
- 'lisp/lisp_gpe_iface.vat',
+ VatExecutor.cmd_from_template(node, 'lisp/lisp_gpe_iface.vat',
state=state)
+class LispGpeForwardEntry(object):
+ """The functionality needed for these methods is not implemented in VPP
+ (VAT). Bug https://jira.fd.io/browse/VPP-334 was open to cover this issue.
+
+ TODO: Implement when VPP-334 is fixed.
+ """
+
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def add_lisp_gpe_forward_entry(node, *args):
+ # TODO: Implement when VPP-334 is fixed.
+ pass
+
+ @staticmethod
+ def del_lisp_gpe_forward_entry(node, *args):
+ # TODO: Implement when VPP-334 is fixed.
+ pass
+
+
class LispMapResolver(object):
"""Class for Lisp map resolver API."""
diff --git a/resources/libraries/python/LispUtil.py b/resources/libraries/python/LispUtil.py
index 8a83dc4d30..c50e626b80 100644
--- a/resources/libraries/python/LispUtil.py
+++ b/resources/libraries/python/LispUtil.py
@@ -15,7 +15,7 @@
from resources.libraries.python.parsers.JsonParser import JsonParser
from resources.libraries.python.topology import Topology
-from resources.libraries.python.VatExecutor import VatExecutor
+from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
class LispUtil(object):
@@ -40,18 +40,25 @@ class LispUtil(object):
return JsonParser().parse_data(vat.get_script_stdout())
@staticmethod
- def vpp_show_lisp_locator_set(node):
+ def vpp_show_lisp_locator_set(node, items_filter):
"""Get lisp locator_set from VPP node.
:param node: VPP node.
+ :param items_filter: Filter which specifies which items should be
+ retrieved - local, remote, empty string = both.
:type node: dict
+ :type items_filter: str
:return: Lisp locator_set data as python list.
:rtype: list
"""
- vat = VatExecutor()
- vat.execute_script_json_out('lisp/show_lisp_locator_set.vat', node)
- return JsonParser().parse_data(vat.get_script_stdout())
+ try:
+ with VatTerminal(node) as vat:
+ response = vat.vat_terminal_exec_cmd_from_template(
+ 'lisp/show_lisp_locator_set.vat', filter=items_filter)
+ return response[0]
+ except ValueError:
+ return []
@staticmethod
def vpp_show_lisp_eid_table(node):
diff --git a/resources/libraries/robot/lisp/lisp_api.robot b/resources/libraries/robot/lisp/lisp_api.robot
index 8094d08b84..4bd22bc036 100644
--- a/resources/libraries/robot/lisp/lisp_api.robot
+++ b/resources/libraries/robot/lisp/lisp_api.robot
@@ -16,6 +16,7 @@
| Library | resources.libraries.python.NodePath
| Library | resources.libraries.python.LispSetup.LispStatus
| Library | resources.libraries.python.LispSetup.LispSetup
+| Library | resources.libraries.python.LispSetup.LispGpeStatus
| Library | resources.libraries.python.LispUtil
*** Keywords ***
@@ -82,7 +83,7 @@
| | ... | \| Then Lisp locator_set is set correctly \| ${nodes['DUT1']} \|
| | ...
| | [Arguments] | ${dut_node}
-| | ${show_locator_set}= | Vpp Show Lisp Locator Set | ${dut_node}
+| | ${show_locator_set}= | Vpp Show Lisp Locator Set | ${dut_node} | local
| | Lisp Locator S Should Be Equal
| | ... | ${locator_set_values} | ${show_locator_set}
@@ -120,7 +121,7 @@
| | ... | \| Then Lisp locator_set should be unset \| ${nodes['DUT1']} \|
| | ...
| | [Arguments] | ${dut_node}
-| | ${show_locator_set}= | Vpp Show Lisp Locator Set | ${dut_node}
+| | ${show_locator_set}= | Vpp Show Lisp Locator Set | ${dut_node} | ${EMPTY}
| | Lisp Is Empty | ${show_locator_set}
| Lisp locator_set data use for test reset locator_set are prepared
@@ -359,3 +360,33 @@
| | [Arguments] | ${dut_node} | ${lisp_status_data}
| | ${show_lisp_stat}= | Vpp Show Lisp State | ${dut_node}
| | Lisp Should Be Equal | ${show_lisp_stat} | ${lisp_status_data[0]}
+
+| Enable Lisp Gpe
+| | [Documentation] | Enable Lisp Gpe on VPP node.
+| | ...
+| | ... | *Arguments:*
+| | ... | - dut_node - DUT node. Type: dictionary
+| | ...
+| | ... | *Return:*
+| | ... | - No value returned
+| | ...
+| | ... | *Example:*
+| | ... | \| Enable Lisp Gpe \| ${nodes['DUT1']} \|
+| | ...
+| | [Arguments] | ${dut_node}
+| | Vpp Lisp Gpe Enable Disable | ${dut_node} | enable
+
+| Disable Lisp Gpe
+| | [Documentation] | Disable Lisp Gpe on VPP node.
+| | ...
+| | ... | *Arguments:*
+| | ... | - dut_node - DUT node. Type: dictionary
+| | ...
+| | ... | *Return:*
+| | ... | - No value returned
+| | ...
+| | ... | *Example:*
+| | ... | \| Disable Lisp Gpe \| ${nodes['DUT1']} \|
+| | ...
+| | [Arguments] | ${dut_node}
+| | Vpp Lisp Gpe Enable Disable | ${dut_node} | disable
diff --git a/resources/libraries/robot/lisp/lispgpe.robot b/resources/libraries/robot/lisp/lispgpe.robot
new file mode 100644
index 0000000000..a5ab102652
--- /dev/null
+++ b/resources/libraries/robot/lisp/lispgpe.robot
@@ -0,0 +1,118 @@
+# 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.
+
+*** Settings ***
+| Documentation | LISP-gpe encapsulation suite keywords
+| Library | resources.libraries.python.topology.Topology
+| Resource | resources/libraries/robot/lisp/lisp_api.robot
+| Library | resources.libraries.python.LispSetup.LispLocatorSet
+| Library | resources.libraries.python.LispSetup.LispLocator
+| Library | resources.libraries.python.LispSetup.LispLocalEid
+| Library | resources.libraries.python.LispSetup.LispAdjacency
+| Library | resources.libraries.python.LispSetup.LispRemoteMapping
+
+*** Keywords ***
+| Set up LISP GPE topology
+| | [Documentation] | Set up LISP GPE topology.
+| | ...
+| | ... | *Arguments:*
+| | ... | - dut1_node - DUT1 node. Type: dictionary
+| | ... | - dut1_if - DUT1 node interface. Type: string
+| | ... | - dut1_int_index - DUT1 node interface index. Type: integer
+| | ... | - dut2_node - DUT2 node. Type: dictionary
+| | ... | - dut2_if - DUT2 node interface. Type: string
+| | ... | - dut2_int_index - DUT2 node interface index. Type: integer
+| | ... | - locator_set - Locator set values. Type: dictionary
+| | ... | - dut1_eid - DUT1 node eid address. Type: dictionary
+| | ... | - dut2_eid - DUT2 node eid address. Type: dictionary
+| | ... | - dut1_static_adjacency - DUT1 static adjacency. Type: dictionary
+| | ... | - dut2_static_adjacency - DUT2 static adjacency. Type: dictionary
+| | ...
+| | ... | *Return:*
+| | ... | - No value returned
+| | ...
+| | ... | *Example:*
+| | ... | \| Set up LISP GPE topology \| ${dut1_node} \| ${interface_name} \
+| | ... | \| None \| ${dut2_node} \| ${interface_name} \| None \
+| | ... | \| ${locator_set} \| ${dut1_eid} \| ${dut2_eid} \
+| | ... | \| ${dut1_static_adjacency} \| ${dut2_static_adjacency} \|
+| | ...
+| | [Arguments]
+| | ... | ${dut1_node} | ${dut1_if} | ${dut1_int_index}
+| | ... | ${dut2_node} | ${dut2_if} | ${dut2_int_index}
+| | ... | ${locator_set} | ${dut1_eid} | ${dut2_eid}
+| | ... | ${dut1_static_adjacency} | ${dut2_static_adjacency}
+| | ...
+# DUT1 settings:
+| | ${dut1_int_index}= | Run Keyword If | ${dut1_int_index} is None
+| | | ... | Get Interface Sw Index | ${dut1_node} | ${dut1_if}
+| | | ... | ELSE | Set Variable | ${dut1_int_index}
+| | Enable Lisp | ${dut1_node}
+| | Enable Lisp GPE | ${dut1_node}
+| | Vpp Add Lisp Locator Set | ${dut1_node}
+| | ... | ${locator_set['locator_name']}
+| | Vpp Add Lisp Locator | ${dut1_node}
+| | ... | ${locator_set['locator_name']}
+| | ... | ${dut1_int_index}
+| | ... | ${locator_set['priority']}
+| | ... | ${locator_set['weight']}
+| | Vpp Add Lisp Local Eid | ${dut1_node}
+| | ... | ${dut1_eid['locator_name']}
+| | ... | ${dut1_eid['vni']}
+| | ... | ${dut1_eid['eid']}
+| | ... | ${dut1_eid['prefix']}
+| | Vpp Add Lisp Remote Mapping | ${dut1_node}
+| | ... | ${dut1_static_adjacency['vni']}
+| | ... | ${dut1_static_adjacency['deid']}
+| | ... | ${dut1_static_adjacency['prefix']}
+| | ... | ${dut1_static_adjacency['seid']}
+| | ... | ${dut1_static_adjacency['prefix']}
+| | ... | ${dut1_static_adjacency['rloc']}
+| | Vpp Add Lisp Adjacency | ${dut1_node}
+| | ... | ${dut1_static_adjacency['vni']}
+| | ... | ${dut1_static_adjacency['deid']}
+| | ... | ${dut1_static_adjacency['prefix']}
+| | ... | ${dut1_static_adjacency['seid']}
+| | ... | ${dut1_static_adjacency['prefix']}
+| | ...
+# DUT2 settings:
+| | ${dut2_int_index}= | Run Keyword If | ${dut2_int_index} is None
+| | | ... | Get Interface Sw Index | ${dut2_node} | ${dut2_if}
+| | | ... | ELSE | Set Variable | ${dut2_int_index}
+| | Enable Lisp | ${dut2_node}
+| | Enable Lisp GPE | ${dut2_node}
+| | Vpp Add Lisp Locator Set | ${dut2_node}
+| | ... | ${locator_set['locator_name']}
+| | Vpp Add Lisp Locator | ${dut2_node}
+| | ... | ${locator_set['locator_name']}
+| | ... | ${dut2_int_index}
+| | ... | ${locator_set['priority']}
+| | ... | ${locator_set['weight']}
+| | Vpp Add Lisp Local Eid | ${dut2_node}
+| | ... | ${dut2_eid['locator_name']}
+| | ... | ${dut2_eid['vni']}
+| | ... | ${dut2_eid['eid']}
+| | ... | ${dut2_eid['prefix']}
+| | Vpp Add Lisp Remote Mapping | ${dut2_node}
+| | ... | ${dut2_static_adjacency['vni']}
+| | ... | ${dut2_static_adjacency['deid']}
+| | ... | ${dut2_static_adjacency['prefix']}
+| | ... | ${dut2_static_adjacency['seid']}
+| | ... | ${dut2_static_adjacency['prefix']}
+| | ... | ${dut2_static_adjacency['rloc']}
+| | Vpp Add Lisp Adjacency | ${dut2_node}
+| | ... | ${dut2_static_adjacency['vni']}
+| | ... | ${dut2_static_adjacency['deid']}
+| | ... | ${dut2_static_adjacency['prefix']}
+| | ... | ${dut2_static_adjacency['seid']}
+| | ... | ${dut2_static_adjacency['prefix']}
diff --git a/resources/templates/vat/lisp/lisp_gpe_status.vat b/resources/templates/vat/lisp/lisp_gpe_status.vat
new file mode 100644
index 0000000000..5c4080afc5
--- /dev/null
+++ b/resources/templates/vat/lisp/lisp_gpe_status.vat
@@ -0,0 +1 @@
+lisp_gpe_enable_disable {state}
diff --git a/resources/templates/vat/lisp/show_lisp_gpe_tunnel.vat b/resources/templates/vat/lisp/show_lisp_gpe_tunnel.vat
new file mode 100644
index 0000000000..802cfbb6a0
--- /dev/null
+++ b/resources/templates/vat/lisp/show_lisp_gpe_tunnel.vat
@@ -0,0 +1 @@
+# TODO: Implement when VPP-334 is fixed. \ No newline at end of file
diff --git a/resources/templates/vat/lisp/show_lisp_locator_set.vat b/resources/templates/vat/lisp/show_lisp_locator_set.vat
index 43768ec421..4f775ff47a 100644
--- a/resources/templates/vat/lisp/show_lisp_locator_set.vat
+++ b/resources/templates/vat/lisp/show_lisp_locator_set.vat
@@ -1 +1 @@
-lisp_locator_set_dump \ No newline at end of file
+lisp_locator_set_dump {filter} \ No newline at end of file
diff --git a/resources/test_data/lisp/ipv4_lispgpe_ipv4/ipv4_lispgpe_ipv4.py b/resources/test_data/lisp/ipv4_lispgpe_ipv4/ipv4_lispgpe_ipv4.py
new file mode 100644
index 0000000000..cd1b6383e6
--- /dev/null
+++ b/resources/test_data/lisp/ipv4_lispgpe_ipv4/ipv4_lispgpe_ipv4.py
@@ -0,0 +1,54 @@
+# 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.
+
+"""Test variables for ip4-lispgpe-ip4 encapsulation test suite."""
+
+# Lisp default global value
+locator_name = 'tst_locator'
+
+# Lisp default locator_set value
+duts_locator_set = {'locator_name': locator_name,
+ 'priority': 1,
+ 'weight': 1}
+
+# IPv4 Lisp static mapping configuration
+dut1_to_dut2_ip4 = '6.0.3.1'
+dut2_to_dut1_ip4 = '6.0.3.2'
+dut1_to_tg_ip4 = '6.0.1.1'
+dut2_to_tg_ip4 = '6.0.2.1'
+tg1_ip4 = '6.0.1.2'
+tg2_ip4 = '6.0.2.2'
+prefix4 = 24
+
+dut1_to_dut2_ip4_static_adjacency = {'vni': 0,
+ 'deid': '6.0.2.0',
+ 'seid': '6.0.1.0',
+ 'rloc': '6.0.3.2',
+ 'prefix': 24}
+dut2_to_dut1_ip4_static_adjacency = {'vni': 0,
+ 'deid': '6.0.1.0',
+ 'seid': '6.0.2.0',
+ 'rloc': '6.0.3.1',
+ 'prefix': 24}
+
+dut1_ip4_eid = {'locator_name': locator_name,
+ 'vni': 0,
+ 'eid': '6.0.1.0',
+ 'prefix': 24}
+dut2_ip4_eid = {'locator_name': locator_name,
+ 'vni': 0,
+ 'eid': '6.0.2.0',
+ 'prefix': 24}
+
+dut1_fib_table = '1'
+dut2_fib_table = '2'
diff --git a/tests/func/lisp/lisp_ipv4_lispgpe_ipv4.robot b/tests/func/lisp/lisp_ipv4_lispgpe_ipv4.robot
new file mode 100644
index 0000000000..8a18962e35
--- /dev/null
+++ b/tests/func/lisp/lisp_ipv4_lispgpe_ipv4.robot
@@ -0,0 +1,179 @@
+# 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.
+
+*** Settings ***
+| Library | resources.libraries.python.topology.Topology
+| Library | resources.libraries.python.NodePath
+| Library | resources.libraries.python.Trace
+| Library | resources.libraries.python.IPUtil
+| Library | resources.libraries.python.LispUtil
+| Resource | resources/libraries/robot/traffic.robot
+| Resource | resources/libraries/robot/default.robot
+| Resource | resources/libraries/robot/interfaces.robot
+| Resource | resources/libraries/robot/testing_path.robot
+| Resource | resources/libraries/robot/ipv4.robot
+| Resource | resources/libraries/robot/lisp/lispgpe.robot
+# Import configuration and test data:
+| Variables | resources/test_data/lisp/ipv4_lispgpe_ipv4/ipv4_lispgpe_ipv4.py
+| ...
+| Force Tags | 3_NODE_SINGLE_LINK_TOPO | VM_ENV | EXPECTED_FAILING
+| ...
+| Test Setup | Run Keywords | Setup all DUTs before test
+| ... | AND | Setup all TGs before traffic script
+| ... | AND | Update All Interface Data On All Nodes | ${nodes}
+| Test Teardown | Run Keywords | Show Packet Trace on All DUTs | ${nodes}
+| ... | AND | Show vpp trace dump on all DUTs
+| ... | AND | VPP Show Errors | ${nodes['DUT1']}
+| ... | AND | VPP Show Errors | ${nodes['DUT2']}
+| ...
+| Documentation | *ip4-lispgpe-ip4 encapsulation test cases*
+| ...
+| ... | *[Top] Network Topologies:* TG-DUT1-DUT2-TG 3-node circular topology
+| ... | with single links between nodes.
+| ... | *[Enc] Packet Encapsulations:* Eth-IPv4-LISP-IPv4-ICMPv4 on DUT1-DUT2,
+| ... | Eth-IPv4-ICMPv4 on TG-DUTn for IPv4 routing over LISPoIPv4 tunnel.
+| ... | *[Cfg] DUT configuration:* DUT1 and DUT2 are configured with IPv4
+| ... | routing and static routes. LISPoIPv4 tunnel is configured between
+| ... | DUT1 and DUT2.
+| ... | *[Ver] TG verification:* Test ICMPv4 Echo Request packets are sent in
+| ... | both directions by TG on links to DUT1 and DUT2; on receive
+| ... | TG verifies packets for correctness and their IPv4 src-addr, dst-addr
+| ... | and MAC addresses.
+| ... | *[Ref] Applicable standard specifications:* RFC6830.
+
+*** Test Cases ***
+| TC01: DUT1 and DUT2 route IPv4 bidirectionally over LISP GPE tunnel using physical interfaces
+| | [Documentation]
+| | ... | Case: ip4-lispgpe-ip4 - phy2lisp \
+| | ... | [Top] TG-DUT1-DUT2-TG.
+| | ... | [Enc] Eth-IPv4-LISPGPE-IPv4-ICMPv4 on DUT1-DUT2, Eth-IPv4-ICMPv4 on
+| | ... | TG-DUTn.
+| | ... | [Cfg] Configure IPv4 LISP static adjacencies on DUT1 and DUT2.
+| | ... | [Ver] Make TG send ICMPv4 Echo Req between its interfaces across both
+| | ... | DUTs and LISP GPE tunnel between them; verify IPv4 headers on received
+| | ... | packets are correct.
+| | ... | [Ref] RFC6830.
+| | ...
+| | Given Path for 3-node testing is set
+| | ... | ${nodes['TG']} | ${nodes['DUT1']} | ${nodes['DUT2']} | ${nodes['TG']}
+| | And Interfaces in 3-node path are up
+| | And IP addresses are set on interfaces
+| | ... | ${dut1_node} | ${dut1_to_dut2} | ${dut1_to_dut2_ip4} | ${prefix4}
+| | ... | ${dut1_node} | ${dut1_to_tg} | ${dut1_to_tg_ip4} | ${prefix4}
+| | ... | ${dut2_node} | ${dut2_to_dut1} | ${dut2_to_dut1_ip4} | ${prefix4}
+| | ... | ${dut2_node} | ${dut2_to_tg} | ${dut2_to_tg_ip4} | ${prefix4}
+| | And VPP IP Probe | ${dut1_node} | ${dut1_to_dut2} | ${dut2_to_dut1_ip4}
+| | And VPP IP Probe | ${dut2_node} | ${dut2_to_dut1} | ${dut1_to_dut2_ip4}
+| | And Add Arp On Dut | ${dut2_node} | ${dut2_to_tg} | ${tg2_ip4}
+| | ... | ${tg_to_dut2_mac}
+| | And Add Arp On Dut | ${dut1_node} | ${dut1_to_tg} | ${tg1_ip4}
+| | ... | ${tg_to_dut1_mac}
+| | When Set up LISP GPE topology
+| | ... | ${dut1_node} | ${dut1_to_dut2} | ${NONE}
+| | ... | ${dut2_node} | ${dut2_to_dut1} | ${NONE}
+| | ... | ${duts_locator_set} | ${dut1_ip4_eid} | ${dut2_ip4_eid}
+| | ... | ${dut1_to_dut2_ip4_static_adjacency}
+| | ... | ${dut2_to_dut1_ip4_static_adjacency}
+| | Then Send Packet And Check Headers
+| | ... | ${tg_node} | ${tg1_ip4} | ${tg2_ip4}
+| | ... | ${tg_to_dut1} | ${tg_to_dut1_mac} | ${dut1_to_tg_mac}
+| | ... | ${tg_to_dut2} | ${dut2_to_tg_mac} | ${tg_to_dut2_mac}
+| | And Send Packet And Check Headers
+| | ... | ${tg_node} | ${tg2_ip4} | ${tg1_ip4}
+| | ... | ${tg_to_dut2} | ${tg_to_dut2_mac} | ${dut2_to_tg_mac}
+| | ... | ${tg_to_dut1} | ${dut1_to_tg_mac} | ${tg_to_dut1_mac}
+
+| TC02: DUT1 and DUT2 route IPv4 bidirectionally over LISP GPE tunnel using physical interfaces and VRF is enabled
+| | [Documentation]
+| | ... | Case: ip4-lispgpe-ip4 - vrf, phy2lisp \
+| | ... | [Top] TG-DUT1-DUT2-TG.
+| | ... | [Enc] Eth-IPv4-LISPGPE-IPv4-ICMPv4 on DUT1-DUT2, Eth-IPv4-ICMPv4 on
+| | ... | TG-DUTn.
+| | ... | [Cfg] Configure IPv4 LISP static adjacencies on DUT1 and DUT2.
+| | ... | [Ver] Make TG send ICMPv4 Echo Req between its interfaces across both
+| | ... | DUTs and LISP GPE tunnel between them; verify IPv4 headers on received
+| | ... | packets are correct.
+| | ... | [Ref] RFC6830.
+| | ...
+| | Given Path for 3-node testing is set
+| | ... | ${nodes['TG']} | ${nodes['DUT1']} | ${nodes['DUT2']} | ${nodes['TG']}
+| | And Interfaces in 3-node path are up
+| | When Setup VRF on DUT | ${dut1_node} | ${dut1_fib_table} | ${dut1_to_dut2}
+| | ... | ${dut2_to_dut1_ip4} | ${dut2_to_dut1_mac} | ${tg2_ip4} | ${dut1_to_tg}
+| | ... | ${tg1_ip4} | ${tg_to_dut1_mac} | ${prefix4}
+| | And Setup VRF on DUT | ${dut2_node} | ${dut2_fib_table} | ${dut2_to_dut1}
+| | ... | ${dut1_to_dut2_ip4} | ${dut1_to_dut2_mac} | ${tg1_ip4} | ${dut2_to_tg}
+| | ... | ${tg2_ip4} | ${tg_to_dut2_mac} | ${prefix4}
+| | And IP addresses are set on interfaces
+| | ... | ${dut1_node} | ${dut1_to_dut2} | ${dut1_to_dut2_ip4} | ${prefix4}
+| | ... | ${dut1_node} | ${dut1_to_tg} | ${dut1_to_tg_ip4} | ${prefix4}
+| | ... | ${dut2_node} | ${dut2_to_dut1} | ${dut2_to_dut1_ip4} | ${prefix4}
+| | ... | ${dut2_node} | ${dut2_to_tg} | ${dut2_to_tg_ip4} | ${prefix4}
+| | And Set up LISP GPE topology
+| | ... | ${dut1_node} | ${dut1_to_dut2} | ${NONE}
+| | ... | ${dut2_node} | ${dut2_to_dut1} | ${NONE}
+| | ... | ${duts_locator_set} | ${dut1_ip4_eid} | ${dut2_ip4_eid}
+| | ... | ${dut1_to_dut2_ip4_static_adjacency}
+| | ... | ${dut2_to_dut1_ip4_static_adjacency}
+| | Then Send Packet And Check Headers
+| | ... | ${tg_node} | ${tg1_ip4} | ${tg2_ip4}
+| | ... | ${tg_to_dut1} | ${tg_to_dut1_mac} | ${dut1_to_tg_mac}
+| | ... | ${tg_to_dut2} | ${dut2_to_tg_mac} | ${tg_to_dut2_mac}
+| | And Send Packet And Check Headers
+| | ... | ${tg_node} | ${tg2_ip4} | ${tg1_ip4}
+| | ... | ${tg_to_dut2} | ${tg_to_dut2_mac} | ${dut2_to_tg_mac}
+| | ... | ${tg_to_dut1} | ${dut1_to_tg_mac} | ${tg_to_dut1_mac}
+
+*** Keywords ***
+| Setup VRF on DUT
+| | [Documentation]
+| | ... | The keyword sets a FIB table on a DUT, assigns two interfaces to it,\
+| | ... | adds two ARP items and a route, see example.
+| | ...
+| | ... | *Example:*
+| | ... | Three-node topology:
+| | ... | TG_if1 - DUT1_if1-DUT1_if2 - DUT2_if1-DUT2_if2 - TG_if2
+| | ... | Create one VRF on each DUT:
+| | ... | \| Setup VRF on DUT \| ${dut1_node} \| ${dut1_fib_table} \
+| | ... | \| ${dut1_to_dut2} \| ${dut2_to_dut1_ip4} \| ${dut2_to_dut1_mac} \
+| | ... | \| ${tg2_ip4} \| ${dut1_to_tg} \| ${tg1_ip4} \| ${tg_to_dut1_mac} \
+| | ... | \| 24 \|
+| | ... | \| Setup VRF on DUT \| ${dut2_node} \| ${dut2_fib_table} \
+| | ... | \| ${dut2_to_dut1} \| ${dut1_to_dut2_ip4} \| ${dut1_to_dut2_mac} \
+| | ... | \| ${tg1_ip4} \| ${dut2_to_tg} \| ${tg2_ip4} \| ${tg_to_dut2_mac} \
+| | ... | \| 24 \|
+| | ...
+| | [Arguments]
+| | ... | ${node} | ${table} | ${route_interface} | ${route_gateway_ip}
+| | ... | ${route_gateway_mac} | ${route_dst_ip} | ${vrf_src_if} | ${src_if_ip}
+| | ... | ${src_if_mac} | ${prefix_len}
+| | ...
+| | ${route_interface_idx}= | Get Interface SW Index
+| | ... | ${node} | ${route_interface}
+| | ...
+| | Add fib table | ${node}
+| | ... | ${route_dst_ip} | ${prefix_len} | ${table}
+| | ... | via ${route_gateway_ip} sw_if_index ${route_interface_idx} multipath
+| | ...
+| | Assign Interface To Fib Table
+| | ... | ${node} | ${route_interface} | ${table}
+| | Assign Interface To Fib Table
+| | ... | ${node} | ${vrf_src_if} | ${table}
+| | ...
+| | Add Arp On Dut | ${node} | ${vrf_src_if}
+| | ... | ${src_if_ip} | ${src_if_mac} | vrf=${table}
+| | Add Arp On Dut | ${node} | ${route_interface}
+| | ... | ${route_gateway_ip} | ${route_gateway_mac} | vrf=${table}
+| | ...
+| | Vpp Route Add | ${node} | ${route_dst_ip} | ${prefix_len}
+| | ... | ${route_gateway_ip} | ${route_interface} | vrf=${table}