summaryrefslogtreecommitdiffstats
path: root/src/plugins/urpf/urpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/urpf/urpf.c')
-rw-r--r--src/plugins/urpf/urpf.c111
1 files changed, 97 insertions, 14 deletions
diff --git a/src/plugins/urpf/urpf.c b/src/plugins/urpf/urpf.c
index 6cf7cda8744..3c3b33c769c 100644
--- a/src/plugins/urpf/urpf.c
+++ b/src/plugins/urpf/urpf.c
@@ -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,35 +96,106 @@ 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 */
+ 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;
+ }
+ }
+}
- urpf_cfgs[af][dir][sw_if_index] = mode;
+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* */