]> git.proxmox.com Git - mirror_frr.git/commitdiff
topotests: add bgp_vpnv6 test allocation
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 1 Feb 2023 16:28:15 +0000 (17:28 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 9 May 2023 19:01:08 +0000 (21:01 +0200)
This test demonstrates that a label is allocated for each
ipv6 next-hop. IPv6 test introduces link local ipv6 addresses
as next hops, and compared to IPv4, one can have two different
next-hops depending if the next-hop is defined by a global
address (static route redistributed) or a bgp peer.

This test checks that:
- The labels are correctly allocated per connected next-hop.
- The default label is used for non connected prefixes.
- The withdraw operation frees the MPLS entry.
- If a recursive route is redistributed by BGP, then the nexthop
tracking will find the appropriate nexthop entry, and the
associated label will be found out.
- When a prefix moves from one peer to one another behind the
vrf, then the MPLS switching operation for return
traffic is changing the outgoing interface to use.
- When the 'label vpn export <value>' MPLS label value is changed,
then the modification is propagated to prefixes which use that value.
- Also, when unconfiguring the per-nexthop allocation mode, check
that the MPLS entries and the VPNv4 entries of r1 are changed
accordingly.
- Reversely, when re-configuring the per-nexthop allocation mode,
check that the allocation mode reuses the other label values.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
16 files changed:
tests/topotests/bgp_vpnv6_per_nexthop_label/__init__.py [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgp_ipv6_routes_vrf1.json [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r11/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r11/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r12/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r12/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r13/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r13/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgp_vpnv6_routes.json [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/rr/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/rr/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py [new file with mode: 0644]

diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/__init__.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgp_ipv6_routes_vrf1.json b/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgp_ipv6_routes_vrf1.json
new file mode 100644 (file)
index 0000000..159879a
--- /dev/null
@@ -0,0 +1,183 @@
+{
+     "vrfName": "vrf1",
+     "localAS": 65500,
+     "routes":
+         {
+            "10:200::/64": [
+                {
+                    "valid": true,
+                    "bestpath": true,
+                    "prefix": "10:200::",
+                    "prefixLen": 64,
+                    "network": "10:200::/64",
+                    "nexthops": [
+                        {
+                            "ip": "192:168::2",
+                            "afi": "ipv6",
+                            "used": true
+                        }
+                    ]
+                }
+            ],
+             "172:31::11/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::11",
+                     "prefixLen":128,
+                     "network":"172:31::11/128",
+                     "peerId":"192:2::100",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::11",
+                             "afi":"ipv6",
+                             "scope":"global"
+                         }
+                     ]
+                 }
+             ],
+             "172:31::12/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::12",
+                     "prefixLen":128,
+                     "network":"172:31::12/128",
+                     "peerId":"192:2::100",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::12",
+                             "afi":"ipv6",
+                             "scope":"global"
+                         },
+                         {
+                             "scope": "link-local",
+                             "used":true
+                         }
+                     ]
+                 }
+             ],
+             "172:31::13/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::13",
+                     "prefixLen":128,
+                     "network":"172:31::13/128",
+                     "peerId":"192:168::255:13",
+                     "nexthops":[
+                         {
+                             "ip":"192:168::255:13",
+                             "afi":"ipv6",
+                             "scope": "global"
+                         },
+                         {
+                             "scope": "link-local"
+                         }
+                     ]
+                 }
+             ],
+             "172:31::14/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::14",
+                     "prefixLen":128,
+                     "network":"172:31::14/128",
+                     "peerId":"(unspec)",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::14",
+                             "afi":"ipv6",
+                             "used":true
+                         }
+                     ]
+                 }
+             ],
+             "172:31::15/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::15",
+                     "prefixLen":128,
+                     "network":"172:31::15/128",
+                     "peerId":"(unspec)",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::12",
+                             "afi":"ipv6",
+                             "used":true
+                         }
+                     ]
+                 }
+             ],
+             "172:31::20/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::20",
+                     "prefixLen":128,
+                     "network":"172:31::20/128",
+                     "peerId":"192:2::100",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::11",
+                             "afi":"ipv6",
+                             "scope":"global"
+                         }
+                     ]
+                 }
+             ],
+             "172:31::111/128": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"172:31::111",
+                     "prefixLen":128,
+                     "network":"172:31::111/128",
+                     "peerId":"192:2::100",
+                     "nexthops":[
+                         {
+                             "ip":"192:2::11",
+                             "afi":"ipv6",
+                             "scope":"global"
+                         }
+                     ]
+                 }
+             ],
+             "192:2::/64": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"192:2::",
+                     "prefixLen":64,
+                     "network":"192:2::/64",
+                     "peerId":"(unspec)",
+                     "nexthops":[
+                         {
+                             "ip":"::",
+                             "afi":"ipv6",
+                             "used":true
+                         }
+                     ]
+                 }
+             ],
+             "192:168::255:0/112": [
+                 {
+                     "valid":true,
+                     "bestpath":true,
+                     "prefix":"192:168::255:0",
+                     "prefixLen":112,
+                     "network":"192:168::255:0/112",
+                     "peerId":"(unspec)",
+                     "nexthops":[
+                         {
+                             "ip":"::",
+                             "afi":"ipv6",
+                             "used":true
+                         }
+                     ]
+                 }
+             ]
+         }
+}
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..74e3e6f
--- /dev/null
@@ -0,0 +1,46 @@
+debug bgp vpn leak-from-vrf
+debug bgp vpn label
+debug bgp nht
+debug bgp updates out
+router bgp 65500
+ bgp router-id 192.168.0.1
+ no bgp ebgp-requires-policy
+ neighbor 192:168::2 remote-as 65501
+ address-family ipv4 unicast
+  no neighbor 192:168::2 activate
+ exit-address-family
+ address-family ipv6 vpn
+  neighbor 192:168::2 activate
+  neighbor 192:168::2 soft-reconfiguration inbound
+ exit-address-family
+!
+router bgp 65500 vrf vrf1
+ bgp router-id 192.168.0.1
+ neighbor 192:2::100 remote-as 65500
+ neighbor 192:168::255:13 remote-as 65500
+ address-family ipv6 unicast
+  neighbor 192:2::100 activate
+  neighbor 192:2::100 route-map rmap in
+  neighbor 192:168::255:13 activate
+  neighbor 192:168::255:13 route-map rmap in
+  redistribute connected
+  redistribute static
+  label vpn export allocation-mode per-nexthop
+  label vpn export auto
+  rd vpn export 444:1
+  rt vpn both 52:100
+  export vpn
+  import vpn
+ exit-address-family
+!
+interface r1-eth0
+ mpls bgp forwarding
+!
+bgp community-list 1 seq 5 permit 10:10
+!
+route-map rmap permit 1
+ match community 1
+ set ipv6 next-hop prefer-global
+!
+route-map rmap permit 2
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r1/zebra.conf
new file mode 100644 (file)
index 0000000..bdad9ee
--- /dev/null
@@ -0,0 +1,18 @@
+log stdout
+debug zebra nht
+!debug zebra kernel msgdump recv
+!debug zebra dplane detailed
+!debug zebra packet recv
+interface r1-eth1 vrf vrf1
+ ipv6 address 192:2::1/64
+!
+interface r1-eth2 vrf vrf1
+ ipv6 address 192:168::255:1/112
+!
+interface r1-eth0
+ ip address 192:168::1/112
+!
+vrf vrf1
+ ipv6 route 172:31::14/128 192:2::14
+ ipv6 route 172:31::15/128 192:2::12
+exit-vrf
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r11/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r11/bgpd.conf
new file mode 100644 (file)
index 0000000..d0d4e3d
--- /dev/null
@@ -0,0 +1,18 @@
+router bgp 65500
+ bgp router-id 11.11.11.11
+ no bgp network import-check
+ neighbor 192:2::100 remote-as 65500
+ address-family ipv4 unicast
+  no neighbor 192:2::100 activate
+ !
+ address-family ipv6 unicast
+  neighbor 192:2::100 activate
+  neighbor 192:2::100 route-map rmap out
+  network 172:31::11/128
+  network 172:31::111/128
+  network 172:31::20/128
+ exit-address-family
+!
+route-map rmap permit 1
+ set community 10:10
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r11/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r11/zebra.conf
new file mode 100644 (file)
index 0000000..a76080d
--- /dev/null
@@ -0,0 +1,4 @@
+log stdout
+interface r11-eth0
+ ipv6 address 192:2::11/64
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r12/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r12/bgpd.conf
new file mode 100644 (file)
index 0000000..d41fb18
--- /dev/null
@@ -0,0 +1,13 @@
+router bgp 65500
+ bgp router-id 12.12.12.12
+ no bgp network import-check
+ neighbor 192:2::100 remote-as 65500
+ address-family ipv4 unicast
+  no neighbor 192:2::100 activate
+ !
+ address-family ipv6 unicast
+  neighbor 192:2::100 activate
+  network 172:31::12/128
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r12/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r12/zebra.conf
new file mode 100644 (file)
index 0000000..df9cae4
--- /dev/null
@@ -0,0 +1,4 @@
+log stdout
+interface r12-eth0
+ ipv6 address 192:2::12/64
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r13/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r13/bgpd.conf
new file mode 100644 (file)
index 0000000..201b905
--- /dev/null
@@ -0,0 +1,16 @@
+router bgp 65500
+ bgp router-id 13.13.13.13
+ no bgp network import-check
+ neighbor 192:168::255:1 remote-as 65500
+ address-family ipv4 unicast
+  no neighbor 192:168::255:1 activate
+ exit-address-family
+ address-family ipv6 unicast
+  neighbor 192:168::255:1 activate
+  neighbor 192:168::255:1 route-map rmap out
+  network 172:31::0:13/128
+ exit-address-family
+!
+route-map rmap permit 1
+ set community 10:10
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r13/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r13/zebra.conf
new file mode 100644 (file)
index 0000000..dfe5994
--- /dev/null
@@ -0,0 +1,4 @@
+log stdout
+interface r13-eth0
+ ipv6 address 192:168::255:13/112
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgp_vpnv6_routes.json b/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgp_vpnv6_routes.json
new file mode 100644 (file)
index 0000000..bb7d5c0
--- /dev/null
@@ -0,0 +1,187 @@
+{
+    "vrfName": "default",
+    "localAS": 65501,
+    "routes":
+    {
+        "routeDistinguishers":
+        {
+            "444:1":
+            {
+                "172:31::11/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::11",
+                        "prefixLen": 128,
+                        "network": "172:31::11/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::12/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::12",
+                        "prefixLen": 128,
+                        "network": "172:31::12/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::13/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::13",
+                        "prefixLen": 128,
+                        "network": "172:31::13/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::14/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::14",
+                        "prefixLen": 128,
+                        "network": "172:31::14/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::15/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::15",
+                        "prefixLen": 128,
+                        "network": "172:31::15/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::20/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::20",
+                        "prefixLen": 128,
+                        "network": "172:31::20/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "172:31::111/128": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "172:31::111",
+                        "prefixLen": 128,
+                        "network": "172:31::111/128",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "192:2::/64": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "192:2::",
+                        "prefixLen": 64,
+                        "network": "192:2::/64",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ],
+                "192:168::255:0/112": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "192:168::255:0",
+                        "prefixLen": 112,
+                        "network": "192:168::255:0/112",
+                        "peerId": "192:168::1",
+                        "nexthops": [
+                            {
+                                "ip": "192:168::1",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ]
+            },
+            "444:2":
+            {
+                "10:200::/64": [
+                    {
+                        "valid": true,
+                        "bestpath": true,
+                        "prefix": "10:200::",
+                        "prefixLen": 64,
+                        "network": "10:200::/64",
+                        "peerId": "(unspec)",
+                        "nhVrfName": "vrf1",
+                        "nexthops": [
+                            {
+                                "ip": "::",
+                                "afi": "ipv6",
+                                "used": true
+                            }
+                        ]
+                    }
+                ]
+            }
+        }
+    }
+}
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..30e9959
--- /dev/null
@@ -0,0 +1,25 @@
+router bgp 65501
+ bgp router-id 192.168.0.2
+ no bgp ebgp-requires-policy
+ neighbor 192:168::1 remote-as 65500
+ address-family ipv4 unicast
+  no neighbor 192:168::1 activate
+ exit-address-family
+ address-family ipv6 vpn
+  neighbor 192:168::1 activate
+ exit-address-family
+!
+router bgp 65501 vrf vrf1
+ bgp router-id 192.168.0.2
+ address-family ipv6 unicast
+  redistribute connected
+  label vpn export 102
+  rd vpn export 444:2
+  rt vpn both 52:100
+  export vpn
+  import vpn
+ exit-address-family
+!
+interface r2-eth0
+ mpls bgp forwarding
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/r2/zebra.conf
new file mode 100644 (file)
index 0000000..47cee95
--- /dev/null
@@ -0,0 +1,7 @@
+log stdout
+interface r2-eth1 vrf vrf1
+ ipv6 address 10:200::2/64
+!
+interface r2-eth0
+ ipv6 address 192:168::2/112
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/rr/bgpd.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/rr/bgpd.conf
new file mode 100644 (file)
index 0000000..8c7664b
--- /dev/null
@@ -0,0 +1,24 @@
+router bgp 65500
+ bgp router-id 100.100.100.100
+ no bgp network import-check
+ neighbor 192:2::1 remote-as 65500
+ neighbor 192:2::11 remote-as 65500
+ neighbor 192:2::12 remote-as 65500
+ address-family ipv4 unicast
+  no neighbor 192:2::1 activate
+  no neighbor 192:2::11 activate
+  no neighbor 192:2::12 activate
+ !
+ address-family ipv6 unicast
+  neighbor 192:2::1 activate
+  neighbor 192:2::1 route-reflector-client
+  neighbor 192:2::1 nexthop-local unchanged
+  neighbor 192:2::11 activate
+  neighbor 192:2::11 route-reflector-client
+  neighbor 192:2::11 nexthop-local unchanged
+  neighbor 192:2::12 activate
+  neighbor 192:2::12 route-reflector-client
+  neighbor 192:2::12 nexthop-local unchanged
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/rr/zebra.conf b/tests/topotests/bgp_vpnv6_per_nexthop_label/rr/zebra.conf
new file mode 100644 (file)
index 0000000..94b82dc
--- /dev/null
@@ -0,0 +1,4 @@
+log stdout
+interface rr-eth0
+ ipv6 address 192:2::100/64
+!
diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py
new file mode 100644 (file)
index 0000000..bb71895
--- /dev/null
@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+#
+# test_bgp_vpnv6_per_nexthop_label.py
+#
+# Copyright 2023 6WIND S.A.
+#
+
+"""
+ test_bgp_vpnv6_per_nexthop_label.py: Test the FRR BGP daemon using EBGP peering
+ Let us exchange VPNv6 updates between both devices
+ Updates from r1 will originate from the same RD, but will have separate
+ label values.
+
+     +----------+
+     |   r11    |
+     |192::2:11 +---+
+     |          |   |                   +----+--------+              +----------+
+     +----------+   |         192::2::1 |vrf | r1     |192:168::/112 |    r2    |
+                    +-------------------+    |       1+--------------+          |
+     +----------+   |                   |VRF1|AS65500 |              | AS65501  |
+     |   r12    |   |    +--------------+    |   VPNV4|              |VPNV4     |
+     |192::2:12 +---+    |192:168::255:1+-+--+--------+              +----------+
+     |          |        |
+     +----------+        |
+                         |
+     +----------+        |
+     |   r13    |        |
+     |192:168:: +--------+
+     | 255:13   |
+     +----------+
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import functools
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+
+pytestmark = [pytest.mark.bgpd]
+
+PREFIXES_R11 = ["172:31::11/128", "172:31::20/128", "172:31::111/128"]
+PREFIXES_R12 = ["172:31::12/128"]
+PREFIXES_REDIST_R12 = ["172:31::15/128"]
+PREFIXES_R13 = ["172:31::13/128"]
+PREFIXES_REDIST_R14 = ["172:31::14/128"]
+PREFIXES_CONNECTED = ["192:168::255/112", "192:2::/64"]
+
+
+def build_topo(tgen):
+    "Build function"
+
+    # Create 2 routers.
+    tgen.add_router("r1")
+    tgen.add_router("r2")
+    tgen.add_router("r11")
+    tgen.add_router("r12")
+    tgen.add_router("r13")
+    tgen.add_router("r14")
+    tgen.add_router("rr")
+
+    switch = tgen.add_switch("s1")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r2"])
+
+    switch = tgen.add_switch("s2")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r11"])
+    switch.add_link(tgen.gears["r12"])
+    switch.add_link(tgen.gears["rr"])
+
+    switch = tgen.add_switch("s3")
+    switch.add_link(tgen.gears["r2"])
+
+    switch = tgen.add_switch("s4")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r13"])
+
+    switch = tgen.add_switch("s5")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r14"])
+
+
+def _populate_iface():
+    tgen = get_topogen()
+    cmds_list = [
+        "ip link add vrf1 type vrf table 10",
+        "echo 100000 > /proc/sys/net/mpls/platform_labels",
+        "ip link set dev vrf1 up",
+        "ip link set dev {0}-eth1 master vrf1",
+        "echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input",
+    ]
+    cmds_list_plus = [
+        "ip link set dev {0}-eth2 master vrf1",
+    ]
+
+    for cmd in cmds_list:
+        input = cmd.format("r1")
+        logger.info("input: " + cmd)
+        output = tgen.net["r1"].cmd(cmd.format("r1"))
+        logger.info("output: " + output)
+
+    for cmd in cmds_list_plus:
+        input = cmd.format("r1")
+        logger.info("input: " + cmd)
+        output = tgen.net["r1"].cmd(cmd.format("r1"))
+        logger.info("output: " + output)
+
+    for cmd in cmds_list:
+        input = cmd.format("r2")
+        logger.info("input: " + cmd)
+        output = tgen.net["r2"].cmd(cmd.format("r2"))
+        logger.info("output: " + output)
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(build_topo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+    _populate_iface()
+
+    for rname, router in router_list.items():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+        )
+
+    # Initialize all routers.
+    tgen.start_router()
+
+
+def teardown_module(_mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    tgen.stop_topology()
+
+
+def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None):
+    """
+    Dump and check that vpnv6 entries have the same MPLS label value
+    * 'router': the router to check
+    * 'group': the list of prefixes to check. a single label value for the group has to be found
+    * 'label_list': check that the label values are not present in the vpnv6 entries
+    *              that list is updated with the present label value
+    * 'label_value_expected': check that the mpls label read is the same as that value
+    """
+
+    stored_label_inited = False
+    for prefix in group:
+        dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True)
+        for rd, pathes in dump.items():
+            for path in pathes["paths"]:
+                assert (
+                    "remoteLabel" in path.keys()
+                ), "{0}, {1}, remoteLabel not present".format(router.name, prefix)
+                logger.info(
+                    "{0}, {1}, label value is {2}".format(
+                        router.name, prefix, path["remoteLabel"]
+                    )
+                )
+                if stored_label_inited:
+                    assert (
+                        path["remoteLabel"] == stored_label
+                    ), "{0}, {1}, label value not expected one (expected {2}, observed {3}".format(
+                        router.name, prefix, stored_label, path["remoteLabel"]
+                    )
+                else:
+                    stored_label = path["remoteLabel"]
+                    stored_label_inited = True
+                    if label_list is not None:
+                        assert (
+                            stored_label not in label_list
+                        ), "{0}, {1}, label already detected in a previous prefix".format(
+                            router.name, prefix
+                        )
+                        label_list.add(stored_label)
+
+                if label_value_expected:
+                    assert (
+                        path["remoteLabel"] == label_value_expected
+                    ), "{0}, {1}, label value not expected (expected {2}, observed {3}".format(
+                        router.name, prefix, label_value_expected, path["remoteLabel"]
+                    )
+
+
+def bgp_vpnv6_table_check_all(router, label_list=None, same=False):
+    """
+    Dump and check that vpnv6 entries are correctly configured with specific label values
+    * 'router': the router to check
+    * 'label_list': check that the label values are not present in the vpnv6 entries
+    *              that list is updated with the present label value found.
+    * 'same': by default, set to False. Addresses groups are classified by addresses.
+    *         if set to True, all entries of all groups should have a unique label value
+    """
+    if same:
+        bgp_vpnv6_table_check(
+            router,
+            group=PREFIXES_R11
+            + PREFIXES_R12
+            + PREFIXES_REDIST_R12
+            + PREFIXES_R13
+            + PREFIXES_REDIST_R14
+            + PREFIXES_CONNECTED,
+            label_list=label_list,
+        )
+    else:
+        for group in (
+            PREFIXES_R11,
+            PREFIXES_R12,
+            PREFIXES_REDIST_R12,
+            PREFIXES_R13,
+            PREFIXES_REDIST_R14,
+            PREFIXES_CONNECTED,
+        ):
+            bgp_vpnv6_table_check(router, group=group, label_list=label_list)
+
+
+def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None):
+    """
+    Dump and check 'show mpls table json' output. An assert is triggered in case test fails
+    * 'router': the router to check
+    * 'blacklist': the list of nexthops (IP or interface) that should not be on output
+    * 'label_list': the list of labels that should be in inLabel value
+    * 'whitelist': the list of nexthops (IP or interface) that should be on output
+    """
+    nexthop_list = []
+    if blacklist:
+        nexthop_list.append(blacklist)
+    logger.info("Checking MPLS labels on {}".format(router.name))
+    dump = router.vtysh_cmd("show mpls table json", isjson=True)
+    for in_label, label_info in dump.items():
+        if label_list is not None:
+            label_list.add(in_label)
+        for nh in label_info["nexthops"]:
+            assert (
+                nh["installed"] == True and nh["type"] == "BGP"
+            ), "{}, show mpls table, nexthop is not installed".format(router.name)
+            if "nexthop" in nh.keys():
+                assert (
+                    nh["nexthop"] not in nexthop_list
+                ), "{}, show mpls table, duplicated or blacklisted nexthop address".format(
+                    router.name
+                )
+                nexthop_list.append(nh["nexthop"])
+            elif "interface" in nh.keys():
+                assert (
+                    nh["interface"] not in nexthop_list
+                ), "{}, show mpls table, duplicated or blacklisted nexthop interface".format(
+                    router.name
+                )
+                nexthop_list.append(nh["interface"])
+            else:
+                assert (
+                    0
+                ), "{}, show mpls table, entry with neither nexthop nor interface".format(
+                    router.name
+                )
+
+    if whitelist:
+        for entry in whitelist:
+            assert (
+                entry in nexthop_list
+            ), "{}, show mpls table, entry with nexthop {} not present in nexthop list".format(
+                router.name, entry
+            )
+
+
+def check_show_bgp_vpn_prefix_not_found(router, ipversion, prefix, rd, label=None):
+    output = json.loads(
+        router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix))
+    )
+    if label:
+        expected = {rd: {"prefix": prefix, "paths": [{"remoteLabel": label}]}}
+    else:
+        expected = {rd: {"prefix": prefix}}
+    ret = topotest.json_cmp(output, expected)
+    if ret is None:
+        return "not good"
+    return None
+
+
+def check_show_bgp_vpn_prefix_found(router, ipversion, prefix, rd):
+    output = json.loads(
+        router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix))
+    )
+    expected = {rd: {"prefix": prefix}}
+    return topotest.json_cmp(output, expected)
+
+
+def check_show_mpls_table_entry_label_found(router, inlabel, interface):
+    output = json.loads(router.vtysh_cmd("show mpls table {} json".format(inlabel)))
+    expected = {
+        "inLabel": inlabel,
+        "installed": True,
+        "nexthops": [{"interface": interface}],
+    }
+    return topotest.json_cmp(output, expected)
+
+
+def check_show_mpls_table_entry_label_not_found(router, inlabel):
+    output = json.loads(router.vtysh_cmd("show mpls table {} json".format(inlabel)))
+    expected = {"inlabel": inlabel, "installed": True}
+    ret = topotest.json_cmp(output, expected)
+    if ret is None:
+        return "not good"
+    return None
+
+
+def mpls_entry_get_interface(router, label):
+    """
+    Assert that the label is in MPLS table
+    Assert an outgoing interface is programmed
+    return the outgoing interface
+    """
+    outgoing_interface = None
+
+    logger.info("Checking MPLS labels on {}".format(router.name))
+    dump = router.vtysh_cmd("show mpls table {} json".format(label), isjson=True)
+    assert dump, "{}, show mpls table, inLabel {} not found".format(router.name, label)
+
+    for nh in dump["nexthops"]:
+        assert (
+            "interface" in nh.keys()
+        ), "{}, show mpls table, nexthop interface not present for MPLS entry {}".format(
+            router.name, label
+        )
+
+        outgoing_interface = nh["interface"]
+
+    return outgoing_interface
+
+
+def test_protocols_convergence():
+    """
+    Assert that all protocols have converged
+    statuses as they depend on it.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Check BGP IPv6 routing tables on VRF1 of r1
+    logger.info("Checking BGP IPv6 routes for convergence on r1 VRF1")
+    router = tgen.gears["r1"]
+    json_file = "{}/{}/bgp_ipv6_routes_vrf1.json".format(CWD, router.name)
+
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp,
+        router,
+        "show bgp vrf vrf1 ipv6 json",
+        expected,
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches'.format(router.name)
+    assert result is None, assertmsg
+
+    logger.info("Checking BGP VPNv6 routes for convergence on r2")
+    router = tgen.gears["r2"]
+    json_file = "{}/{}/bgp_vpnv6_routes.json".format(CWD, router.name)
+    expected = json.loads(open(json_file).read())
+    test_func = partial(
+        topotest.router_json_cmp,
+        router,
+        "show bgp ipv6 vpn json",
+        expected,
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches'.format(router.name)
+    assert result is None, assertmsg
+
+    # Check BGP labels received on r2
+    logger.info("Checking BGP VPNv6 labels on r2")
+    label_list = set()
+    bgp_vpnv6_table_check_all(tgen.gears["r2"], label_list)
+
+    # Check MPLS labels received on r1
+    mpls_table_check(tgen.gears["r1"], label_list)
+
+
+def test_flapping_bgp_vrf_down():
+    """
+    Turn down a remote BGP session
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    logger.info("Unpeering BGP on r11")
+    tgen.gears["r11"].vtysh_cmd(
+        "configure terminal\nrouter bgp 65500\nno neighbor 192:2::100\n",
+        isjson=False,
+    )
+
+    def _bgp_prefix_not_found(router, vrf, ipversion, prefix):
+        output = json.loads(
+            router.vtysh_cmd(
+                "show bgp vrf {} {} {} json".format(vrf, ipversion, prefix)
+            )
+        )
+        expected = {"prefix": prefix}
+        ret = topotest.json_cmp(output, expected)
+        if ret is None:
+            return "not good"
+        return None
+
+    # Check prefix from r11 is not present
+    test_func = functools.partial(
+        _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv6", "172:31::11/128"
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert (
+        success
+    ), "r1, prefix 172:31::11/128 from r11 did not disappear. r11 still connected to rr ?"
+
+    # Check BGP updated received on r2 are not from r11
+    logger.info("Checking BGP VPNv6 labels on r2")
+    for entry in PREFIXES_R11:
+        dump = tgen.gears["r2"].vtysh_cmd(
+            "show bgp ipv6 vpn {} json".format(entry), isjson=True
+        )
+        for rd in dump:
+            assert False, "r2, {}, route distinguisher {} present".format(entry, rd)
+
+    mpls_table_check(tgen.gears["r1"], blacklist=["192:2::11"])
+
+
+def test_flapping_bgp_vrf_up():
+    """
+    Turn up a remote BGP session
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    logger.info("Peering BGP on r11")
+    tgen.gears["r11"].vtysh_cmd(
+        "configure terminal\nrouter bgp 65500\nneighbor 192:2::100 remote-as 65500\n",
+        isjson=False,
+    )
+    tgen.gears["r11"].vtysh_cmd(
+        "configure terminal\nrouter bgp 65500\naddress-family ipv6 unicast\nneighbor 192:2::100 activate\n",
+        isjson=False,
+    )
+
+    # Check r2 gets prefix 172:31::11/128
+    test_func = functools.partial(
+        check_show_bgp_vpn_prefix_found,
+        tgen.gears["r2"],
+        "ipv6",
+        "172:31::11/128",
+        "444:1",
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert (
+        success
+    ), "r2, prefix 172:31::11/128 from r11 not present. r11 still disconnected from rr ?"
+    bgp_vpnv6_table_check_all(tgen.gears["r2"])
+
+
+def test_recursive_route():
+    """
+    Test static recursive route redistributed over BGP
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Enabling recursive static route")
+    tgen.gears["r1"].vtysh_cmd(
+        "configure terminal\nvrf vrf1\nipv6 route 172:31::30/128 172:31::20\n",
+        isjson=False,
+    )
+    logger.info("Checking BGP VPNv6 labels on r2")
+    # that route should be sent along with label for 192.0.2.11
+
+    def _prefix30_not_found(router):
+        output = json.loads(router.vtysh_cmd("show bgp ipv6 vpn 172:31::30/128 json"))
+        expected = {"444:1": {"prefix": "172:31::30/128"}}
+        ret = topotest.json_cmp(output, expected)
+        if ret is None:
+            return "not good"
+        return None
+
+    def _prefix30_found(router):
+        output = json.loads(router.vtysh_cmd("show bgp ipv6 vpn 172:31::30/128 json"))
+        expected = {"444:1": {"prefix": "172:31::30/128"}}
+        return topotest.json_cmp(output, expected)
+
+    # Check r2 received vpnv6 update with 172:31::30
+    test_func = functools.partial(_prefix30_found, tgen.gears["r2"])
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r2, VPNv6 update 172:31::30 not found"
+
+    # that route should be sent along with label for 192::2:11
+    bgp_vpnv6_table_check(
+        tgen.gears["r2"],
+        group=PREFIXES_R11 + ["172:31::30/128"],
+    )
+
+    # diagnostic
+    logger.info("Dumping label nexthop table")
+    tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 label-nexthop detail", isjson=False)
+    logger.info("Dumping nexthop table")
+    tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 nexthop detail", isjson=False)
+
+    logger.info("Disabling recursive static route")
+    tgen.gears["r1"].vtysh_cmd(
+        "configure terminal\nvrf vrf1\nno ipv6 route 172:31::30/128 172:31::20\n",
+        isjson=False,
+    )
+
+    # Check r2 removed 172:31::30 vpnv6 update
+    test_func = functools.partial(_prefix30_not_found, tgen.gears["r2"])
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r2, VPNv6 update 172:31::30 still present"
+
+
+def test_prefix_changes_interface():
+    """
+    Test BGP update for a given prefix learnt on different interface
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Enabling a 172:31::50/128 prefix for r11")
+    tgen.gears["r11"].vtysh_cmd(
+        "configure terminal\nrouter bgp\naddress-family ipv6 unicast\nnetwork 172:31::50/128",
+        isjson=False,
+    )
+
+    # Check r2 received vpnv6 update with 172:31::50
+    test_func = functools.partial(
+        check_show_bgp_vpn_prefix_found,
+        tgen.gears["r2"],
+        "ipv6",
+        "172:31::50/128",
+        "444:1",
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r2, VPNv6 update 172:31::50 not found"
+
+    # diagnostic
+    logger.info("Dumping label nexthop table")
+    tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 label-nexthop detail", isjson=False)
+
+    label_list = set()
+    bgp_vpnv6_table_check(
+        tgen.gears["r2"],
+        group=PREFIXES_R11 + ["172:31::50/128"],
+        label_list=label_list,
+    )
+
+    assert (
+        len(label_list) == 1
+    ), "Multiple Label values found for updates from r11 found"
+
+    oldlabel = label_list.pop()
+    logger.info("r1, getting the outgoing interface used by label {}".format(oldlabel))
+    old_outgoing_interface = mpls_entry_get_interface(tgen.gears["r1"], oldlabel)
+    logger.info(
+        "r1, outgoing interface used by label {} is {}".format(
+            oldlabel, old_outgoing_interface
+        )
+    )
+
+    logger.info("Moving the 172:31::50/128 prefix from r11 to r13")
+    tgen.gears["r11"].vtysh_cmd(
+        "configure terminal\nrouter bgp\naddress-family ipv6 unicast\nno network 172:31::50/128",
+        isjson=False,
+    )
+    tgen.gears["r13"].vtysh_cmd(
+        "configure terminal\nrouter bgp\naddress-family ipv6 unicast\nnetwork 172:31::50/128",
+        isjson=False,
+    )
+
+    # Check r2 removed 172:31::50 vpnv6 update with old label
+    test_func = functools.partial(
+        check_show_bgp_vpn_prefix_not_found,
+        tgen.gears["r2"],
+        "ipv6",
+        "172:31::50/128",
+        "444:1",
+        label=oldlabel,
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert (
+        success
+    ), "r2, vpnv6 update 172:31::50 with old label {0} still present".format(oldlabel)
+
+    # diagnostic
+    logger.info("Dumping label nexthop table")
+    tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 label-nexthop detail", isjson=False)
+
+    # Check r2 received new 172:31::50 vpnv6 update
+    test_func = functools.partial(
+        check_show_bgp_vpn_prefix_found,
+        tgen.gears["r2"],
+        "ipv6",
+        "172:31::50/128",
+        "444:1",
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r2, vpnv6 update 172:31::50 not found"
+
+    label_list = set()
+    bgp_vpnv6_table_check(
+        tgen.gears["r2"],
+        group=["172:31::13/128", "172:31::50/128"],
+        label_list=label_list,
+    )
+    assert (
+        len(label_list) == 1
+    ), "Multiple Label values found for updates from r13 found"
+
+    newlabel = label_list.pop()
+    logger.info("r1, getting the outgoing interface used by label {}".format(newlabel))
+    new_outgoing_interface = mpls_entry_get_interface(tgen.gears["r1"], newlabel)
+    logger.info(
+        "r1, outgoing interface used by label {} is {}".format(
+            newlabel, new_outgoing_interface
+        )
+    )
+    if old_outgoing_interface == new_outgoing_interface:
+        assert 0, "r1, outgoing interface did not change whereas BGP update moved"
+
+    logger.info("Restoring state by removing the 172:31::50/128 prefix from r13")
+    tgen.gears["r13"].vtysh_cmd(
+        "configure terminal\nrouter bgp\naddress-family ipv6 unicast\nno network 172:31::50/128",
+        isjson=False,
+    )
+
+
+def test_changing_default_label_value():
+    """
+    Change the MPLS default value
+    Check that r1 VPNv6 entries have the 222 label value
+    Check that MPLS entry with old label value is no more present
+    Check that MPLS entry for local traffic has inLabel set to 222
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    router = tgen.gears["r1"]
+
+    # counting the number of labels used in the VPNv6 table
+    label_list = set()
+    logger.info("r1, VPNv6 table, check the number of labels used before modification")
+    bgp_vpnv6_table_check_all(router, label_list)
+    old_len = len(label_list)
+    assert (
+        old_len != 1
+    ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len)
+
+    logger.info("r1, vrf1, changing the default MPLS label value to export to 222")
+    router.vtysh_cmd(
+        "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export 222\n",
+        isjson=False,
+    )
+
+    # Check r1 updated the MPLS entry with the 222 label value
+    logger.info(
+        "r1, mpls table, check that MPLS entry with inLabel set to 222 has vrf1 interface"
+    )
+    test_func = functools.partial(
+        check_show_mpls_table_entry_label_found, router, 222, "vrf1"
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r1, mpls entry with label 222 not found"
+
+    # check label repartition is ok
+    logger.info("r1, VPNv6 table, check the number of labels used after modification")
+    label_list = set()
+    bgp_vpnv6_table_check_all(router, label_list)
+    new_len = len(label_list)
+    assert (
+        old_len == new_len
+    ), "r1, number of labels after modification differ from previous, observed {}, expected {} ".format(
+        new_len, old_len
+    )
+
+    logger.info(
+        "r1, VPNv6 table, check that prefixes that were using the vrf label have refreshed the label value to 222"
+    )
+    bgp_vpnv6_table_check(router, group=PREFIXES_CONNECTED, label_value_expected=222)
+
+
+def test_unconfigure_allocation_mode_nexthop():
+    """
+    Test unconfiguring allocation mode per nexthop
+    Check on r2 that new MPLS label values have been propagated
+    Check that show mpls table has no entry with label 17 (previously used)
+    Check that all VPN updates on r1 should have label value moved to 222
+    Check that show mpls table will only have 222 label value
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Unconfiguring allocation mode per nexthop")
+    router = tgen.gears["r1"]
+    dump = router.vtysh_cmd(
+        "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nno label vpn export allocation-mode per-nexthop\n",
+        isjson=False,
+    )
+
+    # Check r1 updated the MPLS entry with the 222 label value
+    logger.info(
+        "r1, mpls table, check that MPLS entry with inLabel set to 17 is not present"
+    )
+    test_func = functools.partial(
+        check_show_mpls_table_entry_label_not_found, router, 17
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r1, mpls entry with label 17 still present"
+
+    # Check vpnv6 routes from r1
+    logger.info("Checking VPNv6 routes on r1")
+    label_list = set()
+    bgp_vpnv6_table_check_all(router, label_list=label_list, same=True)
+    assert len(label_list) == 1, "r1, multiple Label values found for VPNv6 updates"
+
+    new_label = label_list.pop()
+    assert (
+        new_label == 222
+    ), "r1, wrong label value in VPNv6 table, expected 222, observed {}".format(
+        new_label
+    )
+
+    # Check mpls table with 222 value
+    logger.info("Checking MPLS values on show mpls table of r1")
+    label_list = set()
+    label_list.add(222)
+    mpls_table_check(router, label_list=label_list)
+
+
+def test_reconfigure_allocation_mode_nexthop():
+    """
+    Test re-configuring allocation mode per nexthop
+    Check that show mpls table has no entry with label 17
+    Check that all VPN updates on r1 should have multiple label values and not only 222
+    Check that show mpls table will have multiple label values and not only 222
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Reconfiguring allocation mode per nexthop")
+    router = tgen.gears["r1"]
+    dump = router.vtysh_cmd(
+        "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export allocation-mode per-nexthop\n",
+        isjson=False,
+    )
+
+    # Check that show mpls table has no entry with label 17
+    logger.info(
+        "r1, mpls table, check that MPLS entry with inLabel set to 17 is present"
+    )
+    test_func = functools.partial(
+        check_show_mpls_table_entry_label_not_found, router, 17
+    )
+    success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+    assert success, "r1, mpls entry with label 17 still present"
+
+    # Check vpnv6 routes from r1
+    logger.info("Checking VPNv6 routes on r1")
+    label_list = set()
+    bgp_vpnv6_table_check_all(router, label_list=label_list)
+    assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates"
+
+    # Check mpls table with all values
+    logger.info("Checking MPLS values on show mpls table of r1")
+    mpls_table_check(router, label_list=label_list)
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))