ipsec: Use the new tunnel API types to add flow label and TTL copy
[vpp.git] / test / test_ipsec_tun_if_esp.py
index f505fa0..2ef1351 100644 (file)
@@ -7,14 +7,15 @@ from scapy.layers.l2 import Ether, GRE, Dot1Q
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP
 from scapy.layers.inet6 import IPv6
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP
 from scapy.layers.inet6 import IPv6
+from scapy.contrib.mpls import MPLS
 from framework import VppTestRunner
 from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
     IpsecTun4, IpsecTun6,  IpsecTcpTests, mk_scapy_crypt_key, \
     IpsecTun6HandoffTests, IpsecTun4HandoffTests, config_tun_params
 from framework import VppTestRunner
 from template_ipsec import TemplateIpsec, IpsecTun4Tests, IpsecTun6Tests, \
     IpsecTun4, IpsecTun6,  IpsecTcpTests, mk_scapy_crypt_key, \
     IpsecTun6HandoffTests, IpsecTun4HandoffTests, config_tun_params
-from vpp_ipsec_tun_interface import VppIpsecTunInterface
 from vpp_gre_interface import VppGreInterface
 from vpp_ipip_tun_interface import VppIpIpTunInterface
 from vpp_gre_interface import VppGreInterface
 from vpp_ipip_tun_interface import VppIpIpTunInterface
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppMplsLabel, \
+    VppMplsTable, VppMplsRoute, FibPathProto
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort
 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
@@ -82,7 +83,96 @@ def config_tra_params(p, encryption_type, tun_if):
         nat_t_header=p.nat_header)
 
 
         nat_t_header=p.nat_header)
 
 
-class TemplateIpsec4TunIfEsp(TemplateIpsec):
+class TemplateIpsec4TunProtect(object):
+    """ IPsec IPv4 Tunnel protect """
+
+    encryption_type = ESP
+    tun4_encrypt_node_name = "esp4-encrypt-tun"
+    tun4_decrypt_node_name = "esp4-decrypt-tun"
+    tun4_input_node = "ipsec4-tun-input"
+
+    def config_sa_tra(self, p):
+        config_tun_params(p, self.encryption_type, p.tun_if)
+
+        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                  p.auth_algo_vpp_id, p.auth_key,
+                                  p.crypt_algo_vpp_id, p.crypt_key,
+                                  self.vpp_esp_protocol,
+                                  flags=p.flags)
+        p.tun_sa_out.add_vpp_config()
+
+        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id, p.auth_key,
+                                 p.crypt_algo_vpp_id, p.crypt_key,
+                                 self.vpp_esp_protocol,
+                                 flags=p.flags)
+        p.tun_sa_in.add_vpp_config()
+
+    def config_sa_tun(self, p):
+        config_tun_params(p, self.encryption_type, p.tun_if)
+
+        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                  p.auth_algo_vpp_id, p.auth_key,
+                                  p.crypt_algo_vpp_id, p.crypt_key,
+                                  self.vpp_esp_protocol,
+                                  self.tun_if.local_addr[p.addr_type],
+                                  self.tun_if.remote_addr[p.addr_type],
+                                  flags=p.flags)
+        p.tun_sa_out.add_vpp_config()
+
+        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id, p.auth_key,
+                                 p.crypt_algo_vpp_id, p.crypt_key,
+                                 self.vpp_esp_protocol,
+                                 self.tun_if.remote_addr[p.addr_type],
+                                 self.tun_if.local_addr[p.addr_type],
+                                 flags=p.flags)
+        p.tun_sa_in.add_vpp_config()
+
+    def config_protect(self, p):
+        p.tun_protect = VppIpsecTunProtect(self,
+                                           p.tun_if,
+                                           p.tun_sa_out,
+                                           [p.tun_sa_in])
+        p.tun_protect.add_vpp_config()
+
+    def config_network(self, p):
+        if hasattr(p, 'tun_dst'):
+            tun_dst = p.tun_dst
+        else:
+            tun_dst = self.pg0.remote_ip4
+        p.tun_if = VppIpIpTunInterface(self, self.pg0,
+                                       self.pg0.local_ip4,
+                                       tun_dst)
+        p.tun_if.add_vpp_config()
+        p.tun_if.admin_up()
+        p.tun_if.config_ip4()
+        p.tun_if.config_ip6()
+
+        p.route = VppIpRoute(self, p.remote_tun_if_host, 32,
+                             [VppRoutePath(p.tun_if.remote_ip4,
+                                           0xffffffff)])
+        p.route.add_vpp_config()
+        r = VppIpRoute(self, p.remote_tun_if_host6, 128,
+                       [VppRoutePath(p.tun_if.remote_ip6,
+                                     0xffffffff,
+                                     proto=DpoProto.DPO_PROTO_IP6)])
+        r.add_vpp_config()
+
+    def unconfig_network(self, p):
+        p.route.remove_vpp_config()
+        p.tun_if.remove_vpp_config()
+
+    def unconfig_protect(self, p):
+        p.tun_protect.remove_vpp_config()
+
+    def unconfig_sa(self, p):
+        p.tun_sa_out.remove_vpp_config()
+        p.tun_sa_in.remove_vpp_config()
+
+
+class TemplateIpsec4TunIfEsp(TemplateIpsec4TunProtect,
+                             TemplateIpsec):
     """ IPsec tunnel interface tests """
 
     encryption_type = ESP
     """ IPsec tunnel interface tests """
 
     encryption_type = ESP
@@ -102,32 +192,16 @@ class TemplateIpsec4TunIfEsp(TemplateIpsec):
 
         p = self.ipv4_params
 
 
         p = self.ipv4_params
 
-        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                        p.scapy_tun_spi, p.crypt_algo_vpp_id,
-                                        p.crypt_key, p.crypt_key,
-                                        p.auth_algo_vpp_id, p.auth_key,
-                                        p.auth_key)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip4()
-        p.tun_if.config_ip6()
-        config_tun_params(p, self.encryption_type, p.tun_if)
-
-        r = VppIpRoute(self, p.remote_tun_if_host, 32,
-                       [VppRoutePath(p.tun_if.remote_ip4,
-                                     0xffffffff)])
-        r.add_vpp_config()
-        r = VppIpRoute(self, p.remote_tun_if_host6, 128,
-                       [VppRoutePath(p.tun_if.remote_ip6,
-                                     0xffffffff,
-                                     proto=DpoProto.DPO_PROTO_IP6)])
-        r.add_vpp_config()
+        self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
 
     def tearDown(self):
         super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
 
     def tearDown(self):
         super(TemplateIpsec4TunIfEsp, self).tearDown()
 
 
-class TemplateIpsec4TunIfEspUdp(TemplateIpsec):
+class TemplateIpsec4TunIfEspUdp(TemplateIpsec4TunProtect,
+                                TemplateIpsec):
     """ IPsec UDP tunnel interface tests """
 
     tun4_encrypt_node_name = "esp4-encrypt-tun"
     """ IPsec UDP tunnel interface tests """
 
     tun4_encrypt_node_name = "esp4-encrypt-tun"
