summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/nat')
-rw-r--r--src/plugins/nat/nat44-ed/nat44_ed.c153
-rw-r--r--src/plugins/nat/nat44-ed/nat44_ed.h3
-rw-r--r--src/plugins/nat/nat44-ed/nat44_ed_cli.c11
-rw-r--r--src/plugins/nat/nat44-ed/nat44_ed_in2out.c180
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;