summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorNeale Ranns <neale.ranns@cisco.com>2018-10-10 07:22:51 -0700
committerDamjan Marion <dmarion@me.com>2018-11-07 12:00:10 +0000
commit93cc3ee3b3a9c9224a1446625882205f3282a949 (patch)
tree077421ee51238c22181a3b3f4871b648bb1299d3 /test
parentc3df1e9a0ab79c1fe254394748ef441ffe224c43 (diff)
GBP Endpoint Learning
Learning GBP endpoints over vxlan-gbp tunnels Change-Id: I1db9fda5a16802d9ad8b4efd4e475614f3b21502 Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Diffstat (limited to 'test')
-rw-r--r--test/framework.py30
-rw-r--r--test/test_gbp.py1405
-rw-r--r--test/test_l2_flood.py2
-rw-r--r--test/vpp_interface.py3
-rw-r--r--test/vpp_ip.py12
-rw-r--r--test/vpp_ip_route.py100
-rw-r--r--test/vpp_l2.py221
-rw-r--r--test/vpp_mac.py15
-rw-r--r--test/vpp_papi_provider.py166
-rw-r--r--test/vpp_vxlan_gbp_tunnel.py69
10 files changed, 1741 insertions, 282 deletions
diff --git a/test/framework.py b/test/framework.py
index fbe6c370a3f..5bbd56a6ef7 100644
--- a/test/framework.py
+++ b/test/framework.py
@@ -929,7 +929,35 @@ class VppTestCase(unittest.TestCase):
input.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
- rx = output.get_capture(len(pkts))
+ if isinstance(object, (list,)):
+ rx = []
+ for o in output:
+ rx.append(output.get_capture(len(pkts)))
+ else:
+ rx = output.get_capture(len(pkts))
+ return rx
+
+ def send_and_expect_only(self, input, pkts, output, timeout=None):
+ self.vapi.cli("clear trace")
+ input.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ if isinstance(object, (list,)):
+ outputs = output
+ rx = []
+ for o in outputs:
+ rx.append(output.get_capture(len(pkts)))
+ else:
+ rx = output.get_capture(len(pkts))
+ outputs = [output]
+ if not timeout:
+ timeout = 1
+ for i in self.pg_interfaces:
+ if i not in outputs:
+ i.get_capture(0, timeout=timeout)
+ i.assert_nothing_captured()
+ timeout = 0.1
+
return rx
diff --git a/test/test_gbp.py b/test/test_gbp.py
index ef4bf7071eb..a45b2f845b8 100644
--- a/test/test_gbp.py
+++ b/test/test_gbp.py
@@ -5,11 +5,16 @@ import unittest
from framework import VppTestCase, VppTestRunner
from vpp_object import VppObject
from vpp_neighbor import VppNeighbor
-from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
+ VppIpInterfaceAddress, VppIpInterfaceBind, find_route
+from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
+ VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port
+from vpp_vxlan_gbp_tunnel import *
from vpp_ip import *
from vpp_mac import *
from vpp_papi_provider import L2_PORT_TYPE
+from vpp_papi import VppEnum
from scapy.packet import Raw
from scapy.layers.l2 import Ether, ARP
@@ -17,25 +22,43 @@ from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
ICMPv6ND_NA
from scapy.utils6 import in6_getnsma, in6_getnsmac
+from scapy.layers.vxlan import VXLAN
from socket import AF_INET, AF_INET6
from scapy.utils import inet_pton, inet_ntop
from util import mactobinary
-def find_gbp_endpoint(test, sw_if_index, ip=None, mac=None):
- vip = VppIpAddress(ip)
+def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None):
+ if ip:
+ vip = VppIpAddress(ip)
+ if mac:
+ vmac = VppMacAddress(mac)
eps = test.vapi.gbp_endpoint_dump()
+
for ep in eps:
- if ep.endpoint.sw_if_index != sw_if_index:
- continue
- for eip in ep.endpoint.ips:
- if vip == eip:
+ if sw_if_index:
+ if ep.endpoint.sw_if_index != sw_if_index:
+ continue
+ if ip:
+ for eip in ep.endpoint.ips:
+ if vip == eip:
+ return True
+ if mac:
+ if vmac == ep.endpoint.mac:
return True
return False
+def find_gbp_vxlan(test, vni):
+ ts = test.vapi.gbp_vxlan_tunnel_dump()
+ for t in ts:
+ if t.tunnel.vni == vni:
+ return True
+ return False
+
+
class VppGbpEndpoint(VppObject):
"""
GBP Endpoint
@@ -43,7 +66,11 @@ class VppGbpEndpoint(VppObject):
@property
def bin_mac(self):
- return mactobinary(self.itf.remote_mac)
+ return self.vmac.bytes
+
+ @property
+ def mac(self):
+ return self.vmac.address
@property
def mac(self):
@@ -73,7 +100,11 @@ class VppGbpEndpoint(VppObject):
def fips(self):
return [self.fip4, self.fip6]
- def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6):
+ def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
+ flags=0,
+ tun_src="0.0.0.0",
+ tun_dst="0.0.0.0",
+ mac=True):
self._test = test
self.itf = itf
self.epg = epg
@@ -84,14 +115,24 @@ class VppGbpEndpoint(VppObject):
self._ip6 = VppIpAddress(ip6)
self._fip6 = VppIpAddress(fip6)
- self.vmac = VppMacAddress(self.itf.remote_mac)
+ if mac:
+ self.vmac = VppMacAddress(self.itf.remote_mac)
+ else:
+ self.vmac = VppMacAddress("00:00:00:00:00:00")
+
+ self.flags = flags
+ self.tun_src = VppIpAddress(tun_src)
+ self.tun_dst = VppIpAddress(tun_dst)
def add_vpp_config(self):
res = self._test.vapi.gbp_endpoint_add(
self.itf.sw_if_index,
[self.ip4.encode(), self.ip6.encode()],
self.vmac.encode(),
- self.epg.epg)
+ self.epg.epg,
+ self.flags,
+ self.tun_src.encode(),
+ self.tun_dst.encode())
self.handle = res.handle
self._test.registry.register(self, self._test.logger)
@@ -102,9 +143,10 @@ class VppGbpEndpoint(VppObject):
return self.object_id()
def object_id(self):
- return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
- self.ip4.address,
- self.epg.epg)
+ return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
+ self.itf.sw_if_index,
+ self.ip4.address,
+ self.epg.epg)
def query_vpp_config(self):
return find_gbp_endpoint(self._test,
@@ -142,7 +184,7 @@ class VppGbpRecirc(VppObject):
return self.object_id()
def object_id(self):
- return "gbp-recirc;[%d]" % (self.recirc.sw_if_index)
+ return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
def query_vpp_config(self):
rs = self._test.vapi.gbp_recirc_dump()
@@ -156,23 +198,21 @@ class VppGbpSubnet(VppObject):
"""
GBP Subnet
"""
-
- def __init__(self, test, table_id, address, address_len,
- is_internal=True,
- sw_if_index=None, epg=None):
+ def __init__(self, test, rd, address, address_len,
+ type, sw_if_index=None, epg=None):
self._test = test
- self.table_id = table_id
+ self.rd_id = rd.rd_id
self.prefix = VppIpPrefix(address, address_len)
- self.is_internal = is_internal
+ self.type = type
self.sw_if_index = sw_if_index
self.epg = epg
def add_vpp_config(self):
self._test.vapi.gbp_subnet_add_del(
1,
- self.table_id,
- self.is_internal,
+ self.rd_id,
self.prefix.encode(),
+ self.type,
sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
epg_id=self.epg if self.epg else 0xffff)
self._test.registry.register(self, self._test.logger)
@@ -180,21 +220,21 @@ class VppGbpSubnet(VppObject):
def remove_vpp_config(self):
self._test.vapi.gbp_subnet_add_del(
0,
- self.table_id,
- self.is_internal,
- self.prefix.encode())
+ self.rd_id,
+ self.prefix.encode(),
+ self.type)
def __str__(self):
return self.object_id()
def object_id(self):
- return "gbp-subnet;[%d-%s]" % (self.table_id,
- self.prefix)
+ return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
def query_vpp_config(self):
ss = self._test.vapi.gbp_subnet_dump()
for s in ss:
- if s.subnet.table_id == self.table_id and \
+ if s.subnet.rd_id == self.rd_id and \
+ s.subnet.type == self.type and \
s.subnet.prefix == self.prefix:
return True
return False
@@ -217,29 +257,22 @@ class VppGbpEndpointGroup(VppObject):
self.rd = rd
def add_vpp_config(self):
- self._test.vapi.gbp_endpoint_group_add_del(
- 1,
+ self._test.vapi.gbp_endpoint_group_add(
self.epg,
- self.bd,
- self.rd,
- self.rd,
- self.uplink.sw_if_index)
+ self.bd.bd.bd_id,
+ self.rd.rd_id,
+ self.uplink.sw_if_index if self.uplink else INDEX_INVALID)
self._test.registry.register(self, self._test.logger)
def remove_vpp_config(self):
- self._test.vapi.gbp_endpoint_group_add_del(
- 0,
- self.epg,
- self.bd,
- self.rd,
- self.rd,
- self.uplink.sw_if_index)
+ self._test.vapi.gbp_endpoint_group_del(
+ self.epg)
def __str__(self):
return self.object_id()
def object_id(self):
- return "gbp-endpoint-group;[%d]" % (self.epg)
+ return "gbp-endpoint-group:[%d]" % (self.epg)
def query_vpp_config(self):
epgs = self._test.vapi.gbp_endpoint_group_dump()
@@ -249,6 +282,80 @@ class VppGbpEndpointGroup(VppObject):
return False
+class VppGbpBridgeDomain(VppObject):
+ """
+ GBP Bridge Domain
+ """
+
+ def __init__(self, test, bd, bvi, uu_flood=None):
+ self._test = test
+ self.bvi = bvi
+ self.uu_flood = uu_flood
+ self.bd = bd
+
+ def add_vpp_config(self):
+ self._test.vapi.gbp_bridge_domain_add(
+ self.bd.bd_id,
+ self.bvi.sw_if_index,
+ self.uu_flood.sw_if_index if self.uu_flood else INDEX_INVALID)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
+
+ def query_vpp_config(self):
+ bds = self._test.vapi.gbp_bridge_domain_dump()
+ for bd in bds:
+ if bd.bd.bd_id == self.bd.bd_id:
+ return True
+ return False
+
+
+class VppGbpRouteDomain(VppObject):
+ """
+ GBP Route Domain
+ """
+
+ def __init__(self, test, rd_id, t4, t6, ip4_uu=None, ip6_uu=None):
+ self._test = test
+ self.rd_id = rd_id
+ self.t4 = t4
+ self.t6 = t6
+ self.ip4_uu = ip4_uu
+ self.ip6_uu = ip6_uu
+
+ def add_vpp_config(self):
+ self._test.vapi.gbp_route_domain_add(
+ self.rd_id,
+ self.t4.table_id,
+ self.t6.table_id,
+ self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
+ self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.gbp_route_domain_del(self.rd_id)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "gbp-route-domain:[%d]" % (self.rd_id)
+
+ def query_vpp_config(self):
+ rds = self._test.vapi.gbp_route_domain_dump()
+ for rd in rds:
+ if rd.rd.rd_id == self.rd_id:
+ return True
+ return False
+
+
class VppGbpContract(VppObject):
"""
GBP Contract
@@ -279,7 +386,7 @@ class VppGbpContract(VppObject):
return self.object_id()
def object_id(self):
- return "gbp-contract;[%d:%s:%d]" % (self.src_epg,
+ return "gbp-contract:[%d:%s:%d]" % (self.src_epg,
self.dst_epg,
self.acl_index)
@@ -292,6 +399,39 @@ class VppGbpContract(VppObject):
return False
+class VppGbpVxlanTunnel(VppInterface):
+ """
+ GBP VXLAN tunnel
+ """
+
+ def __init__(self, test, vni, bd_rd_id, mode):
+ super(VppGbpVxlanTunnel, self).__init__(test)
+ self._test = test
+ self.vni = vni
+ self.bd_rd_id = bd_rd_id
+ self.mode = mode
+
+ def add_vpp_config(self):
+ r = self._test.vapi.gbp_vxlan_tunnel_add(
+ self.vni,
+ self.bd_rd_id,
+ self.mode)
+ self.set_sw_if_index(r.sw_if_index)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "gbp-vxlan:%d" % (self.vni)
+
+ def query_vpp_config(self):
+ return find_gbp_vxlan(self._test, self.vni)
+
+
class VppGbpAcl(VppObject):
"""
GBP Acl
@@ -337,7 +477,7 @@ class VppGbpAcl(VppObject):
return self.object_id()
def object_id(self):
- return "gbp-acl;[%d]" % (self.acl_index)
+ return "gbp-acl:[%d]" % (self.acl_index)
def query_vpp_config(self):
cs = self._test.vapi.acl_dump()
@@ -354,7 +494,7 @@ class TestGBP(VppTestCase):
super(TestGBP, self).setUp()
self.create_pg_interfaces(range(9))
- self.create_loopback_interfaces(9)
+ self.create_loopback_interfaces(8)
self.router_mac = VppMacAddress("00:11:22:33:44:55")
@@ -362,9 +502,6 @@ class TestGBP(VppTestCase):
i.admin_up()
for i in self.lo_interfaces:
i.admin_up()
- self.vapi.sw_interface_set_mac_address(
- i.sw_if_index,
- self.router_mac.bytes)
def tearDown(self):
for i in self.pg_interfaces:
@@ -465,42 +602,64 @@ class TestGBP(VppTestCase):
def test_gbp(self):
""" Group Based Policy """
- nat_table = VppIpTable(self, 20)
- nat_table.add_vpp_config()
- nat_table = VppIpTable(self, 20, is_ip6=True)
- nat_table.add_vpp_config()
-
#
# Bridge Domains
#
- self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1,
- learn=0, arp_term=1, is_add=1)
- self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1,
- learn=0, arp_term=1, is_add=1)
- self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1,
- learn=0, arp_term=1, is_add=1)
+ bd1 = VppBridgeDomain(self, 1)
+ bd2 = VppBridgeDomain(self, 2)
+ bd20 = VppBridgeDomain(self, 20)
+
+ bd1.add_vpp_config()
+ bd2.add_vpp_config()
+ bd20.add_vpp_config()
+
+ gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
+ gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
+ gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
+
+ gbd1.add_vpp_config()
+ gbd2.add_vpp_config()
+ gbd20.add_vpp_config()
+
+ #
+ # Route Domains
+ #
+ gt4 = VppIpTable(self, 0)
+ gt4.add_vpp_config()
+ gt6 = VppIpTable(self, 0, is_ip6=True)
+ gt6.add_vpp_config()
+ nt4 = VppIpTable(self, 20)
+ nt4.add_vpp_config()
+ nt6 = VppIpTable(self, 20, is_ip6=True)
+ nt6.add_vpp_config()
+
+ rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
+ rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
+
+ rd0.add_vpp_config()
+ rd20.add_vpp_config()
#
# 3 EPGs, 2 of which share a BD.
# 2 NAT EPGs, one for floating-IP subnets, the other for internet
#
- epgs = [VppGbpEndpointGroup(self, 220, 0, 1, self.pg4,
+ epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
self.loop0,
"10.0.0.128",
"2001:10::128"),
- VppGbpEndpointGroup(self, 221, 0, 1, self.pg5,
+ VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
self.loop0,
"10.0.1.128",
"2001:10:1::128"),
- VppGbpEndpointGroup(self, 222, 0, 2, self.pg6,
+ VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
self.loop1,
"10.0.2.128",
"2001:10:2::128"),
- VppGbpEndpointGroup(self, 333, 20, 20, self.pg7,
+ VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
self.loop2,
"11.0.0.128",
"3001::128"),
- VppGbpEndpointGroup(self, 444, 20, 20, self.pg8,
+ VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
self.loop2,
"11.0.0.129",
"3001::129")]
@@ -513,7 +672,7 @@ class TestGBP(VppTestCase):
VppGbpRecirc(self, epgs[3],
self.loop6, is_ext=True),
VppGbpRecirc(self, epgs[4],
- self.loop8, is_ext=True)]
+ self.loop7, is_ext=True)]
epg_nat = epgs[3]
recirc_nat = recircs[3]
@@ -544,8 +703,11 @@ class TestGBP(VppTestCase):
for epg in epgs:
# IP config on the BVI interfaces
if epg != epgs[1] and epg != epgs[4]:
- epg.bvi.set_table_ip4(epg.rd)
- epg.bvi.set_table_ip6(epg.rd)
+ VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
+ VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
+ self.vapi.sw_interface_set_mac_address(
+ epg.bvi.sw_if_index,
+ self.router_mac.bytes)
# The BVIs are NAT inside interfaces
self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
@@ -555,60 +717,37 @@ class TestGBP(VppTestCase):
is_inside=1,
is_add=1)
- self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
- epg.bvi_ip4.bytes,
- 32)
- self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
- epg.bvi_ip6.bytes,
- 128,
- is_ipv6=True)
+ if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
+ if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
+ if_ip4.add_vpp_config()
+ if_ip6.add_vpp_config()
- # EPG uplink interfaces in the BD
- epg.uplink.set_table_ip4(epg.rd)
- epg.uplink.set_table_ip6(epg.rd)
- self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index,
- epg.bd)
+ # EPG uplink interfaces in the RD
+ VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
+ VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
# add the BD ARP termination entry for BVI IP
- self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
- mac=self.router_mac.encode(),
- ip=epg.bvi_ip4.encode(),
- is_ipv6=0,
- is_add=1)
- self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
- mac=self.router_mac.encode(),
- ip=epg.bvi_ip6.encode(),
- is_ipv6=1,
- is_add=1)
-
- # epg[1] shares the same BVI to epg[0]
- if epg != epgs[1] and epg != epgs[4]:
- # BVI in BD
- self.vapi.sw_interface_set_l2_bridge(
- epg.bvi.sw_if_index,
- epg.bd,
- port_type=L2_PORT_TYPE.BVI)
-
- # BVI L2 FIB entry
- self.vapi.l2fib_add_del(self.router_mac.address,
- epg.bd,
- epg.bvi.sw_if_index,
- is_add=1, bvi_mac=1)
+ epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
+ self.router_mac.address,
+ epg.bvi_ip4)
+ epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
+ self.router_mac.address,
+ epg.bvi_ip6)
+ epg.bd_arp_ip4.add_vpp_config()
+ epg.bd_arp_ip6.add_vpp_config()
# EPG in VPP
epg.add_vpp_config()
for recirc in recircs:
# EPG's ingress recirculation interface maps to its RD
- recirc.recirc.set_table_ip4(recirc.epg.rd)
- recirc.recirc.set_table_ip6(recirc.epg.rd)
+ VppIpInterfaceBind(self, recirc.recirc,
+ recirc.epg.rd.t4).add_vpp_config()
+ VppIpInterfaceBind(self, recirc.recirc,
+ recirc.epg.rd.t6).add_vpp_config()
- # in the bridge to allow DVR. L2 emulation to punt to L3
- self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index,
- recirc.epg.bd)
self.vapi.sw_interface_set_l2_emulation(
recirc.recirc.sw_if_index)
-
self.vapi.nat44_interface_add_del_feature(
recirc.recirc.sw_if_index,
is_inside=0,
@@ -620,8 +759,11 @@ class TestGBP(VppTestCase):
recirc.add_vpp_config()
- ep_routes = []
- ep_arps = []
+ for recirc in recircs:
+ self.assertTrue(find_bridge_domain_port(self,
+ recirc.epg.bd.bd.bd_id,
+ recirc.recirc.sw_if_index))
+
for ep in eps:
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
@@ -631,32 +773,6 @@ class TestGBP(VppTestCase):
# the subnet is not attached.
#
for (ip, fip) in zip(ep.ips, ep.fips):
- r = VppIpRoute(self, ip.address, ip.length,
- [VppRoutePath(ip.address,
- ep.epg.bvi.sw_if_index,
- proto=ip.dpo_proto)],
- is_ip6=ip.is_ip6)
- r.add_vpp_config()
- ep_routes.append(r)
-
- #
- # ARP entries for the endpoints
- #
- a = VppNeighbor(self,
- ep.epg.bvi.sw_if_index,
- ep.itf.remote_mac,
- ip.address,
- af=ip.af)
- a.add_vpp_config()
- ep_arps.append(a)
-
- # add the BD ARP termination entry
- self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
- mac=ep.vmac.encode(),
- ip=ip.encode(),
- is_ipv6=ip.is_ip6,
- is_add=1)
-
# Add static mappings for each EP from the 10/8 to 11/8 network
if ip.af == AF_INET:
self.vapi.nat44_add_del_static_mapping(ip.bytes,
@@ -668,16 +784,6 @@ class TestGBP(VppTestCase):
fip.bytes,
vrf_id=0)
- # add each EP itf to the its BD
- self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index,
- ep.epg.bd)
-
- # L2 FIB entry
- self.vapi.l2fib_add_del(ep.mac,
- ep.epg.bd,
- ep.itf.sw_if_index,
- is_add=1)
-
# VPP EP create ...
ep.add_vpp_config()
@@ -699,11 +805,8 @@ class TestGBP(VppTestCase):
# add the BD ARP termination entry for floating IP
for fip in ep.fips:
- self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
- mac=ep.vmac.encode(),
- ip=fip.encode(),
- is_ipv6=fip.is_ip6,
- is_add=1)
+ ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
+ ba.add_vpp_config()
# floating IPs route via EPG recirc
r = VppIpRoute(self, fip.address, fip.length,
@@ -714,27 +817,31 @@ class TestGBP(VppTestCase):
table_id=20,
is_ip6=fip.is_ip6)
r.add_vpp_config()
- ep_routes.append(r)
# L2 FIB entries in the NAT EPG BD to bridge the packets from
# the outside direct to the internal EPG
- self.vapi.l2fib_add_del(ep.mac,
- epg_nat.bd,
- ep.recirc.recirc.sw_if_index,
- is_add=1)
+ lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
+ ep.recirc.recirc, bvi_mac=0)
+ lf.add_vpp_config()
#
- # ARP packets for unknown IP are flooded
+ # ARP packets for unknown IP are sent to the EPG uplink
#
pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
src=self.pg0.remote_mac) /
ARP(op="who-has",
hwdst="ff:ff:ff:ff:ff:ff",
hwsrc=self.pg0.remote_mac,
- pdst=epgs[0].bvi_ip4.address,
- psrc="10.0.0.88"))
+ pdst="10.0.0.88",
+ psrc="10.0.0.99"))
- self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
+ self.vapi.cli("clear trace")
+ self.pg0.add_stream(pkt_arp)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rxd = epgs[0].uplink.get_capture(1)
#
# ARP/ND packets get a response
@@ -751,7 +858,8 @@ class TestGBP(VppTestCase):
nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
d = inet_ntop(AF_INET6, nsma)
- pkt_nd = (Ether(dst=in6_getnsmac(nsma)) /
+ pkt_nd = (Ether(dst=in6_getnsmac(nsma),
+ src=self.pg0.remote_mac) /
IPv6(dst=d, src=eps[0].ip6.address) /
ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
@@ -806,28 +914,40 @@ class TestGBP(VppTestCase):
#
# Add the subnet routes
#
- s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24)
- s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24)
- s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24)
+ s41 = VppGbpSubnet(
+ self, rd0, "10.0.0.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
+ s42 = VppGbpSubnet(
+ self, rd0, "10.0.1.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
+ s43 = VppGbpSubnet(
+ self, rd0, "10.0.2.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
+ s61 = VppGbpSubnet(
+ self, rd0, "2001:10::1", 64,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
+ s62 = VppGbpSubnet(
+ self, rd0, "2001:10:1::1", 64,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
+ s63 = VppGbpSubnet(
+ self, rd0, "2001:10:2::1", 64,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
s41.add_vpp_config()
s42.add_vpp_config()
s43.add_vpp_config()
- s61 = VppGbpSubnet(self, 0, "2001:10::1", 64)
- s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64)
- s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64)
s61.add_vpp_config()
s62.add_vpp_config()
s63.add_vpp_config()
- self.send_and_expect_bridged(self.pg0,
+ self.send_and_expect_bridged(eps[0].itf,
pkt_intra_epg_220_ip4 * 65,
- self.pg4)
- self.send_and_expect_bridged(self.pg3,
+ eps[0].epg.uplink)
+ self.send_and_expect_bridged(eps[0].itf,
pkt_inter_epg_222_ip4 * 65,
- self.pg6)
- self.send_and_expect_bridged6(self.pg3,
+ eps[0].epg.uplink)
+ self.send_and_expect_bridged6(eps[0].itf,
pkt_inter_epg_222_ip6 * 65,
- self.pg6)
+ eps[0].epg.uplink)
self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
@@ -838,6 +958,7 @@ class TestGBP(VppTestCase):
self.logger.info(self.vapi.cli("sh int feat loop6"))
self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
self.logger.info(self.vapi.cli("sh int feat loop3"))
+ self.logger.info(self.vapi.cli("sh int feat pg0"))
#
# Packet destined to unknown unicast is sent on the epg uplink ...
@@ -849,9 +970,9 @@ class TestGBP(VppTestCase):
UDP(sport=1234, dport=1234) /
Raw('\xa5' * 100))
- self.send_and_expect_bridged(self.pg0,
+ self.send_and_expect_bridged(eps[0].itf,
pkt_intra_epg_220_to_uplink * 65,
- self.pg4)
+ eps[0].epg.uplink)
# ... and nowhere else
self.pg1.get_capture(0, timeout=0.1)
self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
@@ -863,9 +984,9 @@ class TestGBP(VppTestCase):
UDP(sport=1234, dport=1234) /
Raw('\xa5' * 100))
- self.send_and_expect_bridged(self.pg2,
+ self.send_and_expect_bridged(eps[2].itf,
pkt_intra_epg_221_to_uplink * 65,
- self.pg5)
+ eps[2].epg.uplink)
#
# Packets from the uplink are forwarded in the absence of a contract
@@ -917,9 +1038,9 @@ class TestGBP(VppTestCase):
UDP(sport=1234, dport=1234) /
Raw('\xa5' * 100))
- self.send_and_assert_no_replies(self.pg0,
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_221 * 65)
- self.send_and_assert_no_replies(self.pg0,
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_222 * 65)
#
@@ -932,10 +1053,10 @@ class TestGBP(VppTestCase):
c1 = VppGbpContract(self, 220, 221, acl_index)
c1.add_vpp_config()
- self.send_and_expect_bridged(self.pg0,
+ self.send_and_expect_bridged(eps[0].itf,
pkt_inter_epg_220_to_221 * 65,
- self.pg2)
- self.send_and_assert_no_replies(self.pg0,
+ eps[2].itf)
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_222 * 65)
#
@@ -944,18 +1065,18 @@ class TestGBP(VppTestCase):
c2 = VppGbpContract(self, 221, 220, acl_index)
c2.add_vpp_config()
- self.send_and_expect_bridged(self.pg0,
+ self.send_and_expect_bridged(eps[0].itf,
pkt_inter_epg_220_to_221 * 65,
- self.pg2)
- self.send_and_expect_bridged(self.pg2,
+ eps[2].itf)
+ self.send_and_expect_bridged(eps[2].itf,
pkt_inter_epg_221_to_220 * 65,
- self.pg0)
+ eps[0].itf)
#
# check that inter group is still disabled for the groups
# not in the contract.
#
- self.send_and_assert_no_replies(self.pg0,
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_222 * 65)
#
@@ -966,9 +1087,9 @@ class TestGBP(VppTestCase):
self.logger.info(self.vapi.cli("sh gbp contract"))
- self.send_and_expect_routed(self.pg0,
+ self.send_and_expect_routed(eps[0].itf,
pkt_inter_epg_220_to_222 * 65,
- self.pg3,
+ eps[3].itf,
self.router_mac.address)
#
@@ -979,45 +1100,53 @@ class TestGBP(VppTestCase):
c3.remove_vpp_config()
acl.remove_vpp_config()
- self.send_and_assert_no_replies(self.pg2,
+ self.send_and_assert_no_replies(eps[2].itf,
pkt_inter_epg_221_to_220 * 65)
- self.send_and_assert_no_replies(self.pg0,
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_221 * 65)
- self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
+ self.send_and_expect_bridged(eps[0].itf,
+ pkt_intra_epg * 65,
+ eps[1].itf)
#
# EPs to the outside world
#
# in the EP's RD an external subnet via the NAT EPG's recirc
- se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0,
- is_internal=False,
- sw_if_index=recirc_nat.recirc.sw_if_index,
- epg=epg_nat.epg)
+ se1 = VppGbpSubnet(
+ self, rd0, "0.0.0.0", 0,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=recirc_nat.recirc.sw_if_index,
+ epg=epg_nat.epg)
+ se2 = VppGbpSubnet(
+ self, rd0, "11.0.0.0", 8,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=recirc_nat.recirc.sw_if_index,
+ epg=epg_nat.epg)
+ se16 = VppGbpSubnet(
+ self, rd0, "::", 0,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=recirc_nat.recirc.sw_if_index,
+ epg=epg_nat.epg)
+ # in the NAT RD an external subnet via the NAT EPG's uplink
+ se3 = VppGbpSubnet(
+ self, rd20, "0.0.0.0", 0,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=epg_nat.uplink.sw_if_index,
+ epg=epg_nat.epg)
+ se36 = VppGbpSubnet(
+ self, rd20, "::", 0,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=epg_nat.uplink.sw_if_index,
+ epg=epg_nat.epg)
+ se4 = VppGbpSubnet(
+ self, rd20, "11.0.0.0", 8,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
+ sw_if_index=epg_nat.uplink.sw_if_index,
+ epg=epg_nat.epg)
se1.add_vpp_config()
- se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8,
- is_internal=False,
- sw_if_index=recirc_nat.recirc.sw_if_index,
- epg=epg_nat.epg)
se2.add_vpp_config()
- se16 = VppGbpSubnet(self, 0, "::", 0,
- is_internal=False,
- sw_if_index=recirc_nat.recirc.sw_if_index,
- epg=epg_nat.epg)
se16.add_vpp_config()
- # in the NAT RD an external subnet via the NAT EPG's uplink
- se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0,
- is_internal=False,
- sw_if_index=epg_nat.uplink.sw_if_index,
- epg=epg_nat.epg)
- se36 = VppGbpSubnet(self, 20, "::", 0,
- is_internal=False,
- sw_if_index=epg_nat.uplink.sw_if_index,
- epg=epg_nat.epg)
- se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8,
- is_internal=False,
- sw_if_index=epg_nat.uplink.sw_if_index,
- epg=epg_nat.epg)
se3.add_vpp_config()
se36.add_vpp_config()
se4.add_vpp_config()
@@ -1039,7 +1168,7 @@ class TestGBP(VppTestCase):
Raw('\xa5' * 100))
# no policy yet
- self.send_and_assert_no_replies(self.pg0,
+ self.send_and_assert_no_replies(eps[0].itf,
pkt_inter_epg_220_to_global * 65)
acl2 = VppGbpAcl(self)
@@ -1053,7 +1182,7 @@ class TestGBP(VppTestCase):
c4 = VppGbpContract(self, 220, 333, acl_index2)
c4.add_vpp_config()
- self.send_and_expect_natted(self.pg0,
+ self.send_and_expect_natted(eps[0].itf,
pkt_inter_epg_220_to_global * 65,
self.pg7,
eps[0].fip4.address)
@@ -1150,24 +1279,7 @@ class TestGBP(VppTestCase):
for epg in epgs:
# IP config on the BVI interfaces
- self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
- epg.bvi_ip4.bytes,
- 32,
- is_add=0)
- self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
- epg.bvi_ip6.bytes,
- 128,
- is_add=0,
- is_ipv6=True)
- self.logger.info(self.vapi.cli("sh int addr"))
-
- epg.uplink.set_table_ip4(0)
- epg.uplink.set_table_ip6(0)
-
if epg != epgs[0] and epg != epgs[3]:
- epg.bvi.set_table_ip4(0)
- epg.bvi.set_table_ip6(0)
-
self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
is_inside=1,
is_add=0)
@@ -1176,9 +1288,8 @@ class TestGBP(VppTestCase):
is_add=0)
for recirc in recircs:
- recirc.recirc.set_table_ip4(0)
- recirc.recirc.set_table_ip6(0)
-
+ self.vapi.sw_interface_set_l2_emulation(
+ recirc.recirc.sw_if_index, enable=0)
self.vapi.nat44_interface_add_del_feature(
recirc.recirc.sw_if_index,
is_inside=0,
@@ -1188,6 +1299,818 @@ class TestGBP(VppTestCase):
is_inside=0,
is_add=0)
+ def test_gbp_learn_l2(self):
+ """ GBP L2 Endpoint Learning """
+
+ learnt = [{'mac': '00:00:11:11:11:01',
+ 'ip': '10.0.0.1',
+ 'ip6': '2001:10::2'},
+ {'mac': '00:00:11:11:11:02',
+ 'ip': '10.0.0.2',
+ 'ip6': '2001:10::3'}]
+
+ #
+ # lower the inactive threshold so these tests pass in a
+ # reasonable amount of time
+ #
+ self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
+
+ #
+ # IP tables
+ #
+ gt4 = VppIpTable(self, 1)
+ gt4.add_vpp_config()
+ gt6 = VppIpTable(self, 1, is_ip6=True)
+ gt6.add_vpp_config()
+
+ rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
+ rd1.add_vpp_config()
+
+ #
+ # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
+ # Pg3 hosts the IP4 UU-flood VXLAN tunnel
+ # Pg4 hosts the IP6 UU-flood VXLAN tunnel
+ #
+ self.pg2.config_ip4()
+ self.pg2.resolve_arp()
+ self.pg2.generate_remote_hosts(4)
+ self.pg2.configure_ipv4_neighbors()
+ self.pg3.config_ip4()
+ self.pg3.resolve_arp()
+ self.pg4.config_ip4()
+ self.pg4.resolve_arp()
+
+ #
+ # a GBP bridge domain with a BVI and a UU-flood interface
+ #
+ bd1 = VppBridgeDomain(self, 1)
+ bd1.add_vpp_config()
+ gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
+ gbd1.add_vpp_config()
+
+ self.logger.info(self.vapi.cli("sh bridge 1 detail"))
+ self.logger.info(self.vapi.cli("sh gbp bridge"))
+
+ # ... and has a /32 applied
+ ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
+ ip_addr.add_vpp_config()
+
+ #
+ # The Endpoint-group in which we are learning endpoints
+ #
+ epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+ None, self.loop0,
+ "10.0.0.128",
+ "2001:10::128")
+ epg_220.add_vpp_config()
+ epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
+ None, self.loop1,
+ "10.0.1.128",
+ "2001:11::128")
+ epg_330.add_vpp_config()
+
+ #
+ # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
+ # leanring enabled
+ #
+ vx_tun_l2_1 = VppGbpVxlanTunnel(
+ self, 99, bd1.bd_id,
+ VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
+ vx_tun_l2_1.add_vpp_config()
+
+ #
+ # A static endpoint that the learnt endpoints are trying to
+ # talk to
+ #
+ ep = VppGbpEndpoint(self, self.pg0,
+ epg_220, None,
+ "10.0.0.127", "11.0.0.127",
+ "2001:10::1", "3001::1")
+ ep.add_vpp_config()
+
+ self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
+
+ # a packet with an sclass from an unknwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[0].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=88, flags=0x88) /
+ Ether(src=learnt[0]["mac"], dst=ep.mac) /
+ IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_assert_no_replies(self.pg2, p)
+
+ #
+ # we should not have learnt a new tunnel endpoint, since
+ # the EPG was not learnt.
+ #
+ self.assertEqual(INDEX_INVALID,
+ find_vxlan_gbp_tunnel(self,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[0].ip4,
+ 99))
+
+ # epg is not learnt, becasue the EPG is unknwon
+ self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
+
+ for ii, l in enumerate(learnt):
+ # a packet with an sclass from a knwon EPG
+ # arriving on an unknown TEP
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=220, flags=0x88) /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, [p], self.pg0)
+
+ # the new TEP
+ tep1_sw_if_index = find_vxlan_gbp_tunnel(
+ self,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ 99)
+ self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+ #
+ # the EP is learnt via the learnt TEP
+ # both from its MAC and its IP
+ #
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ ip=l['ip']))
+
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+ self.logger.info(self.vapi.cli("show gbp vxlan"))
+ self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
+
+ #
+ # If we sleep for the threshold time, the learnt endpoints should
+ # age out
+ #
+ self.sleep(2)
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ tep1_sw_if_index,
+ mac=l['mac']))
+
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+ self.logger.info(self.vapi.cli("show gbp vxlan"))
+ self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
+
+ #
+ # repeat. the do not learn bit is set so the EPs are not learnt
+ #
+ for l in learnt:
+ # a packet with an sclass from a knwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=220, flags=0x88, gpflags="D") /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, p*65, self.pg0)
+
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # repeat
+ #
+ for l in learnt:
+ # a packet with an sclass from a knwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=220, flags=0x88) /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, p*65, self.pg0)
+
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # Static EP replies to dynamics
+ #
+ self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
+ for l in learnt:
+ p = (Ether(src=ep.mac, dst=l['mac']) /
+ IP(dst=l['ip'], src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].src, self.pg2.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
+ self.assertEqual(rx[UDP].dport, 48879)
+ # the UDP source port is a random value for hashing
+ self.assertEqual(rx[VXLAN].gpid, 220)
+ self.assertEqual(rx[VXLAN].vni, 99)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ self.sleep(2)
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # repeat in the other EPG
+ # there's no contract between 220 and 330, but the A-bit is set
+ # so the packet is cleared for delivery
+ #
+ for l in learnt:
+ # a packet with an sclass from a knwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, p*65, self.pg0)
+
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # static EP cannot reach the learnt EPs since there is no contract
+ #
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+ self.logger.info(self.vapi.cli("show l2fib all"))
+ for l in learnt:
+ p = (Ether(src=ep.mac, dst=l['mac']) /
+ IP(dst=l['ip'], src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_assert_no_replies(self.pg0, [p], timeout=0.2)
+
+ #
+ # refresh the entries after the check for no replies above
+ #
+ for l in learnt:
+ # a packet with an sclass from a knwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, p*65, self.pg0)
+
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # Add the contract so they can talk
+ #
+ acl = VppGbpAcl(self)
+ rule = acl.create_rule(permit_deny=1, proto=17)
+ rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
+ acl_index = acl.add_vpp_config([rule, rule2])
+ c1 = VppGbpContract(self, 220, 330, acl_index)
+ c1.add_vpp_config()
+
+ for l in learnt:
+ p = (Ether(src=ep.mac, dst=l['mac']) /
+ IP(dst=l['ip'], src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_expect(self.pg0, [p], self.pg2)
+
+ #
+ # send UU packets from the local EP
+ #
+ self.logger.info(self.vapi.cli("sh bridge 1 detail"))
+ self.logger.info(self.vapi.cli("sh gbp bridge"))
+ p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
+ IP(dst="10.0.0.133", src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
+
+ #
+ # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
+ #
+ tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
+ "239.1.1.1", 88,
+ mcast_itf=self.pg4)
+ tun_bm.add_vpp_config()
+ bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
+ port_type=L2_PORT_TYPE.NORMAL)
+ bp_bm.add_vpp_config()
+
+ self.logger.info(self.vapi.cli("sh bridge 1 detail"))
+
+ p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
+ IP(dst="10.0.0.133", src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
+
+ #
+ # Check v6 Endpoints
+ #
+ for l in learnt:
+ # a packet with an sclass from a knwon EPG
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
+ Ether(src=l['mac'], dst=ep.mac) /
+ IPv6(src=l['ip6'], dst=ep.ip6.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, p*65, self.pg0)
+
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ #
+ # L3 Endpoint Learning
+ # - configured on the bridge's BVI
+ #
+
+ #
+ # clean up
+ #
+ self.sleep(2)
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ vx_tun_l2_1.sw_if_index,
+ mac=l['mac']))
+
+ self.pg2.unconfig_ip4()
+ self.pg3.unconfig_ip4()
+ self.pg4.unconfig_ip4()
+
+ self.logger.info(self.vapi.cli("sh int"))
+ self.logger.info(self.vapi.cli("sh gbp vxlan"))
+
+ def test_gbp_learn_l3(self):
+ """ GBP L3 Endpoint Learning """
+
+ routed_dst_mac = "00:0c:0c:0c:0c:0c"
+ routed_src_mac = "00:22:bd:f8:19:ff"
+
+ learnt = [{'mac': '00:00:11:11:11:02',
+ 'ip': '10.0.1.2',
+ 'ip6': '2001:10::2'},
+ {'mac': '00:00:11:11:11:03',
+ 'ip': '10.0.1.3',
+ 'ip6': '2001:10::3'}]
+
+ #
+ # lower the inactive threshold so these tests pass in a
+ # reasonable amount of time
+ #
+ self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
+
+ #
+ # IP tables
+ #
+ t4 = VppIpTable(self, 1)
+ t4.add_vpp_config()
+ t6 = VppIpTable(self, 1, True)
+ t6.add_vpp_config()
+
+ tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
+ self.pg4.remote_ip4, 114)
+ tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
+ self.pg4.remote_ip4, 116)
+ tun_ip4_uu.add_vpp_config()
+ tun_ip6_uu.add_vpp_config()
+
+ rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
+ rd1.add_vpp_config()
+
+ self.loop0.set_mac(self.router_mac.address)
+
+ #
+ # Bind the BVI to the RD
+ #
+ VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+ VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+
+ #
+ # Pg2 hosts the vxlan tunnel
+ # hosts on pg2 to act as TEPs
+ # pg3 is BD uu-fwd
+ # pg4 is RD uu-fwd
+ #
+ self.pg2.config_ip4()
+ self.pg2.resolve_arp()
+ self.pg2.generate_remote_hosts(4)
+ self.pg2.configure_ipv4_neighbors()
+ self.pg3.config_ip4()
+ self.pg3.resolve_arp()
+ self.pg4.config_ip4()
+ self.pg4.resolve_arp()
+
+ #
+ # a GBP bridge domain with a BVI and a UU-flood interface
+ #
+ bd1 = VppBridgeDomain(self, 1)
+ bd1.add_vpp_config()
+ gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
+ gbd1.add_vpp_config()
+
+ self.logger.info(self.vapi.cli("sh bridge 1 detail"))
+ self.logger.info(self.vapi.cli("sh gbp bridge"))
+ self.logger.info(self.vapi.cli("sh gbp route"))
+ self.logger.info(self.vapi.cli("show l2fib all"))
+
+ # ... and has a /32 and /128 applied
+ ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
+ ip4_addr.add_vpp_config()
+ ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
+ ip6_addr.add_vpp_config()
+
+ #
+ # The Endpoint-group in which we are learning endpoints
+ #
+ epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+ None, self.loop0,
+ "10.0.0.128",
+ "2001:10::128")
+ epg_220.add_vpp_config()
+
+ #
+ # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
+ # leanring enabled
+ #
+ vx_tun_l3 = VppGbpVxlanTunnel(
+ self, 101, rd1.rd_id,
+ VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
+ vx_tun_l3.add_vpp_config()
+
+ #
+ # A static endpoint that the learnt endpoints are trying to
+ # talk to
+ #
+ ep = VppGbpEndpoint(self, self.pg0,
+ epg_220, None,
+ "10.0.0.127", "11.0.0.127",
+ "2001:10::1", "3001::1")
+ ep.add_vpp_config()
+
+ #
+ # learn some remote IPv4 EPs
+ #
+ for ii, l in enumerate(learnt):
+ # a packet with an sclass from a knwon EPG
+ # arriving on an unknown TEP
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=101, gpid=220, flags=0x88) /
+ Ether(src=l['mac'], dst="00:00:00:11:11:11") /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, [p], self.pg0)
+
+ # the new TEP
+ tep1_sw_if_index = find_vxlan_gbp_tunnel(
+ self,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ vx_tun_l3.vni)
+ self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+ # endpoint learnt via the parent GBP-vxlan interface
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l3._sw_if_index,
+ ip=l['ip']))
+
+ #
+ # Static IPv4 EP replies to learnt
+ #
+ for l in learnt:
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IP(dst=l['ip'], src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].src, self.pg2.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
+ self.assertEqual(rx[UDP].dport, 48879)
+ # the UDP source port is a random value for hashing
+ self.assertEqual(rx[VXLAN].gpid, 220)
+ self.assertEqual(rx[VXLAN].vni, 101)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ inner = rx[VXLAN].payload
+
+ self.assertEqual(inner[Ether].src, routed_src_mac)
+ self.assertEqual(inner[Ether].dst, routed_dst_mac)
+ self.assertEqual(inner[IP].src, ep.ip4.address)
+ self.assertEqual(inner[IP].dst, l['ip'])
+
+ self.sleep(2)
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ tep1_sw_if_index,
+ ip=l['ip']))
+
+ #
+ # learn some remote IPv6 EPs
+ #
+ for ii, l in enumerate(learnt):
+ # a packet with an sclass from a knwon EPG
+ # arriving on an unknown TEP
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=101, gpid=220, flags=0x88) /
+ Ether(src=l['mac'], dst="00:00:00:11:11:11") /
+ IPv6(src=l['ip6'], dst=ep.ip6.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, [p], self.pg0)
+
+ # the new TEP
+ tep1_sw_if_index = find_vxlan_gbp_tunnel(
+ self,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ vx_tun_l3.vni)
+ self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+ self.logger.info(self.vapi.cli("show gbp bridge"))
+ self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
+ self.logger.info(self.vapi.cli("show gbp vxlan"))
+ self.logger.info(self.vapi.cli("show int addr"))
+
+ # endpoint learnt via the TEP
+ self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
+
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+ self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
+
+ #
+ # Static EP replies to learnt
+ #
+ for l in learnt:
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IPv6(dst=l['ip6'], src=ep.ip6.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].src, self.pg2.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
+ self.assertEqual(rx[UDP].dport, 48879)
+ # the UDP source port is a random value for hashing
+ self.assertEqual(rx[VXLAN].gpid, 220)
+ self.assertEqual(rx[VXLAN].vni, 101)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ inner = rx[VXLAN].payload
+
+ self.assertEqual(inner[Ether].src, routed_src_mac)
+ self.assertEqual(inner[Ether].dst, routed_dst_mac)
+ self.assertEqual(inner[IPv6].src, ep.ip6.address)
+ self.assertEqual(inner[IPv6].dst, l['ip6'])
+
+ self.logger.info(self.vapi.cli("sh gbp endpoint"))
+ self.sleep(2)
+ for l in learnt:
+ self.assertFalse(find_gbp_endpoint(self,
+ tep1_sw_if_index,
+ ip=l['ip']))
+
+ #
+ # Static sends to unknown EP with no route
+ #
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IP(dst="10.0.0.99", src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.send_and_assert_no_replies(self.pg0, [p])
+
+ #
+ # Add a route to static EP's v4 and v6 subnet
+ # packets should be send on the v4/v6 uu=fwd interface resp.
+ #
+ se_10_24 = VppGbpSubnet(
+ self, rd1, "10.0.0.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
+ se_10_24.add_vpp_config()
+
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IP(dst="10.0.0.99", src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, [p], self.pg4)
+ for rx in rxs:
+ self.assertEqual(rx[IP].src, self.pg4.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
+ self.assertEqual(rx[UDP].dport, 48879)
+ # the UDP source port is a random value for hashing
+ self.assertEqual(rx[VXLAN].gpid, 220)
+ self.assertEqual(rx[VXLAN].vni, 114)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ # policy is not applied to packets sent to the uu-fwd interfaces
+ self.assertFalse(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ #
+ # learn some remote IPv4 EPs
+ #
+ for ii, l in enumerate(learnt):
+ # a packet with an sclass from a knwon EPG
+ # arriving on an unknown TEP
+ p = (Ether(src=self.pg2.remote_mac,
+ dst=self.pg2.local_mac) /
+ IP(src=self.pg2.remote_hosts[1].ip4,
+ dst=self.pg2.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=101, gpid=220, flags=0x88) /
+ Ether(src=l['mac'], dst="00:00:00:11:11:11") /
+ IP(src=l['ip'], dst=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rx = self.send_and_expect(self.pg2, [p], self.pg0)
+
+ # the new TEP
+ tep1_sw_if_index = find_vxlan_gbp_tunnel(
+ self,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ vx_tun_l3.vni)
+ self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
+
+ # endpoint learnt via the parent GBP-vxlan interface
+ self.assertTrue(find_gbp_endpoint(self,
+ vx_tun_l3._sw_if_index,
+ ip=l['ip']))
+
+ #
+ # Add a remote endpoint from the API
+ #
+ rep_88 = VppGbpEndpoint(self, vx_tun_l3,
+ epg_220, None,
+ "10.0.0.88", "11.0.0.88",
+ "2001:10::88", "3001::88",
+ VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ mac=None)
+ rep_88.add_vpp_config()
+
+ #
+ # Add a remote endpoint from the API that matches an existing one
+ #
+ rep_2 = VppGbpEndpoint(self, vx_tun_l3,
+ epg_220, None,
+ learnt[0]['ip'], "11.0.0.101",
+ learnt[0]['ip6'], "3001::101",
+ VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
+ self.pg2.local_ip4,
+ self.pg2.remote_hosts[1].ip4,
+ mac=None)
+ rep_2.add_vpp_config()
+
+ #
+ # Add a route to the leanred EP's v4 subnet
+ # packets should be send on the v4/v6 uu=fwd interface resp.
+ #
+ se_10_1_24 = VppGbpSubnet(
+ self, rd1, "10.0.1.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
+ se_10_1_24.add_vpp_config()
+
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+
+ ips = ["10.0.0.88", learnt[0]['ip']]
+ for ip in ips:
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IP(dst=ip, src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].src, self.pg2.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
+ self.assertEqual(rx[UDP].dport, 48879)
+ # the UDP source port is a random value for hashing
+ self.assertEqual(rx[VXLAN].gpid, 220)
+ self.assertEqual(rx[VXLAN].vni, 101)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ inner = rx[VXLAN].payload
+
+ self.assertEqual(inner[Ether].src, routed_src_mac)
+ self.assertEqual(inner[Ether].dst, routed_dst_mac)
+ self.assertEqual(inner[IP].src, ep.ip4.address)
+ self.assertEqual(inner[IP].dst, ip)
+
+ #
+ # remove the API remote EPs, they are now UU-fwd
+ #
+ rep_88.remove_vpp_config()
+ rep_2.remove_vpp_config()
+
+ self.logger.info(self.vapi.cli("show gbp endpoint"))
+
+ for ip in ips:
+ self.assertFalse(find_gbp_endpoint(self, ip=ip))
+
+ p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
+ IP(dst=ip, src=ep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, [p], self.pg4)
+
+ #
+ # shutdown with learnt endpoint present
+ #
+ self.logger.info(self.vapi.cli("show gbp endpoint-group"))
+
+ #
+ # TODO
+ # remote endpoint becomes local
+ #
+ self.pg2.unconfig_ip4()
+ self.pg3.unconfig_ip4()
+ self.pg4.unconfig_ip4()
+
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
diff --git a/test/test_l2_flood.py b/test/test_l2_flood.py
index 5a2694cbb63..9f3ef533091 100644
--- a/test/test_l2_flood.py
+++ b/test/test_l2_flood.py
@@ -5,7 +5,7 @@ import socket
from framework import VppTestCase, VppTestRunner
from vpp_ip_route import VppIpRoute, VppRoutePath
-from vpp_papi_provider import L2_PORT_TYPE, BRIDGE_FLAGS
+from vpp_l2 import L2_PORT_TYPE, BRIDGE_FLAGS
from scapy.packet import Raw
from scapy.layers.l2 import Ether
diff --git a/test/vpp_interface.py b/test/vpp_interface.py
index c7918fcfbd2..1fe6652cfc7 100644
--- a/test/vpp_interface.py
+++ b/test/vpp_interface.py
@@ -454,3 +454,6 @@ class VppInterface(object):
"admin state")
self.test.assert_equal(if_state.link_up_down, link_up_down,
"link state")
+
+ def __str__(self):
+ return self.name
diff --git a/test/vpp_ip.py b/test/vpp_ip.py
index e92c91943db..6d22c16ff60 100644
--- a/test/vpp_ip.py
+++ b/test/vpp_ip.py
@@ -120,6 +120,10 @@ class VppIpAddress():
return self.addr.bytes
@property
+ def bytes(self):
+ return self.addr.bytes
+
+ @property
def address(self):
return self.addr.address
@@ -169,9 +173,17 @@ class VppIpPrefix():
return self.addr.address
@property
+ def bytes(self):
+ return self.addr.bytes
+
+ @property
def length(self):
return self.len
+ @property
+ def is_ip6(self):
+ return self.addr.is_ip6
+
def __str__(self):
return "%s/%d" % (self.address, self.length)
diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py
index 00a79f44232..45609e80786 100644
--- a/test/vpp_ip_route.py
+++ b/test/vpp_ip_route.py
@@ -35,6 +35,13 @@ class MplsLspMode:
UNIFORM = 1
+def ip_to_dpo_proto(addr):
+ if addr.version is 6:
+ return DpoProto.DPO_PROTO_IP6
+ else:
+ return DpoProto.DPO_PROTO_IP4
+
+
def find_route(test, ip_addr, len, table_id=0, inet=AF_INET):
if inet == AF_INET:
s = 4
@@ -71,6 +78,23 @@ def find_mroute(test, grp_addr, src_addr, grp_addr_len,
return False
+def fib_interface_ip_prefix(test, address, length, sw_if_index):
+ vp = VppIpPrefix(address, length)
+ addrs = test.vapi.ip_address_dump(sw_if_index, is_ipv6=vp.is_ip6)
+
+ if vp.is_ip6:
+ n = 16
+ else:
+ n = 4
+
+ for a in addrs:
+ if a.prefix_length == length and \
+ a.sw_if_index == sw_if_index and \
+ a.ip[:n] == vp.bytes:
+ return True
+ return False
+
+
class VppIpTable(VppObject):
def __init__(self,
@@ -95,6 +119,9 @@ class VppIpTable(VppObject):
is_add=0)
def query_vpp_config(self):
+ if self.table_id == 0:
+ # the default table always exists
+ return False
# find the default route
return find_route(self._test,
"::" if self.is_ip6 else "0.0.0.0",
@@ -111,6 +138,79 @@ class VppIpTable(VppObject):
self.table_id))
+class VppIpInterfaceAddress(VppObject):
+
+ def __init__(self, test, intf, addr, len):
+ self._test = test
+ self.intf = intf
+ self.prefix = VppIpPrefix(addr, len)
+
+ def add_vpp_config(self):
+ self._test.vapi.sw_interface_add_del_address(
+ self.intf.sw_if_index,
+ self.prefix.bytes,
+ self.prefix.length,
+ is_add=1,
+ is_ipv6=self.prefix.is_ip6)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.sw_interface_add_del_address(
+ self.intf.sw_if_index,
+ self.prefix.bytes,
+ self.prefix.length,
+ is_add=0,
+ is_ipv6=self.prefix.is_ip6)
+
+ def query_vpp_config(self):
+ return fib_interface_ip_prefix(self._test,
+ self.prefix.address,
+ self.prefix.length,
+ self.intf.sw_if_index)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "interface-ip-%s-%s" % (self.intf, self.prefix)
+
+
+class VppIpInterfaceBind(VppObject):
+
+ def __init__(self, test, intf, table):
+ self._test = test
+ self.intf = intf
+ self.table = table
+
+ def add_vpp_config(self):
+ if self.table.is_ip6:
+ self.intf.set_table_ip6(self.table.table_id)
+ else:
+ self.intf.set_table_ip4(self.table.table_id)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ if 0 == self.table.table_id:
+ return
+ if self.table.is_ip6:
+ self.intf.set_table_ip6(0)
+ else:
+ self.intf.set_table_ip4(0)
+
+ def query_vpp_config(self):
+ if 0 == self.table.table_id:
+ return False
+ return self._test.vapi.sw_interface_get_table(
+ self.intf.sw_if_index,
+ self.table.is_ip6).vrf_id == self.table.table_id
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "interface-bind-%s-%s" % (self.intf, self.table)
+
+
class VppMplsLabel(object):
def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
self.value = value
diff --git a/test/vpp_l2.py b/test/vpp_l2.py
new file mode 100644
index 00000000000..a6b43efe14c
--- /dev/null
+++ b/test/vpp_l2.py
@@ -0,0 +1,221 @@
+"""
+ L2/BD Types
+
+"""
+
+from vpp_object import *
+from util import mactobinary
+from vpp_ip import VppIpAddress
+from vpp_mac import VppMacAddress
+from vpp_lo_interface import VppLoInterface
+
+
+class L2_PORT_TYPE:
+ NORMAL = 0
+ BVI = 1
+ UU_FWD = 2
+
+
+class BRIDGE_FLAGS:
+ NONE = 0
+ LEARN = 1
+ FWD = 2
+ FLOOD = 4
+ UU_FLOOD = 8
+ ARP_TERM = 16
+
+
+def find_bridge_domain(test, bd_id):
+ bds = test.vapi.bridge_domain_dump(bd_id)
+ return len(bds) == 1
+
+
+def find_bridge_domain_port(test, bd_id, sw_if_index):
+ bds = test.vapi.bridge_domain_dump(bd_id)
+ for bd in bds:
+ for p in bd.sw_if_details:
+ if p.sw_if_index == sw_if_index:
+ return True
+ return False
+
+
+def find_bridge_domain_arp_entry(test, bd_id, mac, ip):
+ vmac = VppMacAddress(mac)
+ vip = VppIpAddress(ip)
+
+ if vip.version == 4:
+ n = 4
+ else:
+ n = 16
+
+ arps = test.vapi.bd_ip_mac_dump(bd_id)
+ for arp in arps:
+ # do IP addr comparison too once .api is fixed...
+ if vmac.bytes == arp.mac_address and \
+ vip.bytes == arp.ip_address[:n]:
+ return True
+ return False
+
+
+def find_l2_fib_entry(test, bd_id, mac, sw_if_index):
+ vmac = VppMacAddress(mac)
+ lfs = test.vapi.l2_fib_table_dump(bd_id)
+ for lf in lfs:
+ if vmac.bytes == lf.mac and sw_if_index == lf.sw_if_index:
+ return True
+ return False
+
+
+class VppBridgeDomain(VppObject):
+
+ def __init__(self, test, bd_id,
+ flood=1, uu_flood=1, forward=1,
+ learn=1, arp_term=1):
+ self._test = test
+ self.bd_id = bd_id
+ self.flood = flood
+ self.uu_flood = uu_flood
+ self.forward = forward
+ self.learn = learn
+ self.arp_term = arp_term
+
+ def add_vpp_config(self):
+ self._test.vapi.bridge_domain_add_del(
+ self.bd_id,
+ is_add=1,
+ flood=self.flood,
+ uu_flood=self.uu_flood,
+ forward=self.forward,
+ learn=self.learn,
+ arp_term=self.arp_term)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.bridge_domain_add_del(self.bd_id, is_add=0)
+
+ def query_vpp_config(self):
+ return find_bridge_domain(self._test, self.bd_id)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "bridge-domain-%d" % (self.bd_id)
+
+
+class VppBridgeDomainPort(VppObject):
+
+ def __init__(self, test, bd, itf,
+ port_type=L2_PORT_TYPE.NORMAL):
+ self._test = test
+ self.bd = bd
+ self.itf = itf
+ self.port_type = port_type
+
+ def add_vpp_config(self):
+ self._test.vapi.sw_interface_set_l2_bridge(
+ self.itf.sw_if_index,
+ self.bd.bd_id,
+ port_type=self.port_type,
+ enable=1)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.sw_interface_set_l2_bridge(
+ self.itf.sw_if_index,
+ self.bd.bd_id,
+ port_type=self.port_type,
+ enable=0)
+
+ def query_vpp_config(self):
+ return find_bridge_domain_port(self._test,
+ self.bd.bd_id,
+ self.itf.sw_if_index)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "BD-Port-%s-%s" % (self.bd, self.itf)
+
+
+class VppBridgeDomainArpEntry(VppObject):
+
+ def __init__(self, test, bd, mac, ip):
+ self._test = test
+ self.bd = bd
+ self.mac = VppMacAddress(mac)
+ self.ip = VppIpAddress(ip)
+
+ def add_vpp_config(self):
+ self._test.vapi.bd_ip_mac_add_del(
+ self.bd.bd_id,
+ self.mac.encode(),
+ self.ip.encode(),
+ is_add=1)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.bd_ip_mac_add_del(
+ self.bd.bd_id,
+ self.mac.encode(),
+ self.ip.encode(),
+ is_add=0)
+
+ def query_vpp_config(self):
+ return find_bridge_domain_arp_entry(self._test,
+ self.bd.bd_id,
+ self.mac.address,
+ self.ip.address)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "BD-Arp-Entry-%s-%s-%s" % (self.bd, self.mac, self.ip.address)
+
+
+class VppL2FibEntry(VppObject):
+
+ def __init__(self, test, bd, mac, itf,
+ static_mac=0, filter_mac=0, bvi_mac=-1):
+ self._test = test
+ self.bd = bd
+ self.mac = VppMacAddress(mac)
+ self.itf = itf
+ self.static_mac = static_mac
+ self.filter_mac = filter_mac
+ if bvi_mac == -1:
+ self.bvi_mac = isinstance(self.itf, VppLoInterface)
+ else:
+ self.bvi_mac = bvi_mac
+
+ def add_vpp_config(self):
+ self._test.vapi.l2fib_add_del(
+ self.mac.address,
+ self.bd.bd_id,
+ self.itf.sw_if_index,
+ is_add=1,
+ static_mac=self.static_mac,
+ filter_mac=self.filter_mac,
+ bvi_mac=self.bvi_mac)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.l2fib_add_del(
+ self.mac.address,
+ self.bd.bd_id,
+ self.itf.sw_if_index,
+ is_add=0)
+
+ def query_vpp_config(self):
+ return find_l2_fib_entry(self._test,
+ self.bd.bd_id,
+ self.mac.address,
+ self.itf.sw_if_index)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "L2-Fib-Entry-%s-%s-%s" % (self.bd, self.mac, self.itf)
diff --git a/test/vpp_mac.py b/test/vpp_mac.py
index c9ee11e6658..c0e69746175 100644
--- a/test/vpp_mac.py
+++ b/test/vpp_mac.py
@@ -22,3 +22,18 @@ class VppMacAddress():
@property
def address(self):
return self.addr.address
+
+ def __str__(self):
+ return self.address
+
+ def __eq__(self, other):
+ if isinstance(other, self.__class__):
+ return self.address == other.addres
+ elif hasattr(other, "bytes"):
+ # vl_api_mac_addres_t
+ return self.bytes == other.bytes
+ else:
+ raise Exception("Comparing VppMacAddress:%s"
+ "with unknown type: %s" %
+ (self, other))
+ return False
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index c2192471437..1adcc1ba24b 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -18,6 +18,7 @@ except:
if do_import:
from vpp_papi import VPP
+ from vpp_l2 import L2_PORT_TYPE
# from vnet/vnet/mpls/mpls_types.h
MPLS_IETF_MAX_LABEL = 0xfffff
@@ -43,21 +44,6 @@ class QOS_SOURCE:
IP = 3
-class L2_PORT_TYPE:
- NORMAL = 0
- BVI = 1
- UU_FWD = 2
-
-
-class BRIDGE_FLAGS:
- NONE = 0
- LEARN = 1
- FWD = 2
- FLOOD = 4
- UU_FLOOD = 8
- ARP_TERM = 16
-
-
class UnexpectedApiReturnValueError(Exception):
""" exception raised when the API return value is unexpected """
pass
@@ -257,6 +243,17 @@ class VppPapiProvider(object):
{'sw_if_index': sw_if_index, 'is_ipv6': is_ipv6,
'vrf_id': table_id})
+ def sw_interface_get_table(self, sw_if_index, is_ipv6):
+ """ Get the IPvX Table-id for the Interface
+
+ :param sw_if_index:
+ :param is_ipv6:
+ :return table_id
+
+ """
+ return self.api(self.papi.sw_interface_get_table,
+ {'sw_if_index': sw_if_index, 'is_ipv6': is_ipv6})
+
def sw_interface_add_del_address(self, sw_if_index, addr, addr_len,
is_ipv6=0, is_add=1, del_all=0):
"""
@@ -277,6 +274,11 @@ class VppPapiProvider(object):
'address_length': addr_len,
'address': addr})
+ def ip_address_dump(self, sw_if_index, is_ipv6=0):
+ return self.api(self.papi.ip_address_dump,
+ {'sw_if_index': sw_if_index,
+ 'is_ipv6': is_ipv6})
+
def sw_interface_set_unnumbered(self, sw_if_index, ip_sw_if_index,
is_add=1):
""" Set the Interface to be unnumbered
@@ -477,10 +479,13 @@ class VppPapiProvider(object):
return self.api(self.papi.bd_ip_mac_add_del,
{'bd_id': bd_id,
'is_add': is_add,
- 'is_ipv6': is_ipv6,
'ip': ip,
'mac': mac})
+ def bd_ip_mac_dump(self, bd_id):
+ return self.api(self.papi.bd_ip_mac_dump,
+ {'bd_id': bd_id})
+
def want_ip4_arp_events(self, enable_disable=1, address=0):
return self.api(self.papi.want_ip4_arp_events,
{'enable_disable': enable_disable,
@@ -647,6 +652,11 @@ class VppPapiProvider(object):
"""
return self.api(self.papi.l2fib_flush_all, {})
+ def l2_fib_table_dump(self, bd_id):
+ """ Dump the L2 FIB """
+ return self.api(self.papi.l2_fib_table_dump,
+ {'bd_id': bd_id})
+
def sw_interface_set_l2_bridge(self, sw_if_index, bd_id,
shg=0, port_type=L2_PORT_TYPE.NORMAL,
enable=1):
@@ -2771,7 +2781,6 @@ class VppPapiProvider(object):
is_add=1,
is_ipv6=0,
encap_table_id=0,
- decap_next_index=0xFFFFFFFF,
vni=0,
instance=0xFFFFFFFF):
"""
@@ -2794,7 +2803,6 @@ class VppPapiProvider(object):
'dst': dst,
'mcast_sw_if_index': mcast_sw_if_index,
'encap_table_id': encap_table_id,
- 'decap_next_index': decap_next_index,
'vni': vni,
'instance': instance}})
@@ -3482,15 +3490,22 @@ class VppPapiProvider(object):
'enable_ip6': 1 if enable_ip6 else 0,
})
- def gbp_endpoint_add(self, sw_if_index, ips, mac, epg):
+ def gbp_endpoint_add(self, sw_if_index, ips, mac, epg, flags,
+ tun_src, tun_dst):
""" GBP endpoint Add """
return self.api(self.papi.gbp_endpoint_add,
{'endpoint': {
'sw_if_index': sw_if_index,
+ 'flags': 0,
'ips': ips,
'n_ips': len(ips),
'mac': mac,
- 'epg_id': epg}})
+ 'epg_id': epg,
+ 'flags': flags,
+ 'tun': {
+ 'src': tun_src,
+ 'dst': tun_dst,
+ }}})
def gbp_endpoint_del(self, handle):
""" GBP endpoint Del """
@@ -3501,24 +3516,73 @@ class VppPapiProvider(object):
""" GBP endpoint Dump """
return self.api(self.papi.gbp_endpoint_dump, {})
- def gbp_endpoint_group_add_del(self, is_add, epg, bd,
- ip4_rd,
- ip6_rd,
- uplink_sw_if_index):
- """ GBP endpoint group Add/Del """
- return self.api(self.papi.gbp_endpoint_group_add_del,
- {'is_add': is_add,
- 'epg': {
+ def gbp_endpoint_group_add(self, epg, bd,
+ rd, uplink_sw_if_index):
+ """ GBP endpoint group Add """
+ return self.api(self.papi.gbp_endpoint_group_add,
+ {'epg':
+ {
'uplink_sw_if_index': uplink_sw_if_index,
'bd_id': bd,
- 'ip4_table_id': ip4_rd,
- 'ip6_table_id': ip6_rd,
- 'epg_id': epg}})
+ 'rd_id': rd,
+ 'epg_id': epg
+ }})
+
+ def gbp_endpoint_group_del(self, epg):
+ """ GBP endpoint group Del """
+ return self.api(self.papi.gbp_endpoint_group_del,
+ {'epg_id': epg})
def gbp_endpoint_group_dump(self):
""" GBP endpoint group Dump """
return self.api(self.papi.gbp_endpoint_group_dump, {})
+ def gbp_bridge_domain_add(self, bd_id,
+ bvi_sw_if_index,
+ uu_fwd_sw_if_index):
+ """ GBP bridge-domain Add """
+ return self.api(self.papi.gbp_bridge_domain_add,
+ {'bd':
+ {
+ 'bvi_sw_if_index': bvi_sw_if_index,
+ 'uu_fwd_sw_if_index': uu_fwd_sw_if_index,
+ 'bd_id': bd_id
+ }})
+
+ def gbp_bridge_domain_del(self, bd_id):
+ """ GBP bridge-domain Del """
+ return self.api(self.papi.gbp_bridge_domain_del,
+ {'bd_id': bd_id})
+
+ def gbp_bridge_domain_dump(self):
+ """ GBP Bridge Domain Dump """
+ return self.api(self.papi.gbp_bridge_domain_dump, {})
+
+ def gbp_route_domain_add(self, rd_id,
+ ip4_table_id,
+ ip6_table_id,
+ ip4_uu_sw_if_index,
+ ip6_uu_sw_if_index):
+ """ GBP route-domain Add """
+ return self.api(self.papi.gbp_route_domain_add,
+ {'rd':
+ {
+ 'ip4_table_id': ip4_table_id,
+ 'ip6_table_id': ip6_table_id,
+ 'ip4_uu_sw_if_index': ip4_uu_sw_if_index,
+ 'ip6_uu_sw_if_index': ip6_uu_sw_if_index,
+ 'rd_id': rd_id
+ }})
+
+ def gbp_route_domain_del(self, rd_id):
+ """ GBP route-domain Del """
+ return self.api(self.papi.gbp_route_domain_del,
+ {'rd_id': rd_id})
+
+ def gbp_route_domain_dump(self):
+ """ GBP Route Domain Dump """
+ return self.api(self.papi.gbp_route_domain_dump, {})
+
def gbp_recirc_add_del(self, is_add, sw_if_index, epg, is_ext):
""" GBP recirc Add/Del """
return self.api(self.papi.gbp_recirc_add_del,
@@ -3532,22 +3596,19 @@ class VppPapiProvider(object):
""" GBP recirc Dump """
return self.api(self.papi.gbp_recirc_dump, {})
- def gbp_subnet_add_del(self, is_add, table_id,
- is_internal,
- prefix,
+ def gbp_subnet_add_del(self, is_add, rd_id,
+ prefix, type,
sw_if_index=0xffffffff,
- epg_id=0xffff,
- is_ip6=False):
+ epg_id=0xffff):
""" GBP Subnet Add/Del """
return self.api(self.papi.gbp_subnet_add_del,
{'is_add': is_add,
'subnet': {
- 'is_internal': is_internal,
- 'is_ip6': is_ip6,
+ 'type': type,
'sw_if_index': sw_if_index,
'epg_id': epg_id,
'prefix': prefix,
- 'table_id': table_id}})
+ 'rd_id': rd_id}})
def gbp_subnet_dump(self):
""" GBP Subnet Dump """
@@ -3566,6 +3627,33 @@ class VppPapiProvider(object):
""" GBP contract Dump """
return self.api(self.papi.gbp_contract_dump, {})
+ def gbp_endpoint_learn_set_inactive_threshold(self, threshold):
+ """ GBP set inactive threshold """
+ return self.api(self.papi.gbp_endpoint_learn_set_inactive_threshold,
+ {'threshold': threshold})
+
+ def gbp_vxlan_tunnel_add(self, vni, bd_rd_id, mode):
+ """ GBP VXLAN tunnel add """
+ return self.api(self.papi.gbp_vxlan_tunnel_add,
+ {
+ 'tunnel': {
+ 'vni': vni,
+ 'mode': mode,
+ 'bd_rd_id': bd_rd_id
+ }
+ })
+
+ def gbp_vxlan_tunnel_del(self, vni):
+ """ GBP VXLAN tunnel del """
+ return self.api(self.papi.gbp_vxlan_tunnel_del,
+ {
+ 'vni': vni,
+ })
+
+ def gbp_vxlan_tunnel_dump(self):
+ """ GBP VXLAN tunnel add/del """
+ return self.api(self.papi.gbp_vxlan_tunnel_dump, {})
+
def ipip_6rd_add_tunnel(self, ip6_table_id, ip6_prefix, ip6_prefix_len,
ip4_table_id, ip4_prefix, ip4_prefix_len, ip4_src,
security_check):
diff --git a/test/vpp_vxlan_gbp_tunnel.py b/test/vpp_vxlan_gbp_tunnel.py
new file mode 100644
index 00000000000..805d4c5f3e2
--- /dev/null
+++ b/test/vpp_vxlan_gbp_tunnel.py
@@ -0,0 +1,69 @@
+
+from vpp_interface import VppInterface
+from vpp_ip import VppIpAddress
+
+
+INDEX_INVALID = 0xffffffff
+
+
+def find_vxlan_gbp_tunnel(test, src, dst, vni):
+ vsrc = VppIpAddress(src)
+ vdst = VppIpAddress(dst)
+
+ ts = test.vapi.vxlan_gbp_tunnel_dump(INDEX_INVALID)
+ for t in ts:
+ if vsrc == t.tunnel.src and \
+ vdst == t.tunnel.dst and \
+ t.tunnel.vni == vni:
+ return t.tunnel.sw_if_index
+ return INDEX_INVALID
+
+
+class VppVxlanGbpTunnel(VppInterface):
+ """
+ VPP VXLAN GBP interface
+ """
+
+ def __init__(self, test, src, dst, vni, mcast_itf=None):
+ """ Create VXLAN-GBP Tunnel interface """
+ super(VppVxlanGbpTunnel, self).__init__(test)
+ self.src = VppIpAddress(src)
+ self.dst = VppIpAddress(dst)
+ self.vni = vni
+ self.mcast_itf = mcast_itf
+
+ def add_vpp_config(self):
+ mcast_sw_if_index = INDEX_INVALID
+ if (self.mcast_itf):
+ mcast_sw_if_index = self.mcast_itf.sw_if_index
+ reply = self.test.vapi.vxlan_gbp_tunnel_add_del(
+ self.src.encode(),
+ self.dst.encode(),
+ vni=self.vni,
+ mcast_sw_if_index=mcast_sw_if_index)
+ self.set_sw_if_index(reply.sw_if_index)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ mcast_sw_if_index = INDEX_INVALID
+ if (self.mcast_itf):
+ mcast_sw_if_index = self.mcast_itf.sw_if_index
+ self.test.vapi.vxlan_gbp_tunnel_add_del(
+ self.src.encode(),
+ self.dst.encode(),
+ vni=self.vni,
+ is_add=0,
+ mcast_sw_if_index=mcast_sw_if_index)
+
+ def query_vpp_config(self):
+ return (INDEX_INVALID != find_vxlan_gbp_tunnel(self._test,
+ self.src.address,
+ self.dst.address,
+ self.vni))
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "vxlan-gbp-%d-%d-%s-%s" % (self.sw_if_index, self.vni,
+ self.src, self.dst)