@@ -148,7 +222,7 @@ class TemplateIpsec4TunIfEspUdp(TemplateIpsec):
                 # ensure the UDP ports are correct before we decrypt
                 # which strips them
                 self.assertTrue(rx.haslayer(UDP))
                 # ensure the UDP ports are correct before we decrypt
                 # which strips them
                 self.assertTrue(rx.haslayer(UDP))
-                self.assert_equal(rx[UDP].sport, 4500)
+                self.assert_equal(rx[UDP].sport, p.nat_header.sport)
                 self.assert_equal(rx[UDP].dport, 4500)
 
                 pkt = sa.decrypt(rx[IP])
                 self.assert_equal(rx[UDP].dport, 4500)
 
                 pkt = sa.decrypt(rx[IP])
@@ -166,6 +240,27 @@ class TemplateIpsec4TunIfEspUdp(TemplateIpsec):
                     pass
                 raise
 
                     pass
                 raise
 
+    def config_sa_tra(self, p):
+        config_tun_params(p, self.encryption_type, p.tun_if)
+
+        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                  p.auth_algo_vpp_id, p.auth_key,
+                                  p.crypt_algo_vpp_id, p.crypt_key,
+                                  self.vpp_esp_protocol,
+                                  flags=p.flags,
+                                  udp_src=p.nat_header.sport,
+                                  udp_dst=p.nat_header.dport)
+        p.tun_sa_out.add_vpp_config()
+
+        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id, p.auth_key,
+                                 p.crypt_algo_vpp_id, p.crypt_key,
+                                 self.vpp_esp_protocol,
+                                 flags=p.flags,
+                                 udp_src=p.nat_header.sport,
+                                 udp_dst=p.nat_header.dport)
+        p.tun_sa_in.add_vpp_config()
+
     def setUp(self):
         super(TemplateIpsec4TunIfEspUdp, self).setUp()
 
     def setUp(self):
         super(TemplateIpsec4TunIfEspUdp, self).setUp()
 
@@ -174,30 +269,11 @@ class TemplateIpsec4TunIfEspUdp(TemplateIpsec):
                    IPSEC_API_SAD_FLAG_UDP_ENCAP)
         p.nat_header = UDP(sport=5454, dport=4500)
 
                    IPSEC_API_SAD_FLAG_UDP_ENCAP)
         p.nat_header = UDP(sport=5454, dport=4500)
 
-    def config_network(self):
-
         self.tun_if = self.pg0
         self.tun_if = self.pg0
-        p = self.ipv4_params
-        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                        p.scapy_tun_spi, p.crypt_algo_vpp_id,
-                                        p.crypt_key, p.crypt_key,
-                                        p.auth_algo_vpp_id, p.auth_key,
-                                        p.auth_key, udp_encap=True)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip4()
-        p.tun_if.config_ip6()
-        config_tun_params(p, self.encryption_type, p.tun_if)
 
 
-        r = VppIpRoute(self, p.remote_tun_if_host, 32,
-                       [VppRoutePath(p.tun_if.remote_ip4,
-                                     0xffffffff)])
-        r.add_vpp_config()
-        r = VppIpRoute(self, p.remote_tun_if_host6, 128,
-                       [VppRoutePath(p.tun_if.remote_ip6,
-                                     0xffffffff,
-                                     proto=DpoProto.DPO_PROTO_IP6)])
-        r.add_vpp_config()
+        self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
 
     def tearDown(self):
         super(TemplateIpsec4TunIfEspUdp, self).tearDown()
 
     def tearDown(self):
         super(TemplateIpsec4TunIfEspUdp, self).tearDown()
@@ -240,8 +316,7 @@ class TestIpsec4TunIfEspUdp(TemplateIpsec4TunIfEspUdp, IpsecTun4Tests):
     tun4_input_node = "ipsec4-tun-input"
 
     def setUp(self):
     tun4_input_node = "ipsec4-tun-input"
 
     def setUp(self):
-        super(TemplateIpsec4TunIfEspUdp, self).setUp()
-        self.config_network()
+        super(TestIpsec4TunIfEspUdp, self).setUp()
 
     def test_keepalive(self):
         """ IPSEC NAT Keepalive """
 
     def test_keepalive(self):
         """ IPSEC NAT Keepalive """
@@ -254,7 +329,7 @@ class TestIpsec4TunIfEspUdpGCM(TemplateIpsec4TunIfEspUdp, IpsecTun4Tests):
     tun4_input_node = "ipsec4-tun-input"
 
     def setUp(self):
     tun4_input_node = "ipsec4-tun-input"
 
     def setUp(self):
-        super(TemplateIpsec4TunIfEspUdp, self).setUp()
+        super(TestIpsec4TunIfEspUdpGCM, self).setUp()
         p = self.ipv4_params
         p.auth_algo_vpp_id = (VppEnum.vl_api_ipsec_integ_alg_t.
                               IPSEC_API_INTEG_ALG_NONE)
         p = self.ipv4_params
         p.auth_algo_vpp_id = (VppEnum.vl_api_ipsec_integ_alg_t.
                               IPSEC_API_INTEG_ALG_NONE)
@@ -264,7 +339,6 @@ class TestIpsec4TunIfEspUdpGCM(TemplateIpsec4TunIfEspUdp, IpsecTun4Tests):
         p.auth_algo = "NULL"
         p.crypt_key = b"JPjyOWBeVEQiMe7hJPjyOWBeVEQiMe7h"
         p.salt = 0
         p.auth_algo = "NULL"
         p.crypt_key = b"JPjyOWBeVEQiMe7hJPjyOWBeVEQiMe7h"
         p.salt = 0
-        self.config_network()
 
 
 class TestIpsec4TunIfEsp2(TemplateIpsec4TunIfEsp, IpsecTcpTests):
 
 
 class TestIpsec4TunIfEsp2(TemplateIpsec4TunIfEsp, IpsecTcpTests):
@@ -272,38 +346,101 @@ class TestIpsec4TunIfEsp2(TemplateIpsec4TunIfEsp, IpsecTcpTests):
     pass
 
 
     pass
 
 
