diff options
Diffstat (limited to 'src/plugins/urpf')
-rw-r--r-- | src/plugins/urpf/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/plugins/urpf/ip4_urpf.c | 2 | ||||
-rw-r--r-- | src/plugins/urpf/ip6_urpf.c | 2 | ||||
-rw-r--r-- | src/plugins/urpf/urpf.api | 45 | ||||
-rw-r--r-- | src/plugins/urpf/urpf.c | 150 | ||||
-rw-r--r-- | src/plugins/urpf/urpf.h | 31 | ||||
-rw-r--r-- | src/plugins/urpf/urpf_api.c | 110 | ||||
-rw-r--r-- | src/plugins/urpf/urpf_dp.h | 343 |
8 files changed, 478 insertions, 209 deletions
diff --git a/src/plugins/urpf/CMakeLists.txt b/src/plugins/urpf/CMakeLists.txt index 2f44e3b2344..f665d30b0bb 100644 --- a/src/plugins/urpf/CMakeLists.txt +++ b/src/plugins/urpf/CMakeLists.txt @@ -22,6 +22,10 @@ add_vpp_plugin(urpf ip4_urpf.c ip6_urpf.c + INSTALL_HEADERS + urpf_dp.h + urpf.h + API_FILES urpf.api ) diff --git a/src/plugins/urpf/ip4_urpf.c b/src/plugins/urpf/ip4_urpf.c index 1d329029478..7cbf81c50c3 100644 --- a/src/plugins/urpf/ip4_urpf.c +++ b/src/plugins/urpf/ip4_urpf.c @@ -74,7 +74,6 @@ VLIB_NODE_FN (ip4_tx_urpf_strict) (vlib_main_t * vm, return (urpf_inline (vm, node, frame, AF_IP4, VLIB_TX, URPF_MODE_STRICT)); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip4_rx_urpf_loose) = { .name = "ip4-rx-urpf-loose", .vector_size = sizeof (u32), @@ -160,7 +159,6 @@ VNET_FEATURE_INIT (ip4_tx_urpf_strict_feat, static) = .arc_name = "ip4-output", .node_name = "ip4-tx-urpf-strict", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/urpf/ip6_urpf.c b/src/plugins/urpf/ip6_urpf.c index 48d991573b5..d278289b5e2 100644 --- a/src/plugins/urpf/ip6_urpf.c +++ b/src/plugins/urpf/ip6_urpf.c @@ -74,7 +74,6 @@ VLIB_NODE_FN (ip6_tx_urpf_strict) (vlib_main_t * vm, return (urpf_inline (vm, node, frame, AF_IP6, VLIB_TX, URPF_MODE_STRICT)); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_rx_urpf_loose) = { .name = "ip6-rx-urpf-loose", .vector_size = sizeof (u32), @@ -160,7 +159,6 @@ VNET_FEATURE_INIT (ip6_tx_urpf_strict_feat, static) = .arc_name = "ip6-output", .node_name = "ip6-tx-urpf-strict", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/urpf/urpf.api b/src/plugins/urpf/urpf.api index 944db08cc94..a4e897afd17 100644 --- a/src/plugins/urpf/urpf.api +++ b/src/plugins/urpf/urpf.api @@ -50,6 +50,51 @@ 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]; +}; + +/** @brief Dump uRPF enabled interface(s) in zero or more urpf_interface_details replies + @param client_index - opaque cookie to identify the sender + @param sw_if_index - sw_if_index of a specific interface, or -1 (default) + to return all uRPF enabled interfaces +*/ +define urpf_interface_dump +{ + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index [default=0xffffffff]; +}; + +/** @brief uRPF enabled interface details +*/ +define urpf_interface_details +{ + u32 context; + vl_api_interface_index_t sw_if_index; + bool is_input; + vl_api_urpf_mode_t mode; + vl_api_address_family_t af; + u32 table_id; +}; + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/urpf/urpf.c b/src/plugins/urpf/urpf.c index 7e1986a4250..1e7d6c0fb91 100644 --- a/src/plugins/urpf/urpf.c +++ b/src/plugins/urpf/urpf.c @@ -17,7 +17,6 @@ #include <vnet/fib/fib_table.h> -/* *INDENT-OFF* */ static const char *urpf_feat_arcs[N_AF][VLIB_N_DIR] = { [AF_IP4] = { @@ -53,15 +52,25 @@ static const char *urpf_feats[N_AF][VLIB_N_DIR][URPF_N_MODES] = }, }, }; -/* *INDENT-ON* */ /** * 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) +format_urpf_trace (u8 *s, va_list *va) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *); + urpf_trace_t *t = va_arg (*va, urpf_trace_t *); + + return format (s, "uRPF:%d fib:%d", t->urpf, t->fib_index); +} + +__clib_export u8 * +format_urpf_mode (u8 *s, va_list *a) { urpf_mode_t mode = va_arg (*a, int); @@ -77,8 +86,8 @@ format_urpf_mode (u8 * s, va_list * a) return (format (s, "unknown")); } -static uword -unformat_urpf_mode (unformat_input_t * input, va_list * args) +__clib_export uword +unformat_urpf_mode (unformat_input_t *input, va_list *args) { urpf_mode_t *mode = va_arg (*args, urpf_mode_t *); @@ -95,35 +104,115 @@ 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) +__clib_export int +urpf_feature_enable_disable (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, u32 sw_if_index, int enable) { - urpf_mode_t old; + return vnet_feature_enable_disable (urpf_feat_arcs[af][dir], + urpf_feats[af][dir][mode], sw_if_index, + enable, 0, 0); +} - vec_validate_init_empty (urpf_cfgs[af][dir], sw_if_index, URPF_MODE_OFF); +__clib_export int +urpf_update (urpf_mode_t mode, u32 sw_if_index, ip_address_family_t af, + vlib_dir_t dir, u32 table_id) +{ + 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; + + 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 +223,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 +241,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 +261,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); @@ -196,12 +295,12 @@ done: * * Example of graph node after range checking is enabled: * @cliexstart{show vlib graph ip4-rx-urpf-loose} - * Name Next Previous - * ip4-rx-urpf-loose ip4-drop [0] ip4-input-no-checksum - * ip4-source-and-port-range- ip4-input + * Name Next Previous + * ip4-rx-urpf-loose ip4-drop [0] ip4-input-no-checksum + * ip4-source-and-port-range- ip4-input * @cliexend * - * Example of how to display the feature enabed on an interface: + * Example of how to display the feature enabled on an interface: * @cliexstart{show ip interface features GigabitEthernet2/0/0} * IP feature paths configured on GigabitEthernet2/0/0... * @@ -229,13 +328,12 @@ done: * @cliexcmd{set urpf ip4 off GigabitEthernet2/0/0} * @endparblock ?*/ -/* *INDENT-OFF* */ 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* */ static clib_error_t * urpf_cli_accept (vlib_main_t * vm, @@ -306,13 +404,11 @@ done: * loose RPF tests: * @cliexcmd{set urpf-accept table 7 10.0.0.0/8 add} ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (urpf_accept_command, static) = { .path = "set urpf-accept", .function = urpf_cli_accept, .short_help = "urpf-accept [table <table-id>] [add|del] <PREFIX>", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/urpf/urpf.h b/src/plugins/urpf/urpf.h index 941cda25f4b..a40a25df16b 100644 --- a/src/plugins/urpf/urpf.h +++ b/src/plugins/urpf/urpf.h @@ -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_ { @@ -32,12 +32,27 @@ typedef enum urpf_mode_t_ #define URPF_N_MODES (URPF_MODE_STRICT+1) -extern u8 *format_urpf_mode (u8 * s, va_list * a); +typedef struct +{ + index_t urpf; + u32 fib_index; +} urpf_trace_t; + +u8 *format_urpf_trace (u8 *s, va_list *va); +u8 *format_urpf_mode (u8 *s, va_list *a); +uword unformat_urpf_mode (unformat_input_t *input, va_list *args); + +typedef struct +{ + urpf_mode_t mode; + u32 fib_index; + u8 fib_index_is_custom; +} urpf_data_t; -extern void urpf_update (urpf_mode_t mode, - u32 sw_if_index, - ip_address_family_t af, vlib_dir_t dir); +extern urpf_data_t *urpf_cfgs[N_AF][VLIB_N_DIR]; +int urpf_update (urpf_mode_t mode, u32 sw_if_index, ip_address_family_t af, + vlib_dir_t dir, u32 table_id); #endif diff --git a/src/plugins/urpf/urpf_api.c b/src/plugins/urpf/urpf_api.c index ad060399347..3d0f4b4e8d4 100644 --- a/src/plugins/urpf/urpf_api.c +++ b/src/plugins/urpf/urpf_api.c @@ -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,85 @@ 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); +} + +static void +send_urpf_interface_details (vpe_api_main_t *am, vl_api_registration_t *reg, + u32 context, const u32 sw_if_index, + const urpf_data_t *ud, + const ip_address_family_t af, + const vlib_dir_t dir) +{ + vl_api_urpf_interface_details_t *mp; + + mp = vl_msg_api_alloc_zero (sizeof (*mp)); + mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_URPF_INTERFACE_DETAILS); + mp->context = context; + + mp->sw_if_index = htonl (sw_if_index); + mp->table_id = htonl (fib_table_get_table_id ( + ud->fib_index, (af == AF_IP4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6))); + mp->af = (vl_api_address_family_t) af; + mp->mode = (vl_api_urpf_mode_t) ud->mode; + mp->is_input = (dir == VLIB_RX); + + vl_api_send_msg (reg, (u8 *) mp); +} + +static void +send_urpf_interface (vpe_api_main_t *am, vl_api_registration_t *reg, + u32 context, const u32 sw_if_index) +{ + urpf_data_t *ud; + vlib_dir_t dir; + ip_address_family_t af; + + FOR_EACH_IP_ADDRESS_FAMILY (af) + FOREACH_VLIB_DIR (dir) + if (sw_if_index < vec_len (urpf_cfgs[af][dir])) + { + ud = &urpf_cfgs[af][dir][sw_if_index]; + if (ud->mode || ud->fib_index_is_custom) + send_urpf_interface_details (am, reg, context, sw_if_index, ud, af, + dir); + } +} + +static void +vl_api_urpf_interface_dump_t_handler (vl_api_urpf_interface_dump_t *mp) +{ + vpe_api_main_t *am = &vpe_api_main; + vl_api_registration_t *reg; + vnet_interface_main_t *im = &vnet_main.interface_main; + vnet_sw_interface_t *si; + u32 sw_if_index = ~0; + int __attribute__ ((unused)) rv = 0; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + sw_if_index = ntohl (mp->sw_if_index); + + if (sw_if_index == ~0) + { + pool_foreach (si, im->sw_interfaces) + { + send_urpf_interface (am, reg, mp->context, si->sw_if_index); + } + return; + } + VALIDATE_SW_IF_INDEX (mp); + send_urpf_interface (am, reg, mp->context, sw_if_index); + BAD_SW_IF_INDEX_LABEL; } #include <urpf/urpf.api.c> @@ -92,12 +194,10 @@ urpf_api_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (urpf_api_init); -/* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Unicast Reverse Path Forwarding (uRPF)", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/urpf/urpf_dp.h b/src/plugins/urpf/urpf_dp.h index bfe1f659171..b17fed7e04b 100644 --- a/src/plugins/urpf/urpf_dp.h +++ b/src/plugins/urpf/urpf_dp.h @@ -53,22 +53,6 @@ * * This file contains the interface unicast source check. */ -typedef struct -{ - index_t urpf; -} urpf_trace_t; - -static u8 * -format_urpf_trace (u8 * s, va_list * va) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *); - urpf_trace_t *t = va_arg (*va, urpf_trace_t *); - - s = format (s, "uRPF:%d", t->urpf); - - return s; -} #define foreach_urpf_error \ _(DROP, "uRPF Drop") \ @@ -87,10 +71,157 @@ typedef enum URPF_N_NEXT, } urpf_next_t; +static_always_inline u32 +urpf_get_fib_index (vlib_buffer_t *b, ip_address_family_t af, vlib_dir_t dir) +{ + u32 sw_if_index = vnet_buffer (b)->sw_if_index[dir]; + return vec_elt (urpf_cfgs[af][dir], sw_if_index).fib_index; +} + +static_always_inline void +urpf_perform_check_x1 (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, vlib_buffer_t *b, const u8 *h, + u32 fib_index, load_balance_t **lb, u32 *pass) +{ + load_balance_t *llb; + u32 lpass; + u32 lb_index; + + ASSERT (fib_index != ~0); + + if (AF_IP4 == af) + { + const ip4_header_t *ip; + + ip = (ip4_header_t *) h; + + lb_index = ip4_fib_forwarding_lookup (fib_index, &ip->src_address); + + /* Pass multicast. */ + lpass = (ip4_address_is_multicast (&ip->src_address) || + ip4_address_is_global_broadcast (&ip->src_address)); + } + else + { + const ip6_header_t *ip; + + ip = (ip6_header_t *) h; + + lb_index = ip6_fib_table_fwding_lookup (fib_index, &ip->src_address); + lpass = ip6_address_is_multicast (&ip->src_address); + } + + llb = load_balance_get (lb_index); + + if (URPF_MODE_STRICT == mode) + { + int res; + + res = fib_urpf_check (llb->lb_urpf, vnet_buffer (b)->sw_if_index[dir]); + if (VLIB_RX == dir) + lpass |= res; + else + { + lpass |= !res && fib_urpf_check_size (llb->lb_urpf); + lpass |= b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + } + } + else + lpass |= fib_urpf_check_size (llb->lb_urpf); + + *lb = llb; + *pass = lpass; +} + +static_always_inline void +urpf_perform_check_x2 (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, vlib_buffer_t *b0, vlib_buffer_t *b1, + const u8 *h0, const u8 *h1, u32 fib_index0, + u32 fib_index1, load_balance_t **lb0, + load_balance_t **lb1, u32 *pass0, u32 *pass1) +{ + load_balance_t *llb0, *llb1; + u32 lpass0, lpass1; + u32 lb_index0, lb_index1; + + ASSERT (fib_index0 != ~0); + ASSERT (fib_index1 != ~0); + + if (AF_IP4 == af) + { + const ip4_header_t *ip0, *ip1; + + ip0 = (ip4_header_t *) h0; + ip1 = (ip4_header_t *) h1; + + ip4_fib_forwarding_lookup_x2 (fib_index0, fib_index1, &ip0->src_address, + &ip1->src_address, &lb_index0, &lb_index1); + /* Pass multicast. */ + lpass0 = (ip4_address_is_multicast (&ip0->src_address) || + ip4_address_is_global_broadcast (&ip0->src_address)); + lpass1 = (ip4_address_is_multicast (&ip1->src_address) || + ip4_address_is_global_broadcast (&ip1->src_address)); + } + else + { + const ip6_header_t *ip0, *ip1; + + ip0 = (ip6_header_t *) h0; + ip1 = (ip6_header_t *) h1; + + lb_index0 = ip6_fib_table_fwding_lookup (fib_index0, &ip0->src_address); + lb_index1 = ip6_fib_table_fwding_lookup (fib_index1, &ip1->src_address); + lpass0 = ip6_address_is_multicast (&ip0->src_address); + lpass1 = ip6_address_is_multicast (&ip1->src_address); + } + + llb0 = load_balance_get (lb_index0); + llb1 = load_balance_get (lb_index1); + + if (URPF_MODE_STRICT == mode) + { + /* for RX the check is: would this source adddress be + * forwarded out of the interface on which it was recieved, + * if yes allow. For TX it's; would this source address be + * forwarded out of the interface through which it is being + * sent, if yes drop. + */ + int res0, res1; + + res0 = + fib_urpf_check (llb0->lb_urpf, vnet_buffer (b0)->sw_if_index[dir]); + res1 = + fib_urpf_check (llb1->lb_urpf, vnet_buffer (b1)->sw_if_index[dir]); + + if (VLIB_RX == dir) + { + lpass0 |= res0; + lpass1 |= res1; + } + else + { + lpass0 |= !res0 && fib_urpf_check_size (llb0->lb_urpf); + lpass1 |= !res1 && fib_urpf_check_size (llb1->lb_urpf); + + /* allow locally generated */ + lpass0 |= b0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + lpass1 |= b1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + } + } + else + { + lpass0 |= fib_urpf_check_size (llb0->lb_urpf); + lpass1 |= fib_urpf_check_size (llb1->lb_urpf); + } + + *lb0 = llb0; + *lb1 = llb1; + *pass0 = lpass0; + *pass1 = lpass1; +} + static_always_inline uword -urpf_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, +urpf_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip_address_family_t af, vlib_dir_t dir, urpf_mode_t mode) { vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; @@ -106,8 +237,8 @@ urpf_inline (vlib_main_t * vm, while (n_left >= 4) { - u32 pass0, lb_index0, pass1, lb_index1; - const load_balance_t *lb0, *lb1; + u32 pass0, pass1; + load_balance_t *lb0 = 0, *lb1 = 0; u32 fib_index0, fib_index1; const u8 *h0, *h1; @@ -121,92 +252,32 @@ urpf_inline (vlib_main_t * vm, h0 = (u8 *) vlib_buffer_get_current (b[0]); h1 = (u8 *) vlib_buffer_get_current (b[1]); - if (VLIB_TX == dir) { h0 += vnet_buffer (b[0])->ip.save_rewrite_length; h1 += vnet_buffer (b[1])->ip.save_rewrite_length; } - if (AF_IP4 == af) - { - const ip4_header_t *ip0, *ip1; - - 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, - &ip1->src_address, - &lb_index0, &lb_index1); - /* Pass multicast. */ - pass0 = (ip4_address_is_multicast (&ip0->src_address) || - ip4_address_is_global_broadcast (&ip0->src_address)); - pass1 = (ip4_address_is_multicast (&ip1->src_address) || - ip4_address_is_global_broadcast (&ip1->src_address)); - } - else - { - 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; - - lb_index0 = ip6_fib_table_fwding_lookup (fib_index0, - &ip0->src_address); - lb_index1 = ip6_fib_table_fwding_lookup (fib_index1, - &ip1->src_address); - pass0 = ip6_address_is_multicast (&ip0->src_address); - pass1 = ip6_address_is_multicast (&ip1->src_address); - } - - lb0 = load_balance_get (lb_index0); - lb1 = load_balance_get (lb_index1); + fib_index0 = urpf_get_fib_index (b[0], af, dir); + fib_index1 = urpf_get_fib_index (b[1], af, dir); + urpf_perform_check_x2 (af, dir, mode, b[0], b[1], h0, h1, fib_index0, + fib_index1, &lb0, &lb1, &pass0, &pass1); - if (URPF_MODE_STRICT == mode) + if (b[0]->flags & VLIB_BUFFER_IS_TRACED) { - /* for RX the check is: would this source adddress be forwarded - * out of the interface on which it was recieved, if yes allow. - * For TX it's; would this source address be forwarded out of the - * interface through which it is being sent, if yes drop. - */ - int res0, res1; - - res0 = fib_urpf_check (lb0->lb_urpf, - vnet_buffer (b[0])->sw_if_index[dir]); - res1 = fib_urpf_check (lb1->lb_urpf, - vnet_buffer (b[1])->sw_if_index[dir]); - - if (VLIB_RX == dir) - { - pass0 |= res0; - pass1 |= res1; - } - else - { - pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf); - pass1 |= !res1 && fib_urpf_check_size (lb1->lb_urpf); - - /* allow locally generated */ - pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - pass1 |= b[1]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + urpf_trace_t *t; + + t = vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->urpf = lb0 ? lb0->lb_urpf : ~0; + t->fib_index = fib_index0; } - else + if (b[1]->flags & VLIB_BUFFER_IS_TRACED) { - pass0 |= fib_urpf_check_size (lb0->lb_urpf); - pass1 |= fib_urpf_check_size (lb1->lb_urpf); + urpf_trace_t *t; + + t = vlib_add_trace (vm, node, b[1], sizeof (*t)); + t->urpf = lb1 ? lb1->lb_urpf : ~0; + t->fib_index = fib_index1; } if (PREDICT_TRUE (pass0)) @@ -223,22 +294,6 @@ urpf_inline (vlib_main_t * vm, next[1] = URPF_NEXT_DROP; b[1]->error = node->errors[URPF_ERROR_DROP]; } - - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[0], sizeof (*t)); - t->urpf = lb0->lb_urpf; - } - if (b[1]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[1], sizeof (*t)); - t->urpf = lb1->lb_urpf; - } - b += 2; next += 2; n_left -= 2; @@ -246,8 +301,8 @@ urpf_inline (vlib_main_t * vm, while (n_left) { - u32 pass0, lb_index0, fib_index0; - const load_balance_t *lb0; + u32 pass0, fib_index0; + load_balance_t *lb0 = 0; const u8 *h0; h0 = (u8 *) vlib_buffer_get_current (b[0]); @@ -255,52 +310,18 @@ urpf_inline (vlib_main_t * vm, if (VLIB_TX == dir) h0 += vnet_buffer (b[0])->ip.save_rewrite_length; - 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; + fib_index0 = urpf_get_fib_index (b[0], af, dir); + urpf_perform_check_x1 (af, dir, mode, b[0], h0, fib_index0, &lb0, + &pass0); - lb_index0 = ip4_fib_forwarding_lookup (fib_index0, - &ip0->src_address); - - /* Pass multicast. */ - pass0 = (ip4_address_is_multicast (&ip0->src_address) || - ip4_address_is_global_broadcast (&ip0->src_address)); - } - else + if (b[0]->flags & VLIB_BUFFER_IS_TRACED) { - 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); - pass0 = ip6_address_is_multicast (&ip0->src_address); - } - - lb0 = load_balance_get (lb_index0); + urpf_trace_t *t; - if (URPF_MODE_STRICT == mode) - { - int res0; - - res0 = fib_urpf_check (lb0->lb_urpf, - vnet_buffer (b[0])->sw_if_index[dir]); - if (VLIB_RX == dir) - pass0 |= res0; - else - { - pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf); - pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + t = vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->urpf = lb0 ? lb0->lb_urpf : ~0; + t->fib_index = fib_index0; } - else - pass0 |= fib_urpf_check_size (lb0->lb_urpf); if (PREDICT_TRUE (pass0)) vnet_feature_next_u16 (&next[0], b[0]); @@ -309,14 +330,6 @@ urpf_inline (vlib_main_t * vm, next[0] = URPF_NEXT_DROP; b[0]->error = node->errors[URPF_ERROR_DROP]; } - - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[0], sizeof (*t)); - t->urpf = lb0->lb_urpf; - } b++; next++; n_left--; |