ipsec: IPSec interface correct drop w/ no protection 69/34869/3
authorNeale Ranns <neale@graphiant.com>
Mon, 10 Jan 2022 10:38:43 +0000 (10:38 +0000)
committerMatthew Smith <mgsmith@netgate.com>
Mon, 17 Jan 2022 19:55:13 +0000 (19:55 +0000)
Type: improvement

When an IPSec interface is first constructed, the end node of the feature arc is not changed, which means it is interface-output.
This means that traffic directed into adjacencies on the link, that do not have protection (w/ an SA), drop like this:

...
00:00:01:111710: ip4-midchain
  tx_sw_if_index 4 dpo-idx 24 : ipv4 via 0.0.0.0 ipsec0: mtu:9000 next:6 flags:[]
  stacked-on:
    [@1]: dpo-drop ip4 flow hash: 0x00000000
  00000000: 4500005c000100003f01cb8cac100202010101010800ecf40000000058585858
  00000020: 58585858585858585858585858585858585858585858585858585858
00:00:01:111829: local0-output
  ipsec0
  00000000: 4500005c000100003f01cb8cac100202010101010800ecf40000000058585858
  00000020: 5858585858585858585858585858585858585858585858585858585858585858
  00000040: 58585858585858585858585858585858585858585858585858585858c2cf08c0
  00000060: 2a2c103cd0126bd8b03c4ec20ce2bd02dd77b3e3a4f49664
00:00:01:112017: error-drop
  rx:pg1
00:00:01:112034: drop
  local0-output: interface is down

although that's a drop, no packets should go to local0, and we want all IPvX packets to go through ipX-drop.

This change sets the interface's end-arc node to the appropriate drop node when the interface is created, and when the last protection is removed.
The resulting drop is:

...
00:00:01:111504: ip4-midchain
  tx_sw_if_index 4 dpo-idx 24 : ipv4 via 0.0.0.0 ipsec0: mtu:9000 next:0 flags:[]
  stacked-on:
    [@1]: dpo-drop ip4 flow hash: 0x00000000
  00000000: 4500005c000100003f01cb8cac100202010101010800ecf40000000058585858
  00000020: 58585858585858585858585858585858585858585858585858585858
00:00:01:111533: ip4-drop
    ICMP: 172.16.2.2 -> 1.1.1.1
      tos 0x00, ttl 63, length 92, checksum 0xcb8c dscp CS0 ecn NON_ECN
      fragment id 0x0001
    ICMP echo_request checksum 0xecf4 id 0
00:00:01:111620: error-drop
  rx:pg1
00:00:01:111640: drop
  null-node: blackholed packets

Signed-off-by: Neale Ranns <neale@graphiant.com>
Change-Id: I7e7de23c541d9f1210a05e6984a688f1f821a155

src/vnet/ipsec/ipsec_itf.c
src/vnet/ipsec/ipsec_itf.h
src/vnet/ipsec/ipsec_tun.c
test/template_ipsec.py
test/test_ipsec_tun_if_esp.py

index fc0bf85..f9c1d77 100644 (file)
@@ -21,6 +21,7 @@
 #include <vnet/ipsec/ipsec.h>
 #include <vnet/adj/adj_midchain.h>
 #include <vnet/ethernet/mac_address.h>
+#include <vnet/mpls/mpls.h>
 
 /* bitmap of Allocated IPSEC_ITF instances */
 static uword *ipsec_itf_instances;
@@ -274,6 +275,20 @@ ipsec_itf_instance_free (u32 instance)
   return 0;
 }
 