-class TemplateIpsec6TunIfEsp(TemplateIpsec):
-    """ IPsec tunnel interface tests """
+class TemplateIpsec6TunProtect(object):
+    """ IPsec IPv6 Tunnel protect """
 
 
-    encryption_type = ESP
+    def config_sa_tra(self, p):
+        config_tun_params(p, self.encryption_type, p.tun_if)
 
 
-    def setUp(self):
-        super(TemplateIpsec6TunIfEsp, self).setUp()
+        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                  p.auth_algo_vpp_id, p.auth_key,
+                                  p.crypt_algo_vpp_id, p.crypt_key,
+                                  self.vpp_esp_protocol)
+        p.tun_sa_out.add_vpp_config()
 
 
-        self.tun_if = self.pg0
+        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id, p.auth_key,
+                                 p.crypt_algo_vpp_id, p.crypt_key,
+                                 self.vpp_esp_protocol)
+        p.tun_sa_in.add_vpp_config()
 
 
-        p = self.ipv6_params
-        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                        p.scapy_tun_spi, p.crypt_algo_vpp_id,
-                                        p.crypt_key, p.crypt_key,
-                                        p.auth_algo_vpp_id, p.auth_key,
-                                        p.auth_key, is_ip6=True)
+    def config_sa_tun(self, p):
+        config_tun_params(p, self.encryption_type, p.tun_if)
+
+        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                  p.auth_algo_vpp_id, p.auth_key,
+                                  p.crypt_algo_vpp_id, p.crypt_key,
+                                  self.vpp_esp_protocol,
+                                  self.tun_if.local_addr[p.addr_type],
+                                  self.tun_if.remote_addr[p.addr_type])
+        p.tun_sa_out.add_vpp_config()
+
+        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id, p.auth_key,
+                                 p.crypt_algo_vpp_id, p.crypt_key,
+                                 self.vpp_esp_protocol,
+                                 self.tun_if.remote_addr[p.addr_type],
+                                 self.tun_if.local_addr[p.addr_type])
+        p.tun_sa_in.add_vpp_config()
+
+    def config_protect(self, p):
+        p.tun_protect = VppIpsecTunProtect(self,
+                                           p.tun_if,
+                                           p.tun_sa_out,
+                                           [p.tun_sa_in])
+        p.tun_protect.add_vpp_config()
+
+    def config_network(self, p):
+        if hasattr(p, 'tun_dst'):
+            tun_dst = p.tun_dst
+        else:
+            tun_dst = self.pg0.remote_ip6
+        p.tun_if = VppIpIpTunInterface(self, self.pg0,
+                                       self.pg0.local_ip6,
+                                       tun_dst)
         p.tun_if.add_vpp_config()
         p.tun_if.admin_up()
         p.tun_if.config_ip6()
         p.tun_if.config_ip4()
         p.tun_if.add_vpp_config()
         p.tun_if.admin_up()
         p.tun_if.config_ip6()
         p.tun_if.config_ip4()
-        config_tun_params(p, self.encryption_type, p.tun_if)
 
 
-        r = VppIpRoute(self, p.remote_tun_if_host, 128,
-                       [VppRoutePath(p.tun_if.remote_ip6,
-                                     0xffffffff,
-                                     proto=DpoProto.DPO_PROTO_IP6)])
-        r.add_vpp_config()
+        p.route = VppIpRoute(self, p.remote_tun_if_host, 128,
+                             [VppRoutePath(p.tun_if.remote_ip6,
+                                           0xffffffff,
+                                           proto=DpoProto.DPO_PROTO_IP6)])
+        p.route.add_vpp_config()
         r = VppIpRoute(self, p.remote_tun_if_host4, 32,
                        [VppRoutePath(p.tun_if.remote_ip4,
                                      0xffffffff)])
         r.add_vpp_config()
 
         r = VppIpRoute(self, p.remote_tun_if_host4, 32,
                        [VppRoutePath(p.tun_if.remote_ip4,
                                      0xffffffff)])
         r.add_vpp_config()
 
+    def unconfig_network(self, p):
+        p.route.remove_vpp_config()
+        p.tun_if.remove_vpp_config()
+
+    def unconfig_protect(self, p):
+        p.tun_protect.remove_vpp_config()
+
+    def unconfig_sa(self, p):
+        p.tun_sa_out.remove_vpp_config()
+        p.tun_sa_in.remove_vpp_config()
+
+
+class TemplateIpsec6TunIfEsp(TemplateIpsec6TunProtect,
+                             TemplateIpsec):
+    """ IPsec tunnel interface tests """
+
+    encryption_type = ESP
+
+    def setUp(self):
+        super(TemplateIpsec6TunIfEsp, self).setUp()
+
+        self.tun_if = self.pg0
+
+        p = self.ipv6_params
+        self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
+
     def tearDown(self):
         super(TemplateIpsec6TunIfEsp, self).tearDown()
 
     def tearDown(self):
         super(TemplateIpsec6TunIfEsp, self).tearDown()
 
@@ -339,7 +476,9 @@ class TestIpsec4TunIfEspHandoff(TemplateIpsec4TunIfEsp,
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
 
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
 
-class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
+class TestIpsec4MultiTunIfEsp(TemplateIpsec4TunProtect,
+                              TemplateIpsec,
+                              IpsecTun4):
     """ IPsec IPv4 Multi Tunnel interface """
 
     encryption_type = ESP
     """ IPsec IPv4 Multi Tunnel interface """
 
     encryption_type = ESP
@@ -370,22 +509,10 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
             p.vpp_tra_spi = p.vpp_tra_spi + ii
             p.tun_dst = self.pg0.remote_hosts[ii].ip4
 
             p.vpp_tra_spi = p.vpp_tra_spi + ii
             p.tun_dst = self.pg0.remote_hosts[ii].ip4
 
-            p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                            p.scapy_tun_spi,
-                                            p.crypt_algo_vpp_id,
-                                            p.crypt_key, p.crypt_key,
-                                            p.auth_algo_vpp_id, p.auth_key,
-                                            p.auth_key,
-                                            dst=p.tun_dst)
-            p.tun_if.add_vpp_config()
-            p.tun_if.admin_up()
-            p.tun_if.config_ip4()
-            config_tun_params(p, self.encryption_type, p.tun_if)
             self.multi_params.append(p)
             self.multi_params.append(p)
-
-            VppIpRoute(self, p.remote_tun_if_host, 32,
-                       [VppRoutePath(p.tun_if.remote_ip4,
-                                     0xffffffff)]).add_vpp_config()
+            self.config_network(p)
+            self.config_sa_tra(p)
+            self.config_protect(p)
 
     def tearDown(self):
         super(TestIpsec4MultiTunIfEsp, self).tearDown()
 
     def tearDown(self):
         super(TestIpsec4MultiTunIfEsp, self).tearDown()
@@ -421,51 +548,38 @@ class TestIpsec4MultiTunIfEsp(TemplateIpsec, IpsecTun4):
             self.verify_encrypted(p, p.vpp_tun_sa, [rx])
 
 
             self.verify_encrypted(p, p.vpp_tun_sa, [rx])
 
 
-class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
+class TestIpsec4TunIfEspAll(TemplateIpsec4TunProtect,
+                            TemplateIpsec,
+                            IpsecTun4):
     """ IPsec IPv4 Tunnel interface all Algos """
 
     encryption_type = ESP
     tun4_encrypt_node_name = "esp4-encrypt-tun"
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
     """ IPsec IPv4 Tunnel interface all Algos """
 
     encryption_type = ESP
     tun4_encrypt_node_name = "esp4-encrypt-tun"
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
-    def config_network(self, p):
-
-        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                        p.scapy_tun_spi,
-                                        p.crypt_algo_vpp_id,
-                                        p.crypt_key, p.crypt_key,
-                                        p.auth_algo_vpp_id, p.auth_key,
-                                        p.auth_key,
-                                        salt=p.salt)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip4()
-        config_tun_params(p, self.encryption_type, p.tun_if)
-        self.logger.info(self.vapi.cli("sh ipsec sa 0"))
-        self.logger.info(self.vapi.cli("sh ipsec sa 1"))
-
-        p.route = VppIpRoute(self, p.remote_tun_if_host, 32,
-                             [VppRoutePath(p.tun_if.remote_ip4,
-                                           0xffffffff)])
-        p.route.add_vpp_config()
-
-    def unconfig_network(self, p):
-        p.tun_if.unconfig_ip4()
-        p.tun_if.remove_vpp_config()
-        p.route.remove_vpp_config()
-
     def setUp(self):
         super(TestIpsec4TunIfEspAll, self).setUp()
 
         self.tun_if = self.pg0
     def setUp(self):
         super(TestIpsec4TunIfEspAll, self).setUp()
 
         self.tun_if = self.pg0
