tests: move plugin tests to src/plugins/*/test
[vpp.git] / src / plugins / gbp / test / test_gbp.py
1 #!/usr/bin/env python
2
3 from socket import AF_INET, AF_INET6
4 import unittest
5
6 from scapy.packet import Raw
7 from scapy.layers.l2 import Ether, ARP, Dot1Q
8 from scapy.layers.inet import IP, UDP, ICMP
9 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
10     ICMPv6ND_NA, ICMPv6EchoRequest
11 from scapy.utils6 import in6_getnsma, in6_getnsmac
12 from scapy.layers.vxlan import VXLAN
13 from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
14 from scapy.utils import inet_pton, inet_ntop
15
16 from framework import VppTestCase, VppTestRunner
17 from vpp_object import VppObject
18 from vpp_interface import VppInterface
19 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
20     VppIpInterfaceAddress, VppIpInterfaceBind, find_route, FibPathProto, \
21     FibPathType
22 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
23     VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port, VppL2Vtr
24 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
25 from vpp_ip import VppIpAddress, VppIpPrefix, DpoProto
26 from vpp_papi import VppEnum, MACAddress
27 from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \
28     VppVxlanGbpTunnel
29 from vpp_neighbor import VppNeighbor
30 try:
31     text_type = unicode
32 except NameError:
33     text_type = str
34
35 NUM_PKTS = 67
36
37
38 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None,
39                       tep=None, sclass=None):
40     if ip:
41         vip = VppIpAddress(ip)
42     if mac:
43         vmac = MACAddress(mac)
44
45     eps = test.vapi.gbp_endpoint_dump()
46
47     for ep in eps:
48         if tep:
49             src = VppIpAddress(tep[0])
50             dst = VppIpAddress(tep[1])
51             if src != ep.endpoint.tun.src or dst != ep.endpoint.tun.dst:
52                 continue
53         if sw_if_index:
54             if ep.endpoint.sw_if_index != sw_if_index:
55                 continue
56         if sclass:
57             if ep.endpoint.sclass != sclass:
58                 continue
59         if ip:
60             for eip in ep.endpoint.ips:
61                 if vip == eip:
62                     return True
63         if mac:
64             if vmac.packed == ep.endpoint.mac:
65                 return True
66
67     return False
68
69
70 def find_gbp_vxlan(test, vni):
71     ts = test.vapi.gbp_vxlan_tunnel_dump()
72     for t in ts:
73         if t.tunnel.vni == vni:
74             return True
75     return False
76
77
78 class VppGbpEndpoint(VppObject):
79     """
80     GBP Endpoint
81     """
82
83     @property
84     def mac(self):
85         return str(self.vmac)
86
87     @property
88     def ip4(self):
89         return self._ip4
90
91     @property
92     def fip4(self):
93         return self._fip4
94
95     @property
96     def ip6(self):
97         return self._ip6
98
99     @property
100     def fip6(self):
101         return self._fip6
102
103     @property
104     def ips(self):
105         return [self.ip4, self.ip6]
106
107     @property
108     def fips(self):
109         return [self.fip4, self.fip6]
110
111     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
112                  flags=0,
113                  tun_src="0.0.0.0",
114                  tun_dst="0.0.0.0",
115                  mac=True):
116         self._test = test
117         self.itf = itf
118         self.epg = epg
119         self.recirc = recirc
120
121         self._ip4 = VppIpAddress(ip4)
122         self._fip4 = VppIpAddress(fip4)
123         self._ip6 = VppIpAddress(ip6)
124         self._fip6 = VppIpAddress(fip6)
125
126         if mac:
127             self.vmac = MACAddress(self.itf.remote_mac)
128         else:
129             self.vmac = MACAddress("00:00:00:00:00:00")
130
131         self.flags = flags
132         self.tun_src = VppIpAddress(tun_src)
133         self.tun_dst = VppIpAddress(tun_dst)
134
135     def add_vpp_config(self):
136         res = self._test.vapi.gbp_endpoint_add(
137             self.itf.sw_if_index,
138             [self.ip4.encode(), self.ip6.encode()],
139             self.vmac.packed,
140             self.epg.sclass,
141             self.flags,
142             self.tun_src.encode(),
143             self.tun_dst.encode())
144         self.handle = res.handle
145         self._test.registry.register(self, self._test.logger)
146
147     def remove_vpp_config(self):
148         self._test.vapi.gbp_endpoint_del(self.handle)
149
150     def object_id(self):
151         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
152                                                 self.itf.sw_if_index,
153                                                 self.ip4.address,
154                                                 self.epg.sclass)
155
156     def query_vpp_config(self):
157         return find_gbp_endpoint(self._test,
158                                  self.itf.sw_if_index,
159                                  self.ip4.address)
160
161
162 class VppGbpRecirc(VppObject):
163     """
164     GBP Recirculation Interface
165     """
166
167     def __init__(self, test, epg, recirc, is_ext=False):
168         self._test = test
169         self.recirc = recirc
170         self.epg = epg
171         self.is_ext = is_ext
172
173     def add_vpp_config(self):
174         self._test.vapi.gbp_recirc_add_del(
175             1,
176             self.recirc.sw_if_index,
177             self.epg.sclass,
178             self.is_ext)
179         self._test.registry.register(self, self._test.logger)
180
181     def remove_vpp_config(self):
182         self._test.vapi.gbp_recirc_add_del(
183             0,
184             self.recirc.sw_if_index,
185             self.epg.sclass,
186             self.is_ext)
187
188     def object_id(self):
189         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
190
191     def query_vpp_config(self):
192         rs = self._test.vapi.gbp_recirc_dump()
193         for r in rs:
194             if r.recirc.sw_if_index == self.recirc.sw_if_index:
195                 return True
196         return False
197
198
199 class VppGbpExtItf(VppObject):
200     """
201     GBP ExtItfulation Interface
202     """
203
204     def __init__(self, test, itf, bd, rd, anon=False):
205         self._test = test
206         self.itf = itf
207         self.bd = bd
208         self.rd = rd
209         self.flags = 1 if anon else 0
210
211     def add_vpp_config(self):
212         self._test.vapi.gbp_ext_itf_add_del(
213             1, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
214         self._test.registry.register(self, self._test.logger)
215
216     def remove_vpp_config(self):
217         self._test.vapi.gbp_ext_itf_add_del(
218             0, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
219
220     def object_id(self):
221         return "gbp-ext-itf:[%d]%s" % (self.itf.sw_if_index,
222                                        " [anon]" if self.flags else "")
223
224     def query_vpp_config(self):
225         rs = self._test.vapi.gbp_ext_itf_dump()
226         for r in rs:
227             if r.ext_itf.sw_if_index == self.itf.sw_if_index:
228                 return True
229         return False
230
231
232 class VppGbpSubnet(VppObject):
233     """
234     GBP Subnet
235     """
236
237     def __init__(self, test, rd, address, address_len,
238                  type, sw_if_index=None, sclass=None):
239         self._test = test
240         self.rd_id = rd.rd_id
241         self.prefix = VppIpPrefix(address, address_len)
242         self.type = type
243         self.sw_if_index = sw_if_index
244         self.sclass = sclass
245
246     def add_vpp_config(self):
247         self._test.vapi.gbp_subnet_add_del(
248             1,
249             self.rd_id,
250             self.prefix.encode(),
251             self.type,
252             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
253             sclass=self.sclass if self.sclass else 0xffff)
254         self._test.registry.register(self, self._test.logger)
255
256     def remove_vpp_config(self):
257         self._test.vapi.gbp_subnet_add_del(
258             0,
259             self.rd_id,
260             self.prefix.encode(),
261             self.type)
262
263     def object_id(self):
264         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
265
266     def query_vpp_config(self):
267         ss = self._test.vapi.gbp_subnet_dump()
268         for s in ss:
269             if s.subnet.rd_id == self.rd_id and \
270                     s.subnet.type == self.type and \
271                     s.subnet.prefix == self.prefix:
272                 return True
273         return False
274
275
276 class VppGbpEndpointRetention(object):
277     def __init__(self, remote_ep_timeout=0xffffffff):
278         self.remote_ep_timeout = remote_ep_timeout
279
280     def encode(self):
281         return {'remote_ep_timeout': self.remote_ep_timeout}
282
283
284 class VppGbpEndpointGroup(VppObject):
285     """
286     GBP Endpoint Group
287     """
288
289     def __init__(self, test, vnid, sclass, rd, bd, uplink,
290                  bvi, bvi_ip4, bvi_ip6=None,
291                  retention=VppGbpEndpointRetention()):
292         self._test = test
293         self.uplink = uplink
294         self.bvi = bvi
295         self.bvi_ip4 = VppIpAddress(bvi_ip4)
296         self.bvi_ip6 = VppIpAddress(bvi_ip6)
297         self.vnid = vnid
298         self.bd = bd
299         self.rd = rd
300         self.sclass = sclass
301         if 0 == self.sclass:
302             self.sclass = 0xffff
303         self.retention = retention
304
305     def add_vpp_config(self):
306         self._test.vapi.gbp_endpoint_group_add(
307             self.vnid,
308             self.sclass,
309             self.bd.bd.bd_id,
310             self.rd.rd_id,
311             self.uplink.sw_if_index if self.uplink else INDEX_INVALID,
312             self.retention.encode())
313         self._test.registry.register(self, self._test.logger)
314
315     def remove_vpp_config(self):
316         self._test.vapi.gbp_endpoint_group_del(self.sclass)
317
318     def object_id(self):
319         return "gbp-endpoint-group:[%d]" % (self.vnid)
320
321     def query_vpp_config(self):
322         epgs = self._test.vapi.gbp_endpoint_group_dump()
323         for epg in epgs:
324             if epg.epg.vnid == self.vnid:
325                 return True
326         return False
327
328
329 class VppGbpBridgeDomain(VppObject):
330     """
331     GBP Bridge Domain
332     """
333
334     def __init__(self, test, bd, rd, bvi, uu_fwd=None,
335                  bm_flood=None, learn=True,
336                  uu_drop=False, bm_drop=False,
337                  ucast_arp=False):
338         self._test = test
339         self.bvi = bvi
340         self.uu_fwd = uu_fwd
341         self.bm_flood = bm_flood
342         self.bd = bd
343         self.rd = rd
344
345         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
346
347         self.flags = e.GBP_BD_API_FLAG_NONE
348         if not learn:
349             self.flags |= e.GBP_BD_API_FLAG_DO_NOT_LEARN
350         if uu_drop:
351             self.flags |= e.GBP_BD_API_FLAG_UU_FWD_DROP
352         if bm_drop:
353             self.flags |= e.GBP_BD_API_FLAG_MCAST_DROP
354         if ucast_arp:
355             self.flags |= e.GBP_BD_API_FLAG_UCAST_ARP
356
357     def add_vpp_config(self):
358         self._test.vapi.gbp_bridge_domain_add(
359             self.bd.bd_id,
360             self.rd.rd_id,
361             self.flags,
362             self.bvi.sw_if_index,
363             self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID,
364             self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID)
365         self._test.registry.register(self, self._test.logger)
366
367     def remove_vpp_config(self):
368         self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
369
370     def object_id(self):
371         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
372
373     def query_vpp_config(self):
374         bds = self._test.vapi.gbp_bridge_domain_dump()
375         for bd in bds:
376             if bd.bd.bd_id == self.bd.bd_id:
377                 return True
378         return False
379
380
381 class VppGbpRouteDomain(VppObject):
382     """
383     GBP Route Domain
384     """
385
386     def __init__(self, test, rd_id, scope, t4, t6, ip4_uu=None, ip6_uu=None):
387         self._test = test
388         self.rd_id = rd_id
389         self.scope = scope
390         self.t4 = t4
391         self.t6 = t6
392         self.ip4_uu = ip4_uu
393         self.ip6_uu = ip6_uu
394
395     def add_vpp_config(self):
396         self._test.vapi.gbp_route_domain_add(
397             self.rd_id,
398             self.scope,
399             self.t4.table_id,
400             self.t6.table_id,
401             self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
402             self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
403         self._test.registry.register(self, self._test.logger)
404
405     def remove_vpp_config(self):
406         self._test.vapi.gbp_route_domain_del(self.rd_id)
407
408     def object_id(self):
409         return "gbp-route-domain:[%d]" % (self.rd_id)
410
411     def query_vpp_config(self):
412         rds = self._test.vapi.gbp_route_domain_dump()
413         for rd in rds:
414             if rd.rd.rd_id == self.rd_id:
415                 return True
416         return False
417
418
419 class VppGbpContractNextHop():
420     def __init__(self, mac, bd, ip, rd):
421         self.mac = mac
422         self.ip = ip
423         self.bd = bd
424         self.rd = rd
425
426     def encode(self):
427         return {'ip': self.ip.encode(),
428                 'mac': self.mac.packed,
429                 'bd_id': self.bd.bd.bd_id,
430                 'rd_id': self.rd.rd_id}
431
432
433 class VppGbpContractRule():
434     def __init__(self, action, hash_mode, nhs=None):
435         self.action = action
436         self.hash_mode = hash_mode
437         self.nhs = [] if nhs is None else nhs
438
439     def encode(self):
440         nhs = []
441         for nh in self.nhs:
442             nhs.append(nh.encode())
443         while len(nhs) < 8:
444             nhs.append({})
445         return {'action': self.action,
446                 'nh_set': {
447                     'hash_mode': self.hash_mode,
448                     'n_nhs': len(self.nhs),
449                     'nhs': nhs}}
450
451     def __repr__(self):
452         return '<VppGbpContractRule action=%s, hash_mode=%s>' % (
453             self.action, self.hash_mode)
454
455
456 class VppGbpContract(VppObject):
457     """
458     GBP Contract
459     """
460
461     def __init__(self, test, scope, sclass, dclass, acl_index,
462                  rules, allowed_ethertypes):
463         self._test = test
464         if not isinstance(rules, list):
465             raise ValueError("'rules' must be a list.")
466         if not isinstance(allowed_ethertypes, list):
467             raise ValueError("'allowed_ethertypes' must be a list.")
468         self.scope = scope
469         self.acl_index = acl_index
470         self.sclass = sclass
471         self.dclass = dclass
472         self.rules = rules
473         self.allowed_ethertypes = allowed_ethertypes
474         while (len(self.allowed_ethertypes) < 16):
475             self.allowed_ethertypes.append(0)
476
477     def add_vpp_config(self):
478         rules = []
479         for r in self.rules:
480             rules.append(r.encode())
481         r = self._test.vapi.gbp_contract_add_del(
482             is_add=1,
483             contract={
484                 'acl_index': self.acl_index,
485                 'scope': self.scope,
486                 'sclass': self.sclass,
487                 'dclass': self.dclass,
488                 'n_rules': len(rules),
489                 'rules': rules,
490                 'n_ether_types': len(self.allowed_ethertypes),
491                 'allowed_ethertypes': self.allowed_ethertypes})
492         self.stats_index = r.stats_index
493         self._test.registry.register(self, self._test.logger)
494
495     def remove_vpp_config(self):
496         self._test.vapi.gbp_contract_add_del(
497             is_add=0,
498             contract={
499                 'acl_index': self.acl_index,
500                 'scope': self.scope,
501                 'sclass': self.sclass,
502                 'dclass': self.dclass,
503                 'n_rules': 0,
504                 'rules': [],
505                 'n_ether_types': len(self.allowed_ethertypes),
506                 'allowed_ethertypes': self.allowed_ethertypes})
507
508     def object_id(self):
509         return "gbp-contract:[%d:%d:%d:%d]" % (self.scope,
510                                                self.sclass,
511                                                self.dclass,
512                                                self.acl_index)
513
514     def query_vpp_config(self):
515         cs = self._test.vapi.gbp_contract_dump()
516         for c in cs:
517             if c.contract.scope == self.scope \
518                and c.contract.sclass == self.sclass \
519                and c.contract.dclass == self.dclass:
520                 return True
521         return False
522
523     def get_drop_stats(self):
524         c = self._test.statistics.get_counter("/net/gbp/contract/drop")
525         return c[0][self.stats_index]
526
527     def get_permit_stats(self):
528         c = self._test.statistics.get_counter("/net/gbp/contract/permit")
529         return c[0][self.stats_index]
530
531
532 class VppGbpVxlanTunnel(VppInterface):
533     """
534     GBP VXLAN tunnel
535     """
536
537     def __init__(self, test, vni, bd_rd_id, mode, src):
538         super(VppGbpVxlanTunnel, self).__init__(test)
539         self._test = test
540         self.vni = vni
541         self.bd_rd_id = bd_rd_id
542         self.mode = mode
543         self.src = src
544
545     def add_vpp_config(self):
546         r = self._test.vapi.gbp_vxlan_tunnel_add(
547             self.vni,
548             self.bd_rd_id,
549             self.mode,
550             self.src)
551         self.set_sw_if_index(r.sw_if_index)
552         self._test.registry.register(self, self._test.logger)
553
554     def remove_vpp_config(self):
555         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
556
557     def object_id(self):
558         return "gbp-vxlan:%d" % (self.sw_if_index)
559
560     def query_vpp_config(self):
561         return find_gbp_vxlan(self._test, self.vni)
562
563
564 class VppGbpAcl(VppObject):
565     """
566     GBP Acl
567     """
568
569     def __init__(self, test):
570         self._test = test
571         self.acl_index = 4294967295
572
573     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
574                     s_prefix=0, s_ip=b'\x00\x00\x00\x00', sport_from=0,
575                     sport_to=65535, d_prefix=0, d_ip=b'\x00\x00\x00\x00',
576                     dport_from=0, dport_to=65535):
577         if proto == -1 or proto == 0:
578             sport_to = 0
579             dport_to = sport_to
580         elif proto == 1 or proto == 58:
581             sport_to = 255
582             dport_to = sport_to
583         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
584                  'srcport_or_icmptype_first': sport_from,
585                  'srcport_or_icmptype_last': sport_to,
586                  'src_ip_prefix_len': s_prefix,
587                  'src_ip_addr': s_ip,
588                  'dstport_or_icmpcode_first': dport_from,
589                  'dstport_or_icmpcode_last': dport_to,
590                  'dst_ip_prefix_len': d_prefix,
591                  'dst_ip_addr': d_ip})
592         return rule
593
594     def add_vpp_config(self, rules):
595
596         reply = self._test.vapi.acl_add_replace(acl_index=self.acl_index,
597                                                 r=rules,
598                                                 tag=b'GBPTest')
599         self.acl_index = reply.acl_index
600         return self.acl_index
601
602     def remove_vpp_config(self):
603         self._test.vapi.acl_del(self.acl_index)
604
605     def object_id(self):
606         return "gbp-acl:[%d]" % (self.acl_index)
607
608     def query_vpp_config(self):
609         cs = self._test.vapi.acl_dump()
610         for c in cs:
611             if c.acl_index == self.acl_index:
612                 return True
613         return False
614
615
616 class TestGBP(VppTestCase):
617     """ GBP Test Case """
618
619     @property
620     def config_flags(self):
621         return VppEnum.vl_api_nat_config_flags_t
622
623     @classmethod
624     def setUpClass(cls):
625         super(TestGBP, cls).setUpClass()
626
627     @classmethod
628     def tearDownClass(cls):
629         super(TestGBP, cls).tearDownClass()
630
631     def setUp(self):
632         super(TestGBP, self).setUp()
633
634         self.create_pg_interfaces(range(9))
635         self.create_loopback_interfaces(8)
636
637         self.router_mac = MACAddress("00:11:22:33:44:55")
638
639         for i in self.pg_interfaces:
640             i.admin_up()
641         for i in self.lo_interfaces:
642             i.admin_up()
643
644         self.vlan_100 = VppDot1QSubint(self, self.pg0, 100)
645         self.vlan_100.admin_up()
646         self.vlan_101 = VppDot1QSubint(self, self.pg0, 101)
647         self.vlan_101.admin_up()
648         self.vlan_102 = VppDot1QSubint(self, self.pg0, 102)
649         self.vlan_102.admin_up()
650
651     def tearDown(self):
652         for i in self.pg_interfaces:
653             i.admin_down()
654         super(TestGBP, self).tearDown()
655         self.vlan_102.remove_vpp_config()
656         self.vlan_101.remove_vpp_config()
657         self.vlan_100.remove_vpp_config()
658
659     def send_and_expect_bridged(self, src, tx, dst):
660         rx = self.send_and_expect(src, tx, dst)
661
662         for r in rx:
663             self.assertEqual(r[Ether].src, tx[0][Ether].src)
664             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
665             self.assertEqual(r[IP].src, tx[0][IP].src)
666             self.assertEqual(r[IP].dst, tx[0][IP].dst)
667         return rx
668
669     def send_and_expect_bridged6(self, src, tx, dst):
670         rx = self.send_and_expect(src, tx, dst)
671
672         for r in rx:
673             self.assertEqual(r[Ether].src, tx[0][Ether].src)
674             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
675             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
676             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
677         return rx
678
679     def send_and_expect_routed(self, src, tx, dst, src_mac):
680         rx = self.send_and_expect(src, tx, dst)
681
682         for r in rx:
683             self.assertEqual(r[Ether].src, src_mac)
684             self.assertEqual(r[Ether].dst, dst.remote_mac)
685             self.assertEqual(r[IP].src, tx[0][IP].src)
686             self.assertEqual(r[IP].dst, tx[0][IP].dst)
687         return rx
688
689     def send_and_expect_routed6(self, src, tx, dst, src_mac):
690         rx = self.send_and_expect(src, tx, dst)
691
692         for r in rx:
693             self.assertEqual(r[Ether].src, src_mac)
694             self.assertEqual(r[Ether].dst, dst.remote_mac)
695             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
696             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
697         return rx
698
699     def send_and_expect_natted(self, src, tx, dst, src_ip):
700         rx = self.send_and_expect(src, tx, dst)
701
702         for r in rx:
703             self.assertEqual(r[Ether].src, tx[0][Ether].src)
704             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
705             self.assertEqual(r[IP].src, src_ip)
706             self.assertEqual(r[IP].dst, tx[0][IP].dst)
707         return rx
708
709     def send_and_expect_natted6(self, src, tx, dst, src_ip):
710         rx = self.send_and_expect(src, tx, dst)
711
712         for r in rx:
713             self.assertEqual(r[Ether].src, tx[0][Ether].src)
714             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
715             self.assertEqual(r[IPv6].src, src_ip)
716             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
717         return rx
718
719     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
720         rx = self.send_and_expect(src, tx, dst)
721
722         for r in rx:
723             self.assertEqual(r[Ether].src, tx[0][Ether].src)
724             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
725             self.assertEqual(r[IP].dst, dst_ip)
726             self.assertEqual(r[IP].src, tx[0][IP].src)
727         return rx
728
729     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
730         rx = self.send_and_expect(src, tx, dst)
731
732         for r in rx:
733             self.assertEqual(r[Ether].src, tx[0][Ether].src)
734             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
735             self.assertEqual(r[IPv6].dst, dst_ip)
736             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
737         return rx
738
739     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
740         rx = self.send_and_expect(src, tx, dst)
741
742         for r in rx:
743             self.assertEqual(r[Ether].src, str(self.router_mac))
744             self.assertEqual(r[Ether].dst, dst.remote_mac)
745             self.assertEqual(r[IP].dst, dst_ip)
746             self.assertEqual(r[IP].src, src_ip)
747         return rx
748
749     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
750         rx = self.send_and_expect(src, tx, dst)
751
752         for r in rx:
753             self.assertEqual(r[Ether].src, str(self.router_mac))
754             self.assertEqual(r[Ether].dst, dst.remote_mac)
755             self.assertEqual(r[IPv6].dst, dst_ip)
756             self.assertEqual(r[IPv6].src, src_ip)
757         return rx
758
759     def send_and_expect_no_arp(self, src, tx, dst):
760         self.pg_send(src, tx)
761         dst.get_capture(0, timeout=1)
762         dst.assert_nothing_captured(remark="")
763         timeout = 0.1
764
765     def send_and_expect_arp(self, src, tx, dst):
766         rx = self.send_and_expect(src, tx, dst)
767
768         for r in rx:
769             self.assertEqual(r[Ether].src, tx[0][Ether].src)
770             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
771             self.assertEqual(r[ARP].psrc, tx[0][ARP].psrc)
772             self.assertEqual(r[ARP].pdst, tx[0][ARP].pdst)
773             self.assertEqual(r[ARP].hwsrc, tx[0][ARP].hwsrc)
774             self.assertEqual(r[ARP].hwdst, tx[0][ARP].hwdst)
775         return rx
776
777     def test_gbp(self):
778         """ Group Based Policy """
779
780         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
781
782         #
783         # Route Domains
784         #
785         gt4 = VppIpTable(self, 0)
786         gt4.add_vpp_config()
787         gt6 = VppIpTable(self, 0, is_ip6=True)
788         gt6.add_vpp_config()
789         nt4 = VppIpTable(self, 20)
790         nt4.add_vpp_config()
791         nt6 = VppIpTable(self, 20, is_ip6=True)
792         nt6.add_vpp_config()
793
794         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
795         rd20 = VppGbpRouteDomain(self, 20, 420, nt4, nt6, None, None)
796
797         rd0.add_vpp_config()
798         rd20.add_vpp_config()
799
800         #
801         # Bridge Domains
802         #
803         bd1 = VppBridgeDomain(self, 1)
804         bd2 = VppBridgeDomain(self, 2)
805         bd20 = VppBridgeDomain(self, 20)
806
807         bd1.add_vpp_config()
808         bd2.add_vpp_config()
809         bd20.add_vpp_config()
810
811         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
812         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
813         gbd20 = VppGbpBridgeDomain(self, bd20, rd20, self.loop2)
814
815         gbd1.add_vpp_config()
816         gbd2.add_vpp_config()
817         gbd20.add_vpp_config()
818
819         #
820         # 3 EPGs, 2 of which share a BD.
821         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
822         #
823         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
824                                     self.pg4, self.loop0,
825                                     "10.0.0.128", "2001:10::128"),
826                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
827                                     self.pg5, self.loop0,
828                                     "10.0.1.128", "2001:10:1::128"),
829                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
830                                     self.pg6, self.loop1,
831                                     "10.0.2.128", "2001:10:2::128"),
832                 VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20,
833                                     self.pg7, self.loop2,
834                                     "11.0.0.128", "3001::128"),
835                 VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20,
836                                     self.pg8, self.loop2,
837                                     "11.0.0.129", "3001::129")]
838         recircs = [VppGbpRecirc(self, epgs[0], self.loop3),
839                    VppGbpRecirc(self, epgs[1], self.loop4),
840                    VppGbpRecirc(self, epgs[2], self.loop5),
841                    VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True),
842                    VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)]
843
844         epg_nat = epgs[3]
845         recirc_nat = recircs[3]
846
847         #
848         # 4 end-points, 2 in the same subnet, 3 in the same BD
849         #
850         eps = [VppGbpEndpoint(self, self.pg0,
851                               epgs[0], recircs[0],
852                               "10.0.0.1", "11.0.0.1",
853                               "2001:10::1", "3001::1"),
854                VppGbpEndpoint(self, self.pg1,
855                               epgs[0], recircs[0],
856                               "10.0.0.2", "11.0.0.2",
857                               "2001:10::2", "3001::2"),
858                VppGbpEndpoint(self, self.pg2,
859                               epgs[1], recircs[1],
860                               "10.0.1.1", "11.0.0.3",
861                               "2001:10:1::1", "3001::3"),
862                VppGbpEndpoint(self, self.pg3,
863                               epgs[2], recircs[2],
864                               "10.0.2.1", "11.0.0.4",
865                               "2001:10:2::1", "3001::4")]
866
867         #
868         # Config related to each of the EPGs
869         #
870         for epg in epgs:
871             # IP config on the BVI interfaces
872             if epg != epgs[1] and epg != epgs[4]:
873                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
874                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
875                 self.vapi.sw_interface_set_mac_address(
876                     epg.bvi.sw_if_index,
877                     self.router_mac.packed)
878
879                 # The BVIs are NAT inside interfaces
880                 flags = self.config_flags.NAT_IS_INSIDE
881                 self.vapi.nat44_interface_add_del_feature(
882                     sw_if_index=epg.bvi.sw_if_index,
883                     flags=flags, is_add=1)
884                 self.vapi.nat66_add_del_interface(
885                     is_add=1, flags=flags,
886                     sw_if_index=epg.bvi.sw_if_index)
887
888             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
889             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
890             if_ip4.add_vpp_config()
891             if_ip6.add_vpp_config()
892
893             # EPG uplink interfaces in the RD
894             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
895             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
896
897             # add the BD ARP termination entry for BVI IP
898             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
899                                                      str(self.router_mac),
900                                                      epg.bvi_ip4.address)
901             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
902                                                      str(self.router_mac),
903                                                      epg.bvi_ip6.address)
904             epg.bd_arp_ip4.add_vpp_config()
905             epg.bd_arp_ip6.add_vpp_config()
906
907             # EPG in VPP
908             epg.add_vpp_config()
909
910         for recirc in recircs:
911             # EPG's ingress recirculation interface maps to its RD
912             VppIpInterfaceBind(self, recirc.recirc,
913                                recirc.epg.rd.t4).add_vpp_config()
914             VppIpInterfaceBind(self, recirc.recirc,
915                                recirc.epg.rd.t6).add_vpp_config()
916
917             self.vapi.nat44_interface_add_del_feature(
918                 sw_if_index=recirc.recirc.sw_if_index, is_add=1)
919             self.vapi.nat66_add_del_interface(
920                 is_add=1,
921                 sw_if_index=recirc.recirc.sw_if_index)
922
923             recirc.add_vpp_config()
924
925         for recirc in recircs:
926             self.assertTrue(find_bridge_domain_port(self,
927                                                     recirc.epg.bd.bd.bd_id,
928                                                     recirc.recirc.sw_if_index))
929
930         for ep in eps:
931             self.pg_enable_capture(self.pg_interfaces)
932             self.pg_start()
933             #
934             # routes to the endpoints. We need these since there are no
935             # adj-fibs due to the fact the the BVI address has /32 and
936             # the subnet is not attached.
937             #
938             for (ip, fip) in zip(ep.ips, ep.fips):
939                 # Add static mappings for each EP from the 10/8 to 11/8 network
940                 if ip.af == AF_INET:
941                     flags = self.config_flags.NAT_IS_ADDR_ONLY
942                     self.vapi.nat44_add_del_static_mapping(
943                         is_add=1,
944                         local_ip_address=ip.bytes,
945                         external_ip_address=fip.bytes,
946                         external_sw_if_index=0xFFFFFFFF,
947                         vrf_id=0,
948                         flags=flags)
949                 else:
950                     self.vapi.nat66_add_del_static_mapping(
951                         local_ip_address=ip.bytes,
952                         external_ip_address=fip.bytes,
953                         vrf_id=0, is_add=1)
954
955             # VPP EP create ...
956             ep.add_vpp_config()
957
958             self.logger.info(self.vapi.cli("sh gbp endpoint"))
959
960             # ... results in a Gratuitous ARP/ND on the EPG's uplink
961             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
962
963             for ii, ip in enumerate(ep.ips):
964                 p = rx[ii]
965
966                 if ip.is_ip6:
967                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
968                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
969                 else:
970                     self.assertTrue(p.haslayer(ARP))
971                     self.assertEqual(p[ARP].psrc, ip.address)
972                     self.assertEqual(p[ARP].pdst, ip.address)
973
974             # add the BD ARP termination entry for floating IP
975             for fip in ep.fips:
976                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac,
977                                              fip.address)
978                 ba.add_vpp_config()
979
980                 # floating IPs route via EPG recirc
981                 r = VppIpRoute(
982                     self, fip.address, fip.length,
983                     [VppRoutePath(fip.address,
984                                   ep.recirc.recirc.sw_if_index,
985                                   type=FibPathType.FIB_PATH_TYPE_DVR,
986                                   proto=fip.dpo_proto)],
987                     table_id=20)
988                 r.add_vpp_config()
989
990             # L2 FIB entries in the NAT EPG BD to bridge the packets from
991             # the outside direct to the internal EPG
992             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
993                                ep.recirc.recirc, bvi_mac=0)
994             lf.add_vpp_config()
995
996         #
997         # ARP packets for unknown IP are sent to the EPG uplink
998         #
999         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
1000                          src=self.pg0.remote_mac) /
1001                    ARP(op="who-has",
1002                        hwdst="ff:ff:ff:ff:ff:ff",
1003                        hwsrc=self.pg0.remote_mac,
1004                        pdst="10.0.0.88",
1005                        psrc="10.0.0.99"))
1006
1007         self.vapi.cli("clear trace")
1008         self.pg0.add_stream(pkt_arp)
1009
1010         self.pg_enable_capture(self.pg_interfaces)
1011         self.pg_start()
1012
1013         rxd = epgs[0].uplink.get_capture(1)
1014
1015         #
1016         # ARP/ND packets get a response
1017         #
1018         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
1019                          src=self.pg0.remote_mac) /
1020                    ARP(op="who-has",
1021                        hwdst="ff:ff:ff:ff:ff:ff",
1022                        hwsrc=self.pg0.remote_mac,
1023                        pdst=epgs[0].bvi_ip4.address,
1024                        psrc=eps[0].ip4.address))
1025
1026         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
1027
1028         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
1029         d = inet_ntop(AF_INET6, nsma)
1030         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
1031                         src=self.pg0.remote_mac) /
1032                   IPv6(dst=d, src=eps[0].ip6.address) /
1033                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
1034                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
1035         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
1036
1037         #
1038         # broadcast packets are flooded
1039         #
1040         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
1041                            src=self.pg0.remote_mac) /
1042                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
1043                      UDP(sport=1234, dport=1234) /
1044                      Raw('\xa5' * 100))
1045
1046         self.vapi.cli("clear trace")
1047         self.pg0.add_stream(pkt_bcast)
1048
1049         self.pg_enable_capture(self.pg_interfaces)
1050         self.pg_start()
1051
1052         rxd = eps[1].itf.get_capture(1)
1053         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1054         rxd = epgs[0].uplink.get_capture(1)
1055         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1056
1057         #
1058         # packets to non-local L3 destinations dropped
1059         #
1060         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
1061                                        dst=str(self.router_mac)) /
1062                                  IP(src=eps[0].ip4.address,
1063                                     dst="10.0.0.99") /
1064                                  UDP(sport=1234, dport=1234) /
1065                                  Raw('\xa5' * 100))
1066         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
1067                                        dst=str(self.router_mac)) /
1068                                  IP(src=eps[0].ip4.address,
1069                                     dst="10.0.1.99") /
1070                                  UDP(sport=1234, dport=1234) /
1071                                  Raw('\xa5' * 100))
1072
1073         self.send_and_assert_no_replies(self.pg0,
1074                                         pkt_intra_epg_220_ip4 * NUM_PKTS)
1075
1076         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
1077                                        dst=str(self.router_mac)) /
1078                                  IPv6(src=eps[0].ip6.address,
1079                                       dst="2001:10::99") /
1080                                  UDP(sport=1234, dport=1234) /
1081                                  Raw('\xa5' * 100))
1082         self.send_and_assert_no_replies(self.pg0,
1083                                         pkt_inter_epg_222_ip6 * NUM_PKTS)
1084
1085         #
1086         # Add the subnet routes
1087         #
1088         s41 = VppGbpSubnet(
1089             self, rd0, "10.0.0.0", 24,
1090             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1091         s42 = VppGbpSubnet(
1092             self, rd0, "10.0.1.0", 24,
1093             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1094         s43 = VppGbpSubnet(
1095             self, rd0, "10.0.2.0", 24,
1096             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1097         s61 = VppGbpSubnet(
1098             self, rd0, "2001:10::1", 64,
1099             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1100         s62 = VppGbpSubnet(
1101             self, rd0, "2001:10:1::1", 64,
1102             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1103         s63 = VppGbpSubnet(
1104             self, rd0, "2001:10:2::1", 64,
1105             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1106         s41.add_vpp_config()
1107         s42.add_vpp_config()
1108         s43.add_vpp_config()
1109         s61.add_vpp_config()
1110         s62.add_vpp_config()
1111         s63.add_vpp_config()
1112
1113         self.send_and_expect_bridged(eps[0].itf,
1114                                      pkt_intra_epg_220_ip4 * NUM_PKTS,
1115                                      eps[0].epg.uplink)
1116         self.send_and_expect_bridged(eps[0].itf,
1117                                      pkt_inter_epg_222_ip4 * NUM_PKTS,
1118                                      eps[0].epg.uplink)
1119         self.send_and_expect_bridged6(eps[0].itf,
1120                                       pkt_inter_epg_222_ip6 * NUM_PKTS,
1121                                       eps[0].epg.uplink)
1122
1123         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1124         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1125         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1126         self.logger.info(self.vapi.cli("sh gbp recirc"))
1127         self.logger.info(self.vapi.cli("sh int"))
1128         self.logger.info(self.vapi.cli("sh int addr"))
1129         self.logger.info(self.vapi.cli("sh int feat loop6"))
1130         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1131         self.logger.info(self.vapi.cli("sh int feat loop3"))
1132         self.logger.info(self.vapi.cli("sh int feat pg0"))
1133
1134         #
1135         # Packet destined to unknown unicast is sent on the epg uplink ...
1136         #
1137         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1138                                              dst="00:00:00:33:44:55") /
1139                                        IP(src=eps[0].ip4.address,
1140                                           dst="10.0.0.99") /
1141                                        UDP(sport=1234, dport=1234) /
1142                                        Raw('\xa5' * 100))
1143
1144         self.send_and_expect_bridged(eps[0].itf,
1145                                      pkt_intra_epg_220_to_uplink * NUM_PKTS,
1146                                      eps[0].epg.uplink)
1147         # ... and nowhere else
1148         self.pg1.get_capture(0, timeout=0.1)
1149         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1150
1151         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1152                                              dst="00:00:00:33:44:66") /
1153                                        IP(src=eps[0].ip4.address,
1154                                           dst="10.0.0.99") /
1155                                        UDP(sport=1234, dport=1234) /
1156                                        Raw('\xa5' * 100))
1157
1158         self.send_and_expect_bridged(eps[2].itf,
1159                                      pkt_intra_epg_221_to_uplink * NUM_PKTS,
1160                                      eps[2].epg.uplink)
1161
1162         #
1163         # Packets from the uplink are forwarded in the absence of a contract
1164         #
1165         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1166                                                dst=self.pg0.remote_mac) /
1167                                          IP(src=eps[0].ip4.address,
1168                                             dst="10.0.0.99") /
1169                                          UDP(sport=1234, dport=1234) /
1170                                          Raw('\xa5' * 100))
1171
1172         self.send_and_expect_bridged(self.pg4,
1173                                      pkt_intra_epg_220_from_uplink * NUM_PKTS,
1174                                      self.pg0)
1175
1176         #
1177         # in the absence of policy, endpoints in the same EPG
1178         # can communicate
1179         #
1180         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1181                                dst=self.pg1.remote_mac) /
1182                          IP(src=eps[0].ip4.address,
1183                             dst=eps[1].ip4.address) /
1184                          UDP(sport=1234, dport=1234) /
1185                          Raw('\xa5' * 100))
1186
1187         self.send_and_expect_bridged(self.pg0,
1188                                      pkt_intra_epg * NUM_PKTS,
1189                                      self.pg1)
1190
1191         #
1192         # in the absence of policy, endpoints in the different EPG
1193         # cannot communicate
1194         #
1195         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1196                                           dst=self.pg2.remote_mac) /
1197                                     IP(src=eps[0].ip4.address,
1198                                        dst=eps[2].ip4.address) /
1199                                     UDP(sport=1234, dport=1234) /
1200                                     Raw('\xa5' * 100))
1201         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1202                                           dst=self.pg0.remote_mac) /
1203                                     IP(src=eps[2].ip4.address,
1204                                        dst=eps[0].ip4.address) /
1205                                     UDP(sport=1234, dport=1234) /
1206                                     Raw('\xa5' * 100))
1207         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1208                                           dst=str(self.router_mac)) /
1209                                     IP(src=eps[0].ip4.address,
1210                                        dst=eps[3].ip4.address) /
1211                                     UDP(sport=1234, dport=1234) /
1212                                     Raw('\xa5' * 100))
1213
1214         self.send_and_assert_no_replies(eps[0].itf,
1215                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1216         self.send_and_assert_no_replies(eps[0].itf,
1217                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1218
1219         #
1220         # A uni-directional contract from EPG 220 -> 221
1221         #
1222         acl = VppGbpAcl(self)
1223         rule = acl.create_rule(permit_deny=1, proto=17)
1224         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1225         acl_index = acl.add_vpp_config([rule, rule2])
1226         c1 = VppGbpContract(
1227             self, 400, epgs[0].sclass, epgs[1].sclass, acl_index,
1228             [VppGbpContractRule(
1229                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1230                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1231                 []),
1232                 VppGbpContractRule(
1233                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1234                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1235                     [])],
1236             [ETH_P_IP, ETH_P_IPV6])
1237         c1.add_vpp_config()
1238
1239         self.send_and_expect_bridged(eps[0].itf,
1240                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1241                                      eps[2].itf)
1242         self.send_and_assert_no_replies(eps[0].itf,
1243                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1244
1245         #
1246         # contract for the return direction
1247         #
1248         c2 = VppGbpContract(
1249             self, 400, epgs[1].sclass, epgs[0].sclass, acl_index,
1250             [VppGbpContractRule(
1251                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1252                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1253                 []),
1254                 VppGbpContractRule(
1255                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1256                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1257                     [])],
1258             [ETH_P_IP, ETH_P_IPV6])
1259         c2.add_vpp_config()
1260
1261         self.send_and_expect_bridged(eps[0].itf,
1262                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1263                                      eps[2].itf)
1264         self.send_and_expect_bridged(eps[2].itf,
1265                                      pkt_inter_epg_221_to_220 * NUM_PKTS,
1266                                      eps[0].itf)
1267
1268         ds = c2.get_drop_stats()
1269         self.assertEqual(ds['packets'], 0)
1270         ps = c2.get_permit_stats()
1271         self.assertEqual(ps['packets'], NUM_PKTS)
1272
1273         #
1274         # the contract does not allow non-IP
1275         #
1276         pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1277                                                  dst=self.pg2.remote_mac) /
1278                                            ARP())
1279         self.send_and_assert_no_replies(eps[0].itf,
1280                                         pkt_non_ip_inter_epg_220_to_221 * 17)
1281
1282         #
1283         # check that inter group is still disabled for the groups
1284         # not in the contract.
1285         #
1286         self.send_and_assert_no_replies(eps[0].itf,
1287                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1288
1289         #
1290         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1291         #
1292         c3 = VppGbpContract(
1293             self, 400, epgs[0].sclass, epgs[2].sclass, acl_index,
1294             [VppGbpContractRule(
1295                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1296                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1297                 []),
1298                 VppGbpContractRule(
1299                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1300                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1301                     [])],
1302             [ETH_P_IP, ETH_P_IPV6])
1303         c3.add_vpp_config()
1304
1305         self.logger.info(self.vapi.cli("sh gbp contract"))
1306
1307         self.send_and_expect_routed(eps[0].itf,
1308                                     pkt_inter_epg_220_to_222 * NUM_PKTS,
1309                                     eps[3].itf,
1310                                     str(self.router_mac))
1311
1312         #
1313         # remove both contracts, traffic stops in both directions
1314         #
1315         c2.remove_vpp_config()
1316         c1.remove_vpp_config()
1317         c3.remove_vpp_config()
1318         acl.remove_vpp_config()
1319
1320         self.send_and_assert_no_replies(eps[2].itf,
1321                                         pkt_inter_epg_221_to_220 * NUM_PKTS)
1322         self.send_and_assert_no_replies(eps[0].itf,
1323                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1324         self.send_and_expect_bridged(eps[0].itf,
1325                                      pkt_intra_epg * NUM_PKTS,
1326                                      eps[1].itf)
1327
1328         #
1329         # EPs to the outside world
1330         #
1331
1332         # in the EP's RD an external subnet via the NAT EPG's recirc
1333         se1 = VppGbpSubnet(
1334             self, rd0, "0.0.0.0", 0,
1335             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1336             sw_if_index=recirc_nat.recirc.sw_if_index,
1337             sclass=epg_nat.sclass)
1338         se2 = VppGbpSubnet(
1339             self, rd0, "11.0.0.0", 8,
1340             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1341             sw_if_index=recirc_nat.recirc.sw_if_index,
1342             sclass=epg_nat.sclass)
1343         se16 = VppGbpSubnet(
1344             self, rd0, "::", 0,
1345             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1346             sw_if_index=recirc_nat.recirc.sw_if_index,
1347             sclass=epg_nat.sclass)
1348         # in the NAT RD an external subnet via the NAT EPG's uplink
1349         se3 = VppGbpSubnet(
1350             self, rd20, "0.0.0.0", 0,
1351             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1352             sw_if_index=epg_nat.uplink.sw_if_index,
1353             sclass=epg_nat.sclass)
1354         se36 = VppGbpSubnet(
1355             self, rd20, "::", 0,
1356             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1357             sw_if_index=epg_nat.uplink.sw_if_index,
1358             sclass=epg_nat.sclass)
1359         se4 = VppGbpSubnet(
1360             self, rd20, "11.0.0.0", 8,
1361             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1362             sw_if_index=epg_nat.uplink.sw_if_index,
1363             sclass=epg_nat.sclass)
1364         se1.add_vpp_config()
1365         se2.add_vpp_config()
1366         se16.add_vpp_config()
1367         se3.add_vpp_config()
1368         se36.add_vpp_config()
1369         se4.add_vpp_config()
1370
1371         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1372         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1373         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1374         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1375                                        eps[0].fip6))
1376
1377         #
1378         # From an EP to an outside address: IN2OUT
1379         #
1380         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1381                                              dst=str(self.router_mac)) /
1382                                        IP(src=eps[0].ip4.address,
1383                                           dst="1.1.1.1") /
1384                                        UDP(sport=1234, dport=1234) /
1385                                        Raw('\xa5' * 100))
1386
1387         # no policy yet
1388         self.send_and_assert_no_replies(eps[0].itf,
1389                                         pkt_inter_epg_220_to_global * NUM_PKTS)
1390
1391         acl2 = VppGbpAcl(self)
1392         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1393                                 sport_to=1234, dport_from=1234, dport_to=1234)
1394         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1395                                  sport_from=1234, sport_to=1234,
1396                                  dport_from=1234, dport_to=1234)
1397
1398         acl_index2 = acl2.add_vpp_config([rule, rule2])
1399         c4 = VppGbpContract(
1400             self, 400, epgs[0].sclass, epgs[3].sclass, acl_index2,
1401             [VppGbpContractRule(
1402                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1403                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1404                 []),
1405                 VppGbpContractRule(
1406                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1407                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1408                     [])],
1409             [ETH_P_IP, ETH_P_IPV6])
1410         c4.add_vpp_config()
1411
1412         self.send_and_expect_natted(eps[0].itf,
1413                                     pkt_inter_epg_220_to_global * NUM_PKTS,
1414                                     self.pg7,
1415                                     eps[0].fip4.address)
1416
1417         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1418                                              dst=str(self.router_mac)) /
1419                                        IPv6(src=eps[0].ip6.address,
1420                                             dst="6001::1") /
1421                                        UDP(sport=1234, dport=1234) /
1422                                        Raw('\xa5' * 100))
1423
1424         self.send_and_expect_natted6(self.pg0,
1425                                      pkt_inter_epg_220_to_global * NUM_PKTS,
1426                                      self.pg7,
1427                                      eps[0].fip6.address)
1428
1429         #
1430         # From a global address to an EP: OUT2IN
1431         #
1432         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1433                                                dst=self.pg0.remote_mac) /
1434                                          IP(dst=eps[0].fip4.address,
1435                                             src="1.1.1.1") /
1436                                          UDP(sport=1234, dport=1234) /
1437                                          Raw('\xa5' * 100))
1438
1439         self.send_and_assert_no_replies(
1440             self.pg7, pkt_inter_epg_220_from_global * NUM_PKTS)
1441
1442         c5 = VppGbpContract(
1443             self, 400, epgs[3].sclass, epgs[0].sclass, acl_index2,
1444             [VppGbpContractRule(
1445                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1446                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1447                 []),
1448                 VppGbpContractRule(
1449                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1450                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1451                     [])],
1452             [ETH_P_IP, ETH_P_IPV6])
1453         c5.add_vpp_config()
1454
1455         self.send_and_expect_unnatted(self.pg7,
1456                                       pkt_inter_epg_220_from_global * NUM_PKTS,
1457                                       eps[0].itf,
1458                                       eps[0].ip4.address)
1459
1460         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1461                                                dst=self.pg0.remote_mac) /
1462                                          IPv6(dst=eps[0].fip6.address,
1463                                               src="6001::1") /
1464                                          UDP(sport=1234, dport=1234) /
1465                                          Raw('\xa5' * 100))
1466
1467         self.send_and_expect_unnatted6(
1468             self.pg7,
1469             pkt_inter_epg_220_from_global * NUM_PKTS,
1470             eps[0].itf,
1471             eps[0].ip6.address)
1472
1473         #
1474         # From a local VM to another local VM using resp. public addresses:
1475         #  IN2OUT2IN
1476         #
1477         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1478                                           dst=str(self.router_mac)) /
1479                                     IP(src=eps[0].ip4.address,
1480                                        dst=eps[1].fip4.address) /
1481                                     UDP(sport=1234, dport=1234) /
1482                                     Raw('\xa5' * 100))
1483
1484         self.send_and_expect_double_natted(eps[0].itf,
1485                                            pkt_intra_epg_220_global * NUM_PKTS,
1486                                            eps[1].itf,
1487                                            eps[0].fip4.address,
1488                                            eps[1].ip4.address)
1489
1490         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1491                                           dst=str(self.router_mac)) /
1492                                     IPv6(src=eps[0].ip6.address,
1493                                          dst=eps[1].fip6.address) /
1494                                     UDP(sport=1234, dport=1234) /
1495                                     Raw('\xa5' * 100))
1496
1497         self.send_and_expect_double_natted6(
1498             eps[0].itf,
1499             pkt_intra_epg_220_global * NUM_PKTS,
1500             eps[1].itf,
1501             eps[0].fip6.address,
1502             eps[1].ip6.address)
1503
1504         #
1505         # cleanup
1506         #
1507         for ep in eps:
1508             # del static mappings for each EP from the 10/8 to 11/8 network
1509             flags = self.config_flags.NAT_IS_ADDR_ONLY
1510             self.vapi.nat44_add_del_static_mapping(
1511                 is_add=0,
1512                 local_ip_address=ep.ip4.bytes,
1513                 external_ip_address=ep.fip4.bytes,
1514                 external_sw_if_index=0xFFFFFFFF,
1515                 vrf_id=0,
1516                 flags=flags)
1517             self.vapi.nat66_add_del_static_mapping(
1518                 local_ip_address=ep.ip6.bytes,
1519                 external_ip_address=ep.fip6.bytes,
1520                 vrf_id=0, is_add=0)
1521
1522         for epg in epgs:
1523             # IP config on the BVI interfaces
1524             if epg != epgs[0] and epg != epgs[3]:
1525                 flags = self.config_flags.NAT_IS_INSIDE
1526                 self.vapi.nat44_interface_add_del_feature(
1527                     sw_if_index=epg.bvi.sw_if_index,
1528                     flags=flags,
1529                     is_add=0)
1530                 self.vapi.nat66_add_del_interface(
1531                     is_add=0, flags=flags,
1532                     sw_if_index=epg.bvi.sw_if_index)
1533
1534         for recirc in recircs:
1535             self.vapi.nat44_interface_add_del_feature(
1536                 sw_if_index=recirc.recirc.sw_if_index,
1537                 is_add=0)
1538             self.vapi.nat66_add_del_interface(
1539                 is_add=0,
1540                 sw_if_index=recirc.recirc.sw_if_index)
1541
1542     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1543                             tep=None, n_tries=100, s_time=1):
1544         while (n_tries):
1545             if not find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep):
1546                 return True
1547             n_tries = n_tries - 1
1548             self.sleep(s_time)
1549         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac))
1550         return False
1551
1552     def test_gbp_learn_l2(self):
1553         """ GBP L2 Endpoint Learning """
1554
1555         drop_no_contract = self.statistics.get_err_counter(
1556             '/err/gbp-policy-port/drop-no-contract')
1557         allow_intra_class = self.statistics.get_err_counter(
1558             '/err/gbp-policy-port/allow-intra-sclass')
1559
1560         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1561         learnt = [{'mac': '00:00:11:11:11:01',
1562                    'ip': '10.0.0.1',
1563                    'ip6': '2001:10::2'},
1564                   {'mac': '00:00:11:11:11:02',
1565                    'ip': '10.0.0.2',
1566                    'ip6': '2001:10::3'}]
1567
1568         #
1569         # IP tables
1570         #
1571         gt4 = VppIpTable(self, 1)
1572         gt4.add_vpp_config()
1573         gt6 = VppIpTable(self, 1, is_ip6=True)
1574         gt6.add_vpp_config()
1575
1576         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
1577         rd1.add_vpp_config()
1578
1579         #
1580         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1581         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1582         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1583         #
1584         self.pg2.config_ip4()
1585         self.pg2.resolve_arp()
1586         self.pg2.generate_remote_hosts(4)
1587         self.pg2.configure_ipv4_neighbors()
1588         self.pg3.config_ip4()
1589         self.pg3.resolve_arp()
1590         self.pg4.config_ip4()
1591         self.pg4.resolve_arp()
1592
1593         #
1594         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1595         #
1596         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1597                                    "239.1.1.1", 88,
1598                                    mcast_itf=self.pg4)
1599         tun_bm.add_vpp_config()
1600
1601         #
1602         # a GBP bridge domain with a BVI and a UU-flood interface
1603         #
1604         bd1 = VppBridgeDomain(self, 1)
1605         bd1.add_vpp_config()
1606         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
1607                                   self.pg3, tun_bm)
1608         gbd1.add_vpp_config()
1609
1610         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1611         self.logger.info(self.vapi.cli("sh gbp bridge"))
1612
1613         # ... and has a /32 applied
1614         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1615         ip_addr.add_vpp_config()
1616
1617         #
1618         # The Endpoint-group in which we are learning endpoints
1619         #
1620         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1621                                       None, self.loop0,
1622                                       "10.0.0.128",
1623                                       "2001:10::128",
1624                                       VppGbpEndpointRetention(2))
1625         epg_220.add_vpp_config()
1626         epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
1627                                       None, self.loop1,
1628                                       "10.0.1.128",
1629                                       "2001:11::128",
1630                                       VppGbpEndpointRetention(2))
1631         epg_330.add_vpp_config()
1632
1633         #
1634         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1635         # learning enabled
1636         #
1637         vx_tun_l2_1 = VppGbpVxlanTunnel(
1638             self, 99, bd1.bd_id,
1639             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
1640             self.pg2.local_ip4)
1641         vx_tun_l2_1.add_vpp_config()
1642
1643         #
1644         # A static endpoint that the learnt endpoints are trying to
1645         # talk to
1646         #
1647         ep = VppGbpEndpoint(self, self.pg0,
1648                             epg_220, None,
1649                             "10.0.0.127", "11.0.0.127",
1650                             "2001:10::1", "3001::1")
1651         ep.add_vpp_config()
1652
1653         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1654
1655         # a packet with an sclass from an unknown EPG
1656         p = (Ether(src=self.pg2.remote_mac,
1657                    dst=self.pg2.local_mac) /
1658              IP(src=self.pg2.remote_hosts[0].ip4,
1659                 dst=self.pg2.local_ip4) /
1660              UDP(sport=1234, dport=48879) /
1661              VXLAN(vni=99, gpid=88, flags=0x88) /
1662              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1663              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1664              UDP(sport=1234, dport=1234) /
1665              Raw('\xa5' * 100))
1666
1667         self.send_and_assert_no_replies(self.pg2, p)
1668
1669         self.logger.info(self.vapi.cli("sh error"))
1670         self.assert_error_counter_equal(
1671             '/err/gbp-policy-port/drop-no-contract',
1672             drop_no_contract + 1)
1673
1674         #
1675         # we should not have learnt a new tunnel endpoint, since
1676         # the EPG was not learnt.
1677         #
1678         self.assertEqual(INDEX_INVALID,
1679                          find_vxlan_gbp_tunnel(self,
1680                                                self.pg2.local_ip4,
1681                                                self.pg2.remote_hosts[0].ip4,
1682                                                99))
1683
1684         # ep is not learnt, because the EPG is unknown
1685         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1686
1687         #
1688         # Learn new EPs from IP packets
1689         #
1690         for ii, l in enumerate(learnt):
1691             # a packet with an sclass from a known EPG
1692             # arriving on an unknown TEP
1693             p = (Ether(src=self.pg2.remote_mac,
1694                        dst=self.pg2.local_mac) /
1695                  IP(src=self.pg2.remote_hosts[1].ip4,
1696                     dst=self.pg2.local_ip4) /
1697                  UDP(sport=1234, dport=48879) /
1698                  VXLAN(vni=99, gpid=112, flags=0x88) /
1699                  Ether(src=l['mac'], dst=ep.mac) /
1700                  IP(src=l['ip'], dst=ep.ip4.address) /
1701                  UDP(sport=1234, dport=1234) /
1702                  Raw('\xa5' * 100))
1703
1704             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1705
1706             # the new TEP
1707             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1708                 self,
1709                 self.pg2.local_ip4,
1710                 self.pg2.remote_hosts[1].ip4,
1711                 99)
1712             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1713
1714             #
1715             # the EP is learnt via the learnt TEP
1716             # both from its MAC and its IP
1717             #
1718             self.assertTrue(find_gbp_endpoint(self,
1719                                               vx_tun_l2_1.sw_if_index,
1720                                               mac=l['mac']))
1721             self.assertTrue(find_gbp_endpoint(self,
1722                                               vx_tun_l2_1.sw_if_index,
1723                                               ip=l['ip']))
1724
1725         self.assert_error_counter_equal(
1726             '/err/gbp-policy-port/allow-intra-sclass',
1727             allow_intra_class + 2)
1728
1729         self.logger.info(self.vapi.cli("show gbp endpoint"))
1730         self.logger.info(self.vapi.cli("show gbp vxlan"))
1731         self.logger.info(self.vapi.cli("show ip mfib"))
1732
1733         #
1734         # If we sleep for the threshold time, the learnt endpoints should
1735         # age out
1736         #
1737         for l in learnt:
1738             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1739                                      mac=l['mac'])
1740
1741         #
1742         # Learn new EPs from GARP packets received on the BD's mcast tunnel
1743         #
1744         for ii, l in enumerate(learnt):
1745             # add some junk in the reserved field of the vxlan-header
1746             # next to the VNI. we should accept since reserved bits are
1747             # ignored on rx.
1748             p = (Ether(src=self.pg2.remote_mac,
1749                        dst=self.pg2.local_mac) /
1750                  IP(src=self.pg2.remote_hosts[1].ip4,
1751                     dst="239.1.1.1") /
1752                  UDP(sport=1234, dport=48879) /
1753                  VXLAN(vni=88, reserved2=0x80, gpid=112, flags=0x88) /
1754                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1755                  ARP(op="who-has",
1756                      psrc=l['ip'], pdst=l['ip'],
1757                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1758
1759             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1760
1761             # the new TEP
1762             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1763                 self,
1764                 self.pg2.local_ip4,
1765                 self.pg2.remote_hosts[1].ip4,
1766                 99)
1767             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1768
1769             #
1770             # the EP is learnt via the learnt TEP
1771             # both from its MAC and its IP
1772             #
1773             self.assertTrue(find_gbp_endpoint(self,
1774                                               vx_tun_l2_1.sw_if_index,
1775                                               mac=l['mac']))
1776             self.assertTrue(find_gbp_endpoint(self,
1777                                               vx_tun_l2_1.sw_if_index,
1778                                               ip=l['ip']))
1779
1780         #
1781         # wait for the learnt endpoints to age out
1782         #
1783         for l in learnt:
1784             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1785                                      mac=l['mac'])
1786
1787         #
1788         # Learn new EPs from L2 packets
1789         #
1790         for ii, l in enumerate(learnt):
1791             # a packet with an sclass from a known EPG
1792             # arriving on an unknown TEP
1793             p = (Ether(src=self.pg2.remote_mac,
1794                        dst=self.pg2.local_mac) /
1795                  IP(src=self.pg2.remote_hosts[1].ip4,
1796                     dst=self.pg2.local_ip4) /
1797                  UDP(sport=1234, dport=48879) /
1798                  VXLAN(vni=99, gpid=112, flags=0x88) /
1799                  Ether(src=l['mac'], dst=ep.mac) /
1800                  Raw('\xa5' * 100))
1801
1802             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1803
1804             # the new TEP
1805             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1806                 self,
1807                 self.pg2.local_ip4,
1808                 self.pg2.remote_hosts[1].ip4,
1809                 99)
1810             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1811
1812             #
1813             # the EP is learnt via the learnt TEP
1814             # both from its MAC and its IP
1815             #
1816             self.assertTrue(find_gbp_endpoint(self,
1817                                               vx_tun_l2_1.sw_if_index,
1818                                               mac=l['mac']))
1819
1820         self.logger.info(self.vapi.cli("show gbp endpoint"))
1821         self.logger.info(self.vapi.cli("show gbp vxlan"))
1822         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1823
1824         #
1825         # wait for the learnt endpoints to age out
1826         #
1827         for l in learnt:
1828             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1829                                      mac=l['mac'])
1830
1831         #
1832         # repeat. the do not learn bit is set so the EPs are not learnt
1833         #
1834         for l in learnt:
1835             # a packet with an sclass from a known EPG
1836             p = (Ether(src=self.pg2.remote_mac,
1837                        dst=self.pg2.local_mac) /
1838                  IP(src=self.pg2.remote_hosts[1].ip4,
1839                     dst=self.pg2.local_ip4) /
1840                  UDP(sport=1234, dport=48879) /
1841                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1842                  Ether(src=l['mac'], dst=ep.mac) /
1843                  IP(src=l['ip'], dst=ep.ip4.address) /
1844                  UDP(sport=1234, dport=1234) /
1845                  Raw('\xa5' * 100))
1846
1847             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1848
1849         for l in learnt:
1850             self.assertFalse(find_gbp_endpoint(self,
1851                                                vx_tun_l2_1.sw_if_index,
1852                                                mac=l['mac']))
1853
1854         #
1855         # repeat
1856         #
1857         for l in learnt:
1858             # a packet with an sclass from a known EPG
1859             # set a reserved bit in addition to the G and I
1860             # reserved bits should not be checked on rx.
1861             p = (Ether(src=self.pg2.remote_mac,
1862                        dst=self.pg2.local_mac) /
1863                  IP(src=self.pg2.remote_hosts[1].ip4,
1864                     dst=self.pg2.local_ip4) /
1865                  UDP(sport=1234, dport=48879) /
1866                  VXLAN(vni=99, gpid=112, flags=0xc8) /
1867                  Ether(src=l['mac'], dst=ep.mac) /
1868                  IP(src=l['ip'], dst=ep.ip4.address) /
1869                  UDP(sport=1234, dport=1234) /
1870                  Raw('\xa5' * 100))
1871
1872             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1873
1874             self.assertTrue(find_gbp_endpoint(self,
1875                                               vx_tun_l2_1.sw_if_index,
1876                                               mac=l['mac']))
1877
1878         #
1879         # Static EP replies to dynamics
1880         #
1881         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1882         for l in learnt:
1883             p = (Ether(src=ep.mac, dst=l['mac']) /
1884                  IP(dst=l['ip'], src=ep.ip4.address) /
1885                  UDP(sport=1234, dport=1234) /
1886                  Raw('\xa5' * 100))
1887
1888             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1889
1890             for rx in rxs:
1891                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1892                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1893                 self.assertEqual(rx[UDP].dport, 48879)
1894                 # the UDP source port is a random value for hashing
1895                 self.assertEqual(rx[VXLAN].gpid, 112)
1896                 self.assertEqual(rx[VXLAN].vni, 99)
1897                 self.assertTrue(rx[VXLAN].flags.G)
1898                 self.assertTrue(rx[VXLAN].flags.Instance)
1899                 self.assertTrue(rx[VXLAN].gpflags.A)
1900                 self.assertFalse(rx[VXLAN].gpflags.D)
1901
1902         for l in learnt:
1903             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1904                                      mac=l['mac'])
1905
1906         #
1907         # repeat in the other EPG
1908         # there's no contract between 220 and 330, but the A-bit is set
1909         # so the packet is cleared for delivery
1910         #
1911         for l in learnt:
1912             # a packet with an sclass from a known EPG
1913             p = (Ether(src=self.pg2.remote_mac,
1914                        dst=self.pg2.local_mac) /
1915                  IP(src=self.pg2.remote_hosts[1].ip4,
1916                     dst=self.pg2.local_ip4) /
1917                  UDP(sport=1234, dport=48879) /
1918                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1919                  Ether(src=l['mac'], dst=ep.mac) /
1920                  IP(src=l['ip'], dst=ep.ip4.address) /
1921                  UDP(sport=1234, dport=1234) /
1922                  Raw('\xa5' * 100))
1923
1924             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1925
1926             self.assertTrue(find_gbp_endpoint(self,
1927                                               vx_tun_l2_1.sw_if_index,
1928                                               mac=l['mac']))
1929
1930         #
1931         # static EP cannot reach the learnt EPs since there is no contract
1932         # only test 1 EP as the others could timeout
1933         #
1934         p = (Ether(src=ep.mac, dst=l['mac']) /
1935              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1936              UDP(sport=1234, dport=1234) /
1937              Raw('\xa5' * 100))
1938
1939         self.send_and_assert_no_replies(self.pg0, [p])
1940
1941         #
1942         # refresh the entries after the check for no replies above
1943         #
1944         for l in learnt:
1945             # a packet with an sclass from a known EPG
1946             p = (Ether(src=self.pg2.remote_mac,
1947                        dst=self.pg2.local_mac) /
1948                  IP(src=self.pg2.remote_hosts[1].ip4,
1949                     dst=self.pg2.local_ip4) /
1950                  UDP(sport=1234, dport=48879) /
1951                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1952                  Ether(src=l['mac'], dst=ep.mac) /
1953                  IP(src=l['ip'], dst=ep.ip4.address) /
1954                  UDP(sport=1234, dport=1234) /
1955                  Raw('\xa5' * 100))
1956
1957             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1958
1959             self.assertTrue(find_gbp_endpoint(self,
1960                                               vx_tun_l2_1.sw_if_index,
1961                                               mac=l['mac']))
1962
1963         #
1964         # Add the contract so they can talk
1965         #
1966         acl = VppGbpAcl(self)
1967         rule = acl.create_rule(permit_deny=1, proto=17)
1968         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1969         acl_index = acl.add_vpp_config([rule, rule2])
1970         c1 = VppGbpContract(
1971             self, 401, epg_220.sclass, epg_330.sclass, acl_index,
1972             [VppGbpContractRule(
1973                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1974                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1975                 []),
1976              VppGbpContractRule(
1977                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1978                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1979                  [])],
1980             [ETH_P_IP, ETH_P_IPV6])
1981         c1.add_vpp_config()
1982
1983         for l in learnt:
1984             p = (Ether(src=ep.mac, dst=l['mac']) /
1985                  IP(dst=l['ip'], src=ep.ip4.address) /
1986                  UDP(sport=1234, dport=1234) /
1987                  Raw('\xa5' * 100))
1988
1989             self.send_and_expect(self.pg0, [p], self.pg2)
1990
1991         #
1992         # send UU packets from the local EP
1993         #
1994         self.logger.info(self.vapi.cli("sh gbp bridge"))
1995         self.logger.info(self.vapi.cli("sh bridge-domain 1 detail"))
1996         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1997                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1998                 UDP(sport=1234, dport=1234) /
1999                 Raw('\xa5' * 100))
2000         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
2001
2002         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2003
2004         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2005                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2006                 UDP(sport=1234, dport=1234) /
2007                 Raw('\xa5' * 100))
2008         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
2009
2010         for rx in rxs:
2011             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2012             self.assertEqual(rx[IP].dst, "239.1.1.1")
2013             self.assertEqual(rx[UDP].dport, 48879)
2014             # the UDP source port is a random value for hashing
2015             self.assertEqual(rx[VXLAN].gpid, 112)
2016             self.assertEqual(rx[VXLAN].vni, 88)
2017             self.assertTrue(rx[VXLAN].flags.G)
2018             self.assertTrue(rx[VXLAN].flags.Instance)
2019             self.assertFalse(rx[VXLAN].gpflags.A)
2020             self.assertFalse(rx[VXLAN].gpflags.D)
2021
2022         acl = VppGbpAcl(self)
2023         rule = acl.create_rule(permit_deny=1, proto=17)
2024         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2025         acl_index = acl.add_vpp_config([rule, rule2])
2026         c2 = VppGbpContract(
2027             self, 401, epg_330.sclass, epg_220.sclass, acl_index,
2028             [VppGbpContractRule(
2029                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2030                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2031                 []),
2032                 VppGbpContractRule(
2033                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2034                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2035                     [])],
2036             [ETH_P_IP, ETH_P_IPV6])
2037         c2.add_vpp_config()
2038
2039         for l in learnt:
2040             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2041                                      mac=l['mac'])
2042         #
2043         # Check v6 Endpoints learning
2044         #
2045         for l in learnt:
2046             # a packet with an sclass from a known EPG
2047             p = (Ether(src=self.pg2.remote_mac,
2048                        dst=self.pg2.local_mac) /
2049                  IP(src=self.pg2.remote_hosts[1].ip4,
2050                     dst=self.pg2.local_ip4) /
2051                  UDP(sport=1234, dport=48879) /
2052                  VXLAN(vni=99, gpid=113, flags=0x88) /
2053                  Ether(src=l['mac'], dst=ep.mac) /
2054                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2055                  UDP(sport=1234, dport=1234) /
2056                  Raw('\xa5' * 100))
2057
2058             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2059             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2060
2061             self.assertTrue(find_gbp_endpoint(
2062                 self,
2063                 vx_tun_l2_1.sw_if_index,
2064                 ip=l['ip6'],
2065                 tep=[self.pg2.local_ip4,
2066                      self.pg2.remote_hosts[1].ip4]))
2067
2068         self.logger.info(self.vapi.cli("sh int"))
2069         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
2070         self.logger.info(self.vapi.cli("sh gbp vxlan"))
2071         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2072         self.logger.info(self.vapi.cli("sh gbp interface"))
2073
2074         #
2075         # EP moves to a different TEP
2076         #
2077         for l in learnt:
2078             # a packet with an sclass from a known EPG
2079             p = (Ether(src=self.pg2.remote_mac,
2080                        dst=self.pg2.local_mac) /
2081                  IP(src=self.pg2.remote_hosts[2].ip4,
2082                     dst=self.pg2.local_ip4) /
2083                  UDP(sport=1234, dport=48879) /
2084                  VXLAN(vni=99, gpid=113, flags=0x88) /
2085                  Ether(src=l['mac'], dst=ep.mac) /
2086                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2087                  UDP(sport=1234, dport=1234) /
2088                  Raw('\xa5' * 100))
2089
2090             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2091             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2092
2093             self.assertTrue(find_gbp_endpoint(
2094                 self,
2095                 vx_tun_l2_1.sw_if_index,
2096                 sclass=113,
2097                 mac=l['mac'],
2098                 tep=[self.pg2.local_ip4,
2099                      self.pg2.remote_hosts[2].ip4]))
2100
2101         #
2102         # v6 remote EP reachability
2103         #
2104         for l in learnt:
2105             p = (Ether(src=ep.mac, dst=l['mac']) /
2106                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2107                  UDP(sport=1234, dport=1234) /
2108                  Raw('\xa5' * 100))
2109
2110             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2111
2112             for rx in rxs:
2113                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2114                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2115                 self.assertEqual(rx[UDP].dport, 48879)
2116                 # the UDP source port is a random value for hashing
2117                 self.assertEqual(rx[VXLAN].gpid, 112)
2118                 self.assertEqual(rx[VXLAN].vni, 99)
2119                 self.assertTrue(rx[VXLAN].flags.G)
2120                 self.assertTrue(rx[VXLAN].flags.Instance)
2121                 self.assertTrue(rx[VXLAN].gpflags.A)
2122                 self.assertFalse(rx[VXLAN].gpflags.D)
2123                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2124
2125         #
2126         # EP changes sclass
2127         #
2128         for l in learnt:
2129             # a packet with an sclass from a known EPG
2130             p = (Ether(src=self.pg2.remote_mac,
2131                        dst=self.pg2.local_mac) /
2132                  IP(src=self.pg2.remote_hosts[2].ip4,
2133                     dst=self.pg2.local_ip4) /
2134                  UDP(sport=1234, dport=48879) /
2135                  VXLAN(vni=99, gpid=112, flags=0x88) /
2136                  Ether(src=l['mac'], dst=ep.mac) /
2137                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2138                  UDP(sport=1234, dport=1234) /
2139                  Raw('\xa5' * 100))
2140
2141             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2142             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2143
2144             self.assertTrue(find_gbp_endpoint(
2145                 self,
2146                 vx_tun_l2_1.sw_if_index,
2147                 mac=l['mac'],
2148                 sclass=112,
2149                 tep=[self.pg2.local_ip4,
2150                      self.pg2.remote_hosts[2].ip4]))
2151
2152         #
2153         # check reachability and contract intra-epg
2154         #
2155         allow_intra_class = self.statistics.get_err_counter(
2156             '/err/gbp-policy-mac/allow-intra-sclass')
2157
2158         for l in learnt:
2159             p = (Ether(src=ep.mac, dst=l['mac']) /
2160                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2161                  UDP(sport=1234, dport=1234) /
2162                  Raw('\xa5' * 100))
2163
2164             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2165
2166             for rx in rxs:
2167                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2168                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2169                 self.assertEqual(rx[UDP].dport, 48879)
2170                 self.assertEqual(rx[VXLAN].gpid, 112)
2171                 self.assertEqual(rx[VXLAN].vni, 99)
2172                 self.assertTrue(rx[VXLAN].flags.G)
2173                 self.assertTrue(rx[VXLAN].flags.Instance)
2174                 self.assertTrue(rx[VXLAN].gpflags.A)
2175                 self.assertFalse(rx[VXLAN].gpflags.D)
2176                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2177
2178             allow_intra_class += NUM_PKTS
2179
2180         self.assert_error_counter_equal(
2181             '/err/gbp-policy-mac/allow-intra-sclass',
2182             allow_intra_class)
2183
2184         #
2185         # clean up
2186         #
2187         for l in learnt:
2188             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2189                                      mac=l['mac'])
2190         self.pg2.unconfig_ip4()
2191         self.pg3.unconfig_ip4()
2192         self.pg4.unconfig_ip4()
2193
2194     def test_gbp_contract(self):
2195         """ GBP Contracts """
2196
2197         #
2198         # Route Domains
2199         #
2200         gt4 = VppIpTable(self, 0)
2201         gt4.add_vpp_config()
2202         gt6 = VppIpTable(self, 0, is_ip6=True)
2203         gt6.add_vpp_config()
2204
2205         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
2206
2207         rd0.add_vpp_config()
2208
2209         #
2210         # Bridge Domains
2211         #
2212         bd1 = VppBridgeDomain(self, 1, arp_term=0)
2213         bd2 = VppBridgeDomain(self, 2, arp_term=0)
2214
2215         bd1.add_vpp_config()
2216         bd2.add_vpp_config()
2217
2218         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
2219         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
2220
2221         gbd1.add_vpp_config()
2222         gbd2.add_vpp_config()
2223
2224         #
2225         # 3 EPGs, 2 of which share a BD.
2226         #
2227         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
2228                                     None, self.loop0,
2229                                     "10.0.0.128", "2001:10::128"),
2230                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
2231                                     None, self.loop0,
2232                                     "10.0.1.128", "2001:10:1::128"),
2233                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
2234                                     None, self.loop1,
2235                                     "10.0.2.128", "2001:10:2::128")]
2236         #
2237         # 4 end-points, 2 in the same subnet, 3 in the same BD
2238         #
2239         eps = [VppGbpEndpoint(self, self.pg0,
2240                               epgs[0], None,
2241                               "10.0.0.1", "11.0.0.1",
2242                               "2001:10::1", "3001::1"),
2243                VppGbpEndpoint(self, self.pg1,
2244                               epgs[0], None,
2245                               "10.0.0.2", "11.0.0.2",
2246                               "2001:10::2", "3001::2"),
2247                VppGbpEndpoint(self, self.pg2,
2248                               epgs[1], None,
2249                               "10.0.1.1", "11.0.0.3",
2250                               "2001:10:1::1", "3001::3"),
2251                VppGbpEndpoint(self, self.pg3,
2252                               epgs[2], None,
2253                               "10.0.2.1", "11.0.0.4",
2254                               "2001:10:2::1", "3001::4")]
2255
2256         #
2257         # Config related to each of the EPGs
2258         #
2259         for epg in epgs:
2260             # IP config on the BVI interfaces
2261             if epg != epgs[1]:
2262                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
2263                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
2264                 self.vapi.sw_interface_set_mac_address(
2265                     epg.bvi.sw_if_index,
2266                     self.router_mac.packed)
2267
2268             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
2269             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
2270             if_ip4.add_vpp_config()
2271             if_ip6.add_vpp_config()
2272
2273             # add the BD ARP termination entry for BVI IP
2274             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
2275                                                      str(self.router_mac),
2276                                                      epg.bvi_ip4.address)
2277             epg.bd_arp_ip4.add_vpp_config()
2278
2279             # EPG in VPP
2280             epg.add_vpp_config()
2281
2282         #
2283         # config ep
2284         #
2285         for ep in eps:
2286             ep.add_vpp_config()
2287
2288         self.logger.info(self.vapi.cli("show gbp endpoint"))
2289         self.logger.info(self.vapi.cli("show interface"))
2290         self.logger.info(self.vapi.cli("show br"))
2291
2292         #
2293         # Intra epg allowed without contract
2294         #
2295         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2296                                           dst=self.pg1.remote_mac) /
2297                                     IP(src=eps[0].ip4.address,
2298                                        dst=eps[1].ip4.address) /
2299                                     UDP(sport=1234, dport=1234) /
2300                                     Raw('\xa5' * 100))
2301
2302         self.send_and_expect_bridged(self.pg0,
2303                                      pkt_intra_epg_220_to_220 * 65,
2304                                      self.pg1)
2305
2306         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2307                                           dst=self.pg1.remote_mac) /
2308                                     IPv6(src=eps[0].ip6.address,
2309                                          dst=eps[1].ip6.address) /
2310                                     UDP(sport=1234, dport=1234) /
2311                                     Raw('\xa5' * 100))
2312
2313         self.send_and_expect_bridged6(self.pg0,
2314                                       pkt_intra_epg_220_to_220 * 65,
2315                                       self.pg1)
2316
2317         #
2318         # Inter epg denied without contract
2319         #
2320         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
2321                                           dst=self.pg2.remote_mac) /
2322                                     IP(src=eps[0].ip4.address,
2323                                        dst=eps[2].ip4.address) /
2324                                     UDP(sport=1234, dport=1234) /
2325                                     Raw('\xa5' * 100))
2326
2327         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
2328
2329         #
2330         # A uni-directional contract from EPG 220 -> 221
2331         #
2332         acl = VppGbpAcl(self)
2333         rule = acl.create_rule(permit_deny=1, proto=17)
2334         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2335         rule3 = acl.create_rule(permit_deny=1, proto=1)
2336         acl_index = acl.add_vpp_config([rule, rule2, rule3])
2337         c1 = VppGbpContract(
2338             self, 400, epgs[0].sclass, epgs[1].sclass, acl_index,
2339             [VppGbpContractRule(
2340                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2341                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2342                 []),
2343              VppGbpContractRule(
2344                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2345                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2346                  []),
2347              VppGbpContractRule(
2348                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2349                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2350                  [])],
2351             [ETH_P_IP, ETH_P_IPV6])
2352         c1.add_vpp_config()
2353
2354         self.send_and_expect_bridged(eps[0].itf,
2355                                      pkt_inter_epg_220_to_221 * 65,
2356                                      eps[2].itf)
2357
2358         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
2359                                           dst=str(self.router_mac)) /
2360                                     IP(src=eps[0].ip4.address,
2361                                        dst=eps[3].ip4.address) /
2362                                     UDP(sport=1234, dport=1234) /
2363                                     Raw('\xa5' * 100))
2364         self.send_and_assert_no_replies(eps[0].itf,
2365                                         pkt_inter_epg_220_to_222 * 65)
2366
2367         #
2368         # ping router IP in different BD
2369         #
2370         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2371                                             dst=str(self.router_mac)) /
2372                                       IP(src=eps[0].ip4.address,
2373                                          dst=epgs[1].bvi_ip4.address) /
2374                                       ICMP(type='echo-request'))
2375
2376         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2377
2378         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2379                                             dst=str(self.router_mac)) /
2380                                       IPv6(src=eps[0].ip6.address,
2381                                            dst=epgs[1].bvi_ip6.address) /
2382                                       ICMPv6EchoRequest())
2383
2384         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2385
2386         #
2387         # contract for the return direction
2388         #
2389         c2 = VppGbpContract(
2390             self, 400, epgs[1].sclass, epgs[0].sclass, acl_index,
2391             [VppGbpContractRule(
2392                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2393                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2394                 []),
2395              VppGbpContractRule(
2396                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2397                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2398                  [])],
2399             [ETH_P_IP, ETH_P_IPV6])
2400         c2.add_vpp_config()
2401
2402         self.send_and_expect_bridged(eps[0].itf,
2403                                      pkt_inter_epg_220_to_221 * 65,
2404                                      eps[2].itf)
2405         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2406                                           dst=self.pg0.remote_mac) /
2407                                     IP(src=eps[2].ip4.address,
2408                                        dst=eps[0].ip4.address) /
2409                                     UDP(sport=1234, dport=1234) /
2410                                     Raw('\xa5' * 100))
2411         self.send_and_expect_bridged(eps[2].itf,
2412                                      pkt_inter_epg_221_to_220 * 65,
2413                                      eps[0].itf)
2414         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2415                                           dst=str(self.router_mac)) /
2416                                     IP(src=eps[2].ip4.address,
2417                                        dst=eps[0].ip4.address) /
2418                                     UDP(sport=1234, dport=1234) /
2419                                     Raw('\xa5' * 100))
2420         self.send_and_expect_routed(eps[2].itf,
2421                                     pkt_inter_epg_221_to_220 * 65,
2422                                     eps[0].itf,
2423                                     str(self.router_mac))
2424         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2425                                           dst=str(self.router_mac)) /
2426                                     IPv6(src=eps[2].ip6.address,
2427                                          dst=eps[0].ip6.address) /
2428                                     UDP(sport=1234, dport=1234) /
2429                                     Raw('\xa5' * 100))
2430         self.send_and_expect_routed6(eps[2].itf,
2431                                      pkt_inter_epg_221_to_220 * 65,
2432                                      eps[0].itf,
2433                                      str(self.router_mac))
2434
2435         #
2436         # contract between 220 and 222 uni-direction
2437         #
2438         c3 = VppGbpContract(
2439             self, 400, epgs[0].sclass, epgs[2].sclass, acl_index,
2440             [VppGbpContractRule(
2441                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2442                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2443                 []),
2444              VppGbpContractRule(
2445                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2446                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2447                  [])],
2448             [ETH_P_IP, ETH_P_IPV6])
2449         c3.add_vpp_config()
2450
2451         self.send_and_expect(eps[0].itf,
2452                              pkt_inter_epg_220_to_222 * 65,
2453                              eps[3].itf)
2454
2455         c3.remove_vpp_config()
2456         c1.remove_vpp_config()
2457         c2.remove_vpp_config()
2458         acl.remove_vpp_config()
2459
2460     def test_gbp_bd_drop_flags(self):
2461         """ GBP BD drop flags """
2462
2463         #
2464         # IP tables
2465         #
2466         gt4 = VppIpTable(self, 1)
2467         gt4.add_vpp_config()
2468         gt6 = VppIpTable(self, 1, is_ip6=True)
2469         gt6.add_vpp_config()
2470
2471         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2472         rd1.add_vpp_config()
2473
2474         #
2475         # a GBP bridge domain with a BVI only
2476         #
2477         bd1 = VppBridgeDomain(self, 1)
2478         bd1.add_vpp_config()
2479
2480         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2481                                   None, None,
2482                                   uu_drop=True, bm_drop=True)
2483         gbd1.add_vpp_config()
2484
2485         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2486         self.logger.info(self.vapi.cli("sh gbp bridge"))
2487
2488         # ... and has a /32 applied
2489         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2490         ip_addr.add_vpp_config()
2491
2492         #
2493         # The Endpoint-group
2494         #
2495         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2496                                       None, self.loop0,
2497                                       "10.0.0.128",
2498                                       "2001:10::128",
2499                                       VppGbpEndpointRetention(2))
2500         epg_220.add_vpp_config()
2501
2502         ep = VppGbpEndpoint(self, self.pg0,
2503                             epg_220, None,
2504                             "10.0.0.127", "11.0.0.127",
2505                             "2001:10::1", "3001::1")
2506         ep.add_vpp_config()
2507
2508         #
2509         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2510         # in bd
2511         #
2512         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2513         self.logger.info(self.vapi.cli("sh gbp bridge"))
2514         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2515                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2516                 UDP(sport=1234, dport=1234) /
2517                 Raw('\xa5' * 100))
2518         self.send_and_assert_no_replies(ep.itf, [p_uu])
2519
2520         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2521                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2522                 UDP(sport=1234, dport=1234) /
2523                 Raw('\xa5' * 100))
2524         self.send_and_assert_no_replies(ep.itf, [p_bm])
2525
2526         self.pg3.unconfig_ip4()
2527
2528         self.logger.info(self.vapi.cli("sh int"))
2529
2530     def test_gbp_bd_arp_flags(self):
2531         """ GBP BD arp flags """
2532
2533         #
2534         # IP tables
2535         #
2536         gt4 = VppIpTable(self, 1)
2537         gt4.add_vpp_config()
2538         gt6 = VppIpTable(self, 1, is_ip6=True)
2539         gt6.add_vpp_config()
2540
2541         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2542         rd1.add_vpp_config()
2543
2544         #
2545         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
2546         #
2547         self.pg4.config_ip4()
2548         self.pg4.resolve_arp()
2549
2550         #
2551         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
2552         #
2553         tun_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2554                                    "239.1.1.1", 88,
2555                                    mcast_itf=self.pg4)
2556         tun_uu.add_vpp_config()
2557
2558         #
2559         # a GBP bridge domain with a BVI and a UU-flood interface
2560         #
2561         bd1 = VppBridgeDomain(self, 1)
2562         bd1.add_vpp_config()
2563
2564         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2565                                   tun_uu, None,
2566                                   ucast_arp=True)
2567         gbd1.add_vpp_config()
2568
2569         # ... and has a /32 applied
2570         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2571         ip_addr.add_vpp_config()
2572
2573         #
2574         # The Endpoint-group
2575         #
2576         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2577                                       None, self.loop0,
2578                                       "10.0.0.128",
2579                                       "2001:10::128",
2580                                       VppGbpEndpointRetention(2))
2581         epg_220.add_vpp_config()
2582
2583         ep = VppGbpEndpoint(self, self.pg0,
2584                             epg_220, None,
2585                             "10.0.0.127", "11.0.0.127",
2586                             "2001:10::1", "3001::1")
2587         ep.add_vpp_config()
2588
2589         #
2590         # send ARP packet from the local EP expect it on the uu interface
2591         #
2592         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2593         self.logger.info(self.vapi.cli("sh gbp bridge"))
2594         p_arp = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2595                  ARP(op="who-has",
2596                      psrc=ep.ip4.address, pdst="10.0.0.99",
2597                      hwsrc=ep.mac,
2598                      hwdst="ff:ff:ff:ff:ff:ff"))
2599         self.send_and_expect(ep.itf, [p_arp], self.pg4)
2600
2601         self.pg4.unconfig_ip4()
2602
2603     def test_gbp_learn_vlan_l2(self):
2604         """ GBP L2 Endpoint w/ VLANs"""
2605
2606         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2607         learnt = [{'mac': '00:00:11:11:11:01',
2608                    'ip': '10.0.0.1',
2609                    'ip6': '2001:10::2'},
2610                   {'mac': '00:00:11:11:11:02',
2611                    'ip': '10.0.0.2',
2612                    'ip6': '2001:10::3'}]
2613
2614         #
2615         # IP tables
2616         #
2617         gt4 = VppIpTable(self, 1)
2618         gt4.add_vpp_config()
2619         gt6 = VppIpTable(self, 1, is_ip6=True)
2620         gt6.add_vpp_config()
2621
2622         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2623         rd1.add_vpp_config()
2624
2625         #
2626         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2627         #
2628         self.pg2.config_ip4()
2629         self.pg2.resolve_arp()
2630         self.pg2.generate_remote_hosts(4)
2631         self.pg2.configure_ipv4_neighbors()
2632         self.pg3.config_ip4()
2633         self.pg3.resolve_arp()
2634
2635         #
2636         # The EP will be on a vlan sub-interface
2637         #
2638         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2639         vlan_11.admin_up()
2640         self.vapi.l2_interface_vlan_tag_rewrite(
2641             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2642             push_dot1q=11)
2643
2644         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2645                                       self.pg3.remote_ip4, 116)
2646         bd_uu_fwd.add_vpp_config()
2647
2648         #
2649         # a GBP bridge domain with a BVI and a UU-flood interface
2650         # The BD is marked as do not learn, so no endpoints are ever
2651         # learnt in this BD.
2652         #
2653         bd1 = VppBridgeDomain(self, 1)
2654         bd1.add_vpp_config()
2655         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, bd_uu_fwd,
2656                                   learn=False)
2657         gbd1.add_vpp_config()
2658
2659         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2660         self.logger.info(self.vapi.cli("sh gbp bridge"))
2661
2662         # ... and has a /32 applied
2663         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2664         ip_addr.add_vpp_config()
2665
2666         #
2667         # The Endpoint-group in which we are learning endpoints
2668         #
2669         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2670                                       None, self.loop0,
2671                                       "10.0.0.128",
2672                                       "2001:10::128",
2673                                       VppGbpEndpointRetention(2))
2674         epg_220.add_vpp_config()
2675
2676         #
2677         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2678         # learning enabled
2679         #
2680         vx_tun_l2_1 = VppGbpVxlanTunnel(
2681             self, 99, bd1.bd_id,
2682             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2683             self.pg2.local_ip4)
2684         vx_tun_l2_1.add_vpp_config()
2685
2686         #
2687         # A static endpoint that the learnt endpoints are trying to
2688         # talk to
2689         #
2690         ep = VppGbpEndpoint(self, vlan_11,
2691                             epg_220, None,
2692                             "10.0.0.127", "11.0.0.127",
2693                             "2001:10::1", "3001::1")
2694         ep.add_vpp_config()
2695
2696         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
2697
2698         #
2699         # Send to the static EP
2700         #
2701         for ii, l in enumerate(learnt):
2702             # a packet with an sclass from a known EPG
2703             # arriving on an unknown TEP
2704             p = (Ether(src=self.pg2.remote_mac,
2705                        dst=self.pg2.local_mac) /
2706                  IP(src=self.pg2.remote_hosts[1].ip4,
2707                     dst=self.pg2.local_ip4) /
2708                  UDP(sport=1234, dport=48879) /
2709                  VXLAN(vni=99, gpid=441, flags=0x88) /
2710                  Ether(src=l['mac'], dst=ep.mac) /
2711                  IP(src=l['ip'], dst=ep.ip4.address) /
2712                  UDP(sport=1234, dport=1234) /
2713                  Raw('\xa5' * 100))
2714
2715             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2716
2717             #
2718             # packet to EP has the EP's vlan tag
2719             #
2720             for rx in rxs:
2721                 self.assertEqual(rx[Dot1Q].vlan, 11)
2722
2723             #
2724             # the EP is not learnt since the BD setting prevents it
2725             # also no TEP too
2726             #
2727             self.assertFalse(find_gbp_endpoint(self,
2728                                                vx_tun_l2_1.sw_if_index,
2729                                                mac=l['mac']))
2730             self.assertEqual(INDEX_INVALID,
2731                              find_vxlan_gbp_tunnel(
2732                                  self,
2733                                  self.pg2.local_ip4,
2734                                  self.pg2.remote_hosts[1].ip4,
2735                                  99))
2736
2737         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2738
2739         #
2740         # static to remotes
2741         # we didn't learn the remotes so they are sent to the UU-fwd
2742         #
2743         for l in learnt:
2744             p = (Ether(src=ep.mac, dst=l['mac']) /
2745                  Dot1Q(vlan=11) /
2746                  IP(dst=l['ip'], src=ep.ip4.address) /
2747                  UDP(sport=1234, dport=1234) /
2748                  Raw('\xa5' * 100))
2749
2750             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2751
2752             for rx in rxs:
2753                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2754                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2755                 self.assertEqual(rx[UDP].dport, 48879)
2756                 # the UDP source port is a random value for hashing
2757                 self.assertEqual(rx[VXLAN].gpid, 441)
2758                 self.assertEqual(rx[VXLAN].vni, 116)
2759                 self.assertTrue(rx[VXLAN].flags.G)
2760                 self.assertTrue(rx[VXLAN].flags.Instance)
2761                 self.assertFalse(rx[VXLAN].gpflags.A)
2762                 self.assertFalse(rx[VXLAN].gpflags.D)
2763
2764         self.pg2.unconfig_ip4()
2765         self.pg3.unconfig_ip4()
2766
2767     def test_gbp_learn_l3(self):
2768         """ GBP L3 Endpoint Learning """
2769
2770         self.vapi.cli("set logging class gbp level debug")
2771
2772         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2773         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2774         routed_src_mac = "00:22:bd:f8:19:ff"
2775
2776         learnt = [{'mac': '00:00:11:11:11:02',
2777                    'ip': '10.0.1.2',
2778                    'ip6': '2001:10::2'},
2779                   {'mac': '00:00:11:11:11:03',
2780                    'ip': '10.0.1.3',
2781                    'ip6': '2001:10::3'}]
2782
2783         #
2784         # IP tables
2785         #
2786         t4 = VppIpTable(self, 1)
2787         t4.add_vpp_config()
2788         t6 = VppIpTable(self, 1, True)
2789         t6.add_vpp_config()
2790
2791         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2792                                        self.pg4.remote_ip4, 114)
2793         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2794                                        self.pg4.remote_ip4, 116)
2795         tun_ip4_uu.add_vpp_config()
2796         tun_ip6_uu.add_vpp_config()
2797
2798         rd1 = VppGbpRouteDomain(self, 2, 401, t4, t6, tun_ip4_uu, tun_ip6_uu)
2799         rd1.add_vpp_config()
2800
2801         self.loop0.set_mac(self.router_mac)
2802
2803         #
2804         # Bind the BVI to the RD
2805         #
2806         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2807         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2808
2809         #
2810         # Pg2 hosts the vxlan tunnel
2811         # hosts on pg2 to act as TEPs
2812         # pg3 is BD uu-fwd
2813         # pg4 is RD uu-fwd
2814         #
2815         self.pg2.config_ip4()
2816         self.pg2.resolve_arp()
2817         self.pg2.generate_remote_hosts(4)
2818         self.pg2.configure_ipv4_neighbors()
2819         self.pg3.config_ip4()
2820         self.pg3.resolve_arp()
2821         self.pg4.config_ip4()
2822         self.pg4.resolve_arp()
2823
2824         #
2825         # a GBP bridge domain with a BVI and a UU-flood interface
2826         #
2827         bd1 = VppBridgeDomain(self, 1)
2828         bd1.add_vpp_config()
2829         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3)
2830         gbd1.add_vpp_config()
2831
2832         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2833         self.logger.info(self.vapi.cli("sh gbp bridge"))
2834         self.logger.info(self.vapi.cli("sh gbp route"))
2835
2836         # ... and has a /32 and /128 applied
2837         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2838         ip4_addr.add_vpp_config()
2839         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2840         ip6_addr.add_vpp_config()
2841
2842         #
2843         # The Endpoint-group in which we are learning endpoints
2844         #
2845         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2846                                       None, self.loop0,
2847                                       "10.0.0.128",
2848                                       "2001:10::128",
2849                                       VppGbpEndpointRetention(2))
2850         epg_220.add_vpp_config()
2851
2852         #
2853         # The VXLAN GBP tunnel is in L3 mode with learning enabled
2854         #
2855         vx_tun_l3 = VppGbpVxlanTunnel(
2856             self, 101, rd1.rd_id,
2857             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2858             self.pg2.local_ip4)
2859         vx_tun_l3.add_vpp_config()
2860
2861         #
2862         # A static endpoint that the learnt endpoints are trying to
2863         # talk to
2864         #
2865         ep = VppGbpEndpoint(self, self.pg0,
2866                             epg_220, None,
2867                             "10.0.0.127", "11.0.0.127",
2868                             "2001:10::1", "3001::1")
2869         ep.add_vpp_config()
2870
2871         #
2872         # learn some remote IPv4 EPs
2873         #
2874         for ii, l in enumerate(learnt):
2875             # a packet with an sclass from a known EPG
2876             # arriving on an unknown TEP
2877             p = (Ether(src=self.pg2.remote_mac,
2878                        dst=self.pg2.local_mac) /
2879                  IP(src=self.pg2.remote_hosts[1].ip4,
2880                     dst=self.pg2.local_ip4) /
2881                  UDP(sport=1234, dport=48879) /
2882                  VXLAN(vni=101, gpid=441, flags=0x88) /
2883                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2884                  IP(src=l['ip'], dst=ep.ip4.address) /
2885                  UDP(sport=1234, dport=1234) /
2886                  Raw('\xa5' * 100))
2887
2888             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2889
2890             # the new TEP
2891             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2892                 self,
2893                 self.pg2.local_ip4,
2894                 self.pg2.remote_hosts[1].ip4,
2895                 vx_tun_l3.vni)
2896             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2897
2898             # endpoint learnt via the parent GBP-vxlan interface
2899             self.assertTrue(find_gbp_endpoint(self,
2900                                               vx_tun_l3._sw_if_index,
2901                                               ip=l['ip']))
2902
2903         #
2904         # Static IPv4 EP replies to learnt
2905         #
2906         for l in learnt:
2907             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2908                  IP(dst=l['ip'], src=ep.ip4.address) /
2909                  UDP(sport=1234, dport=1234) /
2910                  Raw('\xa5' * 100))
2911
2912             rxs = self.send_and_expect(self.pg0, p * 1, self.pg2)
2913
2914             for rx in rxs:
2915                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2916                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2917                 self.assertEqual(rx[UDP].dport, 48879)
2918                 # the UDP source port is a random value for hashing
2919                 self.assertEqual(rx[VXLAN].gpid, 441)
2920                 self.assertEqual(rx[VXLAN].vni, 101)
2921                 self.assertTrue(rx[VXLAN].flags.G)
2922                 self.assertTrue(rx[VXLAN].flags.Instance)
2923                 self.assertTrue(rx[VXLAN].gpflags.A)
2924                 self.assertFalse(rx[VXLAN].gpflags.D)
2925
2926                 inner = rx[VXLAN].payload
2927
2928                 self.assertEqual(inner[Ether].src, routed_src_mac)
2929                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2930                 self.assertEqual(inner[IP].src, ep.ip4.address)
2931                 self.assertEqual(inner[IP].dst, l['ip'])
2932
2933         for l in learnt:
2934             self.assertFalse(find_gbp_endpoint(self,
2935                                                tep1_sw_if_index,
2936                                                ip=l['ip']))
2937
2938         #
2939         # learn some remote IPv6 EPs
2940         #
2941         for ii, l in enumerate(learnt):
2942             # a packet with an sclass from a known EPG
2943             # arriving on an unknown TEP
2944             p = (Ether(src=self.pg2.remote_mac,
2945                        dst=self.pg2.local_mac) /
2946                  IP(src=self.pg2.remote_hosts[1].ip4,
2947                     dst=self.pg2.local_ip4) /
2948                  UDP(sport=1234, dport=48879) /
2949                  VXLAN(vni=101, gpid=441, flags=0x88) /
2950                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2951                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2952                  UDP(sport=1234, dport=1234) /
2953                  Raw('\xa5' * 100))
2954
2955             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2956
2957             # the new TEP
2958             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2959                 self,
2960                 self.pg2.local_ip4,
2961                 self.pg2.remote_hosts[1].ip4,
2962                 vx_tun_l3.vni)
2963             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2964
2965             self.logger.info(self.vapi.cli("show gbp bridge"))
2966             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2967             self.logger.info(self.vapi.cli("show gbp vxlan"))
2968             self.logger.info(self.vapi.cli("show int addr"))
2969
2970             # endpoint learnt via the TEP
2971             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2972
2973         self.logger.info(self.vapi.cli("show gbp endpoint"))
2974         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2975
2976         #
2977         # Static EP replies to learnt
2978         #
2979         for l in learnt:
2980             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2981                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2982                  UDP(sport=1234, dport=1234) /
2983                  Raw('\xa5' * 100))
2984
2985             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2986
2987             for rx in rxs:
2988                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2989                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2990                 self.assertEqual(rx[UDP].dport, 48879)
2991                 # the UDP source port is a random value for hashing
2992                 self.assertEqual(rx[VXLAN].gpid, 441)
2993                 self.assertEqual(rx[VXLAN].vni, 101)
2994                 self.assertTrue(rx[VXLAN].flags.G)
2995                 self.assertTrue(rx[VXLAN].flags.Instance)
2996                 self.assertTrue(rx[VXLAN].gpflags.A)
2997                 self.assertFalse(rx[VXLAN].gpflags.D)
2998
2999                 inner = rx[VXLAN].payload
3000
3001                 self.assertEqual(inner[Ether].src, routed_src_mac)
3002                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
3003                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
3004                 self.assertEqual(inner[IPv6].dst, l['ip6'])
3005
3006         self.logger.info(self.vapi.cli("sh gbp endpoint"))
3007         for l in learnt:
3008             self.wait_for_ep_timeout(ip=l['ip'])
3009
3010         #
3011         # Static sends to unknown EP with no route
3012         #
3013         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3014              IP(dst="10.0.0.99", src=ep.ip4.address) /
3015              UDP(sport=1234, dport=1234) /
3016              Raw('\xa5' * 100))
3017
3018         self.send_and_assert_no_replies(self.pg0, [p])
3019
3020         #
3021         # Add a route to static EP's v4 and v6 subnet
3022         #
3023         se_10_24 = VppGbpSubnet(
3024             self, rd1, "10.0.0.0", 24,
3025             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3026         se_10_24.add_vpp_config()
3027
3028         #
3029         # static pings router
3030         #
3031         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3032              IP(dst=epg_220.bvi_ip4.address, src=ep.ip4.address) /
3033              UDP(sport=1234, dport=1234) /
3034              Raw('\xa5' * 100))
3035
3036         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3037
3038         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3039              IPv6(dst=epg_220.bvi_ip6.address, src=ep.ip6.address) /
3040              UDP(sport=1234, dport=1234) /
3041              Raw('\xa5' * 100))
3042
3043         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3044
3045         #
3046         # packets to address in the subnet are sent on the uu-fwd
3047         #
3048         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3049              IP(dst="10.0.0.99", src=ep.ip4.address) /
3050              UDP(sport=1234, dport=1234) /
3051              Raw('\xa5' * 100))
3052
3053         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3054         for rx in rxs:
3055             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
3056             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
3057             self.assertEqual(rx[UDP].dport, 48879)
3058             # the UDP source port is a random value for hashing
3059             self.assertEqual(rx[VXLAN].gpid, 441)
3060             self.assertEqual(rx[VXLAN].vni, 114)
3061             self.assertTrue(rx[VXLAN].flags.G)
3062             self.assertTrue(rx[VXLAN].flags.Instance)
3063             # policy is not applied to packets sent to the uu-fwd interfaces
3064             self.assertFalse(rx[VXLAN].gpflags.A)
3065             self.assertFalse(rx[VXLAN].gpflags.D)
3066
3067         #
3068         # learn some remote IPv4 EPs
3069         #
3070         for ii, l in enumerate(learnt):
3071             # a packet with an sclass from a known EPG
3072             # arriving on an unknown TEP
3073             p = (Ether(src=self.pg2.remote_mac,
3074                        dst=self.pg2.local_mac) /
3075                  IP(src=self.pg2.remote_hosts[2].ip4,
3076                     dst=self.pg2.local_ip4) /
3077                  UDP(sport=1234, dport=48879) /
3078                  VXLAN(vni=101, gpid=441, flags=0x88) /
3079                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3080                  IP(src=l['ip'], dst=ep.ip4.address) /
3081                  UDP(sport=1234, dport=1234) /
3082                  Raw('\xa5' * 100))
3083
3084             rx = self.send_and_expect(self.pg2, [p], self.pg0)
3085
3086             # the new TEP
3087             tep1_sw_if_index = find_vxlan_gbp_tunnel(
3088                 self,
3089                 self.pg2.local_ip4,
3090                 self.pg2.remote_hosts[2].ip4,
3091                 vx_tun_l3.vni)
3092             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
3093
3094             # endpoint learnt via the parent GBP-vxlan interface
3095             self.assertTrue(find_gbp_endpoint(self,
3096                                               vx_tun_l3._sw_if_index,
3097                                               ip=l['ip']))
3098
3099         #
3100         # Add a remote endpoint from the API
3101         #
3102         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
3103                                 epg_220, None,
3104                                 "10.0.0.88", "11.0.0.88",
3105                                 "2001:10::88", "3001::88",
3106                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3107                                 self.pg2.local_ip4,
3108                                 self.pg2.remote_hosts[2].ip4,
3109                                 mac=None)
3110         rep_88.add_vpp_config()
3111
3112         #
3113         # Add a remote endpoint from the API that matches an existing one
3114         # this is a lower priority, hence the packet is sent to the DP leanrt
3115         # TEP
3116         #
3117         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
3118                                epg_220, None,
3119                                learnt[0]['ip'], "11.0.0.101",
3120                                learnt[0]['ip6'], "3001::101",
3121                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3122                                self.pg2.local_ip4,
3123                                self.pg2.remote_hosts[1].ip4,
3124                                mac=None)
3125         rep_2.add_vpp_config()
3126
3127         #
3128         # Add a route to the learned EP's v4 subnet
3129         #  packets should be send on the v4/v6 uu=fwd interface resp.
3130         #
3131         se_10_1_24 = VppGbpSubnet(
3132             self, rd1, "10.0.1.0", 24,
3133             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3134         se_10_1_24.add_vpp_config()
3135
3136         self.logger.info(self.vapi.cli("show gbp endpoint"))
3137
3138         ips = ["10.0.0.88", learnt[0]['ip']]
3139         for ip in ips:
3140             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3141                  IP(dst=ip, src=ep.ip4.address) /
3142                  UDP(sport=1234, dport=1234) /
3143                  Raw('\xa5' * 100))
3144
3145             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3146
3147             for rx in rxs:
3148                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3149                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3150                 self.assertEqual(rx[UDP].dport, 48879)
3151                 # the UDP source port is a random value for hashing
3152                 self.assertEqual(rx[VXLAN].gpid, 441)
3153                 self.assertEqual(rx[VXLAN].vni, 101)
3154                 self.assertTrue(rx[VXLAN].flags.G)
3155                 self.assertTrue(rx[VXLAN].flags.Instance)
3156                 self.assertTrue(rx[VXLAN].gpflags.A)
3157                 self.assertFalse(rx[VXLAN].gpflags.D)
3158
3159                 inner = rx[VXLAN].payload
3160
3161                 self.assertEqual(inner[Ether].src, routed_src_mac)
3162                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
3163                 self.assertEqual(inner[IP].src, ep.ip4.address)
3164                 self.assertEqual(inner[IP].dst, ip)
3165
3166         #
3167         # remove the API remote EPs, only API sourced is gone, the DP
3168         # learnt one remains
3169         #
3170         rep_88.remove_vpp_config()
3171         rep_2.remove_vpp_config()
3172
3173         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
3174
3175         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3176              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
3177              UDP(sport=1234, dport=1234) /
3178              Raw('\xa5' * 100))
3179         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
3180
3181         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
3182
3183         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3184              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
3185              UDP(sport=1234, dport=1234) /
3186              Raw('\xa5' * 100))
3187         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3188
3189         #
3190         # to appease the testcase we cannot have the registered EP still
3191         # present (because it's DP learnt) when the TC ends so wait until
3192         # it is removed
3193         #
3194         self.wait_for_ep_timeout(ip=rep_88.ip4.address)
3195         self.wait_for_ep_timeout(ip=rep_2.ip4.address)
3196
3197         #
3198         # Same as above, learn a remote EP via CP and DP
3199         # this time remove the DP one first. expect the CP data to remain
3200         #
3201         rep_3 = VppGbpEndpoint(self, vx_tun_l3,
3202                                epg_220, None,
3203                                "10.0.1.4", "11.0.0.103",
3204                                "2001::10:3", "3001::103",
3205                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3206                                self.pg2.local_ip4,
3207                                self.pg2.remote_hosts[1].ip4,
3208                                mac=None)
3209         rep_3.add_vpp_config()
3210
3211         p = (Ether(src=self.pg2.remote_mac,
3212                    dst=self.pg2.local_mac) /
3213              IP(src=self.pg2.remote_hosts[2].ip4,
3214                 dst=self.pg2.local_ip4) /
3215              UDP(sport=1234, dport=48879) /
3216              VXLAN(vni=101, gpid=441, flags=0x88) /
3217              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3218              IP(src="10.0.1.4", dst=ep.ip4.address) /
3219              UDP(sport=1234, dport=1234) /
3220              Raw('\xa5' * 100))
3221         rxs = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
3222
3223         self.assertTrue(find_gbp_endpoint(self,
3224                                           vx_tun_l3._sw_if_index,
3225                                           ip=rep_3.ip4.address,
3226                                           tep=[self.pg2.local_ip4,
3227                                                self.pg2.remote_hosts[2].ip4]))
3228
3229         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3230              IP(dst="10.0.1.4", src=ep.ip4.address) /
3231              UDP(sport=1234, dport=1234) /
3232              Raw('\xa5' * 100))
3233         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3234
3235         # host 2 is the DP learned TEP
3236         for rx in rxs:
3237             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3238             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3239
3240         self.wait_for_ep_timeout(ip=rep_3.ip4.address,
3241                                  tep=[self.pg2.local_ip4,
3242                                       self.pg2.remote_hosts[2].ip4])
3243
3244         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3245
3246         # host 1 is the CP learned TEP
3247         for rx in rxs:
3248             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3249             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
3250
3251         #
3252         # shutdown with learnt endpoint present
3253         #
3254         p = (Ether(src=self.pg2.remote_mac,
3255                    dst=self.pg2.local_mac) /
3256              IP(src=self.pg2.remote_hosts[1].ip4,
3257                 dst=self.pg2.local_ip4) /
3258              UDP(sport=1234, dport=48879) /
3259              VXLAN(vni=101, gpid=441, flags=0x88) /
3260              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3261              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
3262              UDP(sport=1234, dport=1234) /
3263              Raw('\xa5' * 100))
3264
3265         rx = self.send_and_expect(self.pg2, [p], self.pg0)
3266
3267         # endpoint learnt via the parent GBP-vxlan interface
3268         self.assertTrue(find_gbp_endpoint(self,
3269                                           vx_tun_l3._sw_if_index,
3270                                           ip=l['ip']))
3271
3272         #
3273         # TODO
3274         # remote endpoint becomes local
3275         #
3276         self.pg2.unconfig_ip4()
3277         self.pg3.unconfig_ip4()
3278         self.pg4.unconfig_ip4()
3279
3280     def test_gbp_redirect(self):
3281         """ GBP Endpoint Redirect """
3282
3283         self.vapi.cli("set logging class gbp level debug")
3284
3285         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3286         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3287         routed_src_mac = "00:22:bd:f8:19:ff"
3288
3289         learnt = [{'mac': '00:00:11:11:11:02',
3290                    'ip': '10.0.1.2',
3291                    'ip6': '2001:10::2'},
3292                   {'mac': '00:00:11:11:11:03',
3293                    'ip': '10.0.1.3',
3294                    'ip6': '2001:10::3'}]
3295
3296         #
3297         # IP tables
3298         #
3299         t4 = VppIpTable(self, 1)
3300         t4.add_vpp_config()
3301         t6 = VppIpTable(self, 1, True)
3302         t6.add_vpp_config()
3303
3304         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6)
3305         rd1.add_vpp_config()
3306
3307         self.loop0.set_mac(self.router_mac)
3308
3309         #
3310         # Bind the BVI to the RD
3311         #
3312         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3313         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3314
3315         #
3316         # Pg7 hosts a BD's UU-fwd
3317         #
3318         self.pg7.config_ip4()
3319         self.pg7.resolve_arp()
3320
3321         #
3322         # a GBP bridge domains for the EPs
3323         #
3324         bd1 = VppBridgeDomain(self, 1)
3325         bd1.add_vpp_config()
3326         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
3327         gbd1.add_vpp_config()
3328
3329         bd2 = VppBridgeDomain(self, 2)
3330         bd2.add_vpp_config()
3331         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
3332         gbd2.add_vpp_config()
3333
3334         # ... and has a /32 and /128 applied
3335         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
3336         ip4_addr.add_vpp_config()
3337         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
3338         ip6_addr.add_vpp_config()
3339         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
3340         ip4_addr.add_vpp_config()
3341         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
3342         ip6_addr.add_vpp_config()
3343
3344         #
3345         # The Endpoint-groups in which we are learning endpoints
3346         #
3347         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
3348                                       None, gbd1.bvi,
3349                                       "10.0.0.128",
3350                                       "2001:10::128",
3351                                       VppGbpEndpointRetention(2))
3352         epg_220.add_vpp_config()
3353         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
3354                                       None, gbd2.bvi,
3355                                       "10.0.1.128",
3356                                       "2001:11::128",
3357                                       VppGbpEndpointRetention(2))
3358         epg_221.add_vpp_config()
3359         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
3360                                       None, gbd1.bvi,
3361                                       "10.0.2.128",
3362                                       "2001:12::128",
3363                                       VppGbpEndpointRetention(2))
3364         epg_222.add_vpp_config()
3365
3366         #
3367         # a GBP bridge domains for the SEPs
3368         #
3369         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3370                                    self.pg7.remote_ip4, 116)
3371         bd_uu1.add_vpp_config()
3372         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3373                                    self.pg7.remote_ip4, 117)
3374         bd_uu2.add_vpp_config()
3375
3376         bd3 = VppBridgeDomain(self, 3)
3377         bd3.add_vpp_config()
3378         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
3379                                   bd_uu1, learn=False)
3380         gbd3.add_vpp_config()
3381         bd4 = VppBridgeDomain(self, 4)
3382         bd4.add_vpp_config()
3383         gbd4 = VppGbpBridgeDomain(self, bd4, rd1, self.loop3,
3384                                   bd_uu2, learn=False)
3385         gbd4.add_vpp_config()
3386
3387         #
3388         # EPGs in which the service endpoints exist
3389         #
3390         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
3391                                       None, gbd1.bvi,
3392                                       "12.0.0.128",
3393                                       "4001:10::128",
3394                                       VppGbpEndpointRetention(2))
3395         epg_320.add_vpp_config()
3396         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
3397                                       None, gbd2.bvi,
3398                                       "12.0.1.128",
3399                                       "4001:11::128",
3400                                       VppGbpEndpointRetention(2))
3401         epg_321.add_vpp_config()
3402
3403         #
3404         # three local endpoints
3405         #
3406         ep1 = VppGbpEndpoint(self, self.pg0,
3407                              epg_220, None,
3408                              "10.0.0.1", "11.0.0.1",
3409                              "2001:10::1", "3001:10::1")
3410         ep1.add_vpp_config()
3411         ep2 = VppGbpEndpoint(self, self.pg1,
3412                              epg_221, None,
3413                              "10.0.1.1", "11.0.1.1",
3414                              "2001:11::1", "3001:11::1")
3415         ep2.add_vpp_config()
3416         ep3 = VppGbpEndpoint(self, self.pg2,
3417                              epg_222, None,
3418                              "10.0.2.2", "11.0.2.2",
3419                              "2001:12::1", "3001:12::1")
3420         ep3.add_vpp_config()
3421
3422         #
3423         # service endpoints
3424         #
3425         sep1 = VppGbpEndpoint(self, self.pg3,
3426                               epg_320, None,
3427                               "12.0.0.1", "13.0.0.1",
3428                               "4001:10::1", "5001:10::1")
3429         sep1.add_vpp_config()
3430         sep2 = VppGbpEndpoint(self, self.pg4,
3431                               epg_320, None,
3432                               "12.0.0.2", "13.0.0.2",
3433                               "4001:10::2", "5001:10::2")
3434         sep2.add_vpp_config()
3435         sep3 = VppGbpEndpoint(self, self.pg5,
3436                               epg_321, None,
3437                               "12.0.1.1", "13.0.1.1",
3438                               "4001:11::1", "5001:11::1")
3439         sep3.add_vpp_config()
3440         # this EP is not installed immediately
3441         sep4 = VppGbpEndpoint(self, self.pg6,
3442                               epg_321, None,
3443                               "12.0.1.2", "13.0.1.2",
3444                               "4001:11::2", "5001:11::2")
3445
3446         #
3447         # an L2 switch packet between local EPs in different EPGs
3448         #  different dest ports on each so the are LB hashed differently
3449         #
3450         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3451                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
3452                UDP(sport=1234, dport=1234) /
3453                Raw('\xa5' * 100)),
3454               (Ether(src=ep3.mac, dst=ep1.mac) /
3455                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
3456                UDP(sport=1234, dport=1234) /
3457                Raw('\xa5' * 100))]
3458         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3459                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
3460                UDP(sport=1234, dport=1234) /
3461                Raw('\xa5' * 100)),
3462               (Ether(src=ep3.mac, dst=ep1.mac) /
3463                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
3464                UDP(sport=1234, dport=1230) /
3465                Raw('\xa5' * 100))]
3466
3467         # should be dropped since no contract yet
3468         self.send_and_assert_no_replies(self.pg0, [p4[0]])
3469         self.send_and_assert_no_replies(self.pg0, [p6[0]])
3470
3471         #
3472         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
3473         # one of the next-hops is via an EP that is not known
3474         #
3475         acl = VppGbpAcl(self)
3476         rule4 = acl.create_rule(permit_deny=1, proto=17)
3477         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3478         acl_index = acl.add_vpp_config([rule4, rule6])
3479
3480         #
3481         # test the src-ip hash mode
3482         #
3483         c1 = VppGbpContract(
3484             self, 402, epg_220.sclass, epg_222.sclass, acl_index,
3485             [VppGbpContractRule(
3486                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3487                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3488                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3489                                        sep1.ip4, sep1.epg.rd),
3490                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3491                                        sep2.ip4, sep2.epg.rd)]),
3492                 VppGbpContractRule(
3493                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3494                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3495                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3496                                            sep3.ip6, sep3.epg.rd),
3497                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3498                                            sep4.ip6, sep4.epg.rd)])],
3499             [ETH_P_IP, ETH_P_IPV6])
3500         c1.add_vpp_config()
3501
3502         c2 = VppGbpContract(
3503             self, 402, epg_222.sclass, epg_220.sclass, acl_index,
3504             [VppGbpContractRule(
3505                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3506                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3507                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3508                                        sep1.ip4, sep1.epg.rd),
3509                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3510                                        sep2.ip4, sep2.epg.rd)]),
3511                 VppGbpContractRule(
3512                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3513                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3514                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3515                                            sep3.ip6, sep3.epg.rd),
3516                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3517                                            sep4.ip6, sep4.epg.rd)])],
3518             [ETH_P_IP, ETH_P_IPV6])
3519         c2.add_vpp_config()
3520
3521         #
3522         # send again with the contract preset, now packets arrive
3523         # at SEP1 or SEP2 depending on the hashing
3524         #
3525         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3526
3527         for rx in rxs:
3528             self.assertEqual(rx[Ether].src, routed_src_mac)
3529             self.assertEqual(rx[Ether].dst, sep1.mac)
3530             self.assertEqual(rx[IP].src, ep1.ip4.address)
3531             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3532
3533         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
3534
3535         for rx in rxs:
3536             self.assertEqual(rx[Ether].src, routed_src_mac)
3537             self.assertEqual(rx[Ether].dst, sep2.mac)
3538             self.assertEqual(rx[IP].src, ep3.ip4.address)
3539             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3540
3541         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3542
3543         for rx in rxs:
3544             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3545             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3546             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3547             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3548             self.assertEqual(rx[VXLAN].vni, 117)
3549             self.assertTrue(rx[VXLAN].flags.G)
3550             self.assertTrue(rx[VXLAN].flags.Instance)
3551             # redirect policy has been applied
3552             self.assertTrue(rx[VXLAN].gpflags.A)
3553             self.assertFalse(rx[VXLAN].gpflags.D)
3554
3555             inner = rx[VXLAN].payload
3556
3557             self.assertEqual(inner[Ether].src, routed_src_mac)
3558             self.assertEqual(inner[Ether].dst, sep4.mac)
3559             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3560             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3561
3562         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
3563
3564         for rx in rxs:
3565             self.assertEqual(rx[Ether].src, routed_src_mac)
3566             self.assertEqual(rx[Ether].dst, sep3.mac)
3567             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
3568             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
3569
3570         #
3571         # programme the unknown EP
3572         #
3573         sep4.add_vpp_config()
3574
3575         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3576
3577         for rx in rxs:
3578             self.assertEqual(rx[Ether].src, routed_src_mac)
3579             self.assertEqual(rx[Ether].dst, sep4.mac)
3580             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3581             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
3582
3583         #
3584         # and revert back to unprogrammed
3585         #
3586         sep4.remove_vpp_config()
3587
3588         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3589
3590         for rx in rxs:
3591             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3592             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3593             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3594             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3595             self.assertEqual(rx[VXLAN].vni, 117)
3596             self.assertTrue(rx[VXLAN].flags.G)
3597             self.assertTrue(rx[VXLAN].flags.Instance)
3598             # redirect policy has been applied
3599             self.assertTrue(rx[VXLAN].gpflags.A)
3600             self.assertFalse(rx[VXLAN].gpflags.D)
3601
3602             inner = rx[VXLAN].payload
3603
3604             self.assertEqual(inner[Ether].src, routed_src_mac)
3605             self.assertEqual(inner[Ether].dst, sep4.mac)
3606             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3607             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3608
3609         c1.remove_vpp_config()
3610         c2.remove_vpp_config()
3611
3612         #
3613         # test the symmetric hash mode
3614         #
3615         c1 = VppGbpContract(
3616             self, 402, epg_220.sclass, epg_222.sclass, acl_index,
3617             [VppGbpContractRule(
3618                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3619                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3620                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3621                                        sep1.ip4, sep1.epg.rd),
3622                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3623                                        sep2.ip4, sep2.epg.rd)]),
3624                 VppGbpContractRule(
3625                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3626                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3627                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3628                                            sep3.ip6, sep3.epg.rd),
3629                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3630                                            sep4.ip6, sep4.epg.rd)])],
3631             [ETH_P_IP, ETH_P_IPV6])
3632         c1.add_vpp_config()
3633
3634         c2 = VppGbpContract(
3635             self, 402, epg_222.sclass, epg_220.sclass, acl_index,
3636             [VppGbpContractRule(
3637                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3638                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3639                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3640                                        sep1.ip4, sep1.epg.rd),
3641                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3642                                        sep2.ip4, sep2.epg.rd)]),
3643                 VppGbpContractRule(
3644                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3645                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3646                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3647                                            sep3.ip6, sep3.epg.rd),
3648                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3649                                            sep4.ip6, sep4.epg.rd)])],
3650             [ETH_P_IP, ETH_P_IPV6])
3651         c2.add_vpp_config()
3652
3653         #
3654         # send again with the contract preset, now packets arrive
3655         # at SEP1 for both directions
3656         #
3657         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3658
3659         for rx in rxs:
3660             self.assertEqual(rx[Ether].src, routed_src_mac)
3661             self.assertEqual(rx[Ether].dst, sep1.mac)
3662             self.assertEqual(rx[IP].src, ep1.ip4.address)
3663             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3664
3665         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3666
3667         for rx in rxs:
3668             self.assertEqual(rx[Ether].src, routed_src_mac)
3669             self.assertEqual(rx[Ether].dst, sep1.mac)
3670             self.assertEqual(rx[IP].src, ep3.ip4.address)
3671             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3672
3673         #
3674         # programme the unknown EP for the L3 tests
3675         #
3676         sep4.add_vpp_config()
3677
3678         #
3679         # an L3 switch packet between local EPs in different EPGs
3680         #  different dest ports on each so the are LB hashed differently
3681         #
3682         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3683                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
3684                UDP(sport=1234, dport=1234) /
3685                Raw('\xa5' * 100)),
3686               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3687                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
3688                UDP(sport=1234, dport=1234) /
3689                Raw('\xa5' * 100))]
3690         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3691                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
3692                UDP(sport=1234, dport=1234) /
3693                Raw('\xa5' * 100)),
3694               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3695                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
3696                UDP(sport=1234, dport=1234) /
3697                Raw('\xa5' * 100))]
3698
3699         c3 = VppGbpContract(
3700             self, 402, epg_220.sclass, epg_221.sclass, acl_index,
3701             [VppGbpContractRule(
3702                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3703                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3704                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3705                                        sep1.ip4, sep1.epg.rd),
3706                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3707                                        sep2.ip4, sep2.epg.rd)]),
3708                 VppGbpContractRule(
3709                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3710                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3711                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3712                                            sep3.ip6, sep3.epg.rd),
3713                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3714                                            sep4.ip6, sep4.epg.rd)])],
3715             [ETH_P_IP, ETH_P_IPV6])
3716         c3.add_vpp_config()
3717
3718         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3719
3720         for rx in rxs:
3721             self.assertEqual(rx[Ether].src, routed_src_mac)
3722             self.assertEqual(rx[Ether].dst, sep1.mac)
3723             self.assertEqual(rx[IP].src, ep1.ip4.address)
3724             self.assertEqual(rx[IP].dst, ep2.ip4.address)
3725
3726         #
3727         # learn a remote EP in EPG 221
3728         #   packets coming from unknown remote EPs will be leant & redirected
3729         #
3730         vx_tun_l3 = VppGbpVxlanTunnel(
3731             self, 444, rd1.rd_id,
3732             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3733             self.pg2.local_ip4)
3734         vx_tun_l3.add_vpp_config()
3735
3736         c4 = VppGbpContract(
3737             self, 402, epg_221.sclass, epg_220.sclass, acl_index,
3738             [VppGbpContractRule(
3739                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3740                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3741                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3742                                        sep1.ip4, sep1.epg.rd),
3743                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3744                                        sep2.ip4, sep2.epg.rd)]),
3745                 VppGbpContractRule(
3746                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3747                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3748                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3749                                            sep3.ip6, sep3.epg.rd),
3750                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3751                                            sep4.ip6, sep4.epg.rd)])],
3752             [ETH_P_IP, ETH_P_IPV6])
3753         c4.add_vpp_config()
3754
3755         p = (Ether(src=self.pg7.remote_mac,
3756                    dst=self.pg7.local_mac) /
3757              IP(src=self.pg7.remote_ip4,
3758                 dst=self.pg7.local_ip4) /
3759              UDP(sport=1234, dport=48879) /
3760              VXLAN(vni=444, gpid=441, flags=0x88) /
3761              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3762              IP(src="10.0.0.88", dst=ep1.ip4.address) /
3763              UDP(sport=1234, dport=1234) /
3764              Raw('\xa5' * 100))
3765
3766         # unknown remote EP to local EP redirected
3767         rxs = self.send_and_expect(self.pg7, [p], sep1.itf)
3768
3769         for rx in rxs:
3770             self.assertEqual(rx[Ether].src, routed_src_mac)
3771             self.assertEqual(rx[Ether].dst, sep1.mac)
3772             self.assertEqual(rx[IP].src, "10.0.0.88")
3773             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3774
3775         # endpoint learnt via the parent GBP-vxlan interface
3776         self.assertTrue(find_gbp_endpoint(self,
3777                                           vx_tun_l3._sw_if_index,
3778                                           ip="10.0.0.88"))
3779
3780         p = (Ether(src=self.pg7.remote_mac,
3781                    dst=self.pg7.local_mac) /
3782              IP(src=self.pg7.remote_ip4,
3783                 dst=self.pg7.local_ip4) /
3784              UDP(sport=1234, dport=48879) /
3785              VXLAN(vni=444, gpid=441, flags=0x88) /
3786              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3787              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
3788              UDP(sport=1234, dport=1234) /
3789              Raw('\xa5' * 100))
3790
3791         # unknown remote EP to local EP redirected (ipv6)
3792         rxs = self.send_and_expect(self.pg7, [p], sep3.itf)
3793
3794         for rx in rxs:
3795             self.assertEqual(rx[Ether].src, routed_src_mac)
3796             self.assertEqual(rx[Ether].dst, sep3.mac)
3797             self.assertEqual(rx[IPv6].src, "2001:10::88")
3798             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
3799
3800         # endpoint learnt via the parent GBP-vxlan interface
3801         self.assertTrue(find_gbp_endpoint(self,
3802                                           vx_tun_l3._sw_if_index,
3803                                           ip="2001:10::88"))
3804
3805         #
3806         # L3 switch from local to remote EP
3807         #
3808         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3809                IP(src=ep1.ip4.address, dst="10.0.0.88") /
3810                UDP(sport=1234, dport=1234) /
3811                Raw('\xa5' * 100))]
3812         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3813                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
3814                UDP(sport=1234, dport=1234) /
3815                Raw('\xa5' * 100))]
3816
3817         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3818
3819         for rx in rxs:
3820             self.assertEqual(rx[Ether].src, routed_src_mac)
3821             self.assertEqual(rx[Ether].dst, sep1.mac)
3822             self.assertEqual(rx[IP].src, ep1.ip4.address)
3823             self.assertEqual(rx[IP].dst, "10.0.0.88")
3824
3825         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3826
3827         for rx in rxs:
3828             self.assertEqual(rx[Ether].src, routed_src_mac)
3829             self.assertEqual(rx[Ether].dst, sep4.mac)
3830             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3831             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3832
3833         #
3834         # test the dst-ip hash mode
3835         #
3836         c5 = VppGbpContract(
3837             self, 402, epg_220.sclass, epg_221.sclass, acl_index,
3838             [VppGbpContractRule(
3839                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3840                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3841                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3842                                        sep1.ip4, sep1.epg.rd),
3843                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3844                                        sep2.ip4, sep2.epg.rd)]),
3845                 VppGbpContractRule(
3846                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3847                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3848                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3849                                            sep3.ip6, sep3.epg.rd),
3850                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3851                                            sep4.ip6, sep4.epg.rd)])],
3852             [ETH_P_IP, ETH_P_IPV6])
3853         c5.add_vpp_config()
3854
3855         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3856
3857         for rx in rxs:
3858             self.assertEqual(rx[Ether].src, routed_src_mac)
3859             self.assertEqual(rx[Ether].dst, sep1.mac)
3860             self.assertEqual(rx[IP].src, ep1.ip4.address)
3861             self.assertEqual(rx[IP].dst, "10.0.0.88")
3862
3863         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3864
3865         for rx in rxs:
3866             self.assertEqual(rx[Ether].src, routed_src_mac)
3867             self.assertEqual(rx[Ether].dst, sep3.mac)
3868             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3869             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3870
3871         #
3872         # a programmed remote SEP in EPG 320
3873         #
3874
3875         # gbp vxlan tunnel for the remote SEP
3876         vx_tun_l3_sep = VppGbpVxlanTunnel(
3877             self, 555, rd1.rd_id,
3878             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3879             self.pg2.local_ip4)
3880         vx_tun_l3_sep.add_vpp_config()
3881
3882         # remote SEP
3883         sep5 = VppGbpEndpoint(self, vx_tun_l3_sep,
3884                               epg_320, None,
3885                               "12.0.0.10", "13.0.0.10",
3886                               "4001:10::10", "5001:10::10",
3887                               ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3888                               self.pg7.local_ip4,
3889                               self.pg7.remote_ip4,
3890                               mac=None)
3891         sep5.add_vpp_config()
3892
3893         #
3894         # local l3out redirect tests
3895         #
3896
3897         # add local l3out
3898         # the external bd
3899         self.loop4.set_mac(self.router_mac)
3900         VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config()
3901         VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config()
3902         ebd = VppBridgeDomain(self, 100)
3903         ebd.add_vpp_config()
3904         gebd = VppGbpBridgeDomain(self, ebd, rd1, self.loop4, None, None)
3905         gebd.add_vpp_config()
3906         # the external epg
3907         eepg = VppGbpEndpointGroup(self, 888, 765, rd1, gebd,
3908                                    None, gebd.bvi,
3909                                    "10.1.0.128",
3910                                    "2001:10:1::128",
3911                                    VppGbpEndpointRetention(2))
3912         eepg.add_vpp_config()
3913         # add subnets to BVI
3914         VppIpInterfaceAddress(
3915             self,
3916             gebd.bvi,
3917             "10.1.0.128",
3918             24).add_vpp_config()
3919         VppIpInterfaceAddress(
3920             self,
3921             gebd.bvi,
3922             "2001:10:1::128",
3923             64).add_vpp_config()
3924         # ... which are L3-out subnets
3925         VppGbpSubnet(self, rd1, "10.1.0.0", 24,
3926                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3927                      sclass=765).add_vpp_config()
3928         VppGbpSubnet(self, rd1, "2001:10:1::128", 64,
3929                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3930                      sclass=765).add_vpp_config()
3931         # external endpoints
3932         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3933         eep1 = VppGbpEndpoint(self, self.vlan_100, eepg, None, "10.1.0.1",
3934                               "11.1.0.1", "2001:10:1::1", "3001:10:1::1",
3935                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3936         eep1.add_vpp_config()
3937         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3938         eep2 = VppGbpEndpoint(self, self.vlan_101, eepg, None, "10.1.0.2",
3939                               "11.1.0.2", "2001:10:1::2", "3001:10:1::2",
3940                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3941         eep2.add_vpp_config()
3942
3943         # external subnets reachable though eep1 and eep2 respectively
3944         VppIpRoute(self, "10.220.0.0", 24,
3945                    [VppRoutePath(eep1.ip4.address, eep1.epg.bvi.sw_if_index)],
3946                    table_id=t4.table_id).add_vpp_config()
3947         VppGbpSubnet(self, rd1, "10.220.0.0", 24,
3948                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3949                      sclass=4220).add_vpp_config()
3950         VppIpRoute(self, "10:220::", 64,
3951                    [VppRoutePath(eep1.ip6.address, eep1.epg.bvi.sw_if_index)],
3952                    table_id=t6.table_id).add_vpp_config()
3953         VppGbpSubnet(self, rd1, "10:220::", 64,
3954                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3955                      sclass=4220).add_vpp_config()
3956         VppIpRoute(self, "10.221.0.0", 24,
3957                    [VppRoutePath(eep2.ip4.address, eep2.epg.bvi.sw_if_index)],
3958                    table_id=t4.table_id).add_vpp_config()
3959         VppGbpSubnet(self, rd1, "10.221.0.0", 24,
3960                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3961                      sclass=4221).add_vpp_config()
3962         VppIpRoute(self, "10:221::", 64,
3963                    [VppRoutePath(eep2.ip6.address, eep2.epg.bvi.sw_if_index)],
3964                    table_id=t6.table_id).add_vpp_config()
3965         VppGbpSubnet(self, rd1, "10:221::", 64,
3966                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3967                      sclass=4221).add_vpp_config()
3968
3969         #
3970         # l3out redirect to remote (known, then unknown) SEP
3971         #
3972
3973         # packets from 1 external subnet to the other
3974         p = [(Ether(src=eep1.mac, dst=self.router_mac) /
3975               Dot1Q(vlan=100) /
3976               IP(src="10.220.0.17", dst="10.221.0.65") /
3977               UDP(sport=1234, dport=1234) /
3978               Raw('\xa5' * 100)),
3979              (Ether(src=eep1.mac, dst=self.router_mac) /
3980               Dot1Q(vlan=100) /
3981               IPv6(src="10:220::17", dst="10:221::65") /
3982               UDP(sport=1234, dport=1234) /
3983               Raw('\xa5' * 100))]
3984
3985         # packets should be dropped in absence of contract
3986         self.send_and_assert_no_replies(self.pg0, p)
3987
3988         # contract redirecting to sep5
3989         VppGbpContract(
3990             self, 402, 4220, 4221, acl_index,
3991             [VppGbpContractRule(
3992                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3993                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3994                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
3995                                        sep5.ip4, sep5.epg.rd)]),
3996                 VppGbpContractRule(
3997                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3998                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3999                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4000                                            sep5.ip6, sep5.epg.rd)])],
4001             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4002
4003         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4004
4005         for rx, tx in zip(rxs, p):
4006             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4007             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4008             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4009             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4010             # this should use the programmed remote leaf TEP
4011             self.assertEqual(rx[VXLAN].vni, 555)
4012             self.assertEqual(rx[VXLAN].gpid, 4220)
4013             self.assertTrue(rx[VXLAN].flags.G)
4014             self.assertTrue(rx[VXLAN].flags.Instance)
4015             # redirect policy has been applied
4016             self.assertTrue(rx[VXLAN].gpflags.A)
4017             self.assertTrue(rx[VXLAN].gpflags.D)
4018             rxip = rx[VXLAN][Ether].payload
4019             txip = tx[Dot1Q].payload
4020             self.assertEqual(rxip.src, txip.src)
4021             self.assertEqual(rxip.dst, txip.dst)
4022
4023         # remote SEP: it is now an unknown remote SEP and should go
4024         # to spine proxy
4025         sep5.remove_vpp_config()
4026
4027         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4028
4029         for rx, tx in zip(rxs, p):
4030             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4031             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4032             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4033             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4034             # this should use the spine proxy TEP
4035             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4036             self.assertEqual(rx[VXLAN].gpid, 4220)
4037             self.assertTrue(rx[VXLAN].flags.G)
4038             self.assertTrue(rx[VXLAN].flags.Instance)
4039             # redirect policy has been applied
4040             self.assertTrue(rx[VXLAN].gpflags.A)
4041             self.assertTrue(rx[VXLAN].gpflags.D)
4042             rxip = rx[VXLAN][Ether].payload
4043             txip = tx[Dot1Q].payload
4044             self.assertEqual(rxip.src, txip.src)
4045             self.assertEqual(rxip.dst, txip.dst)
4046
4047         #
4048         # l3out redirect to local SEP
4049         #
4050
4051         # change the contract between l3out to redirect to local SEPs
4052         # instead of remote SEP
4053         VppGbpContract(
4054             self, 402, 4220, 4221, acl_index,
4055             [VppGbpContractRule(
4056                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4057                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4058                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4059                                        sep1.ip4, sep1.epg.rd)]),
4060                 VppGbpContractRule(
4061                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4062                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4063                     [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4064                                            sep1.ip6, sep1.epg.rd)])],
4065             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4066
4067         rxs = self.send_and_expect(self.pg0, p, sep1.itf)
4068         for rx, tx in zip(rxs, p):
4069             self.assertEqual(rx[Ether].src, routed_src_mac)
4070             self.assertEqual(rx[Ether].dst, sep1.mac)
4071             rxip = rx[Ether].payload
4072             txip = tx[Ether].payload
4073             self.assertEqual(rxip.src, txip.src)
4074             self.assertEqual(rxip.dst, txip.dst)
4075
4076         #
4077         # redirect remote EP to remote (known then unknown) SEP
4078         #
4079
4080         # remote SEP known again
4081         sep5.add_vpp_config()
4082
4083         # contract to redirect to learnt SEP
4084         VppGbpContract(
4085             self, 402, epg_221.sclass, epg_222.sclass, acl_index,
4086             [VppGbpContractRule(
4087                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4088                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4089                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4090                                        sep5.ip4, sep5.epg.rd)]),
4091                 VppGbpContractRule(
4092                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4093                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4094                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4095                                            sep5.ip6, sep5.epg.rd)])],
4096             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4097
4098         # packets from unknown EP 221 to known EP in EPG 222
4099         # should be redirected to known remote SEP
4100         base = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4101                 IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4102                 UDP(sport=1234, dport=48879) /
4103                 VXLAN(vni=444, gpid=441, flags=0x88) /
4104                 Ether(src="00:22:22:22:22:44", dst=str(self.router_mac)))
4105         p = [(base /
4106               IP(src="10.0.1.100", dst=ep3.ip4.address) /
4107               UDP(sport=1234, dport=1234) /
4108               Raw('\xa5' * 100)),
4109              (base /
4110               IPv6(src="2001:10::100", dst=ep3.ip6.address) /
4111               UDP(sport=1234, dport=1234) /
4112               Raw('\xa5' * 100))]
4113
4114         # unknown remote EP to local EP redirected to known remote SEP
4115         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4116
4117         for rx, tx in zip(rxs, p):
4118             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4119             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4120             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4121             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4122             # this should use the programmed remote leaf TEP
4123             self.assertEqual(rx[VXLAN].vni, 555)
4124             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4125             self.assertTrue(rx[VXLAN].flags.G)
4126             self.assertTrue(rx[VXLAN].flags.Instance)
4127             # redirect policy has been applied
4128             self.assertTrue(rx[VXLAN].gpflags.A)
4129             self.assertFalse(rx[VXLAN].gpflags.D)
4130             rxip = rx[VXLAN][Ether].payload
4131             txip = tx[VXLAN][Ether].payload
4132             self.assertEqual(rxip.src, txip.src)
4133             self.assertEqual(rxip.dst, txip.dst)
4134
4135         # endpoint learnt via the parent GBP-vxlan interface
4136         self.assertTrue(find_gbp_endpoint(self,
4137                                           vx_tun_l3._sw_if_index,
4138                                           ip="10.0.1.100"))
4139         self.assertTrue(find_gbp_endpoint(self,
4140                                           vx_tun_l3._sw_if_index,
4141                                           ip="2001:10::100"))
4142
4143         # remote SEP: it is now an unknown remote SEP and should go
4144         # to spine proxy
4145         sep5.remove_vpp_config()
4146
4147         # remote EP (coming from spine proxy) to local EP redirected to
4148         # known remote SEP
4149         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4150
4151         for rx, tx in zip(rxs, p):
4152             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4153             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4154             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4155             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4156             # this should use the spine proxy TEP
4157             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4158             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4159             self.assertTrue(rx[VXLAN].flags.G)
4160             self.assertTrue(rx[VXLAN].flags.Instance)
4161             # redirect policy has been applied
4162             self.assertTrue(rx[VXLAN].gpflags.A)
4163             self.assertFalse(rx[VXLAN].gpflags.D)
4164             rxip = rx[VXLAN][Ether].payload
4165             txip = tx[VXLAN][Ether].payload
4166             self.assertEqual(rxip.src, txip.src)
4167             self.assertEqual(rxip.dst, txip.dst)
4168
4169         #
4170         # cleanup
4171         #
4172         self.pg7.unconfig_ip4()
4173
4174     def test_gbp_l3_out(self):
4175         """ GBP L3 Out """
4176
4177         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4178         self.vapi.cli("set logging class gbp level debug")
4179
4180         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4181         routed_src_mac = "00:22:bd:f8:19:ff"
4182
4183         #
4184         # IP tables
4185         #
4186         t4 = VppIpTable(self, 1)
4187         t4.add_vpp_config()
4188         t6 = VppIpTable(self, 1, True)
4189         t6.add_vpp_config()
4190
4191         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
4192         rd1.add_vpp_config()
4193
4194         self.loop0.set_mac(self.router_mac)
4195
4196         #
4197         # Bind the BVI to the RD
4198         #
4199         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4200         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4201
4202         #
4203         # Pg7 hosts a BD's BUM
4204         # Pg1 some other l3 interface
4205         #
4206         self.pg7.config_ip4()
4207         self.pg7.resolve_arp()
4208
4209         #
4210         # a multicast vxlan-gbp tunnel for broadcast in the BD
4211         #
4212         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
4213                                    "239.1.1.1", 88,
4214                                    mcast_itf=self.pg7)
4215         tun_bm.add_vpp_config()
4216
4217         #
4218         # a GBP external bridge domains for the EPs
4219         #
4220         bd1 = VppBridgeDomain(self, 1)
4221         bd1.add_vpp_config()
4222         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, tun_bm)
4223         gbd1.add_vpp_config()
4224
4225         #
4226         # The Endpoint-groups in which the external endpoints exist
4227         #
4228         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
4229                                       None, gbd1.bvi,
4230                                       "10.0.0.128",
4231                                       "2001:10::128",
4232                                       VppGbpEndpointRetention(2))
4233         epg_220.add_vpp_config()
4234
4235         # the BVIs have the subnets applied ...
4236         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
4237         ip4_addr.add_vpp_config()
4238         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
4239         ip6_addr.add_vpp_config()
4240
4241         # ... which are L3-out subnets
4242         l3o_1 = VppGbpSubnet(
4243             self, rd1, "10.0.0.0", 24,
4244             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4245             sclass=113)
4246         l3o_1.add_vpp_config()
4247
4248         #
4249         # an external interface attached to the outside world and the
4250         # external BD
4251         #
4252         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
4253         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
4254         vlan_144 = VppDot1QSubint(self, self.pg0, 144)
4255         vlan_144.admin_up()
4256         # vlan_102 is not poped
4257
4258         #
4259         # an unicast vxlan-gbp for inter-RD traffic
4260         #
4261         vx_tun_l3 = VppGbpVxlanTunnel(
4262             self, 444, rd1.rd_id,
4263             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
4264             self.pg2.local_ip4)
4265         vx_tun_l3.add_vpp_config()
4266
4267         #
4268         # External Endpoints
4269         #
4270         eep1 = VppGbpEndpoint(self, self.vlan_100,
4271                               epg_220, None,
4272                               "10.0.0.1", "11.0.0.1",
4273                               "2001:10::1", "3001::1",
4274                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4275         eep1.add_vpp_config()
4276         eep2 = VppGbpEndpoint(self, self.vlan_101,
4277                               epg_220, None,
4278                               "10.0.0.2", "11.0.0.2",
4279                               "2001:10::2", "3001::2",
4280                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4281         eep2.add_vpp_config()
4282         eep3 = VppGbpEndpoint(self, self.vlan_102,
4283                               epg_220, None,
4284                               "10.0.0.3", "11.0.0.3",
4285                               "2001:10::3", "3001::3",
4286                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4287         eep3.add_vpp_config()
4288
4289         #
4290         # A remote external endpoint
4291         #
4292         rep = VppGbpEndpoint(self, vx_tun_l3,
4293                              epg_220, None,
4294                              "10.0.0.101", "11.0.0.101",
4295                              "2001:10::101", "3001::101",
4296                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
4297                              self.pg7.local_ip4,
4298                              self.pg7.remote_ip4,
4299                              mac=None)
4300         rep.add_vpp_config()
4301
4302         #
4303         # EP1 impersonating EP3 is dropped
4304         #
4305         p = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4306              Dot1Q(vlan=100) /
4307              ARP(op="who-has",
4308                  psrc="10.0.0.3", pdst="10.0.0.128",
4309                  hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4310         self.send_and_assert_no_replies(self.pg0, p)
4311
4312         #
4313         # ARP packet from External EPs are accepted and replied to
4314         #
4315         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4316                  Dot1Q(vlan=100) /
4317                  ARP(op="who-has",
4318                      psrc=eep1.ip4.address, pdst="10.0.0.128",
4319                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4320         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4321
4322         #
4323         # ARP packet from host in remote subnet are accepted and replied to
4324         #
4325         p_arp = (Ether(src=eep3.mac, dst="ff:ff:ff:ff:ff:ff") /
4326                  Dot1Q(vlan=102) /
4327                  ARP(op="who-has",
4328                      psrc=eep3.ip4.address, pdst="10.0.0.128",
4329                      hwsrc=eep3.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4330         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4331
4332         #
4333         # packets destined to unknown addresses in the BVI's subnet
4334         # are ARP'd for
4335         #
4336         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4337               Dot1Q(vlan=100) /
4338               IP(src="10.0.0.1", dst="10.0.0.88") /
4339               UDP(sport=1234, dport=1234) /
4340               Raw('\xa5' * 100))
4341         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4342               Dot1Q(vlan=100) /
4343               IPv6(src="2001:10::1", dst="2001:10::88") /
4344               UDP(sport=1234, dport=1234) /
4345               Raw('\xa5' * 100))
4346
4347         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
4348
4349         for rx in rxs:
4350             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4351             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4352             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4353             self.assertEqual(rx[IP].dst, "239.1.1.1")
4354             self.assertEqual(rx[VXLAN].vni, 88)
4355             self.assertTrue(rx[VXLAN].flags.G)
4356             self.assertTrue(rx[VXLAN].flags.Instance)
4357             # policy was applied to the original IP packet
4358             self.assertEqual(rx[VXLAN].gpid, 113)
4359             self.assertTrue(rx[VXLAN].gpflags.A)
4360             self.assertFalse(rx[VXLAN].gpflags.D)
4361
4362             inner = rx[VXLAN].payload
4363
4364             self.assertTrue(inner.haslayer(ARP))
4365
4366         #
4367         # remote to external
4368         #
4369         p = (Ether(src=self.pg7.remote_mac,
4370                    dst=self.pg7.local_mac) /
4371              IP(src=self.pg7.remote_ip4,
4372                 dst=self.pg7.local_ip4) /
4373              UDP(sport=1234, dport=48879) /
4374              VXLAN(vni=444, gpid=113, flags=0x88) /
4375              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4376              IP(src="10.0.0.101", dst="10.0.0.1") /
4377              UDP(sport=1234, dport=1234) /
4378              Raw('\xa5' * 100))
4379
4380         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4381
4382         #
4383         # local EP pings router
4384         #
4385         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4386              Dot1Q(vlan=100) /
4387              IP(src=eep1.ip4.address, dst="10.0.0.128") /
4388              ICMP(type='echo-request'))
4389
4390         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4391
4392         for rx in rxs:
4393             self.assertEqual(rx[Ether].src, str(self.router_mac))
4394             self.assertEqual(rx[Ether].dst, eep1.mac)
4395             self.assertEqual(rx[Dot1Q].vlan, 100)
4396
4397         #
4398         # local EP pings other local EP
4399         #
4400         p = (Ether(src=eep1.mac, dst=eep2.mac) /
4401              Dot1Q(vlan=100) /
4402              IP(src=eep1.ip4.address, dst=eep2.ip4.address) /
4403              ICMP(type='echo-request'))
4404
4405         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4406
4407         for rx in rxs:
4408             self.assertEqual(rx[Ether].src, eep1.mac)
4409             self.assertEqual(rx[Ether].dst, eep2.mac)
4410             self.assertEqual(rx[Dot1Q].vlan, 101)
4411
4412         #
4413         # local EP pings router w/o vlan tag poped
4414         #
4415         p = (Ether(src=eep3.mac, dst=str(self.router_mac)) /
4416              Dot1Q(vlan=102) /
4417              IP(src=eep3.ip4.address, dst="10.0.0.128") /
4418              ICMP(type='echo-request'))
4419
4420         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4421
4422         for rx in rxs:
4423             self.assertEqual(rx[Ether].src, str(self.router_mac))
4424             self.assertEqual(rx[Ether].dst, self.vlan_102.remote_mac)
4425
4426         #
4427         # A ip4 subnet reachable through the external EP1
4428         #
4429         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
4430                             [VppRoutePath(eep1.ip4.address,
4431                                           eep1.epg.bvi.sw_if_index)],
4432                             table_id=t4.table_id)
4433         ip_220.add_vpp_config()
4434
4435         l3o_220 = VppGbpSubnet(
4436             self, rd1, "10.220.0.0", 24,
4437             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4438             sclass=4220)
4439         l3o_220.add_vpp_config()
4440
4441         #
4442         # An ip6 subnet reachable through the external EP1
4443         #
4444         ip6_220 = VppIpRoute(self, "10:220::", 64,
4445                              [VppRoutePath(eep1.ip6.address,
4446                                            eep1.epg.bvi.sw_if_index)],
4447                              table_id=t6.table_id)
4448         ip6_220.add_vpp_config()
4449
4450         l3o6_220 = VppGbpSubnet(
4451             self, rd1, "10:220::", 64,
4452             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4453             sclass=4220)
4454         l3o6_220.add_vpp_config()
4455
4456         #
4457         # A subnet reachable through the external EP2
4458         #
4459         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
4460                             [VppRoutePath(eep2.ip4.address,
4461                                           eep2.epg.bvi.sw_if_index)],
4462                             table_id=t4.table_id)
4463         ip_221.add_vpp_config()
4464
4465         l3o_221 = VppGbpSubnet(
4466             self, rd1, "10.221.0.0", 24,
4467             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4468             sclass=4221)
4469         l3o_221.add_vpp_config()
4470
4471         #
4472         # ping between hosts in remote subnets
4473         #  dropped without a contract
4474         #
4475         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4476              Dot1Q(vlan=100) /
4477              IP(src="10.220.0.1", dst="10.221.0.1") /
4478              ICMP(type='echo-request'))
4479
4480         self.send_and_assert_no_replies(self.pg0, p * 1)
4481
4482         #
4483         # contract for the external nets to communicate
4484         #
4485         acl = VppGbpAcl(self)
4486         rule4 = acl.create_rule(permit_deny=1, proto=17)
4487         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
4488         acl_index = acl.add_vpp_config([rule4, rule6])
4489
4490         #
4491         # A contract with the wrong scope is not matched
4492         #
4493         c_44 = VppGbpContract(
4494             self, 44, 4220, 4221, acl_index,
4495             [VppGbpContractRule(
4496                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4497                 []),
4498                 VppGbpContractRule(
4499                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4500                     [])],
4501             [ETH_P_IP, ETH_P_IPV6])
4502         c_44.add_vpp_config()
4503         self.send_and_assert_no_replies(self.pg0, p * 1)
4504
4505         c1 = VppGbpContract(
4506             self, 55, 4220, 4221, acl_index,
4507             [VppGbpContractRule(
4508                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4509                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4510                 []),
4511                 VppGbpContractRule(
4512                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4513                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4514                     [])],
4515             [ETH_P_IP, ETH_P_IPV6])
4516         c1.add_vpp_config()
4517
4518         #
4519         # Contracts allowing ext-net 200 to talk with external EPs
4520         #
4521         c2 = VppGbpContract(
4522             self, 55, 4220, 113, acl_index,
4523             [VppGbpContractRule(
4524                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4525                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4526                 []),
4527                 VppGbpContractRule(
4528                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4529                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4530                     [])],
4531             [ETH_P_IP, ETH_P_IPV6])
4532         c2.add_vpp_config()
4533         c3 = VppGbpContract(
4534             self, 55, 113, 4220, acl_index,
4535             [VppGbpContractRule(
4536                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4537                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4538                 []),
4539                 VppGbpContractRule(
4540                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4541                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4542                     [])],
4543             [ETH_P_IP, ETH_P_IPV6])
4544         c3.add_vpp_config()
4545
4546         #
4547         # ping between hosts in remote subnets
4548         #
4549         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4550              Dot1Q(vlan=100) /
4551              IP(src="10.220.0.1", dst="10.221.0.1") /
4552              UDP(sport=1234, dport=1234) /
4553              Raw('\xa5' * 100))
4554
4555         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4556
4557         for rx in rxs:
4558             self.assertEqual(rx[Ether].src, str(self.router_mac))
4559             self.assertEqual(rx[Ether].dst, eep2.mac)
4560             self.assertEqual(rx[Dot1Q].vlan, 101)
4561
4562         # we did not learn these external hosts
4563         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
4564         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
4565
4566         #
4567         # from remote external EP to local external EP
4568         #
4569         p = (Ether(src=self.pg7.remote_mac,
4570                    dst=self.pg7.local_mac) /
4571              IP(src=self.pg7.remote_ip4,
4572                 dst=self.pg7.local_ip4) /
4573              UDP(sport=1234, dport=48879) /
4574              VXLAN(vni=444, gpid=113, flags=0x88) /
4575              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4576              IP(src="10.0.0.101", dst="10.220.0.1") /
4577              UDP(sport=1234, dport=1234) /
4578              Raw('\xa5' * 100))
4579
4580         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4581
4582         #
4583         # ping from an external host to the remote external EP
4584         #
4585         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4586              Dot1Q(vlan=100) /
4587              IP(src="10.220.0.1", dst=rep.ip4.address) /
4588              UDP(sport=1234, dport=1234) /
4589              Raw('\xa5' * 100))
4590
4591         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
4592
4593         for rx in rxs:
4594             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4595             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4596             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4597             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4598             self.assertEqual(rx[VXLAN].vni, 444)
4599             self.assertTrue(rx[VXLAN].flags.G)
4600             self.assertTrue(rx[VXLAN].flags.Instance)
4601             # the sclass of the ext-net the packet came from
4602             self.assertEqual(rx[VXLAN].gpid, 4220)
4603             # policy was applied to the original IP packet
4604             self.assertTrue(rx[VXLAN].gpflags.A)
4605             # since it's an external host the reciever should not learn it
4606             self.assertTrue(rx[VXLAN].gpflags.D)
4607             inner = rx[VXLAN].payload
4608             self.assertEqual(inner[IP].src, "10.220.0.1")
4609             self.assertEqual(inner[IP].dst, rep.ip4.address)
4610
4611         #
4612         # An external subnet reachable via the remote external EP
4613         #
4614
4615         #
4616         # first the VXLAN-GBP tunnel over which it is reached
4617         #
4618         vx_tun_r1 = VppVxlanGbpTunnel(
4619             self, self.pg7.local_ip4,
4620             self.pg7.remote_ip4, 445,
4621             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4622                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4623         vx_tun_r1.add_vpp_config()
4624         VppIpInterfaceBind(self, vx_tun_r1, t4).add_vpp_config()
4625
4626         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
4627
4628         #
4629         # then the special adj to resolve through on that tunnel
4630         #
4631         n1 = VppNeighbor(self,
4632                          vx_tun_r1.sw_if_index,
4633                          "00:0c:0c:0c:0c:0c",
4634                          self.pg7.remote_ip4)
4635         n1.add_vpp_config()
4636
4637         #
4638         # the route via the adj above
4639         #
4640         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
4641                             [VppRoutePath(self.pg7.remote_ip4,
4642                                           vx_tun_r1.sw_if_index)],
4643                             table_id=t4.table_id)
4644         ip_222.add_vpp_config()
4645
4646         l3o_222 = VppGbpSubnet(
4647             self, rd1, "10.222.0.0", 24,
4648             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4649             sclass=4222)
4650         l3o_222.add_vpp_config()
4651
4652         #
4653         # ping between hosts in local and remote external subnets
4654         #  dropped without a contract
4655         #
4656         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4657              Dot1Q(vlan=100) /
4658              IP(src="10.220.0.1", dst="10.222.0.1") /
4659              UDP(sport=1234, dport=1234) /
4660              Raw('\xa5' * 100))
4661
4662         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
4663
4664         #
4665         # Add contracts ext-nets for 220 -> 222
4666         #
4667         c4 = VppGbpContract(
4668             self, 55, 4220, 4222, acl_index,
4669             [VppGbpContractRule(
4670                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4671                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4672                 []),
4673                 VppGbpContractRule(
4674                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4675                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4676                     [])],
4677             [ETH_P_IP, ETH_P_IPV6])
4678         c4.add_vpp_config()
4679
4680         #
4681         # ping from host in local to remote external subnets
4682         #
4683         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4684              Dot1Q(vlan=100) /
4685              IP(src="10.220.0.1", dst="10.222.0.1") /
4686              UDP(sport=1234, dport=1234) /
4687              Raw('\xa5' * 100))
4688
4689         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
4690
4691         for rx in rxs:
4692             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4693             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4694             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4695             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4696             self.assertEqual(rx[VXLAN].vni, 445)
4697             self.assertTrue(rx[VXLAN].flags.G)
4698             self.assertTrue(rx[VXLAN].flags.Instance)
4699             # the sclass of the ext-net the packet came from
4700             self.assertEqual(rx[VXLAN].gpid, 4220)
4701             # policy was applied to the original IP packet
4702             self.assertTrue(rx[VXLAN].gpflags.A)
4703             # since it's an external host the reciever should not learn it
4704             self.assertTrue(rx[VXLAN].gpflags.D)
4705             inner = rx[VXLAN].payload
4706             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
4707             self.assertEqual(inner[IP].src, "10.220.0.1")
4708             self.assertEqual(inner[IP].dst, "10.222.0.1")
4709
4710         #
4711         # make the external subnet ECMP
4712         #
4713         vx_tun_r2 = VppVxlanGbpTunnel(
4714             self, self.pg7.local_ip4,
4715             self.pg7.remote_ip4, 446,
4716             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4717                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4718         vx_tun_r2.add_vpp_config()
4719         VppIpInterfaceBind(self, vx_tun_r2, t4).add_vpp_config()
4720
4721         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
4722
4723         n2 = VppNeighbor(self,
4724                          vx_tun_r2.sw_if_index,
4725                          "00:0c:0c:0c:0c:0c",
4726                          self.pg7.remote_ip4)
4727         n2.add_vpp_config()
4728
4729         ip_222.modify([VppRoutePath(self.pg7.remote_ip4,
4730                                     vx_tun_r1.sw_if_index),
4731                        VppRoutePath(self.pg7.remote_ip4,
4732                                     vx_tun_r2.sw_if_index)])
4733
4734         #
4735         # now expect load-balance
4736         #
4737         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
4738               Dot1Q(vlan=100) /
4739               IP(src="10.220.0.1", dst="10.222.0.1") /
4740               UDP(sport=1234, dport=1234) /
4741               Raw('\xa5' * 100)),
4742              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4743               Dot1Q(vlan=100) /
4744               IP(src="10.220.0.1", dst="10.222.0.1") /
4745               UDP(sport=1222, dport=1235) /
4746              Raw('\xa5' * 100))]
4747
4748         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4749
4750         self.assertEqual(rxs[0][VXLAN].vni, 445)
4751         self.assertEqual(rxs[1][VXLAN].vni, 446)
4752
4753         #
4754         # Same LB test for v6
4755         #
4756         n3 = VppNeighbor(self,
4757                          vx_tun_r1.sw_if_index,
4758                          "00:0c:0c:0c:0c:0c",
4759                          self.pg7.remote_ip6)
4760         n3.add_vpp_config()
4761         n4 = VppNeighbor(self,
4762                          vx_tun_r2.sw_if_index,
4763                          "00:0c:0c:0c:0c:0c",
4764                          self.pg7.remote_ip6)
4765         n4.add_vpp_config()
4766
4767         ip_222_6 = VppIpRoute(self, "10:222::", 64,
4768                               [VppRoutePath(self.pg7.remote_ip6,
4769                                             vx_tun_r1.sw_if_index),
4770                                VppRoutePath(self.pg7.remote_ip6,
4771                                             vx_tun_r2.sw_if_index)],
4772                               table_id=t6.table_id)
4773         ip_222_6.add_vpp_config()
4774
4775         l3o_222_6 = VppGbpSubnet(
4776             self, rd1, "10:222::", 64,
4777             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4778             sclass=4222)
4779         l3o_222_6.add_vpp_config()
4780
4781         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
4782               Dot1Q(vlan=100) /
4783               IPv6(src="10:220::1", dst="10:222::1") /
4784               UDP(sport=1234, dport=1234) /
4785               Raw('\xa5' * 100)),
4786              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4787               Dot1Q(vlan=100) /
4788               IPv6(src="10:220::1", dst="10:222::1") /
4789               UDP(sport=7777, dport=8881) /
4790              Raw('\xa5' * 100))]
4791
4792         self.logger.info(self.vapi.cli("sh ip6 fib 10:222::1"))
4793         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4794
4795         self.assertEqual(rxs[0][VXLAN].vni, 445)
4796         self.assertEqual(rxs[1][VXLAN].vni, 446)
4797
4798         #
4799         # ping from host in remote to local external subnets
4800         # there's no contract for this, but the A bit is set.
4801         #
4802         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4803              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4804              UDP(sport=1234, dport=48879) /
4805              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4806              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4807              IP(src="10.222.0.1", dst="10.220.0.1") /
4808              UDP(sport=1234, dport=1234) /
4809              Raw('\xa5' * 100))
4810
4811         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
4812         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
4813
4814         #
4815         # ping from host in remote to remote external subnets
4816         #   this is dropped by reflection check.
4817         #
4818         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4819              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4820              UDP(sport=1234, dport=48879) /
4821              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4822              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4823              IP(src="10.222.0.1", dst="10.222.0.2") /
4824              UDP(sport=1234, dport=1234) /
4825              Raw('\xa5' * 100))
4826
4827         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
4828
4829         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4830              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4831              UDP(sport=1234, dport=48879) /
4832              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4833              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4834              IPv6(src="10:222::1", dst="10:222::2") /
4835              UDP(sport=1234, dport=1234) /
4836              Raw('\xa5' * 100))
4837
4838         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
4839
4840         #
4841         # local EP
4842         #
4843         lep1 = VppGbpEndpoint(self, vlan_144,
4844                               epg_220, None,
4845                               "10.0.0.44", "11.0.0.44",
4846                               "2001:10::44", "3001::44")
4847         lep1.add_vpp_config()
4848
4849         #
4850         # local EP to local ip4 external subnet
4851         #
4852         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
4853              Dot1Q(vlan=144) /
4854              IP(src=lep1.ip4.address, dst="10.220.0.1") /
4855              UDP(sport=1234, dport=1234) /
4856              Raw('\xa5' * 100))
4857
4858         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4859
4860         for rx in rxs:
4861             self.assertEqual(rx[Ether].src, str(self.router_mac))
4862             self.assertEqual(rx[Ether].dst, eep1.mac)
4863             self.assertEqual(rx[Dot1Q].vlan, 100)
4864
4865         #
4866         # local EP to local ip6 external subnet
4867         #
4868         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
4869              Dot1Q(vlan=144) /
4870              IPv6(src=lep1.ip6.address, dst="10:220::1") /
4871              UDP(sport=1234, dport=1234) /
4872              Raw('\xa5' * 100))
4873
4874         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4875
4876         for rx in rxs:
4877             self.assertEqual(rx[Ether].src, str(self.router_mac))
4878             self.assertEqual(rx[Ether].dst, eep1.mac)
4879             self.assertEqual(rx[Dot1Q].vlan, 100)
4880
4881         #
4882         # ip4 and ip6 subnets that load-balance
4883         #
4884         ip_20 = VppIpRoute(self, "10.20.0.0", 24,
4885                            [VppRoutePath(eep1.ip4.address,
4886                                          eep1.epg.bvi.sw_if_index),
4887                             VppRoutePath(eep2.ip4.address,
4888                                          eep2.epg.bvi.sw_if_index)],
4889                            table_id=t4.table_id)
4890         ip_20.add_vpp_config()
4891
4892         l3o_20 = VppGbpSubnet(
4893             self, rd1, "10.20.0.0", 24,
4894             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4895             sclass=4220)
4896         l3o_20.add_vpp_config()
4897
4898         ip6_20 = VppIpRoute(self, "10:20::", 64,
4899                             [VppRoutePath(eep1.ip6.address,
4900                                           eep1.epg.bvi.sw_if_index),
4901                              VppRoutePath(eep2.ip6.address,
4902                                           eep2.epg.bvi.sw_if_index)],
4903                             table_id=t6.table_id)
4904         ip6_20.add_vpp_config()
4905
4906         l3o6_20 = VppGbpSubnet(
4907             self, rd1, "10:20::", 64,
4908             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4909             sclass=4220)
4910         l3o6_20.add_vpp_config()
4911
4912         self.logger.info(self.vapi.cli("sh ip fib 10.20.0.1"))
4913         self.logger.info(self.vapi.cli("sh ip6 fib 10:20::1"))
4914
4915         # two ip6 packets whose port are chosen so they load-balance
4916         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
4917               Dot1Q(vlan=144) /
4918               IPv6(src=lep1.ip6.address, dst="10:20::1") /
4919               UDP(sport=1234, dport=1234) /
4920               Raw('\xa5' * 100)),
4921              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
4922               Dot1Q(vlan=144) /
4923               IPv6(src=lep1.ip6.address, dst="10:20::1") /
4924               UDP(sport=124, dport=1230) /
4925               Raw('\xa5' * 100))]
4926
4927         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
4928
4929         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
4930         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
4931
4932         # two ip4 packets whose port are chosen so they load-balance
4933         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
4934               Dot1Q(vlan=144) /
4935               IP(src=lep1.ip4.address, dst="10.20.0.1") /
4936               UDP(sport=1235, dport=1235) /
4937               Raw('\xa5' * 100)),
4938              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
4939               Dot1Q(vlan=144) /
4940               IP(src=lep1.ip4.address, dst="10.20.0.1") /
4941               UDP(sport=124, dport=1230) /
4942               Raw('\xa5' * 100))]
4943
4944         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
4945
4946         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
4947         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
4948
4949         #
4950         # cleanup
4951         #
4952         ip_222.remove_vpp_config()
4953         self.pg7.unconfig_ip4()
4954         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
4955         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
4956
4957     def test_gbp_anon_l3_out(self):
4958         """ GBP Anonymous L3 Out """
4959
4960         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4961         self.vapi.cli("set logging class gbp level debug")
4962
4963         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4964         routed_src_mac = "00:22:bd:f8:19:ff"
4965
4966         #
4967         # IP tables
4968         #
4969         t4 = VppIpTable(self, 1)
4970         t4.add_vpp_config()
4971         t6 = VppIpTable(self, 1, True)
4972         t6.add_vpp_config()
4973
4974         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
4975         rd1.add_vpp_config()
4976
4977         self.loop0.set_mac(self.router_mac)
4978
4979         #
4980         # Bind the BVI to the RD
4981         #
4982         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4983         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4984
4985         #
4986         # Pg7 hosts a BD's BUM
4987         # Pg1 some other l3 interface
4988         #
4989         self.pg7.config_ip4()
4990         self.pg7.resolve_arp()
4991
4992         #
4993         # a GBP external bridge domains for the EPs
4994         #
4995         bd1 = VppBridgeDomain(self, 1)
4996         bd1.add_vpp_config()
4997         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, None)
4998         gbd1.add_vpp_config()
4999
5000         #
5001         # The Endpoint-groups in which the external endpoints exist
5002         #
5003         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
5004                                       None, gbd1.bvi,
5005                                       "10.0.0.128",
5006                                       "2001:10::128",
5007                                       VppGbpEndpointRetention(2))
5008         epg_220.add_vpp_config()
5009
5010         # the BVIs have the subnet applied ...
5011         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
5012         ip4_addr.add_vpp_config()
5013
5014         # ... which is an Anonymous L3-out subnets
5015         l3o_1 = VppGbpSubnet(
5016             self, rd1, "10.0.0.0", 24,
5017             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_ANON_L3_OUT,
5018             sclass=113)
5019         l3o_1.add_vpp_config()
5020
5021         #
5022         # an external interface attached to the outside world and the
5023         # external BD
5024         #
5025         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
5026         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
5027
5028         #
5029         # vlan_100 and vlan_101 are anonymous l3-out interfaces
5030         #
5031         ext_itf = VppGbpExtItf(self, self.vlan_100, bd1, rd1, anon=True)
5032         ext_itf.add_vpp_config()
5033         ext_itf = VppGbpExtItf(self, self.vlan_101, bd1, rd1, anon=True)
5034         ext_itf.add_vpp_config()
5035
5036         #
5037         # an unicast vxlan-gbp for inter-RD traffic
5038         #
5039         vx_tun_l3 = VppGbpVxlanTunnel(
5040             self, 444, rd1.rd_id,
5041             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
5042             self.pg2.local_ip4)
5043         vx_tun_l3.add_vpp_config()
5044
5045         #
5046         # A remote external endpoint
5047         #
5048         rep = VppGbpEndpoint(self, vx_tun_l3,
5049                              epg_220, None,
5050                              "10.0.0.201", "11.0.0.201",
5051                              "2001:10::201", "3001::101",
5052                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
5053                              self.pg7.local_ip4,
5054                              self.pg7.remote_ip4,
5055                              mac=None)
5056         rep.add_vpp_config()
5057
5058         #
5059         # ARP packet from host in external subnet are accepted, flooded and
5060         # replied to. We expect 2 packets:
5061         #   - APR request flooded over the other vlan subif
5062         #   - ARP reply from BVI
5063         #
5064         p_arp = (Ether(src=self.vlan_100.remote_mac,
5065                        dst="ff:ff:ff:ff:ff:ff") /
5066                  Dot1Q(vlan=100) /
5067                  ARP(op="who-has",
5068                      psrc="10.0.0.100",
5069                      pdst="10.0.0.128",
5070                      hwsrc=self.vlan_100.remote_mac,
5071                      hwdst="ff:ff:ff:ff:ff:ff"))
5072         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5073
5074         p_arp = (Ether(src=self.vlan_101.remote_mac,
5075                        dst="ff:ff:ff:ff:ff:ff") /
5076                  Dot1Q(vlan=101) /
5077                  ARP(op="who-has",
5078                      psrc='10.0.0.101',
5079                      pdst="10.0.0.128",
5080                      hwsrc=self.vlan_101.remote_mac,
5081                      hwdst="ff:ff:ff:ff:ff:ff"))
5082         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5083
5084         #
5085         # remote to external
5086         #
5087         p = (Ether(src=self.pg7.remote_mac,
5088                    dst=self.pg7.local_mac) /
5089              IP(src=self.pg7.remote_ip4,
5090                 dst=self.pg7.local_ip4) /
5091              UDP(sport=1234, dport=48879) /
5092              VXLAN(vni=vx_tun_l3.vni, gpid=epg_220.sclass, flags=0x88) /
5093              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5094              IP(src=str(rep.ip4), dst="10.0.0.100") /
5095              UDP(sport=1234, dport=1234) /
5096              Raw('\xa5' * 100))
5097         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5098
5099         #
5100         # local EP pings router
5101         #
5102         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5103              Dot1Q(vlan=100) /
5104              IP(src="10.0.0.100", dst="10.0.0.128") /
5105              ICMP(type='echo-request'))
5106         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5107
5108         for rx in rxs:
5109             self.assertEqual(rx[Ether].src, str(self.router_mac))
5110             self.assertEqual(rx[Ether].dst, self.vlan_100.remote_mac)
5111             self.assertEqual(rx[Dot1Q].vlan, 100)
5112
5113         #
5114         # local EP pings other local EP
5115         #
5116         p = (Ether(src=self.vlan_100.remote_mac,
5117                    dst=self.vlan_101.remote_mac) /
5118              Dot1Q(vlan=100) /
5119              IP(src="10.0.0.100", dst="10.0.0.101") /
5120              ICMP(type='echo-request'))
5121         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5122
5123         for rx in rxs:
5124             self.assertEqual(rx[Ether].src, self.vlan_100.remote_mac)
5125             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5126             self.assertEqual(rx[Dot1Q].vlan, 101)
5127
5128         #
5129         # A subnet reachable through an external router on vlan 100
5130         #
5131         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
5132                             [VppRoutePath("10.0.0.100",
5133                                           epg_220.bvi.sw_if_index)],
5134                             table_id=t4.table_id)
5135         ip_220.add_vpp_config()
5136
5137         l3o_220 = VppGbpSubnet(
5138             self, rd1, "10.220.0.0", 24,
5139             # note: this a "regular" L3 out subnet (not connected)
5140             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5141             sclass=4220)
5142         l3o_220.add_vpp_config()
5143
5144         #
5145         # A subnet reachable through an external router on vlan 101
5146         #
5147         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
5148                             [VppRoutePath("10.0.0.101",
5149                                           epg_220.bvi.sw_if_index)],
5150                             table_id=t4.table_id)
5151         ip_221.add_vpp_config()
5152
5153         l3o_221 = VppGbpSubnet(
5154             self, rd1, "10.221.0.0", 24,
5155             # note: this a "regular" L3 out subnet (not connected)
5156             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5157             sclass=4221)
5158         l3o_221.add_vpp_config()
5159
5160         #
5161         # ping between hosts in remote subnets
5162         #  dropped without a contract
5163         #
5164         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5165              Dot1Q(vlan=100) /
5166              IP(src="10.220.0.1", dst="10.221.0.1") /
5167              ICMP(type='echo-request'))
5168
5169         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5170
5171         #
5172         # contract for the external nets to communicate
5173         #
5174         acl = VppGbpAcl(self)
5175         rule4 = acl.create_rule(permit_deny=1, proto=17)
5176         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
5177         acl_index = acl.add_vpp_config([rule4, rule6])
5178
5179         c1 = VppGbpContract(
5180             self, 55, 4220, 4221, acl_index,
5181             [VppGbpContractRule(
5182                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5183                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5184                 []),
5185                 VppGbpContractRule(
5186                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5187                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5188                     [])],
5189             [ETH_P_IP, ETH_P_IPV6])
5190         c1.add_vpp_config()
5191
5192         #
5193         # Contracts allowing ext-net 200 to talk with external EPs
5194         #
5195         c2 = VppGbpContract(
5196             self, 55, 4220, 113, acl_index,
5197             [VppGbpContractRule(
5198                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5199                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5200                 []),
5201                 VppGbpContractRule(
5202                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5203                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5204                     [])],
5205             [ETH_P_IP, ETH_P_IPV6])
5206         c2.add_vpp_config()
5207         c3 = VppGbpContract(
5208             self, 55, 113, 4220, acl_index,
5209             [VppGbpContractRule(
5210                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5211                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5212                 []),
5213                 VppGbpContractRule(
5214                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5215                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5216                     [])],
5217             [ETH_P_IP, ETH_P_IPV6])
5218         c3.add_vpp_config()
5219
5220         #
5221         # ping between hosts in remote subnets
5222         #
5223         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5224              Dot1Q(vlan=100) /
5225              IP(src="10.220.0.1", dst="10.221.0.1") /
5226              UDP(sport=1234, dport=1234) /
5227              Raw('\xa5' * 100))
5228
5229         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5230
5231         for rx in rxs:
5232             self.assertEqual(rx[Ether].src, str(self.router_mac))
5233             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5234             self.assertEqual(rx[Dot1Q].vlan, 101)
5235
5236         # we did not learn these external hosts
5237         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
5238         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
5239
5240         #
5241         # from remote external EP to local external EP
5242         #
5243         p = (Ether(src=self.pg7.remote_mac,
5244                    dst=self.pg7.local_mac) /
5245              IP(src=self.pg7.remote_ip4,
5246                 dst=self.pg7.local_ip4) /
5247              UDP(sport=1234, dport=48879) /
5248              VXLAN(vni=444, gpid=113, flags=0x88) /
5249              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5250              IP(src=rep.ip4.address, dst="10.220.0.1") /
5251              UDP(sport=1234, dport=1234) /
5252              Raw('\xa5' * 100))
5253
5254         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5255
5256         #
5257         # ping from an external host to the remote external EP
5258         #
5259         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5260              Dot1Q(vlan=100) /
5261              IP(src="10.220.0.1", dst=rep.ip4.address) /
5262              UDP(sport=1234, dport=1234) /
5263              Raw('\xa5' * 100))
5264
5265         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
5266
5267         for rx in rxs:
5268             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5269             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5270             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5271             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5272             self.assertEqual(rx[VXLAN].vni, 444)
5273             self.assertTrue(rx[VXLAN].flags.G)
5274             self.assertTrue(rx[VXLAN].flags.Instance)
5275             # the sclass of the ext-net the packet came from
5276             self.assertEqual(rx[VXLAN].gpid, 4220)
5277             # policy was applied to the original IP packet
5278             self.assertTrue(rx[VXLAN].gpflags.A)
5279             # since it's an external host the reciever should not learn it
5280             self.assertTrue(rx[VXLAN].gpflags.D)
5281             inner = rx[VXLAN].payload
5282             self.assertEqual(inner[IP].src, "10.220.0.1")
5283             self.assertEqual(inner[IP].dst, rep.ip4.address)
5284
5285         #
5286         # An external subnet reachable via the remote external EP
5287         #
5288
5289         #
5290         # first the VXLAN-GBP tunnel over which it is reached
5291         #
5292         vx_tun_r = VppVxlanGbpTunnel(
5293             self, self.pg7.local_ip4,
5294             self.pg7.remote_ip4, 445,
5295             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5296                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5297         vx_tun_r.add_vpp_config()
5298         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
5299
5300         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5301
5302         #
5303         # then the special adj to resolve through on that tunnel
5304         #
5305         n1 = VppNeighbor(self,
5306                          vx_tun_r.sw_if_index,
5307                          "00:0c:0c:0c:0c:0c",
5308                          self.pg7.remote_ip4)
5309         n1.add_vpp_config()
5310
5311         #
5312         # the route via the adj above
5313         #
5314         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
5315                             [VppRoutePath(self.pg7.remote_ip4,
5316                                           vx_tun_r.sw_if_index)],
5317                             table_id=t4.table_id)
5318         ip_222.add_vpp_config()
5319
5320         l3o_222 = VppGbpSubnet(
5321             self, rd1, "10.222.0.0", 24,
5322             # note: this a "regular" l3out subnet (not connected)
5323             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5324             sclass=4222)
5325         l3o_222.add_vpp_config()
5326
5327         #
5328         # ping between hosts in local and remote external subnets
5329         #  dropped without a contract
5330         #
5331         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5332              Dot1Q(vlan=100) /
5333              IP(src="10.220.0.1", dst="10.222.0.1") /
5334              UDP(sport=1234, dport=1234) /
5335              Raw('\xa5' * 100))
5336
5337         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5338
5339         #
5340         # Add contracts ext-nets for 220 -> 222
5341         #
5342         c4 = VppGbpContract(
5343             self, 55, 4220, 4222, acl_index,
5344             [VppGbpContractRule(
5345                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5346                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5347                 []),
5348                 VppGbpContractRule(
5349                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5350                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5351                     [])],
5352             [ETH_P_IP, ETH_P_IPV6])
5353         c4.add_vpp_config()
5354
5355         #
5356         # ping from host in local to remote external subnets
5357         #
5358         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5359              Dot1Q(vlan=100) /
5360              IP(src="10.220.0.1", dst="10.222.0.1") /
5361              UDP(sport=1234, dport=1234) /
5362              Raw('\xa5' * 100))
5363
5364         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
5365
5366         for rx in rxs:
5367             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5368             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5369             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5370             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5371             self.assertEqual(rx[VXLAN].vni, 445)
5372             self.assertTrue(rx[VXLAN].flags.G)
5373             self.assertTrue(rx[VXLAN].flags.Instance)
5374             # the sclass of the ext-net the packet came from
5375             self.assertEqual(rx[VXLAN].gpid, 4220)
5376             # policy was applied to the original IP packet
5377             self.assertTrue(rx[VXLAN].gpflags.A)
5378             # since it's an external host the reciever should not learn it
5379             self.assertTrue(rx[VXLAN].gpflags.D)
5380             inner = rx[VXLAN].payload
5381             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
5382             self.assertEqual(inner[IP].src, "10.220.0.1")
5383             self.assertEqual(inner[IP].dst, "10.222.0.1")
5384
5385         #
5386         # ping from host in remote to local external subnets
5387         # there's no contract for this, but the A bit is set.
5388         #
5389         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5390              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5391              UDP(sport=1234, dport=48879) /
5392              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5393              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5394              IP(src="10.222.0.1", dst="10.220.0.1") /
5395              UDP(sport=1234, dport=1234) /
5396              Raw('\xa5' * 100))
5397
5398         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
5399         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
5400
5401         #
5402         # ping from host in remote to remote external subnets
5403         #   this is dropped by reflection check.
5404         #
5405         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5406              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5407              UDP(sport=1234, dport=48879) /
5408              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5409              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5410              IP(src="10.222.0.1", dst="10.222.0.2") /
5411              UDP(sport=1234, dport=1234) /
5412              Raw('\xa5' * 100))
5413
5414         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5415
5416         #
5417         # cleanup
5418         #
5419         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
5420         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
5421         self.pg7.unconfig_ip4()
5422
5423
5424 if __name__ == '__main__':
5425     unittest.main(testRunner=VppTestRunner)