urpf: add mode for specific fib index lookup

this patch adds a mode to urpf in order to perform the lookup in a specified vrf instead of the interface vrf
Type: feature
Change-Id: Ieb91de6ccdfbf32b6939364f3bebeecd2d57af19
Signed-off-by: hedi bouattour <hedibouattour2010@gmail.com>
This commit is contained in:
hedi bouattour
2022-09-14 12:39:23 +00:00
committed by Neale Ranns
parent 9260b8861e
commit b3605eab5a
5 changed files with 176 additions and 39 deletions

View File

@@ -50,6 +50,27 @@ autoreply define urpf_update
vl_api_interface_index_t sw_if_index;
};
/**
* @brief Enable uRPF on a given interface in a given direction
* @param client_index - opaque cookie to identify the sender
* @param context - sender context, to match reply w/ request
* @param mode - Mode
* @param af - Address Family
* @param sw_if_index - Interface
* @param is_input - Direction.
* @param table-id - Table ID
*/
autoreply define urpf_update_v2
{
u32 client_index;
u32 context;
bool is_input[default = true];
vl_api_urpf_mode_t mode;
vl_api_address_family_t af;
vl_api_interface_index_t sw_if_index;
u32 table_id [default=0xffffffff];
};
/*
* fd.io coding-style-patch-verification: ON
*

View File

@@ -58,7 +58,8 @@ static const char *urpf_feats[N_AF][VLIB_N_DIR][URPF_N_MODES] =
/**
* Per-af, per-direction, per-interface uRPF configs
*/
static urpf_mode_t *urpf_cfgs[N_AF][VLIB_N_DIR];
urpf_data_t *urpf_cfgs[N_AF][VLIB_N_DIR];
u8 *
format_urpf_mode (u8 * s, va_list * a)
@@ -95,34 +96,105 @@ unformat_urpf_mode (unformat_input_t * input, va_list * args)
return 0;
}
void
urpf_update (urpf_mode_t mode,
u32 sw_if_index, ip_address_family_t af, vlib_dir_t dir)
int
urpf_update (urpf_mode_t mode, u32 sw_if_index, ip_address_family_t af,
vlib_dir_t dir, u32 table_id)
{
urpf_mode_t old;
fib_protocol_t proto;
u32 fib_index;
if (table_id != ~0)
{
proto = ip_address_family_to_fib_proto (af);
fib_index = fib_table_find (proto, table_id);
if (fib_index == (~0))
return VNET_API_ERROR_INVALID_VALUE;
}
else
{
bool is_ip4 = (AF_IP4 == af);
u32 *fib_index_by_sw_if_index = is_ip4 ?
ip4_main.fib_index_by_sw_if_index :
ip6_main.fib_index_by_sw_if_index;
vec_validate_init_empty (urpf_cfgs[af][dir], sw_if_index, URPF_MODE_OFF);
fib_index = fib_index_by_sw_if_index[sw_if_index];
}
urpf_data_t old;
urpf_mode_t off = URPF_MODE_OFF;
urpf_data_t empty = { .fib_index = 0, .mode = off };
vec_validate_init_empty (urpf_cfgs[af][dir], sw_if_index, empty);
old = urpf_cfgs[af][dir][sw_if_index];
if (mode != old)
urpf_data_t data = { .fib_index = fib_index,
.mode = mode,
.fib_index_is_custom = (table_id != ~0) };
urpf_cfgs[af][dir][sw_if_index] = data;
if (data.mode != old.mode || data.fib_index != old.fib_index)
{
if (URPF_MODE_OFF != old)
if (URPF_MODE_OFF != old.mode)
/* disable what we have */
vnet_feature_enable_disable (urpf_feat_arcs[af][dir],
urpf_feats[af][dir][old],
urpf_feats[af][dir][old.mode],
sw_if_index, 0, 0, 0);
if (URPF_MODE_OFF != mode)
if (URPF_MODE_OFF != data.mode)
/* enable what's new */
vnet_feature_enable_disable (urpf_feat_arcs[af][dir],
urpf_feats[af][dir][mode],
urpf_feats[af][dir][data.mode],
sw_if_index, 1, 0, 0);
}
/* else - no change to existing config */
urpf_cfgs[af][dir][sw_if_index] = mode;
return 0;
}
static void
urpf_table_bind_v4 (ip4_main_t *im, uword opaque, u32 sw_if_index,
u32 new_fib_index, u32 old_fib_index)
{
vlib_dir_t dir;
urpf_data_t empty = { .fib_index = 0, .mode = URPF_MODE_OFF };
FOREACH_VLIB_DIR (dir)
{
vec_validate_init_empty (urpf_cfgs[AF_IP4][dir], sw_if_index, empty);
if (!urpf_cfgs[AF_IP4][dir][sw_if_index].fib_index_is_custom)
{
urpf_cfgs[AF_IP4][dir][sw_if_index].fib_index = new_fib_index;
}
}
}
static void
urpf_table_bind_v6 (ip6_main_t *im, uword opaque, u32 sw_if_index,
u32 new_fib_index, u32 old_fib_index)
{
vlib_dir_t dir;
urpf_data_t empty = { .fib_index = 0, .mode = URPF_MODE_OFF };
FOREACH_VLIB_DIR (dir)
{
vec_validate_init_empty (urpf_cfgs[AF_IP6][dir], sw_if_index, empty);
if (!urpf_cfgs[AF_IP6][dir][sw_if_index].fib_index_is_custom)
{
urpf_cfgs[AF_IP6][dir][sw_if_index].fib_index = new_fib_index;
}
}
}
static clib_error_t *
urpf_init (vlib_main_t *vm)
{
ip4_table_bind_callback_t cb4 = {
.function = urpf_table_bind_v4,
};
vec_add1 (ip4_main.table_bind_callbacks, cb4);
ip6_table_bind_callback_t cb6 = {
.function = urpf_table_bind_v6,
};
vec_add1 (ip6_main.table_bind_callbacks, cb6);
return (NULL);
}
VLIB_INIT_FUNCTION (urpf_init);
static clib_error_t *
urpf_cli_update (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -134,11 +206,13 @@ urpf_cli_update (vlib_main_t * vm,
urpf_mode_t mode;
u32 sw_if_index;
vlib_dir_t dir;
u32 table_id;
sw_if_index = ~0;
af = AF_IP4;
dir = VLIB_RX;
mode = URPF_MODE_STRICT;
table_id = ~0;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
@@ -150,6 +224,8 @@ urpf_cli_update (vlib_main_t * vm,
;
else if (unformat (line_input, "%U", unformat_urpf_mode, &mode))
;
else if (unformat (line_input, "table %d", &table_id))
;
else if (unformat (line_input, "%U", unformat_ip_address_family, &af))
;
else if (unformat (line_input, "%U", unformat_vlib_rx_tx, &dir))
@@ -168,7 +244,13 @@ urpf_cli_update (vlib_main_t * vm,
goto done;
}
urpf_update (mode, sw_if_index, af, dir);
int rv = 0;
rv = urpf_update (mode, sw_if_index, af, dir, table_id);
if (rv)
{
error = clib_error_return (0, "unknown table id");
goto done;
}
done:
unformat_free (line_input);
@@ -233,7 +315,8 @@ done:
VLIB_CLI_COMMAND (set_interface_ip_source_check_command, static) = {
.path = "set urpf",
.function = urpf_cli_update,
.short_help = "set urpf [ip4|ip6] [rx|tx] [off|strict|loose] <INTERFACE>",
.short_help = "set urpf [ip4|ip6] [rx|tx] [off|strict|loose] "
"<INTERFACE> [table <table>]",
};
/* *INDENT-ON* */

View File

@@ -18,10 +18,10 @@
#include <vnet/ip/ip_types.h>
#define foreach_urpf_mode \
_(OFF, "off") \
_(LOOSE, "loose") \
_(STRICT, "strict") \
#define foreach_urpf_mode \
_ (OFF, "off") \
_ (LOOSE, "loose") \
_ (STRICT, "strict")
typedef enum urpf_mode_t_
{
@@ -34,10 +34,17 @@ typedef enum urpf_mode_t_
extern u8 *format_urpf_mode (u8 * s, va_list * a);
extern void urpf_update (urpf_mode_t mode,
u32 sw_if_index,
ip_address_family_t af, vlib_dir_t dir);
typedef struct
{
urpf_mode_t mode;
u32 fib_index;
u8 fib_index_is_custom;
} urpf_data_t;
extern urpf_data_t *urpf_cfgs[N_AF][VLIB_N_DIR];
extern int urpf_update (urpf_mode_t mode, u32 sw_if_index,
ip_address_family_t af, vlib_dir_t dir, u32 fib_index);
#endif

View File

@@ -26,6 +26,8 @@
#include <vnet/format_fns.h>
#include <urpf/urpf.api_enum.h>
#include <urpf/urpf.api_types.h>
#include <vnet/fib/fib_table.h>
#include <vnet/ip/ip_types.h>
/**
* Base message ID fot the plugin
@@ -62,7 +64,34 @@ vl_api_urpf_update_t_handler (vl_api_urpf_update_t * mp)
VALIDATE_SW_IF_INDEX (mp);
rv = urpf_mode_decode (mp->mode, &mode);
if (rv)
goto done;
rv = ip_address_family_decode (mp->af, &af);
if (rv)
goto done;
rv = urpf_update (mode, htonl (mp->sw_if_index), af,
(mp->is_input ? VLIB_RX : VLIB_TX), 0);
if (rv)
goto done;
BAD_SW_IF_INDEX_LABEL;
done:
REPLY_MACRO (VL_API_URPF_UPDATE_REPLY);
}
static void
vl_api_urpf_update_v2_t_handler (vl_api_urpf_update_v2_t *mp)
{
vl_api_urpf_update_reply_t *rmp;
ip_address_family_t af;
urpf_mode_t mode;
int rv = 0;
VALIDATE_SW_IF_INDEX (mp);
rv = urpf_mode_decode (mp->mode, &mode);
if (rv)
goto done;
@@ -71,12 +100,15 @@ vl_api_urpf_update_t_handler (vl_api_urpf_update_t * mp)
if (rv)
goto done;
urpf_update (mode, htonl (mp->sw_if_index), af,
(mp->is_input ? VLIB_RX : VLIB_TX));
rv = urpf_update (mode, htonl (mp->sw_if_index), af,
(mp->is_input ? VLIB_RX : VLIB_TX), ntohl (mp->table_id));
if (rv)
goto done;
BAD_SW_IF_INDEX_LABEL;
done:
REPLY_MACRO (VL_API_URPF_UPDATE_REPLY);
REPLY_MACRO (VL_API_URPF_UPDATE_V2_REPLY);
}
#include <urpf/urpf.api.c>

View File

@@ -128,6 +128,11 @@ urpf_inline (vlib_main_t * vm,
h1 += vnet_buffer (b[1])->ip.save_rewrite_length;
}
fib_index0 =
urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
fib_index1 =
urpf_cfgs[af][dir][vnet_buffer (b[1])->sw_if_index[dir]].fib_index;
if (AF_IP4 == af)
{
const ip4_header_t *ip0, *ip1;
@@ -135,11 +140,6 @@ urpf_inline (vlib_main_t * vm,
ip0 = (ip4_header_t *) h0;
ip1 = (ip4_header_t *) h1;
fib_index0 = ip4_main.fib_index_by_sw_if_index
[vnet_buffer (b[0])->sw_if_index[dir]];
fib_index1 = ip4_main.fib_index_by_sw_if_index
[vnet_buffer (b[1])->sw_if_index[dir]];
ip4_fib_forwarding_lookup_x2 (fib_index0,
fib_index1,
&ip0->src_address,
@@ -155,11 +155,6 @@ urpf_inline (vlib_main_t * vm,
{
const ip6_header_t *ip0, *ip1;
fib_index0 = ip6_main.fib_index_by_sw_if_index
[vnet_buffer (b[0])->sw_if_index[dir]];
fib_index1 = ip6_main.fib_index_by_sw_if_index
[vnet_buffer (b[1])->sw_if_index[dir]];
ip0 = (ip6_header_t *) h0;
ip1 = (ip6_header_t *) h1;
@@ -255,12 +250,13 @@ urpf_inline (vlib_main_t * vm,
if (VLIB_TX == dir)
h0 += vnet_buffer (b[0])->ip.save_rewrite_length;
fib_index0 =
urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index;
if (AF_IP4 == af)
{
const ip4_header_t *ip0;
fib_index0 = ip4_main.fib_index_by_sw_if_index
[vnet_buffer (b[0])->sw_if_index[dir]];
ip0 = (ip4_header_t *) h0;
lb_index0 = ip4_fib_forwarding_lookup (fib_index0,
@@ -275,8 +271,6 @@ urpf_inline (vlib_main_t * vm,
const ip6_header_t *ip0;
ip0 = (ip6_header_t *) h0;
fib_index0 = ip6_main.fib_index_by_sw_if_index
[vnet_buffer (b[0])->sw_if_index[dir]];
lb_index0 = ip6_fib_table_fwding_lookup (fib_index0,
&ip0->src_address);