gbp: Add support for ACL
[vpp.git] / test / test_gbp.py
1 #!/usr/bin/env python
2
3 import unittest
4
5 from framework import VppTestCase, VppTestRunner
6 from vpp_object import VppObject
7 from vpp_neighbor import VppNeighbor
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, DpoProto
9
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS,  ICMPv6NDOptSrcLLAddr, \
14     ICMPv6ND_NA
15 from scapy.utils6 import in6_getnsma, in6_getnsmac
16
17 from socket import AF_INET, AF_INET6
18 from scapy.utils import inet_pton, inet_ntop
19 from util import mactobinary
20
21
22 class VppGbpEndpoint(VppObject):
23     """
24     GBP Endpoint
25     """
26
27     @property
28     def bin_mac(self):
29         return mactobinary(self.itf.remote_mac)
30
31     @property
32     def mac(self):
33         return self.itf.remote_mac
34
35     def __init__(self, test, itf, epg, recirc, ip, fip, is_ip6=False):
36         self._test = test
37         self.itf = itf
38         self.epg = epg
39         self.recirc = recirc
40         self.ip = ip
41         self.floating_ip = fip
42         self.is_ip6 = is_ip6
43         if is_ip6:
44             self.proto = DpoProto.DPO_PROTO_IP6
45             self.af = AF_INET6
46             self.is_ip6 = True
47             self.ip_len = 128
48         else:
49             self.proto = DpoProto.DPO_PROTO_IP4
50             self.af = AF_INET
51             self.is_ip6 = False
52             self.ip_len = 32
53         self.ip_n = inet_pton(self.af, ip)
54         self.floating_ip_n = inet_pton(self.af, fip)
55
56     def add_vpp_config(self):
57         self._test.vapi.gbp_endpoint_add_del(
58             1,
59             self.itf.sw_if_index,
60             self.ip_n,
61             self.is_ip6,
62             self.epg.epg)
63         self._test.registry.register(self, self._test.logger)
64
65     def remove_vpp_config(self):
66         self._test.vapi.gbp_endpoint_add_del(
67             0,
68             self.itf.sw_if_index,
69             self.ip_n,
70             self.is_ip6,
71             self.epg.epg)
72
73     def __str__(self):
74         return self.object_id()
75
76     def object_id(self):
77         return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
78                                             self.ip,
79                                             self.epg.epg)
80
81     def query_vpp_config(self):
82         eps = self._test.vapi.gbp_endpoint_dump()
83         for ep in eps:
84             if self.is_ip6:
85                 if ep.endpoint.address == self.ip_n \
86                    and ep.endpoint.sw_if_index == self.itf.sw_if_index:
87                     return True
88             else:
89                 if ep.endpoint.address[:4] == self.ip_n \
90                    and ep.endpoint.sw_if_index == self.itf.sw_if_index:
91                     return True
92         return False
93
94
95 class VppGbpRecirc(VppObject):
96     """
97     GBP Recirculation Interface
98     """
99
100     def __init__(self, test, epg, recirc, is_ext=False):
101         self._test = test
102         self.recirc = recirc
103         self.epg = epg
104         self.is_ext = is_ext
105
106     def add_vpp_config(self):
107         self._test.vapi.gbp_recirc_add_del(
108             1,
109             self.recirc.sw_if_index,
110             self.epg.epg,
111             self.is_ext)
112         self._test.registry.register(self, self._test.logger)
113
114     def remove_vpp_config(self):
115         self._test.vapi.gbp_recirc_add_del(
116             0,
117             self.recirc.sw_if_index,
118             self.epg.epg,
119             self.is_ext)
120
121     def __str__(self):
122         return self.object_id()
123
124     def object_id(self):
125         return "gbp-recirc;[%d]" % (self.recirc.sw_if_index)
126
127     def query_vpp_config(self):
128         rs = self._test.vapi.gbp_recirc_dump()
129         for r in rs:
130             if r.recirc.sw_if_index == self.recirc.sw_if_index:
131                 return True
132         return False
133
134
135 class VppGbpSubnet(VppObject):
136     """
137     GBP Subnet
138     """
139
140     def __init__(self, test, table_id, address, address_len,
141                  is_internal=True, is_ip6=False,
142                  sw_if_index=None, epg=None):
143         self._test = test
144         self.table_id = table_id
145         self.address = address
146         self.address_len = address_len
147         self.is_ip6 = is_ip6
148         if is_ip6:
149             self.address_n = inet_pton(AF_INET6, address)
150         else:
151             self.address_n = inet_pton(AF_INET, address)
152         self.is_internal = is_internal
153         self.sw_if_index = sw_if_index
154         self.epg = epg
155
156     def add_vpp_config(self):
157         self._test.vapi.gbp_subnet_add_del(
158             1,
159             self.table_id,
160             self.is_internal,
161             self.address_n,
162             self.address_len,
163             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
164             epg_id=self.epg if self.epg else 0xffffffff,
165             is_ip6=self.is_ip6)
166         self._test.registry.register(self, self._test.logger)
167
168     def remove_vpp_config(self):
169         self._test.vapi.gbp_subnet_add_del(
170             0,
171             self.table_id,
172             self.is_internal,
173             self.address_n,
174             self.address_len,
175             is_ip6=self.is_ip6)
176
177     def __str__(self):
178         return self.object_id()
179
180     def object_id(self):
181         return "gbp-subnet;[%d:%s/%d]" % (self.table_id,
182                                           self.address,
183                                           self.address_len)
184
185     def query_vpp_config(self):
186         ss = self._test.vapi.gbp_subnet_dump()
187         for s in ss:
188             if s.subnet.table_id == self.table_id and \
189                s.subnet.address_length == self.address_len and \
190                s.subnet.is_ip6 == self.is_ip6:
191                 if self.is_ip6:
192                     if s.subnet.address == self.address_n:
193                         return True
194                 else:
195                     if s.subnet.address[:4] == self.address_n:
196                         return True
197         return False
198
199
200 class VppGbpEndpointGroup(VppObject):
201     """
202     GBP Endpoint Group
203     """
204
205     def __init__(self, test, epg, rd, bd, uplink,
206                  bvi, bvi_ip4, bvi_ip6=None):
207         self._test = test
208         self.uplink = uplink
209         self.bvi = bvi
210         self.bvi_ip4 = bvi_ip4
211         self.bvi_ip4_n = inet_pton(AF_INET, bvi_ip4)
212         self.bvi_ip6 = bvi_ip6
213         self.bvi_ip6_n = inet_pton(AF_INET6, bvi_ip6)
214         self.epg = epg
215         self.bd = bd
216         self.rd = rd
217
218     def add_vpp_config(self):
219         self._test.vapi.gbp_endpoint_group_add_del(
220             1,
221             self.epg,
222             self.bd,
223             self.rd,
224             self.rd,
225             self.uplink.sw_if_index)
226         self._test.registry.register(self, self._test.logger)
227
228     def remove_vpp_config(self):
229         self._test.vapi.gbp_endpoint_group_add_del(
230             0,
231             self.epg,
232             self.bd,
233             self.rd,
234             self.rd,
235             self.uplink.sw_if_index)
236
237     def __str__(self):
238         return self.object_id()
239
240     def object_id(self):
241         return "gbp-endpoint-group;[%d]" % (self.epg)
242
243     def query_vpp_config(self):
244         epgs = self._test.vapi.gbp_endpoint_group_dump()
245         for epg in epgs:
246             if epg.epg.epg_id == self.epg:
247                 return True
248         return False
249
250
251 class VppGbpContract(VppObject):
252     """
253     GBP Contract
254     """
255
256     def __init__(self, test, src_epg, dst_epg, acl_index):
257         self._test = test
258         self.acl_index = acl_index
259         self.src_epg = src_epg
260         self.dst_epg = dst_epg
261
262     def add_vpp_config(self):
263         self._test.vapi.gbp_contract_add_del(
264             1,
265             self.src_epg,
266             self.dst_epg,
267             self.acl_index)
268         self._test.registry.register(self, self._test.logger)
269
270     def remove_vpp_config(self):
271         self._test.vapi.gbp_contract_add_del(
272             0,
273             self.src_epg,
274             self.dst_epg,
275             self.acl_index)
276
277     def __str__(self):
278         return self.object_id()
279
280     def object_id(self):
281         return "gbp-contract;[%d:%s:%d]" % (self.src_epg,
282                                             self.dst_epg,
283                                             self.acl_index)
284
285     def query_vpp_config(self):
286         cs = self._test.vapi.gbp_contract_dump()
287         for c in cs:
288             if c.contract.src_epg == self.src_epg \
289                and c.contract.dst_epg == self.dst_epg:
290                 return True
291         return False
292
293
294 class VppGbpAcl(VppObject):
295     """
296     GBP Acl
297     """
298
299     def __init__(self, test):
300         self._test = test
301         self.acl_index = 4294967295
302
303     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
304                     s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
305                     sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
306                     dport_from=0, dport_to=65535):
307         if proto == -1 or proto == 0:
308             sport_to = 0
309             dport_to = sport_to
310         elif proto == 1 or proto == 58:
311             sport_to = 255
312             dport_to = sport_to
313         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
314                  'srcport_or_icmptype_first': sport_from,
315                  'srcport_or_icmptype_last': sport_to,
316                  'src_ip_prefix_len': s_prefix,
317                  'src_ip_addr': s_ip,
318                  'dstport_or_icmpcode_first': dport_from,
319                  'dstport_or_icmpcode_last': dport_to,
320                  'dst_ip_prefix_len': d_prefix,
321                  'dst_ip_addr': d_ip})
322         return rule
323
324     def add_vpp_config(self, rules):
325
326         reply = self._test.vapi.acl_add_replace(self.acl_index,
327                                                 r=rules,
328                                                 tag='GBPTest')
329         self.acl_index = reply.acl_index
330         return self.acl_index
331
332     def remove_vpp_config(self):
333         self._test.vapi.acl_del(self.acl_index)
334
335     def __str__(self):
336         return self.object_id()
337
338     def object_id(self):
339         return "gbp-acl;[%d]" % (self.acl_index)
340
341     def query_vpp_config(self):
342         cs = self._test.vapi.acl_dump()
343         for c in cs:
344             if c.acl_index == self.acl_index:
345                 return True
346         return False
347
348
349 class TestGBP(VppTestCase):
350     """ GBP Test Case """
351
352     def setUp(self):
353         super(TestGBP, self).setUp()
354
355         self.create_pg_interfaces(range(9))
356         self.create_loopback_interfaces(9)
357
358         self.router_mac = "00:11:22:33:44:55"
359
360         for i in self.pg_interfaces:
361             i.admin_up()
362         for i in self.lo_interfaces:
363             i.admin_up()
364             self.vapi.sw_interface_set_mac_address(
365                 i.sw_if_index,
366                 mactobinary(self.router_mac))
367
368     def tearDown(self):
369         for i in self.pg_interfaces:
370             i.admin_down()
371
372         super(TestGBP, self).tearDown()
373
374     def send_and_expect_bridged(self, src, tx, dst):
375         rx = self.send_and_expect(src, tx, dst)
376
377         for r in rx:
378             self.assertEqual(r[Ether].src, tx[0][Ether].src)
379             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
380             self.assertEqual(r[IP].src, tx[0][IP].src)
381             self.assertEqual(r[IP].dst, tx[0][IP].dst)
382         return rx
383
384     def send_and_expect_bridged6(self, src, tx, dst):
385         rx = self.send_and_expect(src, tx, dst)
386
387         for r in rx:
388             self.assertEqual(r[Ether].src, tx[0][Ether].src)
389             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
390             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
391             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
392         return rx
393
394     def send_and_expect_routed(self, src, tx, dst, src_mac):
395         rx = self.send_and_expect(src, tx, dst)
396
397         for r in rx:
398             self.assertEqual(r[Ether].src, src_mac)
399             self.assertEqual(r[Ether].dst, dst.remote_mac)
400             self.assertEqual(r[IP].src, tx[0][IP].src)
401             self.assertEqual(r[IP].dst, tx[0][IP].dst)
402         return rx
403
404     def send_and_expect_natted(self, src, tx, dst, src_ip):
405         rx = self.send_and_expect(src, tx, dst)
406
407         for r in rx:
408             self.assertEqual(r[Ether].src, tx[0][Ether].src)
409             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
410             self.assertEqual(r[IP].src, src_ip)
411             self.assertEqual(r[IP].dst, tx[0][IP].dst)
412         return rx
413
414     def send_and_expect_natted6(self, src, tx, dst, src_ip):
415         rx = self.send_and_expect(src, tx, dst)
416
417         for r in rx:
418             self.assertEqual(r[Ether].src, tx[0][Ether].src)
419             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
420             self.assertEqual(r[IPv6].src, src_ip)
421             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
422         return rx
423
424     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
425         rx = self.send_and_expect(src, tx, dst)
426
427         for r in rx:
428             self.assertEqual(r[Ether].src, tx[0][Ether].src)
429             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
430             self.assertEqual(r[IP].dst, dst_ip)
431             self.assertEqual(r[IP].src, tx[0][IP].src)
432         return rx
433
434     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
435         rx = self.send_and_expect(src, tx, dst)
436
437         for r in rx:
438             self.assertEqual(r[Ether].src, tx[0][Ether].src)
439             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
440             self.assertEqual(r[IPv6].dst, dst_ip)
441             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
442         return rx
443
444     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
445         rx = self.send_and_expect(src, tx, dst)
446
447         for r in rx:
448             self.assertEqual(r[Ether].src, self.router_mac)
449             self.assertEqual(r[Ether].dst, dst.remote_mac)
450             self.assertEqual(r[IP].dst, dst_ip)
451             self.assertEqual(r[IP].src, src_ip)
452         return rx
453
454     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
455         rx = self.send_and_expect(src, tx, dst)
456
457         for r in rx:
458             self.assertEqual(r[Ether].src, self.router_mac)
459             self.assertEqual(r[Ether].dst, dst.remote_mac)
460             self.assertEqual(r[IPv6].dst, dst_ip)
461             self.assertEqual(r[IPv6].src, src_ip)
462         return rx
463
464     def test_gbp(self):
465         """ Group Based Policy """
466
467         nat_table = VppIpTable(self, 20)
468         nat_table.add_vpp_config()
469         nat_table = VppIpTable(self, 20, is_ip6=True)
470         nat_table.add_vpp_config()
471
472         #
473         # Bridge Domains
474         #
475         self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1,
476                                         learn=0, arp_term=1, is_add=1)
477         self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1,
478                                         learn=0, arp_term=1, is_add=1)
479         self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1,
480                                         learn=0, arp_term=1, is_add=1)
481
482         #
483         # 3 EPGs, 2 of which share a BD.
484         #
485         epgs = []
486         recircs = []
487         epgs.append(VppGbpEndpointGroup(self, 220, 0, 1, self.pg4,
488                                         self.loop0,
489                                         "10.0.0.128",
490                                         "2001:10::128"))
491         recircs.append(VppGbpRecirc(self, epgs[0],
492                                     self.loop3))
493         epgs.append(VppGbpEndpointGroup(self, 221, 0, 1, self.pg5,
494                                         self.loop0,
495                                         "10.0.1.128",
496                                         "2001:10:1::128"))
497         recircs.append(VppGbpRecirc(self, epgs[1],
498                                     self.loop4))
499         epgs.append(VppGbpEndpointGroup(self, 222, 0, 2, self.pg6,
500                                         self.loop1,
501                                         "10.0.2.128",
502                                         "2001:10:2::128"))
503         recircs.append(VppGbpRecirc(self, epgs[2],
504                                     self.loop5))
505
506         #
507         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
508         #
509         epgs.append(VppGbpEndpointGroup(self, 333, 20, 20, self.pg7,
510                                         self.loop2,
511                                         "11.0.0.128",
512                                         "3001::128"))
513         recircs.append(VppGbpRecirc(self, epgs[3],
514                                     self.loop6, is_ext=True))
515         epgs.append(VppGbpEndpointGroup(self, 444, 20, 20, self.pg8,
516                                         self.loop2,
517                                         "11.0.0.129",
518                                         "3001::129"))
519         recircs.append(VppGbpRecirc(self, epgs[4],
520                                     self.loop8, is_ext=True))
521
522         epg_nat = epgs[3]
523         recirc_nat = recircs[3]
524
525         #
526         # 4 end-points, 2 in the same subnet, 3 in the same BD
527         #
528         eps = []
529         eps.append(VppGbpEndpoint(self, self.pg0,
530                                   epgs[0], recircs[0],
531                                   "10.0.0.1",
532                                   "11.0.0.1"))
533         eps.append(VppGbpEndpoint(self, self.pg1,
534                                   epgs[0], recircs[0],
535                                   "10.0.0.2",
536                                   "11.0.0.2"))
537         eps.append(VppGbpEndpoint(self, self.pg2,
538                                   epgs[1], recircs[1],
539                                   "10.0.1.1",
540                                   "11.0.0.3"))
541         eps.append(VppGbpEndpoint(self, self.pg3,
542                                   epgs[2], recircs[2],
543                                   "10.0.2.1",
544                                   "11.0.0.4"))
545         eps.append(VppGbpEndpoint(self, self.pg0,
546                                   epgs[0], recircs[0],
547                                   "2001:10::1",
548                                   "3001::1",
549                                   is_ip6=True))
550         eps.append(VppGbpEndpoint(self, self.pg1,
551                                   epgs[0], recircs[0],
552                                   "2001:10::2",
553                                   "3001::2",
554                                   is_ip6=True))
555         eps.append(VppGbpEndpoint(self, self.pg2,
556                                   epgs[1], recircs[1],
557                                   "2001:10:1::1",
558                                   "3001::3",
559                                   is_ip6=True))
560         eps.append(VppGbpEndpoint(self, self.pg3,
561                                   epgs[2], recircs[2],
562                                   "2001:10:2::1",
563                                   "3001::4",
564                                   is_ip6=True))
565
566         #
567         # Config related to each of the EPGs
568         #
569         for epg in epgs:
570             # IP config on the BVI interfaces
571             if epg != epgs[1] and epg != epgs[4]:
572                 epg.bvi.set_table_ip4(epg.rd)
573                 epg.bvi.set_table_ip6(epg.rd)
574
575                 # The BVIs are NAT inside interfaces
576                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
577                                                           is_inside=1,
578                                                           is_add=1)
579                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
580                                                   is_inside=1,
581                                                   is_add=1)
582
583             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
584                                                    epg.bvi_ip4_n,
585                                                    32)
586             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
587                                                    epg.bvi_ip6_n,
588                                                    128,
589                                                    is_ipv6=True)
590
591             # EPG uplink interfaces in the BD
592             epg.uplink.set_table_ip4(epg.rd)
593             epg.uplink.set_table_ip6(epg.rd)
594             self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index,
595                                                  epg.bd)
596
597             # add the BD ARP termination entry for BVI IP
598             self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
599                                         mac=mactobinary(self.router_mac),
600                                         ip=epg.bvi_ip4_n,
601                                         is_ipv6=0,
602                                         is_add=1)
603             self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
604                                         mac=mactobinary(self.router_mac),
605                                         ip=epg.bvi_ip6_n,
606                                         is_ipv6=1,
607                                         is_add=1)
608
609             # epg[1] shares the same BVI to epg[0]
610             if epg != epgs[1] and epg != epgs[4]:
611                 # BVI in BD
612                 self.vapi.sw_interface_set_l2_bridge(epg.bvi.sw_if_index,
613                                                      epg.bd,
614                                                      bvi=1)
615                 # BVI L2 FIB entry
616                 self.vapi.l2fib_add_del(self.router_mac,
617                                         epg.bd,
618                                         epg.bvi.sw_if_index,
619                                         is_add=1, bvi_mac=1)
620
621             # EPG in VPP
622             epg.add_vpp_config()
623
624         for recirc in recircs:
625             # EPG's ingress recirculation interface maps to its RD
626             recirc.recirc.set_table_ip4(recirc.epg.rd)
627             recirc.recirc.set_table_ip6(recirc.epg.rd)
628
629             # in the bridge to allow DVR. L2 emulation to punt to L3
630             self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index,
631                                                  recirc.epg.bd)
632             self.vapi.sw_interface_set_l2_emulation(
633                 recirc.recirc.sw_if_index)
634
635             self.vapi.nat44_interface_add_del_feature(
636                 recirc.recirc.sw_if_index,
637                 is_inside=0,
638                 is_add=1)
639             self.vapi.nat66_add_del_interface(
640                 recirc.recirc.sw_if_index,
641                 is_inside=0,
642                 is_add=1)
643
644             recirc.add_vpp_config()
645
646         ep_routes = []
647         ep_arps = []
648         for ep in eps:
649             self.pg_enable_capture(self.pg_interfaces)
650             self.pg_start()
651             #
652             # routes to the endpoints. We need these since there are no
653             # adj-fibs due to the fact the the BVI address has /32 and
654             # the subnet is not attached.
655             #
656             r = VppIpRoute(self, ep.ip, ep.ip_len,
657                            [VppRoutePath(ep.ip,
658                                          ep.epg.bvi.sw_if_index,
659                                          proto=ep.proto)],
660                            is_ip6=ep.is_ip6)
661             r.add_vpp_config()
662             ep_routes.append(r)
663
664             #
665             # ARP entries for the endpoints
666             #
667             a = VppNeighbor(self,
668                             ep.epg.bvi.sw_if_index,
669                             ep.itf.remote_mac,
670                             ep.ip, af=ep.af)
671             a.add_vpp_config()
672             ep_arps.append(a)
673
674             # add each EP itf to the its BD
675             self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index,
676                                                  ep.epg.bd)
677
678             # add the BD ARP termination entry
679             self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
680                                         mac=ep.bin_mac,
681                                         ip=ep.ip_n,
682                                         is_ipv6=0,
683                                         is_add=1)
684
685             # L2 FIB entry
686             self.vapi.l2fib_add_del(ep.mac,
687                                     ep.epg.bd,
688                                     ep.itf.sw_if_index,
689                                     is_add=1)
690
691             # Add static mappings for each EP from the 10/8 to 11/8 network
692             if ep.af == AF_INET:
693                 self.vapi.nat44_add_del_static_mapping(ep.ip_n,
694                                                        ep.floating_ip_n,
695                                                        vrf_id=0,
696                                                        addr_only=1)
697             else:
698                 self.vapi.nat66_add_del_static_mapping(ep.ip_n,
699                                                        ep.floating_ip_n,
700                                                        vrf_id=0)
701
702             # VPP EP create ...
703             ep.add_vpp_config()
704
705             # ... results in a Gratuitous ARP/ND on the EPG's uplink
706             rx = ep.epg.uplink.get_capture(1, timeout=0.2)
707
708             if ep.is_ip6:
709                 self.assertTrue(rx[0].haslayer(ICMPv6ND_NA))
710                 self.assertEqual(rx[0][ICMPv6ND_NA].tgt, ep.ip)
711             else:
712                 self.assertTrue(rx[0].haslayer(ARP))
713                 self.assertEqual(rx[0][ARP].psrc, ep.ip)
714                 self.assertEqual(rx[0][ARP].pdst, ep.ip)
715
716             # add the BD ARP termination entry for floating IP
717             self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
718                                         mac=ep.bin_mac,
719                                         ip=ep.floating_ip_n,
720                                         is_ipv6=ep.is_ip6,
721                                         is_add=1)
722
723             # floating IPs route via EPG recirc
724             r = VppIpRoute(self, ep.floating_ip, ep.ip_len,
725                            [VppRoutePath(ep.floating_ip,
726                                          ep.recirc.recirc.sw_if_index,
727                                          is_dvr=1,
728                                          proto=ep.proto)],
729                            table_id=20,
730                            is_ip6=ep.is_ip6)
731             r.add_vpp_config()
732             ep_routes.append(r)
733
734             # L2 FIB entries in the NAT EPG BD to bridge the packets from
735             # the outside direct to the internal EPG
736             self.vapi.l2fib_add_del(ep.mac,
737                                     epg_nat.bd,
738                                     ep.recirc.recirc.sw_if_index,
739                                     is_add=1)
740
741         #
742         # ARP packets for unknown IP are flooded
743         #
744         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
745                          src=self.pg0.remote_mac) /
746                    ARP(op="who-has",
747                        hwdst="ff:ff:ff:ff:ff:ff",
748                        hwsrc=self.pg0.remote_mac,
749                        pdst=epgs[0].bvi_ip4,
750                        psrc="10.0.0.88"))
751
752         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
753
754         #
755         # ARP/ND packets get a response
756         #
757         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
758                          src=self.pg0.remote_mac) /
759                    ARP(op="who-has",
760                        hwdst="ff:ff:ff:ff:ff:ff",
761                        hwsrc=self.pg0.remote_mac,
762                        pdst=epgs[0].bvi_ip4,
763                        psrc=eps[0].ip))
764
765         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
766
767         nsma = in6_getnsma(inet_pton(AF_INET6, eps[4].ip))
768         d = inet_ntop(AF_INET6, nsma)
769         pkt_nd = (Ether(dst=in6_getnsmac(nsma)) /
770                   IPv6(dst=d, src=eps[4].ip) /
771                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
772                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
773         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
774
775         #
776         # broadcast packets are flooded
777         #
778         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
779                            src=self.pg0.remote_mac) /
780                      IP(src=eps[0].ip, dst="232.1.1.1") /
781                      UDP(sport=1234, dport=1234) /
782                      Raw('\xa5' * 100))
783
784         self.vapi.cli("clear trace")
785         self.pg0.add_stream(pkt_bcast)
786
787         self.pg_enable_capture(self.pg_interfaces)
788         self.pg_start()
789
790         rxd = eps[1].itf.get_capture(1)
791         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
792         rxd = epgs[0].uplink.get_capture(1)
793         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
794
795         #
796         # packets to non-local L3 destinations dropped
797         #
798         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
799                                        dst=self.router_mac) /
800                                  IP(src=eps[0].ip, dst="10.0.0.99") /
801                                  UDP(sport=1234, dport=1234) /
802                                  Raw('\xa5' * 100))
803         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
804                                        dst=self.router_mac) /
805                                  IP(src=eps[0].ip, dst="10.0.1.99") /
806                                  UDP(sport=1234, dport=1234) /
807                                  Raw('\xa5' * 100))
808
809         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
810
811         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
812                                        dst=self.router_mac) /
813                                  IPv6(src=eps[4].ip, dst="2001:10::99") /
814                                  UDP(sport=1234, dport=1234) /
815                                  Raw('\xa5' * 100))
816         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
817
818         #
819         # Add the subnet routes
820         #
821         s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24)
822         s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24)
823         s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24)
824         s41.add_vpp_config()
825         s42.add_vpp_config()
826         s43.add_vpp_config()
827         s61 = VppGbpSubnet(self, 0, "2001:10::1", 64, is_ip6=True)
828         s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64, is_ip6=True)
829         s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64, is_ip6=True)
830         s61.add_vpp_config()
831         s62.add_vpp_config()
832         s63.add_vpp_config()
833
834         self.send_and_expect_bridged(self.pg0,
835                                      pkt_intra_epg_220_ip4 * 65,
836                                      self.pg4)
837         self.send_and_expect_bridged(self.pg3,
838                                      pkt_inter_epg_222_ip4 * 65,
839                                      self.pg6)
840         self.send_and_expect_bridged6(self.pg3,
841                                       pkt_inter_epg_222_ip6 * 65,
842                                       self.pg6)
843
844         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
845         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
846         self.logger.info(self.vapi.cli("sh gbp endpoint"))
847         self.logger.info(self.vapi.cli("sh gbp recirc"))
848         self.logger.info(self.vapi.cli("sh int"))
849         self.logger.info(self.vapi.cli("sh int addr"))
850         self.logger.info(self.vapi.cli("sh int feat loop6"))
851         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
852         self.logger.info(self.vapi.cli("sh int feat loop3"))
853
854         #
855         # Packet destined to unknown unicast is sent on the epg uplink ...
856         #
857         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
858                                              dst="00:00:00:33:44:55") /
859                                        IP(src=eps[0].ip, dst="10.0.0.99") /
860                                        UDP(sport=1234, dport=1234) /
861                                        Raw('\xa5' * 100))
862
863         self.send_and_expect_bridged(self.pg0,
864                                      pkt_intra_epg_220_to_uplink * 65,
865                                      self.pg4)
866         # ... and nowhere else
867         self.pg1.get_capture(0, timeout=0.1)
868         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
869
870         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
871                                              dst="00:00:00:33:44:66") /
872                                        IP(src=eps[0].ip, dst="10.0.0.99") /
873                                        UDP(sport=1234, dport=1234) /
874                                        Raw('\xa5' * 100))
875
876         self.send_and_expect_bridged(self.pg2,
877                                      pkt_intra_epg_221_to_uplink * 65,
878                                      self.pg5)
879
880         #
881         # Packets from the uplink are forwarded in the absence of a contract
882         #
883         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
884                                                dst=self.pg0.remote_mac) /
885                                          IP(src=eps[0].ip, dst="10.0.0.99") /
886                                          UDP(sport=1234, dport=1234) /
887                                          Raw('\xa5' * 100))
888
889         self.send_and_expect_bridged(self.pg4,
890                                      pkt_intra_epg_220_from_uplink * 65,
891                                      self.pg0)
892
893         #
894         # in the absence of policy, endpoints in the same EPG
895         # can communicate
896         #
897         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
898                                dst=self.pg1.remote_mac) /
899                          IP(src=eps[0].ip, dst=eps[1].ip) /
900                          UDP(sport=1234, dport=1234) /
901                          Raw('\xa5' * 100))
902
903         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
904
905         #
906         # in the abscense of policy, endpoints in the different EPG
907         # cannot communicate
908         #
909         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
910                                           dst=self.pg2.remote_mac) /
911                                     IP(src=eps[0].ip, dst=eps[2].ip) /
912                                     UDP(sport=1234, dport=1234) /
913                                     Raw('\xa5' * 100))
914         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
915                                           dst=self.pg0.remote_mac) /
916                                     IP(src=eps[2].ip, dst=eps[0].ip) /
917                                     UDP(sport=1234, dport=1234) /
918                                     Raw('\xa5' * 100))
919         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
920                                           dst=self.router_mac) /
921                                     IP(src=eps[0].ip, dst=eps[3].ip) /
922                                     UDP(sport=1234, dport=1234) /
923                                     Raw('\xa5' * 100))
924
925         self.send_and_assert_no_replies(self.pg0,
926                                         pkt_inter_epg_220_to_221 * 65)
927         self.send_and_assert_no_replies(self.pg0,
928                                         pkt_inter_epg_220_to_222 * 65)
929
930         #
931         # A uni-directional contract from EPG 220 -> 221
932         #
933         acl = VppGbpAcl(self)
934         rule = acl.create_rule(permit_deny=1, proto=17)
935         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
936         acl_index = acl.add_vpp_config([rule, rule2])
937         c1 = VppGbpContract(self, 220, 221, acl_index)
938         c1.add_vpp_config()
939
940         self.send_and_expect_bridged(self.pg0,
941                                      pkt_inter_epg_220_to_221 * 65,
942                                      self.pg2)
943         self.send_and_assert_no_replies(self.pg0,
944                                         pkt_inter_epg_220_to_222 * 65)
945
946         #
947         # contract for the return direction
948         #
949         c2 = VppGbpContract(self, 221, 220, acl_index)
950         c2.add_vpp_config()
951
952         self.send_and_expect_bridged(self.pg0,
953                                      pkt_inter_epg_220_to_221 * 65,
954                                      self.pg2)
955         self.send_and_expect_bridged(self.pg2,
956                                      pkt_inter_epg_221_to_220 * 65,
957                                      self.pg0)
958
959         #
960         # check that inter group is still disabled for the groups
961         # not in the contract.
962         #
963         self.send_and_assert_no_replies(self.pg0,
964                                         pkt_inter_epg_220_to_222 * 65)
965
966         #
967         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
968         #
969         c3 = VppGbpContract(self, 220, 222, acl_index)
970         c3.add_vpp_config()
971
972         self.logger.info(self.vapi.cli("sh gbp contract"))
973
974         self.send_and_expect_routed(self.pg0,
975                                     pkt_inter_epg_220_to_222 * 65,
976                                     self.pg3,
977                                     self.router_mac)
978
979         #
980         # remove both contracts, traffic stops in both directions
981         #
982         c2.remove_vpp_config()
983         c1.remove_vpp_config()
984         c3.remove_vpp_config()
985         acl.remove_vpp_config()
986
987         self.send_and_assert_no_replies(self.pg2,
988                                         pkt_inter_epg_221_to_220 * 65)
989         self.send_and_assert_no_replies(self.pg0,
990                                         pkt_inter_epg_220_to_221 * 65)
991         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
992
993         #
994         # EPs to the outside world
995         #
996
997         # in the EP's RD an external subnet via the NAT EPG's recirc
998         se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0,
999                            is_internal=False,
1000                            sw_if_index=recirc_nat.recirc.sw_if_index,
1001                            epg=epg_nat.epg)
1002         se1.add_vpp_config()
1003         se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8,
1004                            is_internal=False,
1005                            sw_if_index=recirc_nat.recirc.sw_if_index,
1006                            epg=epg_nat.epg)
1007         se2.add_vpp_config()
1008         se16 = VppGbpSubnet(self, 0, "::", 0,
1009                             is_internal=False,
1010                             sw_if_index=recirc_nat.recirc.sw_if_index,
1011                             epg=epg_nat.epg,
1012                             is_ip6=True)
1013         se16.add_vpp_config()
1014         # in the NAT RD an external subnet via the NAT EPG's uplink
1015         se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0,
1016                            is_internal=False,
1017                            sw_if_index=epg_nat.uplink.sw_if_index,
1018                            epg=epg_nat.epg)
1019         se36 = VppGbpSubnet(self, 20, "::", 0,
1020                             is_internal=False,
1021                             sw_if_index=epg_nat.uplink.sw_if_index,
1022                             epg=epg_nat.epg,
1023                             is_ip6=True)
1024         se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8,
1025                            is_internal=False,
1026                            sw_if_index=epg_nat.uplink.sw_if_index,
1027                            epg=epg_nat.epg)
1028         se3.add_vpp_config()
1029         se36.add_vpp_config()
1030         se4.add_vpp_config()
1031
1032         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1033         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1034         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1035         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1036                                        eps[4].floating_ip))
1037
1038         #
1039         # From an EP to an outside addess: IN2OUT
1040         #
1041         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1042                                              dst=self.router_mac) /
1043                                        IP(src=eps[0].ip, dst="1.1.1.1") /
1044                                        UDP(sport=1234, dport=1234) /
1045                                        Raw('\xa5' * 100))
1046
1047         # no policy yet
1048         self.send_and_assert_no_replies(self.pg0,
1049                                         pkt_inter_epg_220_to_global * 65)
1050
1051         acl2 = VppGbpAcl(self)
1052         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1053                                 sport_to=1234, dport_from=1234, dport_to=1234)
1054         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1055                                  sport_from=1234, sport_to=1234,
1056                                  dport_from=1234, dport_to=1234)
1057
1058         acl_index2 = acl2.add_vpp_config([rule, rule2])
1059         c4 = VppGbpContract(self, 220, 333, acl_index2)
1060         c4.add_vpp_config()
1061
1062         self.send_and_expect_natted(self.pg0,
1063                                     pkt_inter_epg_220_to_global * 65,
1064                                     self.pg7,
1065                                     eps[0].floating_ip)
1066
1067         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1068                                              dst=self.router_mac) /
1069                                        IPv6(src=eps[4].ip, dst="6001::1") /
1070                                        UDP(sport=1234, dport=1234) /
1071                                        Raw('\xa5' * 100))
1072
1073         self.send_and_expect_natted6(self.pg0,
1074                                      pkt_inter_epg_220_to_global * 65,
1075                                      self.pg7,
1076                                      eps[4].floating_ip)
1077
1078         #
1079         # From a global address to an EP: OUT2IN
1080         #
1081         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
1082                                                dst=self.pg0.remote_mac) /
1083                                          IP(dst=eps[0].floating_ip,
1084                                             src="1.1.1.1") /
1085                                          UDP(sport=1234, dport=1234) /
1086                                          Raw('\xa5' * 100))
1087
1088         self.send_and_assert_no_replies(self.pg7,
1089                                         pkt_inter_epg_220_from_global * 65)
1090
1091         c5 = VppGbpContract(self, 333, 220, acl_index2)
1092         c5.add_vpp_config()
1093
1094         self.send_and_expect_unnatted(self.pg7,
1095                                       pkt_inter_epg_220_from_global * 65,
1096                                       eps[0].itf,
1097                                       eps[0].ip)
1098
1099         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
1100                                                dst=self.pg0.remote_mac) /
1101                                          IPv6(dst=eps[4].floating_ip,
1102                                               src="6001::1") /
1103                                          UDP(sport=1234, dport=1234) /
1104                                          Raw('\xa5' * 100))
1105
1106         self.send_and_expect_unnatted6(self.pg7,
1107                                        pkt_inter_epg_220_from_global * 65,
1108                                        eps[4].itf,
1109                                        eps[4].ip)
1110
1111         #
1112         # From a local VM to another local VM using resp. public addresses:
1113         #  IN2OUT2IN
1114         #
1115         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1116                                           dst=self.router_mac) /
1117                                     IP(src=eps[0].ip,
1118                                        dst=eps[1].floating_ip) /
1119                                     UDP(sport=1234, dport=1234) /
1120                                     Raw('\xa5' * 100))
1121
1122         self.send_and_expect_double_natted(eps[0].itf,
1123                                            pkt_intra_epg_220_global * 65,
1124                                            eps[1].itf,
1125                                            eps[0].floating_ip,
1126                                            eps[1].ip)
1127
1128         pkt_intra_epg_220_global = (Ether(src=self.pg4.remote_mac,
1129                                           dst=self.router_mac) /
1130                                     IPv6(src=eps[4].ip,
1131                                          dst=eps[5].floating_ip) /
1132                                     UDP(sport=1234, dport=1234) /
1133                                     Raw('\xa5' * 100))
1134
1135         self.send_and_expect_double_natted6(eps[4].itf,
1136                                             pkt_intra_epg_220_global * 65,
1137                                             eps[5].itf,
1138                                             eps[4].floating_ip,
1139                                             eps[5].ip)
1140
1141         #
1142         # cleanup
1143         #
1144         for ep in eps:
1145             # del static mappings for each EP from the 10/8 to 11/8 network
1146             if ep.af == AF_INET:
1147                 self.vapi.nat44_add_del_static_mapping(ep.ip_n,
1148                                                        ep.floating_ip_n,
1149                                                        vrf_id=0,
1150                                                        addr_only=1,
1151                                                        is_add=0)
1152             else:
1153                 self.vapi.nat66_add_del_static_mapping(ep.ip_n,
1154                                                        ep.floating_ip_n,
1155                                                        vrf_id=0,
1156                                                        is_add=0)
1157
1158         for epg in epgs:
1159             # IP config on the BVI interfaces
1160             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
1161                                                    epg.bvi_ip4_n,
1162                                                    32,
1163                                                    is_add=0)
1164             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
1165                                                    epg.bvi_ip6_n,
1166                                                    128,
1167                                                    is_add=0,
1168                                                    is_ipv6=True)
1169             self.logger.info(self.vapi.cli("sh int addr"))
1170
1171             epg.uplink.set_table_ip4(0)
1172             epg.uplink.set_table_ip6(0)
1173
1174             if epg != epgs[0] and epg != epgs[3]:
1175                 epg.bvi.set_table_ip4(0)
1176                 epg.bvi.set_table_ip6(0)
1177
1178                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1179                                                           is_inside=1,
1180                                                           is_add=0)
1181                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1182                                                   is_inside=1,
1183                                                   is_add=0)
1184
1185         for recirc in recircs:
1186             recirc.recirc.set_table_ip4(0)
1187             recirc.recirc.set_table_ip6(0)
1188
1189             self.vapi.nat44_interface_add_del_feature(
1190                 recirc.recirc.sw_if_index,
1191                 is_inside=0,
1192                 is_add=0)
1193             self.vapi.nat66_add_del_interface(
1194                 recirc.recirc.sw_if_index,
1195                 is_inside=0,
1196                 is_add=0)
1197
1198
1199 if __name__ == '__main__':
1200     unittest.main(testRunner=VppTestRunner)