ip_session_redirect: add dump api for session redirects 43/42843/5
authorHadi Rayan Al-Sandid <halsandi@cisco.com>
Wed, 23 Apr 2025 10:19:13 +0000 (12:19 +0200)
committerBenoit Ganne <bganne@cisco.com>
Tue, 6 May 2025 07:30:38 +0000 (07:30 +0000)
Type: improvement

Change-Id: Icd6e94535d388e4c2c08c8ab383fea8cac324d66
Signed-off-by: Hadi Rayan Al-Sandid <halsandi@cisco.com>
src/plugins/ip_session_redirect/api.c
src/plugins/ip_session_redirect/ip_session_redirect.api
src/plugins/ip_session_redirect/ip_session_redirect.h
src/plugins/ip_session_redirect/redirect.c
src/plugins/ip_session_redirect/test_api.c
test/test_ip_session_redirect.py

index 1d17d55..5c7bc65 100644 (file)
  * limitations under the License. */
 
 #include <vlib/vlib.h>
+#include <vnet/fib/fib_path_list.h>
 #include <vnet/fib/fib_api.h>
 #include <vnet/ip/ip_format_fns.h>
+#include <vnet/classify/vnet_classify.h>
 #include <vlibmemory/api.h>
 #include <vlibapi/api.h>
 
@@ -105,6 +107,68 @@ vl_api_ip_session_redirect_del_t_handler (vl_api_ip_session_redirect_del_t *mp)
   REPLY_MACRO (VL_API_IP_SESSION_REDIRECT_DEL_REPLY);
 }
 
+static void
+send_ip_session_redirect_details (vl_api_registration_t *reg, u32 table_index,
+                                 u32 context)
+{
+  ip_session_redirect_main_t *im = &ip_session_redirect_main;
+  ip_session_redirect_t *ipr;
+  ip_session_redirect_t *iprs = im->pool;
+
+  pool_foreach (ipr, iprs)
+    {
+      if (~0 == table_index || ipr->table_index == table_index)
+       {
+         vl_api_ip_session_redirect_details_t *rmp;
+         vl_api_fib_path_t *fp;
+         fib_route_path_t *rpath;
+         fib_path_encode_ctx_t walk_ctx = {
+           .rpaths = NULL,
+         };
+         u8 n_paths = fib_path_list_get_n_paths (ipr->pl);
+         /* match_len is computed without table index at the end of the match
+          * string */
+         u32 match_len = vec_len (ipr->match_and_table_index) - 4;
+
+         rmp = vl_msg_api_alloc_zero (sizeof (*rmp) +
+                                      sizeof (rmp->paths[0]) * n_paths);
+         rmp->_vl_msg_id =
+           ntohs (REPLY_MSG_ID_BASE + VL_API_IP_SESSION_REDIRECT_DETAILS);
+         rmp->context = context;
+         rmp->opaque_index = htonl (ipr->opaque_index);
+         rmp->table_index = htonl (ipr->table_index);
+         rmp->match_length = htonl (match_len);
+         rmp->is_punt = ipr->is_punt;
+         rmp->is_ip6 = ipr->is_ip6;
+         clib_memcpy (rmp->match, ipr->match_and_table_index, match_len);
+         rmp->n_paths = n_paths;
+         fp = rmp->paths;
+         rmp->retval = 0;
+         fib_path_list_walk_w_ext (ipr->pl, NULL, fib_path_encode, &walk_ctx);
+         vec_foreach (rpath, walk_ctx.rpaths)
+           {
+             fib_api_path_encode (rpath, fp);
+             fp++;
+           }
+
+         vl_api_send_msg (reg, (u8 *) rmp);
+       }
+    }
+}
+
+static void
+vl_api_ip_session_redirect_dump_t_handler (
+  vl_api_ip_session_redirect_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  u32 table_index = ntohl (mp->table_index);
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (reg == 0)
+    return;
+
+  send_ip_session_redirect_details (reg, table_index, mp->context);
+}
+
 #include "ip_session_redirect.api.c"
 static clib_error_t *
 ip_session_redirect_plugin_api_hookup (vlib_main_t *vm)
index 2bf2373..769d15b 100644 (file)
@@ -99,6 +99,47 @@ autoreply define ip_session_redirect_del
   option status="in_progress";
 };
 
