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