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