+void
+ipsec_itf_reset_tx_nodes (u32 sw_if_index)
+{
+  vnet_feature_modify_end_node (
+    ip4_main.lookup_main.output_feature_arc_index, sw_if_index,
+    vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip4-drop")->index);
+  vnet_feature_modify_end_node (
+    ip6_main.lookup_main.output_feature_arc_index, sw_if_index,
+    vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip6-drop")->index);
+  vnet_feature_modify_end_node (
+    mpls_main.output_feature_arc_index, sw_if_index,
+    vlib_get_node_by_name (vlib_get_main (), (u8 *) "mpls-drop")->index);
+}
+
 int
 ipsec_itf_create (u32 user_instance, tunnel_mode_t mode, u32 * sw_if_indexp)
 {
@@ -318,6 +333,7 @@ ipsec_itf_create (u32 user_instance, tunnel_mode_t mode, u32 * sw_if_indexp)
   ipsec_itf_index_by_sw_if_index[hi->sw_if_index] = t_idx;
 
   ipsec_itf->ii_sw_if_index = *sw_if_indexp = hi->sw_if_index;
+  ipsec_itf_reset_tx_nodes (hi->sw_if_index);
 
   return 0;
 }
index 7de0274..bf13096 100644 (file)
@@ -102,6 +102,7 @@ typedef struct ipsec_itf_t_
 extern int ipsec_itf_create (u32 user_instance,
                             tunnel_mode_t mode, u32 * sw_if_indexp);
 extern int ipsec_itf_delete (u32 sw_if_index);
+extern void ipsec_itf_reset_tx_nodes (u32 sw_if_index);
 
 extern void ipsec_itf_adj_stack (adj_index_t ai, u32 sai);
 extern void ipsec_itf_adj_unstack (adj_index_t ai);
index ef84d13..543be8a 100644 (file)
@@ -175,12 +175,6 @@ ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
   return (next);
 }
 
-static void
-ipsec_tun_reset_tx_nodes (u32 sw_if_index)
-{
-  vnet_reset_interface_l3_output_node (vlib_get_main (), sw_if_index);
-}
-
 static void
 ipsec_tun_setup_tx_nodes (u32 sw_if_index, const ipsec_tun_protect_t *itp)
 {
@@ -444,7 +438,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
 
   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
     {
-      ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index);
+      ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
       idi->id_itp = INDEX_INVALID;
 
       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
@@ -460,7 +454,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
 
       if (0 == hash_elts (idi->id_hash))
        {
-         ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index);
+         ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
          hash_free (idi->id_hash);
          idi->id_hash = NULL;
        }
index d9a9d1b..9927cc7 100644 (file)
@@ -1375,7 +1375,17 @@ class IpsecTun6(object):
                     pass
                 raise
 
-    def verify_drop_tun_66(self, p_in, count=1, payload_size=64):
+    def verify_drop_tun_tx_66(self, p_in, count=1, payload_size=64):
+        self.vapi.cli("clear errors")
+        self.vapi.cli("clear ipsec sa")
+
+        send_pkts = self.gen_pkts6(p_in, self.pg1, src=self.pg1.remote_ip6,
+                                   dst=p_in.remote_tun_if_host, count=count,
+                                   payload_size=payload_size)
+        self.send_and_assert_no_replies(self.tun_if, send_pkts)
+        self.logger.info(self.vapi.cli("sh punt stats"))
+
+    def verify_drop_tun_rx_66(self, p_in, count=1, payload_size=64):
         self.vapi.cli("clear errors")
         self.vapi.cli("clear ipsec sa")
 
@@ -1385,7 +1395,12 @@ class IpsecTun6(object):
                                            dst=self.pg1.remote_ip6,
                                            count=count)
         self.send_and_assert_no_replies(self.tun_if, send_pkts)
-        self.logger.info(self.vapi.cli("sh punt stats"))
+
+    def verify_drop_tun_66(self, p_in, count=1, payload_size=64):
+        self.verify_drop_tun_tx_66(p_in, count=count,
+                                   payload_size=payload_size)
+        self.verify_drop_tun_rx_66(p_in, count=count,
+                                   payload_size=payload_size)
 
     def verify_tun_66(self, p_in, p_out=None, count=1, payload_size=64):
         self.vapi.cli("clear errors")
index 6865c90..8b6f619 100644 (file)
@@ -2345,7 +2345,7 @@ class TestIpsec6TunProtect(TemplateIpsec,
         p.tun_protect.update_vpp_config(np3.tun_sa_out,
                                         [np3.tun_sa_in])
         self.verify_tun_66(np3, np3, count=127)
-        self.verify_drop_tun_66(np, count=127)
+        self.verify_drop_tun_rx_66(np, count=127)
 
         self.assertEqual(p.tun_if.get_rx_stats(), 127*9)
         self.assertEqual(p.tun_if.get_tx_stats(), 127*8)
@@ -2621,6 +2621,10 @@ class TestIpsecItf4(TemplateIpsec,
         p = self.ipv4_params
 
         self.config_network(p)
+        config_tun_params(p, self.encryption_type, None,
+                          self.pg0.local_ip4,
+                          self.pg0.remote_ip4)
+        self.verify_tun_dropped_44(p, count=n_pkts)
         self.config_sa_tun(p,
                            self.pg0.local_ip4,
                            self.pg0.remote_ip4)
@@ -2693,7 +2697,7 @@ class TestIpsecItf4(TemplateIpsec,
                            self.pg0.remote_ip4)
         self.config_protect(p)
 
-        self.logger.error(self.vapi.cli("sh ipsec sa"))
+        self.logger.info(self.vapi.cli("sh ipsec sa"))
         self.verify_tun_44(p, count=n_pkts)
 
         # teardown
@@ -2912,7 +2916,7 @@ class TestIpsecItf6(TemplateIpsec,
     def tearDown(self):
         super(TestIpsecItf6, self).tearDown()
 
-    def test_tun_44(self):
+    def test_tun_66(self):
         """IPSEC interface IPv6"""
 
         tf = VppEnum.vl_api_tunnel_encap_decap_flags_t
@@ -2924,6 +2928,10 @@ class TestIpsecItf6(TemplateIpsec,
         p.tun_flags = tf.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_HOP_LIMIT
 
         self.config_network(p)
+        config_tun_params(p, self.encryption_type, None,
+                          self.pg0.local_ip6,
+                          self.pg0.remote_ip6)
+        self.verify_drop_tun_66(p, count=n_pkts)
         self.config_sa_tun(p,
                            self.pg0.local_ip6,
                            self.pg0.remote_ip6)