+        p = self.ipv4_params
+
+        self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
 
     def tearDown(self):
 
     def tearDown(self):
+        p = self.ipv4_params
+        self.unconfig_protect(p)
+        self.unconfig_network(p)
+        self.unconfig_sa(p)
+
         super(TestIpsec4TunIfEspAll, self).tearDown()
 
     def rekey(self, p):
         #
         # change the key and the SPI
         #
         super(TestIpsec4TunIfEspAll, self).tearDown()
 
     def rekey(self, p):
         #
         # change the key and the SPI
         #
+        np = copy.copy(p)
         p.crypt_key = b'X' + p.crypt_key[1:]
         p.scapy_tun_spi += 1
         p.scapy_tun_sa_id += 1
         p.crypt_key = b'X' + p.crypt_key[1:]
         p.scapy_tun_spi += 1
         p.scapy_tun_sa_id += 1
@@ -476,19 +590,9 @@ class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
 
         config_tun_params(p, self.encryption_type, p.tun_if)
 
 
         config_tun_params(p, self.encryption_type, p.tun_if)
 
-        p.tun_sa_in = VppIpsecSA(self,
-                                 p.scapy_tun_sa_id,
-                                 p.scapy_tun_spi,
-                                 p.auth_algo_vpp_id,
-                                 p.auth_key,
-                                 p.crypt_algo_vpp_id,
-                                 p.crypt_key,
-                                 self.vpp_esp_protocol,
-                                 flags=p.flags,
-                                 salt=p.salt)
         p.tun_sa_out = VppIpsecSA(self,
         p.tun_sa_out = VppIpsecSA(self,
-                                  p.vpp_tun_sa_id,
-                                  p.vpp_tun_spi,
+                                  p.scapy_tun_sa_id,
+                                  p.scapy_tun_spi,
                                   p.auth_algo_vpp_id,
                                   p.auth_key,
                                   p.crypt_algo_vpp_id,
                                   p.auth_algo_vpp_id,
                                   p.auth_key,
                                   p.crypt_algo_vpp_id,
@@ -496,15 +600,22 @@ class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
                                   self.vpp_esp_protocol,
                                   flags=p.flags,
                                   salt=p.salt)
                                   self.vpp_esp_protocol,
                                   flags=p.flags,
                                   salt=p.salt)
+        p.tun_sa_in = VppIpsecSA(self,
+                                 p.vpp_tun_sa_id,
+                                 p.vpp_tun_spi,
+                                 p.auth_algo_vpp_id,
+                                 p.auth_key,
+                                 p.crypt_algo_vpp_id,
+                                 p.crypt_key,
+                                 self.vpp_esp_protocol,
+                                 flags=p.flags,
+                                 salt=p.salt)
         p.tun_sa_in.add_vpp_config()
         p.tun_sa_out.add_vpp_config()
 
         p.tun_sa_in.add_vpp_config()
         p.tun_sa_out.add_vpp_config()
 
-        self.vapi.ipsec_tunnel_if_set_sa(sw_if_index=p.tun_if.sw_if_index,
-                                         sa_id=p.tun_sa_in.id,
-                                         is_outbound=1)
-        self.vapi.ipsec_tunnel_if_set_sa(sw_if_index=p.tun_if.sw_if_index,
-                                         sa_id=p.tun_sa_out.id,
-                                         is_outbound=0)
+        self.config_protect(p)
+        np.tun_sa_out.remove_vpp_config()
+        np.tun_sa_in.remove_vpp_config()
         self.logger.info(self.vapi.cli("sh ipsec sa"))
 
     def test_tun_44(self):
         self.logger.info(self.vapi.cli("sh ipsec sa"))
 
     def test_tun_44(self):
@@ -580,7 +691,7 @@ class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
             for algo in algos:
                 # with self.subTest(algo=algo['scapy']):
 
             for algo in algos:
                 # with self.subTest(algo=algo['scapy']):
 
-                p = copy.copy(self.ipv4_params)
+                p = self.ipv4_params
                 p.auth_algo_vpp_id = algo['vpp-integ']
                 p.crypt_algo_vpp_id = algo['vpp-crypto']
                 p.crypt_algo = algo['scapy-crypto']
                 p.auth_algo_vpp_id = algo['vpp-integ']
                 p.crypt_algo_vpp_id = algo['vpp-crypto']
                 p.crypt_algo = algo['scapy-crypto']
@@ -588,34 +699,27 @@ class TestIpsec4TunIfEspAll(TemplateIpsec, IpsecTun4):
                 p.crypt_key = algo['key']
                 p.salt = algo['salt']
 
                 p.crypt_key = algo['key']
                 p.salt = algo['salt']
 
-                self.config_network(p)
-
-                self.verify_tun_44(p, count=127)
-                c = p.tun_if.get_rx_stats()
-                self.assertEqual(c['packets'], 127)
-                c = p.tun_if.get_tx_stats()
-                self.assertEqual(c['packets'], 127)
-
                 #
                 # rekey the tunnel
                 #
                 self.rekey(p)
                 self.verify_tun_44(p, count=127)
 
                 #
                 # rekey the tunnel
                 #
                 self.rekey(p)
                 self.verify_tun_44(p, count=127)
 
-                self.unconfig_network(p)
-                p.tun_sa_out.remove_vpp_config()
-                p.tun_sa_in.remove_vpp_config()
-
 
 
-class TestIpsec4TunIfEspNoAlgo(TemplateIpsec, IpsecTun4):
+class TestIpsec4TunIfEspNoAlgo(TemplateIpsec4TunProtect,
+                               TemplateIpsec,
+                               IpsecTun4):
     """ IPsec IPv4 Tunnel interface no Algos """
 
     encryption_type = ESP
     tun4_encrypt_node_name = "esp4-encrypt-tun"
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
     """ IPsec IPv4 Tunnel interface no Algos """
 
     encryption_type = ESP
     tun4_encrypt_node_name = "esp4-encrypt-tun"
     tun4_decrypt_node_name = "esp4-decrypt-tun"
 
-    def config_network(self, p):
+    def setUp(self):
+        super(TestIpsec4TunIfEspNoAlgo, self).setUp()
 
 
+        self.tun_if = self.pg0
+        p = self.ipv4_params
         p.auth_algo_vpp_id = (VppEnum.vl_api_ipsec_integ_alg_t.
                               IPSEC_API_INTEG_ALG_NONE)
         p.auth_algo = 'NULL'
         p.auth_algo_vpp_id = (VppEnum.vl_api_ipsec_integ_alg_t.
                               IPSEC_API_INTEG_ALG_NONE)
         p.auth_algo = 'NULL'
