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