* 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>
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)
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")
#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);
#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)
#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>
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"
/*
import unittest
+import ipaddress
import socket
from scapy.packet import Raw
)
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
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)