@@ -626,35 +730,6 @@ class TestIpsec4TunIfEspNoAlgo(TemplateIpsec, IpsecTun4):
         p.crypt_algo = 'NULL'
         p.crypt_key = []
 
         p.crypt_algo = 'NULL'
         p.crypt_key = []
 
-        p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                        p.scapy_tun_spi,
-                                        p.crypt_algo_vpp_id,
-                                        p.crypt_key, p.crypt_key,
-                                        p.auth_algo_vpp_id, p.auth_key,
-                                        p.auth_key,
-                                        salt=p.salt)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip4()
-        config_tun_params(p, self.encryption_type, p.tun_if)
-        self.logger.info(self.vapi.cli("sh ipsec sa 0"))
-        self.logger.info(self.vapi.cli("sh ipsec sa 1"))
-
-        p.route = VppIpRoute(self, p.remote_tun_if_host, 32,
-                             [VppRoutePath(p.tun_if.remote_ip4,
-                                           0xffffffff)])
-        p.route.add_vpp_config()
-
-    def unconfig_network(self, p):
-        p.tun_if.unconfig_ip4()
-        p.tun_if.remove_vpp_config()
-        p.route.remove_vpp_config()
-
-    def setUp(self):
-        super(TestIpsec4TunIfEspNoAlgo, self).setUp()
-
-        self.tun_if = self.pg0
-
     def tearDown(self):
         super(TestIpsec4TunIfEspNoAlgo, self).tearDown()
 
     def tearDown(self):
         super(TestIpsec4TunIfEspNoAlgo, self).tearDown()
 
@@ -663,15 +738,21 @@ class TestIpsec4TunIfEspNoAlgo(TemplateIpsec, IpsecTun4):
         p = self.ipv4_params
 
         self.config_network(p)
         p = self.ipv4_params
 
         self.config_network(p)
+        self.config_sa_tra(p)
+        self.config_protect(p)
 
         tx = self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
                            dst=p.remote_tun_if_host)
         self.send_and_assert_no_replies(self.pg1, tx)
 
 
         tx = self.gen_pkts(self.pg1, src=self.pg1.remote_ip4,
                            dst=p.remote_tun_if_host)
         self.send_and_assert_no_replies(self.pg1, tx)
 
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
-class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
+class TestIpsec6MultiTunIfEsp(TemplateIpsec6TunProtect,
+                              TemplateIpsec,
+                              IpsecTun6):
     """ IPsec IPv6 Multi Tunnel interface """
 
     encryption_type = ESP
     """ IPsec IPv6 Multi Tunnel interface """
 
     encryption_type = ESP
@@ -700,25 +781,12 @@ class TestIpsec6MultiTunIfEsp(TemplateIpsec, IpsecTun6):
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
+            p.tun_dst = self.pg0.remote_hosts[ii].ip6
 
 
-            p.tun_if = VppIpsecTunInterface(self, self.pg0, p.vpp_tun_spi,
-                                            p.scapy_tun_spi,
-                                            p.crypt_algo_vpp_id,
-                                            p.crypt_key, p.crypt_key,
-                                            p.auth_algo_vpp_id, p.auth_key,
-                                            p.auth_key, is_ip6=True,
-                                            dst=self.pg0.remote_hosts[ii].ip6)
-            p.tun_if.add_vpp_config()
-            p.tun_if.admin_up()
-            p.tun_if.config_ip6()
-            config_tun_params(p, self.encryption_type, p.tun_if)
             self.multi_params.append(p)
             self.multi_params.append(p)
-
-            r = VppIpRoute(self, p.remote_tun_if_host, 128,
-                           [VppRoutePath(p.tun_if.remote_ip6,
-                                         0xffffffff,
-                                         proto=DpoProto.DPO_PROTO_IP6)])
-            r.add_vpp_config()
+            self.config_network(p)
+            self.config_sa_tra(p)
+            self.config_protect(p)
 
     def tearDown(self):
         super(TestIpsec6MultiTunIfEsp, self).tearDown()
 
     def tearDown(self):
         super(TestIpsec6MultiTunIfEsp, self).tearDown()
