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