diff options
author | Filip Varga <fivarga@cisco.com> | 2021-10-04 14:36:05 +0200 |
---|---|---|
committer | Ole Tr�an <otroan@employees.org> | 2022-01-04 12:03:17 +0000 |
commit | aed42948510a94922566fa1a4bfb6eec281e5dee (patch) | |
tree | 5c6eb192efc72124884af13e9ccf53e26e1cf0e3 | |
parent | fa74a64def2132fb0c81e981547ac65888751aa9 (diff) |
nat: nat44-ed pool address allocation improvement
This patch improves algorithm responsible for choosing nat pool address
during dynamic session creation.
Patch synchronizes nat pool address attributes with vpp interfaces doing
so gives nat option to determine correct nat pool address when creating
dynamic session.
Improvements:
* match dst address subnet and src fib with nat pool address
* for output-feature also fallback match of tx_sw_if_index with nat
pool address
Type: improvement
Change-Id: I594638bc76fc1153f582add376838b4b72ff573a
Signed-off-by: Filip Varga <fivarga@cisco.com>
-rw-r--r-- | src/plugins/nat/nat44-ed/nat44_ed.c | 153 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ed/nat44_ed.h | 3 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ed/nat44_ed_cli.c | 11 | ||||
-rw-r--r-- | src/plugins/nat/nat44-ed/nat44_ed_in2out.c | 180 |
4 files changed, 289 insertions, 58 deletions
diff --git a/src/plugins/nat/nat44-ed/nat44_ed.c b/src/plugins/nat/nat44-ed/nat44_ed.c index 56c5ab2e32f..7907d8ffa6b 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.c +++ b/src/plugins/nat/nat44-ed/nat44_ed.c @@ -309,6 +309,112 @@ is_snat_address_used_in_static_mapping (snat_main_t *sm, ip4_address_t addr) return 0; } +static ip_interface_address_t * +nat44_ed_get_ip_interface_address (u32 sw_if_index, ip4_address_t addr) +{ + snat_main_t *sm = &snat_main; + + ip_lookup_main_t *lm = &sm->ip4_main->lookup_main; + ip_interface_address_t *ia; + ip4_address_t *ip4a; + + foreach_ip_interface_address ( + lm, ia, sw_if_index, 1, ({ + ip4a = ip_interface_address_get_address (lm, ia); + nat_log_debug ("sw_if_idx: %u addr: %U ? %U", sw_if_index, + format_ip4_address, ip4a, format_ip4_address, &addr); + if (ip4a->as_u32 == addr.as_u32) + { + return ia; + } + })); + return NULL; +} + +static int +nat44_ed_resolve_nat_addr_len (snat_address_t *ap, + snat_interface_t *interfaces) +{ + ip_interface_address_t *ia; + snat_interface_t *i; + u32 fib_index; + + pool_foreach (i, interfaces) + { + if (!nat44_ed_is_interface_outside (i)) + { + continue; + } + + fib_index = ip4_fib_table_get_index_for_sw_if_index (i->sw_if_index); + if (fib_index != ap->fib_index) + { + continue; + } + + if ((ia = nat44_ed_get_ip_interface_address (i->sw_if_index, ap->addr))) + { + ap->addr_len = ia->address_length; + ap->sw_if_index = i->sw_if_index; + ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len)) + << (32 - ap->addr_len); + + nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + return 0; + } + } + return 1; +} + +static void +nat44_ed_update_outside_if_addresses (snat_address_t *ap) +{ + snat_main_t *sm = &snat_main; + + if (!nat44_ed_resolve_nat_addr_len (ap, sm->interfaces)) + { + return; + } + + if (!nat44_ed_resolve_nat_addr_len (ap, sm->output_feature_interfaces)) + { + return; + } +} + +static void +nat44_ed_bind_if_addr_to_nat_addr (u32 sw_if_index) +{ + snat_main_t *sm = &snat_main; + ip_interface_address_t *ia; + snat_address_t *ap; + + u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + + vec_foreach (ap, sm->addresses) + { + if (fib_index != ap->fib_index) + { + continue; + } + + if ((ia = nat44_ed_get_ip_interface_address (sw_if_index, ap->addr))) + { + ap->addr_len = ia->address_length; + ap->sw_if_index = sw_if_index; + ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len)) + << (32 - ap->addr_len); + + nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + return; + } + } +} + static void nat44_ed_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, int is_add) @@ -424,6 +530,7 @@ nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) vec_add2 (sm->addresses, ap, 1); } + ap->addr_len = ~0; ap->fib_index = ~0; ap->addr = *addr; @@ -433,12 +540,13 @@ nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); } - if (!twice_nat) - { - // if we don't have enabled interface we don't add address - // to fib - nat44_ed_add_del_addr_to_fib_foreach_out_if (addr, 1); - } + if (!twice_nat) + { + // if we don't have enabled interface we don't add address + // to fib + nat44_ed_add_del_addr_to_fib_foreach_out_if (addr, 1); + nat44_ed_update_outside_if_addresses (ap); + } return 0; } @@ -1641,6 +1749,8 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); } else { @@ -1850,6 +1960,8 @@ nat44_ed_add_output_interface (u32 sw_if_index) nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); + return 0; } @@ -3244,7 +3356,7 @@ nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque, { snat_main_t *sm = &snat_main; snat_static_map_resolve_t *rp; - snat_address_t *addresses = sm->addresses; + snat_address_t *ap, *addresses = sm->addresses; u8 twice_nat = 0; int rv, i; @@ -3259,6 +3371,33 @@ nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque, if (!is_sw_if_index_reg_for_auto_resolve ( sm->auto_add_sw_if_indices_twice_nat, sw_if_index)) { + // interface resolve + u32 fib_index = + ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + vec_foreach (ap, sm->addresses) + { + if ((fib_index == ap->fib_index) && + (address->as_u32 == ap->addr.as_u32)) + { + if (!is_delete) + { + ap->addr_len = address_length; + ap->sw_if_index = sw_if_index; + ap->net.as_u32 = (ap->addr.as_u32 >> (32 - ap->addr_len)) + << (32 - ap->addr_len); + + nat_log_debug ( + "pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + } + else + { + ap->addr_len = ~0; + } + break; + } + } return; } else diff --git a/src/plugins/nat/nat44-ed/nat44_ed.h b/src/plugins/nat/nat44-ed/nat44_ed.h index 9fb34aa45f1..d8cc0d3aece 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.h +++ b/src/plugins/nat/nat44-ed/nat44_ed.h @@ -359,7 +359,10 @@ typedef CLIB_PACKED(struct typedef struct { ip4_address_t addr; + ip4_address_t net; + u32 sw_if_index; u32 fib_index; + u32 addr_len; } snat_address_t; typedef struct diff --git a/src/plugins/nat/nat44-ed/nat44_ed_cli.c b/src/plugins/nat/nat44-ed/nat44_ed_cli.c index ba74b7dd51f..9743ce6e6ea 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_cli.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_cli.c @@ -632,10 +632,14 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, { vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); if (ap->fib_index != ~0) - vlib_cli_output (vm, " tenant VRF: %u", - fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); + vlib_cli_output ( + vm, " tenant VRF: %u", + fib_table_get (ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + + if (ap->addr_len != ~0) + vlib_cli_output (vm, " synced with interface address"); } vlib_cli_output (vm, "NAT44 twice-nat pool addresses:"); vec_foreach (ap, sm->twice_nat_addresses) @@ -646,6 +650,9 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + + if (ap->addr_len != ~0) + vlib_cli_output (vm, " synced with interface address"); } return 0; } diff --git a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c index 73dacce57e6..e93198a8079 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c @@ -201,50 +201,129 @@ nat_ed_alloc_addr_and_port_with_snat_address ( } static int -nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, +nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, + u32 tx_sw_if_index, u32 nat_proto, u32 thread_index, ip4_address_t s_addr, - u32 snat_thread_index, snat_session_t *s, - ip4_address_t *outside_addr, u16 *outside_port) + ip4_address_t d_addr, u32 snat_thread_index, + snat_session_t *s, ip4_address_t *outside_addr, + u16 *outside_port) { - int i; - snat_address_t *a, *ga = 0; - if (vec_len (sm->addresses) > 0) { u32 s_addr_offset = s_addr.as_u32 % vec_len (sm->addresses); + snat_address_t *a, *ja = 0, *ra = 0, *ba = 0; + int i; - for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) + // output feature + if (tx_sw_if_index != ~0) { - a = sm->addresses + i; - if (a->fib_index == rx_fib_index) + for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) { - return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, - snat_thread_index, s, outside_addr, outside_port); + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if (a->sw_if_index == tx_sw_if_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, + sm->port_per_thread, snat_thread_index, s, + outside_addr, outside_port); + } + ra = a; + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } - else if (a->fib_index == ~0) + for (i = 0; i < s_addr_offset; ++i) { - ga = a; + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if (a->sw_if_index == tx_sw_if_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, + sm->port_per_thread, snat_thread_index, s, + outside_addr, outside_port); + } + ra = a; + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } - } - - for (i = 0; i < s_addr_offset; ++i) - { - a = sm->addresses + i; - if (a->fib_index == rx_fib_index) + if (ra) { return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, + sm, nat_proto, thread_index, ra, sm->port_per_thread, snat_thread_index, s, outside_addr, outside_port); } - else if (a->fib_index == ~0) + } + else + { + // frist try nat pool addresses to sw interface addreses mappings + for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) { - ga = a; + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, sm->port_per_thread, + snat_thread_index, s, outside_addr, outside_port); + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } + } + for (i = 0; i < s_addr_offset; ++i) + { + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, sm->port_per_thread, + snat_thread_index, s, outside_addr, outside_port); + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } } - if (ga) + if (ja || ba) { + a = ja ? ja : ba; return nat_ed_alloc_addr_and_port_with_snat_address ( sm, nat_proto, thread_index, a, sm->port_per_thread, snat_thread_index, s, outside_addr, outside_port); @@ -266,7 +345,6 @@ nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr) .fp_addr = {.ip4.as_u32 = addr.as_u32,} , }; - // TODO: multiple vrfs none can resolve addr vec_foreach (outside_fib, sm->outside_fibs) { fei = fib_table_lookup (outside_fib->fib_index, &pfx); @@ -307,7 +385,7 @@ nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr, static u32 slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr, ip4_address_t r_addr, u16 l_port, - u16 r_port, u8 proto, u32 rx_fib_index, + u16 r_port, u8 proto, u32 rx_fib_index, u32 tx_sw_if_index, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next, u32 thread_index, f64 now) { @@ -415,9 +493,9 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); - if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, proto, thread_index, - l_addr, tsm->snat_thread_index, s, - &outside_addr, &outside_port)) + if (nat_ed_alloc_addr_and_port ( + sm, rx_fib_index, tx_sw_if_index, proto, thread_index, l_addr, + r_addr, tsm->snat_thread_index, s, &outside_addr, &outside_port)) { nat_elog_notice (sm, "addresses exhausted"); b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; @@ -682,11 +760,11 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, /* hairpinning */ pool_foreach (i, sm->output_feature_interfaces) - { - if ((nat44_ed_is_interface_inside (i)) && - (rx_sw_if_index == i->sw_if_index)) - return 0; - } + { + if ((nat44_ed_is_interface_inside (i)) && + (rx_sw_if_index == i->sw_if_index)) + return 0; + } return 1; } @@ -696,9 +774,10 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, static inline u32 icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, icmp46_header_t *icmp, u32 sw_if_index, - u32 rx_fib_index, vlib_node_runtime_t *node, - u32 next, f64 now, u32 thread_index, - snat_session_t **s_p, int is_multi_worker) + u32 tx_sw_if_index, u32 rx_fib_index, + vlib_node_runtime_t *node, u32 next, f64 now, + u32 thread_index, snat_session_t **s_p, + int is_multi_worker) { vlib_main_t *vm = vlib_get_main (); u16 checksum; @@ -717,11 +796,11 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, return NAT_NEXT_DROP; } - if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0) + if (tx_sw_if_index != ~0) { if (PREDICT_FALSE (nat44_ed_not_translate_output_feature ( sm, b, ip, lookup_sport, lookup_dport, thread_index, sw_if_index, - vnet_buffer (b)->sw_if_index[VLIB_TX], now, is_multi_worker))) + tx_sw_if_index, now, is_multi_worker))) { return next; } @@ -742,9 +821,10 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, return NAT_NEXT_DROP; } - next = slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, - lookup_sport, lookup_dport, ip->protocol, rx_fib_index, - &s, node, next, thread_index, vlib_time_now (vm)); + next = + slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, lookup_sport, + lookup_dport, ip->protocol, rx_fib_index, tx_sw_if_index, &s, + node, next, thread_index, vlib_time_now (vm)); if (NAT_NEXT_DROP == next) goto out; @@ -1316,8 +1396,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) { next[0] = icmp_in2out_ed_slow_path ( - sm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node, next[0], - now, thread_index, &s0, is_multi_worker); + sm, b0, ip0, icmp0, rx_sw_if_index0, tx_sw_if_index0, + rx_fib_index0, node, next[0], now, thread_index, &s0, + is_multi_worker); if (NAT_NEXT_DROP != next[0] && s0 && NAT_ED_TRNSL_ERR_SUCCESS != (translation_error = nat_6t_flow_buf_translate_i2o ( @@ -1383,11 +1464,12 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, goto trace0; } - next[0] = slow_path_ed ( - vm, sm, b0, ip0->src_address, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port, ip0->protocol, - rx_fib_index0, &s0, node, next[0], thread_index, now); + next[0] = + slow_path_ed (vm, sm, b0, ip0->src_address, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + ip0->protocol, rx_fib_index0, tx_sw_if_index0, &s0, + node, next[0], thread_index, now); if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP)) goto trace0; |