@@ -1426,7 +1494,7 @@ class TestIpsecGre6IfEspTra(TemplateIpsec,
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
-    def gen_pkts6(self, sw_intf, src, dst, count=1,
+    def gen_pkts6(self, p, sw_intf, src, dst, count=1,
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src="1::1", dst="1::2") /
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src="1::1", dst="1::2") /
@@ -1656,7 +1724,7 @@ class TestIpsecMGreIfEspTra6(TemplateIpsec, IpsecTun6):
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
-    def gen_pkts6(self, sw_intf, src, dst, count=1,
+    def gen_pkts6(self, p, sw_intf, src, dst, count=1,
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src="1::1", dst=dst) /
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src="1::1", dst=dst) /
@@ -1721,138 +1789,54 @@ class TestIpsecMGreIfEspTra6(TemplateIpsec, IpsecTun6):
 
             p.scapy_tra_sa_id = p.scapy_tra_sa_id + ii
             p.scapy_tra_spi = p.scapy_tra_spi + ii
 
             p.scapy_tra_sa_id = p.scapy_tra_sa_id + ii
             p.scapy_tra_spi = p.scapy_tra_spi + ii
-            p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
-            p.vpp_tra_spi = p.vpp_tra_spi + ii
-            p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
-                                      p.auth_algo_vpp_id, p.auth_key,
-                                      p.crypt_algo_vpp_id, p.crypt_key,
-                                      self.vpp_esp_protocol)
-            p.tun_sa_out.add_vpp_config()
-
-            p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
-                                     p.auth_algo_vpp_id, p.auth_key,
-                                     p.crypt_algo_vpp_id, p.crypt_key,
-                                     self.vpp_esp_protocol)
-            p.tun_sa_in.add_vpp_config()
-
-            # in this v6 variant add the teibs first then the protection
-            p.tun_dst = self.pg0.remote_hosts[ii].ip6
-            VppTeib(self, p.tun_if,
-                    p.tun_if.remote_hosts[ii].ip6,
-                    p.tun_dst).add_vpp_config()
-
-            p.tun_protect = VppIpsecTunProtect(
-                self,
-                p.tun_if,
-                p.tun_sa_out,
-                [p.tun_sa_in],
-                nh=p.tun_if.remote_hosts[ii].ip6)
-            p.tun_protect.add_vpp_config()
-            config_tra_params(p, self.encryption_type, p.tun_if)
-            self.multi_params.append(p)
-
-            VppIpRoute(self, p.remote_tun_if_host, 128,
-                       [VppRoutePath(p.tun_if.remote_hosts[ii].ip6,
-                                     p.tun_if.sw_if_index)]).add_vpp_config()
-            p.tun_dst = self.pg0.remote_hosts[ii].ip6
-
-        self.logger.info(self.vapi.cli("sh log"))
-        self.logger.info(self.vapi.cli("sh ipsec protect-hash"))
-        self.logger.info(self.vapi.cli("sh adj 41"))
-
-    def tearDown(self):
-        p = self.ipv6_params
-        p.tun_if.unconfig_ip6()
-        super(TestIpsecMGreIfEspTra6, self).tearDown()
-
-    def test_tun_66(self):
-        """mGRE IPSec 66"""
-        for p in self.multi_params:
-            self.verify_tun_66(p, count=63)
-
-
-class TemplateIpsec4TunProtect(object):
-    """ IPsec IPv4 Tunnel protect """
-
-    encryption_type = ESP
-    tun4_encrypt_node_name = "esp4-encrypt-tun"
-    tun4_decrypt_node_name = "esp4-decrypt-tun"
-    tun4_input_node = "ipsec4-tun-input"
-
-    def config_sa_tra(self, p):
-        config_tun_params(p, self.encryption_type, p.tun_if)
-
-        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
-                                  p.auth_algo_vpp_id, p.auth_key,
-                                  p.crypt_algo_vpp_id, p.crypt_key,
-                                  self.vpp_esp_protocol,
-                                  flags=p.flags)
-        p.tun_sa_out.add_vpp_config()
-
-        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
-                                 p.auth_algo_vpp_id, p.auth_key,
-                                 p.crypt_algo_vpp_id, p.crypt_key,
-                                 self.vpp_esp_protocol,
-                                 flags=p.flags)
-        p.tun_sa_in.add_vpp_config()
-
-    def config_sa_tun(self, p):
-        config_tun_params(p, self.encryption_type, p.tun_if)
-
-        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
-                                  p.auth_algo_vpp_id, p.auth_key,
-                                  p.crypt_algo_vpp_id, p.crypt_key,
-                                  self.vpp_esp_protocol,
-                                  self.tun_if.local_addr[p.addr_type],
-                                  self.tun_if.remote_addr[p.addr_type],
-                                  flags=p.flags)
-        p.tun_sa_out.add_vpp_config()
+            p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
+            p.vpp_tra_spi = p.vpp_tra_spi + ii
+            p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
+                                      p.auth_algo_vpp_id, p.auth_key,
+                                      p.crypt_algo_vpp_id, p.crypt_key,
+                                      self.vpp_esp_protocol)
+            p.tun_sa_out.add_vpp_config()
 
 
-        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
-                                 p.auth_algo_vpp_id, p.auth_key,
-                                 p.crypt_algo_vpp_id, p.crypt_key,
-                                 self.vpp_esp_protocol,
-                                 self.tun_if.remote_addr[p.addr_type],
-                                 self.tun_if.local_addr[p.addr_type],
-                                 flags=p.flags)
-        p.tun_sa_in.add_vpp_config()
+            p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
+                                     p.auth_algo_vpp_id, p.auth_key,
+                                     p.crypt_algo_vpp_id, p.crypt_key,
+                                     self.vpp_esp_protocol)
+            p.tun_sa_in.add_vpp_config()
 
 
-    def config_protect(self, p):
-        p.tun_protect = VppIpsecTunProtect(self,
-                                           p.tun_if,
-                                           p.tun_sa_out,
-                                           [p.tun_sa_in])
-        p.tun_protect.add_vpp_config()
+            # in this v6 variant add the teibs first then the protection
+            p.tun_dst = self.pg0.remote_hosts[ii].ip6
+            VppTeib(self, p.tun_if,
+                    p.tun_if.remote_hosts[ii].ip6,
+                    p.tun_dst).add_vpp_config()
 
 
-    def config_network(self, p):
-        p.tun_if = VppIpIpTunInterface(self, self.pg0,
-                                       self.pg0.local_ip4,
-                                       self.pg0.remote_ip4)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip4()
-        p.tun_if.config_ip6()
+            p.tun_protect = VppIpsecTunProtect(
+                self,
+                p.tun_if,
+                p.tun_sa_out,
+                [p.tun_sa_in],
+                nh=p.tun_if.remote_hosts[ii].ip6)
+            p.tun_protect.add_vpp_config()
+            config_tra_params(p, self.encryption_type, p.tun_if)
+            self.multi_params.append(p)
 
 
-        p.route = VppIpRoute(self, p.remote_tun_if_host, 32,
-                             [VppRoutePath(p.tun_if.remote_ip4,
-                                           0xffffffff)])
-        p.route.add_vpp_config()
-        r = VppIpRoute(self, p.remote_tun_if_host6, 128,
-                       [VppRoutePath(p.tun_if.remote_ip6,
-                                     0xffffffff,
-                                     proto=DpoProto.DPO_PROTO_IP6)])
-        r.add_vpp_config()
+            VppIpRoute(self, p.remote_tun_if_host, 128,
+                       [VppRoutePath(p.tun_if.remote_hosts[ii].ip6,
+                                     p.tun_if.sw_if_index)]).add_vpp_config()
+            p.tun_dst = self.pg0.remote_hosts[ii].ip6
 
 
-    def unconfig_network(self, p):
-        p.route.remove_vpp_config()
-        p.tun_if.remove_vpp_config()
+        self.logger.info(self.vapi.cli("sh log"))
+        self.logger.info(self.vapi.cli("sh ipsec protect-hash"))
+        self.logger.info(self.vapi.cli("sh adj 41"))
 
 
-    def unconfig_protect(self, p):
-        p.tun_protect.remove_vpp_config()
+    def tearDown(self):
+        p = self.ipv6_params
+        p.tun_if.unconfig_ip6()
+        super(TestIpsecMGreIfEspTra6, self).tearDown()
 
 
-    def unconfig_sa(self, p):
-        p.tun_sa_out.remove_vpp_config()
-        p.tun_sa_in.remove_vpp_config()
+    def test_tun_66(self):
+        """mGRE IPSec 66"""
+        for p in self.multi_params:
+            self.verify_tun_66(p, count=63)
 
 
 class TestIpsec4TunProtect(TemplateIpsec,
 
 
 class TestIpsec4TunProtect(TemplateIpsec,
@@ -2126,81 +2110,6 @@ class TestIpsec4TunProtectTunDrop(TemplateIpsec,
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
-class TemplateIpsec6TunProtect(object):
-    """ IPsec IPv6 Tunnel protect """
-
-    def config_sa_tra(self, p):
-        config_tun_params(p, self.encryption_type, p.tun_if)
-
-        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
-                                  p.auth_algo_vpp_id, p.auth_key,
-                                  p.crypt_algo_vpp_id, p.crypt_key,
-                                  self.vpp_esp_protocol)
-        p.tun_sa_out.add_vpp_config()
-
-        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
-                                 p.auth_algo_vpp_id, p.auth_key,
-                                 p.crypt_algo_vpp_id, p.crypt_key,
-                                 self.vpp_esp_protocol)
-        p.tun_sa_in.add_vpp_config()
-
-    def config_sa_tun(self, p):
-        config_tun_params(p, self.encryption_type, p.tun_if)
-
-        p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
-                                  p.auth_algo_vpp_id, p.auth_key,
-                                  p.crypt_algo_vpp_id, p.crypt_key,
-                                  self.vpp_esp_protocol,
-                                  self.tun_if.local_addr[p.addr_type],
-                                  self.tun_if.remote_addr[p.addr_type])
-        p.tun_sa_out.add_vpp_config()
-
-        p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
-                                 p.auth_algo_vpp_id, p.auth_key,
-                                 p.crypt_algo_vpp_id, p.crypt_key,
-                                 self.vpp_esp_protocol,
-                                 self.tun_if.remote_addr[p.addr_type],
-                                 self.tun_if.local_addr[p.addr_type])
-        p.tun_sa_in.add_vpp_config()
-
-    def config_protect(self, p):
-        p.tun_protect = VppIpsecTunProtect(self,
-                                           p.tun_if,
-                                           p.tun_sa_out,
-                                           [p.tun_sa_in])
-        p.tun_protect.add_vpp_config()
-
-    def config_network(self, p):
-        p.tun_if = VppIpIpTunInterface(self, self.pg0,
-                                       self.pg0.local_ip6,
-                                       self.pg0.remote_ip6)
-        p.tun_if.add_vpp_config()
-        p.tun_if.admin_up()
-        p.tun_if.config_ip6()
-        p.tun_if.config_ip4()
-
-        p.route = VppIpRoute(self, p.remote_tun_if_host, 128,
-                             [VppRoutePath(p.tun_if.remote_ip6,
-                                           0xffffffff,
-                                           proto=DpoProto.DPO_PROTO_IP6)])
-        p.route.add_vpp_config()
-        r = VppIpRoute(self, p.remote_tun_if_host4, 32,
-                       [VppRoutePath(p.tun_if.remote_ip4,
-                                     0xffffffff)])
-        r.add_vpp_config()
-
-    def unconfig_network(self, p):
-        p.route.remove_vpp_config()
-        p.tun_if.remove_vpp_config()
-
-    def unconfig_protect(self, p):
-        p.tun_protect.remove_vpp_config()
-
-    def unconfig_sa(self, p):
-        p.tun_sa_out.remove_vpp_config()
-        p.tun_sa_in.remove_vpp_config()
-
-
 class TestIpsec6TunProtect(TemplateIpsec,
                            TemplateIpsec6TunProtect,
                            IpsecTun6):
 class TestIpsec6TunProtect(TemplateIpsec,
                            TemplateIpsec6TunProtect,
                            IpsecTun6):