+/** \brief Dump available session redirections
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param table_index - classifier table index
+*/
+
+define ip_session_redirect_dump
+{
+  u32 client_index;
+  u32 context;
+  u32 table_index;
+};
+
+/** \brief Session redirection operational state response
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param table_index - classifier table index
+    @param opaque_index - classifier session opaque index
+    @param is_punt - true = punted traffic, false = forwarded traffic
+    @param is_ip6 - true = payload proto is ip6, false = payload proto is ip4
+    @param match_len - classifier session match length in bytes (max is 80-bytes)
+    @param match - classifier session match
+    @param n_paths - number of paths
+    @param paths - the paths of the redirect
+*/
+
+define ip_session_redirect_details
+{
+  u32 context;
+  i32 retval;
+  u32 table_index;
+  u32 opaque_index;
+  bool is_punt;
+  bool is_ip6;
+  u32 match_length;
+  u8 match[80];
+  u8 n_paths;
+  vl_api_fib_path_t paths[n_paths];
+};
+
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index 45f64ee..8005276 100644 (file)
 
 #include <vnet/fib/fib_node.h>
 
+typedef struct
+{
+  u8 *match_and_table_index;
+  dpo_id_t dpo;           /* forwarding dpo */
+  fib_node_t node; /* linkage into the FIB graph */
+  fib_node_index_t pl;
+  u32 sibling;
+  u32 parent_node_index;
+  u32 opaque_index;
+  u32 table_index;
+  fib_forward_chain_type_t payload_type;
+  u8 is_punt : 1;
+  u8 is_ip6 : 1;
+} ip_session_redirect_t;
+
+typedef struct
+{
+  ip_session_redirect_t *pool;
+  u32 *session_by_match_and_table_index;
+  fib_node_type_t fib_node_type;
+} ip_session_redirect_main_t;
+
+extern ip_session_redirect_main_t ip_session_redirect_main;
+
 int ip_session_redirect_add (vlib_main_t *vm, u32 table_index,
                             u32 opaque_index, dpo_proto_t proto, int is_punt,
                             const u8 *match, const fib_route_path_t *rpaths);
index ea18182..b8442ef 100644 (file)
 #include <vpp/app/version.h>
 #include "ip_session_redirect.h"
 
-typedef struct
-{
-  u8 *match_and_table_index;
-  dpo_id_t dpo;           /* forwarding dpo */
-  fib_node_t node; /* linkage into the FIB graph */
-  fib_node_index_t pl;
-  u32 sibling;
-  u32 parent_node_index;
-  u32 opaque_index;
-  u32 table_index;
-  fib_forward_chain_type_t payload_type;
-  u8 is_punt : 1;
-  u8 is_ip6 : 1;
-} ip_session_redirect_t;
-
-typedef struct
-{
-  ip_session_redirect_t *pool;
-  u32 *session_by_match_and_table_index;
-  fib_node_type_t fib_node_type;
-} ip_session_redirect_main_t;
-
-static ip_session_redirect_main_t ip_session_redirect_main;
+ip_session_redirect_main_t ip_session_redirect_main;
 
 static int
 ip_session_redirect_stack (ip_session_redirect_t *ipr)
index e4026a6..850a61d 100644 (file)
@@ -14,6 +14,7 @@
 #include <vlib/vlib.h>
 #include <vnet/fib/fib_api.h>
 #include <vnet/ip/ip_format_fns.h>
+#include <vnet/fib/fib_path_list.h>
 #include <vnet/classify/vnet_classify.h>
 #include <vat/vat.h>
 #include <vlibapi/api.h>
@@ -184,6 +185,79 @@ api_ip_session_redirect_del (vat_main_t *vam)
   return ret;
 }
 
