diff options
Diffstat (limited to 'src/plugins/nat')
-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; |