@@ -2354,7 +2263,7 @@ class TestIpsec6TunProtectTun(TemplateIpsec,
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
                            Raw(b'X' * payload_size))
                 for i in range(count)]
 
-    def gen_pkts6(self, sw_intf, src, dst, count=1,
+    def gen_pkts6(self, p, sw_intf, src, dst, count=1,
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src=src, dst=dst) /
                   payload_size=100):
         return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
                 IPv6(src=src, dst=dst) /
@@ -2663,6 +2572,82 @@ class TestIpsecItf4(TemplateIpsec,
         self.unconfig_network(p)
 
 
         self.unconfig_network(p)
 
 
+class TestIpsecItf4MPLS(TemplateIpsec,
+                        TemplateIpsecItf4,
+                        IpsecTun4):
+    """ IPsec Interface MPLSoIPv4 """
+
+    tun4_encrypt_node_name = "esp-mpls-encrypt-tun"
+
+    def setUp(self):
+        super(TestIpsecItf4MPLS, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsecItf4MPLS, self).tearDown()
+
+    def gen_encrypt_pkts(self, p, sa, sw_intf, src, dst, count=1,
+                         payload_size=100):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(MPLS(label=44, ttl=3) /
+                           IP(src=src, dst=dst) /
+                           UDP(sport=1166, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def verify_encrypted(self, p, sa, rxs):
+        for rx in rxs:
+            try:
+                pkt = sa.decrypt(rx[IP])
+                if not pkt.haslayer(IP):
+                    pkt = IP(pkt[Raw].load)
+                self.assert_packet_checksums_valid(pkt)
+                self.assert_equal(pkt[MPLS].label, 44)
+                self.assert_equal(pkt[IP].dst, p.remote_tun_if_host)
+            except (IndexError, AssertionError):
+                self.logger.debug(ppp("Unexpected packet:", rx))
+                try:
+                    self.logger.debug(ppp("Decrypted packet:", pkt))
+                except:
+                    pass
+                raise
+
+    def test_tun_mpls_o_ip4(self):
+        """IPSEC interface MPLS over IPv4"""
+
+        n_pkts = 127
+        p = self.ipv4_params
+        f = FibPathProto
+
+        tbl = VppMplsTable(self, 0)
+        tbl.add_vpp_config()
+
+        self.config_network(p)
+        # deag MPLS routes from the tunnel
+        r4 = VppMplsRoute(self, 44, 1,
+                          [VppRoutePath(
+                              self.pg1.remote_ip4,
+                              self.pg1.sw_if_index)]).add_vpp_config()
+        p.route.modify([VppRoutePath(p.tun_if.remote_ip4,
+                                     p.tun_if.sw_if_index,
+                                     labels=[VppMplsLabel(44)])])
+        p.tun_if.enable_mpls()
+
+        self.config_sa_tun(p,
+                           self.pg0.local_ip4,
+                           self.pg0.remote_ip4)
+        self.config_protect(p)
+
+        self.verify_tun_44(p, count=n_pkts)
+
+        # cleanup
+        p.tun_if.disable_mpls()
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 class TemplateIpsecItf6(object):
     """ IPsec Interface IPv6 """
 
 class TemplateIpsecItf6(object):
     """ IPsec Interface IPv6 """
 
@@ -2674,12 +2659,19 @@ class TemplateIpsecItf6(object):
     def config_sa_tun(self, p, src, dst):
         config_tun_params(p, self.encryption_type, None, src, dst)
 
     def config_sa_tun(self, p, src, dst):
         config_tun_params(p, self.encryption_type, None, src, dst)
 
+        if not hasattr(p, 'tun_flags'):
+            p.tun_flags = None
+        if not hasattr(p, 'hop_limit'):
+            p.hop_limit = 255
+
         p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
                                   p.auth_algo_vpp_id, p.auth_key,
                                   p.crypt_algo_vpp_id, p.crypt_key,
                                   self.vpp_esp_protocol,
                                   src, dst,
         p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi,
                                   p.auth_algo_vpp_id, p.auth_key,
                                   p.crypt_algo_vpp_id, p.crypt_key,
                                   self.vpp_esp_protocol,
                                   src, dst,
-                                  flags=p.flags)
+                                  flags=p.flags,
+                                  tun_flags=p.tun_flags,
+                                  hop_limit=p.hop_limit)
         p.tun_sa_out.add_vpp_config()
 
         p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
         p.tun_sa_out.add_vpp_config()
 
         p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi,
@@ -2744,8 +2736,13 @@ class TestIpsecItf6(TemplateIpsec,
     def test_tun_44(self):
         """IPSEC interface IPv6"""
 
     def test_tun_44(self):
         """IPSEC interface IPv6"""
 
+        tf = VppEnum.vl_api_tunnel_encap_decap_flags_t
         n_pkts = 127
         p = self.ipv6_params
         n_pkts = 127
         p = self.ipv6_params
+        p.inner_hop_limit = 24
+        p.outer_hop_limit = 23
+        p.outer_flow_label = 243224
+        p.tun_flags = tf.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT
 
         self.config_network(p)
         self.config_sa_tun(p,
 
         self.config_network(p)
         self.config_sa_tun(p,
@@ -2791,6 +2788,12 @@ class TestIpsecItf6(TemplateIpsec,
         np.vpp_tun_sa_id += 1
         np.tun_if.local_spi = p.vpp_tun_spi
         np.tun_if.remote_spi = p.scapy_tun_spi
         np.vpp_tun_sa_id += 1
         np.tun_if.local_spi = p.vpp_tun_spi
         np.tun_if.remote_spi = p.scapy_tun_spi
+        np.inner_hop_limit = 24
+        np.outer_hop_limit = 128
+        np.inner_flow_label = 0xabcde
+        np.outer_flow_label = 0xabcde
+        np.hop_limit = 128
+        np.tun_flags = tf.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_FLOW_LABEL
 
         self.config_sa_tun(np,
                            self.pg0.local_ip6,
 
         self.config_sa_tun(np,
                            self.pg0.local_ip6,
@@ -2843,6 +2846,7 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
             try:
                 self.assertEqual(rx[IP].tos,
                                  VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF << 2)
             try:
                 self.assertEqual(rx[IP].tos,
                                  VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF << 2)
+                self.assertEqual(rx[IP].ttl, p.hop_limit)
                 pkt = sa.decrypt(rx[IP])
                 if not pkt.haslayer(IP):
                     pkt = IP(pkt[Raw].load)
                 pkt = sa.decrypt(rx[IP])
                 if not pkt.haslayer(IP):
                     pkt = IP(pkt[Raw].load)
@@ -2891,6 +2895,7 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
             p.scapy_tra_spi = p.scapy_tra_spi + ii
             p.vpp_tra_sa_id = p.vpp_tra_sa_id + ii
             p.vpp_tra_spi = p.vpp_tra_spi + ii
+            p.hop_limit = ii+10
             p.tun_sa_out = VppIpsecSA(
                 self, p.scapy_tun_sa_id, p.scapy_tun_spi,
                 p.auth_algo_vpp_id, p.auth_key,
             p.tun_sa_out = VppIpsecSA(
                 self, p.scapy_tun_sa_id, p.scapy_tun_spi,
                 p.auth_algo_vpp_id, p.auth_key,
@@ -2898,7 +2903,8 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
                 self.vpp_esp_protocol,
                 self.pg0.local_ip4,
                 self.pg0.remote_hosts[ii].ip4,
                 self.vpp_esp_protocol,
                 self.pg0.local_ip4,
                 self.pg0.remote_hosts[ii].ip4,
-                dscp=VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF)
+                dscp=VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF,
+                hop_limit=p.hop_limit)
             p.tun_sa_out.add_vpp_config()
 
             p.tun_sa_in = VppIpsecSA(
             p.tun_sa_out.add_vpp_config()
 
             p.tun_sa_in = VppIpsecSA(
@@ -2908,7 +2914,8 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
                 self.vpp_esp_protocol,
                 self.pg0.remote_hosts[ii].ip4,
                 self.pg0.local_ip4,
                 self.vpp_esp_protocol,
                 self.pg0.remote_hosts[ii].ip4,
                 self.pg0.local_ip4,
-                dscp=VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF)
+                dscp=VppEnum.vl_api_ip_dscp_t.IP_API_DSCP_EF,
+                hop_limit=p.hop_limit)
             p.tun_sa_in.add_vpp_config()
 
             p.tun_protect = VppIpsecTunProtect(
             p.tun_sa_in.add_vpp_config()
 
             p.tun_protect = VppIpsecTunProtect(
@@ -2941,5 +2948,82 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
             self.verify_tun_44(p, count=N_PKTS)
 
 
             self.verify_tun_44(p, count=N_PKTS)
 
 
+class TestIpsecItf6MPLS(TemplateIpsec,
+                        TemplateIpsecItf6,
+                        IpsecTun6):
+    """ IPsec Interface MPLSoIPv6 """
+
+    tun6_encrypt_node_name = "esp-mpls-encrypt-tun"
+
+    def setUp(self):
+        super(TestIpsecItf6MPLS, self).setUp()
+
+        self.tun_if = self.pg0
+
+    def tearDown(self):
+        super(TestIpsecItf6MPLS, self).tearDown()
+
+    def gen_encrypt_pkts6(self, p, sa, sw_intf, src, dst, count=1,
+                          payload_size=100):
+        return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+                sa.encrypt(MPLS(label=66, ttl=3) /
+                           IPv6(src=src, dst=dst) /
+                           UDP(sport=1166, dport=2233) /
+                           Raw(b'X' * payload_size))
+                for i in range(count)]
+
+    def verify_encrypted6(self, p, sa, rxs):
+        for rx in rxs:
+            try:
+                pkt = sa.decrypt(rx[IPv6])
+                if not pkt.haslayer(IPv6):
+                    pkt = IP(pkt[Raw].load)
+                self.assert_packet_checksums_valid(pkt)
+                self.assert_equal(pkt[MPLS].label, 66)
+                self.assert_equal(pkt[IPv6].dst, p.remote_tun_if_host)
+            except (IndexError, AssertionError):
+                self.logger.debug(ppp("Unexpected packet:", rx))
+                try:
+                    self.logger.debug(ppp("Decrypted packet:", pkt))
+                except:
+                    pass
+                raise
+
+    def test_tun_mpls_o_ip6(self):
+        """IPSEC interface MPLS over IPv6"""
+
+        n_pkts = 127
+        p = self.ipv6_params
+        f = FibPathProto
+
+        tbl = VppMplsTable(self, 0)
+        tbl.add_vpp_config()
+
+        self.config_network(p)
+        # deag MPLS routes from the tunnel
+        r6 = VppMplsRoute(self, 66, 1,
+                          [VppRoutePath(
+                              self.pg1.remote_ip6,
+                              self.pg1.sw_if_index)],
+                          eos_proto=f.FIB_PATH_NH_PROTO_IP6).add_vpp_config()
+        p.route.modify([VppRoutePath(p.tun_if.remote_ip6,
+                                     p.tun_if.sw_if_index,
+                                     labels=[VppMplsLabel(66)])])
+        p.tun_if.enable_mpls()
+
+        self.config_sa_tun(p,
+                           self.pg0.local_ip6,
+                           self.pg0.remote_ip6)
+        self.config_protect(p)
+
+        self.verify_tun_66(p, count=n_pkts)
+
+        # cleanup
+        p.tun_if.disable_mpls()
+        self.unconfig_protect(p)
+        self.unconfig_sa(p)
+        self.unconfig_network(p)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)