+static int
+api_ip_session_redirect_dump (vat_main_t *vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_ip_session_redirect_dump_t *mp;
+  u32 table_index = ~0;
+  int ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "table %d", &table_index))
+       ;
+      else
+       break;
+    }
+
+  /* Construct the API message */
+  M (IP_SESSION_REDIRECT_DUMP, mp);
+  mp->table_index = htonl (table_index);
+
+  S (mp)
+
+  /* Wait for a reply... */
+  W (ret);
+  return ret;
+}
+
+static void
+vl_api_ip_session_redirect_details_t_handler (
+  vl_api_ip_session_redirect_details_t *mp)
+{
+  vat_main_t *vam = ip_session_redirect_test_main.vat_main;
+  int rv;
+  u32 table_index;
+  u32 opaque_index;
+  u32 match_len;
+  u8 match[80];
+  u8 n_paths;
+  fib_route_path_t *paths_ = 0;
+  u8 *out = 0;
+
+  table_index = ntohl (mp->table_index);
+  opaque_index = ntohl (mp->opaque_index);
+  match_len = ntohl (mp->match_length);
+  const char *type = mp->is_punt ? "[punt]" : "[acl]";
+  const char *ip = mp->is_ip6 ? "[ip6]" : "[ip4]";
+  clib_memcpy (match, mp->match, match_len);
+  n_paths = mp->n_paths;
+
+  for (int i = 0; i < n_paths; i++)
+    {
+      fib_route_path_t path;
+      if ((rv = fib_api_path_decode (&mp->paths[i], &path)))
+       goto err;
+      vec_add1 (paths_, path);
+    }
+
+  out =
+    format (out, "table %d match %U %s %s opaque_index 0x%x\n", table_index,
+           format_hex_bytes, match, match_len, type, ip, opaque_index);
+  out = format (out, " via:\n");
+  for (int i = 0; i < n_paths; i++)
+    {
+      fib_route_path_t *path = &paths_[i];
+      out = format (out, "  %U", format_fib_route_path, path);
+    }
+
+  fformat (vam->ofp, (char *) out);
+err:
+  vec_free (out);
+}
+
 #include "ip_session_redirect.api_test.c"
 
 /*
index 3fed62b..5e1bee9 100644 (file)
@@ -2,6 +2,7 @@
 
 import unittest
 
+import ipaddress
 import socket
 
 from scapy.packet import Raw
@@ -83,6 +84,33 @@ class TestIpSessionRedirect(VppTestCase):
         )
         return r.new_table_index
 
+    def verify_session_dump_entry(
+        self,
+        sess,
+        table_index,
+        is_punt,
+        is_ip6,
+        match_len,
+        match,
+        n_paths,
+        sess_path_ip,
+    ):
+        self.assertEqual(sess.table_index, table_index)
+        self.assertEqual(sess.is_punt, is_punt)
+        self.assertEqual(sess.is_ip6, is_ip6)
+        self.assertEqual(sess.match_length, match_len)
+        self.assertEqual(sess.match[:match_len], match)
+        self.assertEqual(sess.n_paths, n_paths)
+        for i, ip in enumerate(sess_path_ip):
+            if is_ip6:
+                self.assertEqual(
+                    sess.paths[i].nh.address.ip6, ipaddress.IPv6Address(ip)
+                )
+            else:
+                self.assertEqual(
+                    sess.paths[i].nh.address.ip4, ipaddress.IPv4Address(ip)
+                )
+
     def __test_redirect(self, sport, dport, is_punt, is_ip6):
         if is_ip6:
             af = VppEnum.vl_api_address_family_t.ADDRESS_IP6
@@ -194,6 +222,47 @@ class TestIpSessionRedirect(VppTestCase):
         t = self.vapi.classify_table_info(table_id=table_index)
         self.assertEqual(t.active_sessions, 2)
 
+        # update matching entry so that it is multi-path
+        paths = [
+            VppRoutePath(nh1, 0xFFFFFFFF).encode(),
+            VppRoutePath(nh2, 0xFFFFFFFF).encode(),
+        ]
+        self.vapi.ip_session_redirect_add_v2(
+            table_index=table_index,
+            match_len=len(match2),
+            match=match2,
+            is_punt=is_punt,
+            n_paths=2,
+            paths=paths,
+            proto=proto,
+        )
+
+        # verify that session dump has 2 entries
+        sessions_dump = self.vapi.ip_session_redirect_dump(table_index=table_index)
+        self.assertEqual(len(sessions_dump), 2)
+
+        # verify session dump entries
+        self.verify_session_dump_entry(
+            sessions_dump[0],
+            table_index,
+            is_punt,
+            is_ip6,
+            len(match1),
+            match1,
+            1,
+            [nh1],
+        )
+        self.verify_session_dump_entry(
+            sessions_dump[1],
+            table_index,
+            is_punt,
+            is_ip6,
+            len(match2),
+            match2,
+            2,
+            [nh1, nh2],
+        )
+
         # cleanup
         self.vapi.ip_session_redirect_del(table_index, len(match2), match2)
         self.vapi.ip_session_redirect_del(table_index, len(match1), match1)