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