misc: add filter for specific error for pcap trace 93/31493/10
authorBenoît Ganne <bganne@cisco.com>
Wed, 3 Mar 2021 16:37:25 +0000 (17:37 +0100)
committerDave Barach <openvpp@barachs.net>
Thu, 22 Apr 2021 11:12:59 +0000 (11:12 +0000)
Type: feature

Change-Id: I325257454df1cc22833fa6a1dedd4739d4d5a558
Signed-off-by: Benoît Ganne <bganne@cisco.com>
src/vlib/error.c
src/vlib/error.h
src/vnet/classify/pcap_classify.h
src/vnet/interface.h
src/vnet/interface_cli.c
src/vnet/vnet.h
test/test_trace_filter.py

index 99664c6..1a84e7e 100644 (file)
@@ -210,6 +210,37 @@ vlib_register_errors (vlib_main_t * vm,
   }
 }
 
+uword
+unformat_vlib_error (unformat_input_t *input, va_list *args)
+{
+  vlib_main_t *vm = va_arg (*args, vlib_main_t *);
+  const vlib_error_main_t *em = &vm->error_main;
+  vlib_error_t *error_index = va_arg (*args, vlib_error_t *);
+  const vlib_node_t *node;
+  char *error_name;
+  u32 node_index;
+  vlib_error_t i;
+
+  if (!unformat (input, "%U.%s", unformat_vlib_node, vm, &node_index,
+                &error_name))
+    return 0;
+
+  node = vlib_get_node (vm, node_index);
+  for (i = 0; i < node->n_errors; i++)
+    {
+      vlib_error_t ei = node->error_heap_index + i;
+      if (strcmp (em->counters_heap[ei].name, error_name) == 0)
+       {
+         *error_index = ei;
+         vec_free (error_name);
+         return 1;
+       }
+    }
+
+  vec_free (error_name);
+  return 0;
+}
+
 static char *
 sev2str (enum vl_counter_severity_e s)
 {
index 11757e0..2bffc6b 100644 (file)
@@ -40,6 +40,8 @@
 #ifndef included_vlib_error_h
 #define included_vlib_error_h
 
+#include <vppinfra/format.h>
+
 typedef u16 vlib_error_t;
 
 enum vl_counter_severity_e
@@ -75,6 +77,8 @@ void vlib_register_errors (struct vlib_main_t *vm,
                           u32 n_errors, char *error_strings[],
                           vl_counter_t counters[]);
 
+unformat_function_t unformat_vlib_error;
+
 #endif /* included_vlib_error_h */
 
 /*
index 1f1c38f..e079816 100644 (file)
@@ -33,6 +33,7 @@ vnet_is_packet_pcaped (vnet_pcap_t *pp, vlib_buffer_t *b, u32 sw_if_index)
 {
   const u32 pcap_sw_if_index = pp->pcap_sw_if_index;
   const u32 filter_classify_table_index = pp->filter_classify_table_index;
+  const vlib_error_t pcap_error_index = pp->pcap_error_index;
 
   if (pcap_sw_if_index != 0)
     {
@@ -42,6 +43,9 @@ vnet_is_packet_pcaped (vnet_pcap_t *pp, vlib_buffer_t *b, u32 sw_if_index)
        return 0; /* wrong interface, skip */
     }
 
+  if (pcap_error_index != (vlib_error_t) ~0 && pcap_error_index != b->error)
+    return 0; /* wrong error */
+
   if (filter_classify_table_index != ~0 &&
       vnet_is_packet_traced_inline (b, filter_classify_table_index,
                                    0 /* full classify */) != 1)
index b36d02c..9d2f2a1 100644 (file)
@@ -1039,6 +1039,7 @@ typedef struct
   u8 free_data;
   u32 sw_if_index;
   int filter;
+  vlib_error_t drop_err;
 } vnet_pcap_dispatch_trace_args_t;
 
 int vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t *);
index 9ade975..6dadbb8 100644 (file)
@@ -2034,6 +2034,7 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a)
          cm->classify_table_index_by_sw_if_index[0];
       else
        pp->filter_classify_table_index = ~0;
+      pp->pcap_error_index = a->drop_err;
       pp->pcap_rx_enable = a->rx_enable;
       pp->pcap_tx_enable = a->tx_enable;
       pp->pcap_drop_enable = a->drop_enable;
@@ -2045,6 +2046,7 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a)
       pp->pcap_tx_enable = 0;
       pp->pcap_drop_enable = 0;
       pp->filter_classify_table_index = ~0;
+      pp->pcap_error_index = ~0;
       if (pm->n_packets_captured)
        {
          clib_error_t *error;
@@ -2091,6 +2093,7 @@ pcap_trace_command_fn (vlib_main_t * vm,
   int filter = 0;
   int free_data = 0;
   u32 sw_if_index = 0;         /* default: any interface */
+  vlib_error_t drop_err = ~0;  /* default: any error */
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -2124,6 +2127,9 @@ pcap_trace_command_fn (vlib_main_t * vm,
       else if (unformat (line_input, "interface %U",
                         unformat_vnet_sw_interface, vnm, &sw_if_index))
        ;
+      else if (unformat (line_input, "error %U", unformat_vlib_error, vm,
+                        &drop_err))
+       ;
       else if (unformat (line_input, "preallocate-data %=",
                         &preallocate_data, 1))
        ;
@@ -2155,6 +2161,7 @@ pcap_trace_command_fn (vlib_main_t * vm,
   a->sw_if_index = sw_if_index;
   a->filter = filter;
   a->max_bytes_per_pkt = max_bytes_per_pkt;
+  a->drop_err = drop_err;
 
   rv = vnet_pcap_dispatch_trace_configure (a);
 
@@ -2235,6 +2242,9 @@ pcap_trace_command_fn (vlib_main_t * vm,
  *   filter. The filter will only be executed if the per-interface or
  *   any-interface tests fail.
  *
+ * - <b>error <node>.<error></b> - filter packets based on a specific error.
+ *   For example: error {ip4-udp-lookup}.{No listener for dst port}
+ *
  * - <b>file <name></b> - Used to specify the output filename. The file will
  *   be placed in the '<em>/tmp</em>' directory, so only the filename is
  *   supported. Directory should not be entered. If file already exists, file
@@ -2255,7 +2265,8 @@ pcap_trace_command_fn (vlib_main_t * vm,
  * pcap tx capture is off...
  * @cliexend
  * Example of how to start a tx packet capture:
- * @cliexstart{pcap trace tx max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap}
+ * @cliexstart{pcap trace tx max 35 intfc GigabitEthernet0/8/0 file
+vppTest.pcap}
  * @cliexend
  * Example of how to display the status of a tx packet capture in progress:
  * @cliexstart{pcap trace status}
index 1deaff6..24afe63 100644 (file)
@@ -70,6 +70,7 @@ typedef struct
   u32 pcap_sw_if_index;
   pcap_main_t pcap_main;
   u32 filter_classify_table_index;
+  vlib_error_t pcap_error_index;
 } vnet_pcap_t;
 
 typedef struct vnet_main_t
index 8869b32..fd250ac 100644 (file)
@@ -174,7 +174,7 @@ class TestTracefilter(VppTestCase):
             "match l3 ip4 proto 17 l4 src_port 2345")
         self.cli(
             "pcap trace rx tx max 1000 intfc pg0 "
-            "file vpp_test_trace_filter.pcap filter")
+            "file vpp_test_trace_filter_test_pcap.pcap filter")
         # the packet we are trying to match
         p = list()
         for i in range(100):
@@ -198,7 +198,7 @@ class TestTracefilter(VppTestCase):
         self.del_pcap_filters()
 
         # check captured pcap
-        pcap = rdpcap("/tmp/vpp_test_trace_filter.pcap")
+        pcap = rdpcap("/tmp/vpp_test_trace_filter_test_pcap.pcap")
         self.assertEqual(len(pcap), 9 + 17)
         p_ = str(p[5])
         for i in range(9):
@@ -207,6 +207,38 @@ class TestTracefilter(VppTestCase):
         for i in range(9, 9 + 17):
             self.assertEqual(str(pcap[i]), p_)
 
+    def test_pcap_drop(self):
+        """ Drop Packet Capture Filter Test """
+        self.cli(
+            "pcap trace drop max 1000 "
+            "error {ip4-udp-lookup}.{No listener for dst port} "
+            "file vpp_test_trace_filter_test_pcap_drop.pcap")
+        # the packet we are trying to match
+        p = list()
+        for i in range(17):
+            # this packet should be forwarded
+            p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+                      IP(src=self.pg0.remote_hosts[0].ip4,
+                         dst=self.pg1.remote_ip4) /
+                      UDP(sport=2345, dport=1234) / Raw('\xa5' * 100)))
+            # this packet should be captured (no listener)
+            p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+                      IP(src=self.pg0.remote_hosts[0].ip4,
+                         dst=self.pg0.local_ip4) /
+                      UDP(sport=2345, dport=1234) / Raw('\xa5' * 100)))
+        # this packet will be blackholed but not captured
+        p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+                  IP(src=self.pg0.remote_hosts[0].ip4, dst="0.0.0.0") /
+                  UDP(sport=2345, dport=1234) / Raw('\xa5' * 100)))
+
+        self.send_and_expect(self.pg0, p, self.pg1, n_rx=17, trace=False)
+
+        self.cli("pcap trace drop off")
+
+        # check captured pcap
+        pcap = rdpcap("/tmp/vpp_test_trace_filter_test_pcap_drop.pcap")
+        self.assertEqual(len(pcap), 17)
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)