X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat44-ed%2Fnat44_ed.c;h=3b1c9a2c89f0866864d65c169ee8f533d19bda18;hb=691c630b7;hp=b1917f3b36c56637beb89f6237a458f02f5c4668;hpb=ff334db797c9cede308367ef1c27bd8dfce0baf4;p=vpp.git diff --git a/src/plugins/nat/nat44-ed/nat44_ed.c b/src/plugins/nat/nat44-ed/nat44_ed.c index b1917f3b36c..3b1c9a2c89f 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.c +++ b/src/plugins/nat/nat44-ed/nat44_ed.c @@ -1,6 +1,4 @@ /* - * snat.c - simple nat plugin - * * Copyright (c) 2016 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +36,7 @@ #include #include -#include +#include snat_main_t snat_main; @@ -78,7 +76,6 @@ static_always_inline void nat_validate_interface_counters (snat_main_t *sm, } \ while (0) -/* Hook up input features */ VNET_FEATURE_INIT (nat_pre_in2out, static) = { .arc_name = "ip4-unicast", .node_name = "nat-pre-in2out", @@ -92,6 +89,18 @@ VNET_FEATURE_INIT (nat_pre_out2in, static) = { "ip4-dhcp-client-detect", "ip4-sv-reassembly-feature"), }; +VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = { + .arc_name = "ip4-unicast", + .node_name = "nat44-ed-classify", + .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", + "ip4-sv-reassembly-feature"), +}; +VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = { + .arc_name = "ip4-unicast", + .node_name = "nat44-handoff-classify", + .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", + "ip4-sv-reassembly-feature"), +}; VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = { .arc_name = "ip4-unicast", .node_name = "nat44-in2out-worker-handoff", @@ -103,17 +112,6 @@ VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = { .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", "ip4-dhcp-client-detect"), }; -VNET_FEATURE_INIT (ip4_snat_in2out, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-in2out", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-out2in", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", - "ip4-dhcp-client-detect"), -}; VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = { .arc_name = "ip4-unicast", .node_name = "nat44-ed-in2out", @@ -125,32 +123,9 @@ VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = { .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", "ip4-dhcp-client-detect"), }; -VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-ed-classify", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-handoff-classify", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-in2out-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-out2in-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", - "ip4-dhcp-client-detect"), -}; - -/* Hook up output features */ -VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = { +VNET_FEATURE_INIT (nat_pre_in2out_output, static) = { .arc_name = "ip4-output", - .node_name = "nat44-in2out-output", + .node_name = "nat-pre-in2out-output", .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), }; @@ -160,12 +135,6 @@ VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = { .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), }; -VNET_FEATURE_INIT (nat_pre_in2out_output, static) = { - .arc_name = "ip4-output", - .node_name = "nat-pre-in2out-output", - .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), - .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), -}; VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = { .arc_name = "ip4-output", .node_name = "nat44-ed-in2out-output", @@ -179,33 +148,20 @@ VLIB_PLUGIN_REGISTER () = { }; static void nat44_ed_db_init (u32 translations, u32 translation_buckets); - -static void nat44_ed_db_free (); +static void nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm); + +static int nat44_ed_add_static_mapping_internal ( + ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, + ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag); +static int nat44_ed_del_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, + u16 l_port, u16 e_port, + ip_protocol_t proto, + u32 vrf_id, u32 flags); u32 nat_calc_bihash_buckets (u32 n_elts); -u8 * -format_ed_session_kvp (u8 * s, va_list * args) -{ - clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *); - - u8 proto; - u16 r_port, l_port; - ip4_address_t l_addr, r_addr; - u32 fib_index; - - split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port); - s = format (s, - "local %U:%d remote %U:%d proto %U fib %d thread-index %u " - "session-index %u", - format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port), - format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port), - format_ip_protocol, proto, fib_index, - ed_value_get_thread_index (v), ed_value_get_session_index (v)); - - return s; -} - static_always_inline int nat44_ed_sm_i2o_add (snat_main_t *sm, snat_static_mapping_t *m, ip4_address_t addr, u16 port, u32 fib_index, u8 proto) @@ -283,60 +239,197 @@ nat44_ed_free_session_data (snat_main_t *sm, snat_session_t *s, } } +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 -is_snat_address_used_in_static_mapping (snat_main_t *sm, ip4_address_t addr) +nat44_ed_resolve_nat_addr_len (snat_address_t *ap, + snat_interface_t *interfaces) { - snat_static_mapping_t *m; - pool_foreach (m, sm->static_mappings) + ip_interface_address_t *ia; + snat_interface_t *i; + u32 fib_index; + + pool_foreach (i, interfaces) { - if (is_sm_addr_only (m->flags) || is_sm_out2in_only (m->flags) || - is_sm_identity_nat (m->flags)) + if (!nat44_ed_is_interface_outside (i)) { continue; } - if (m->external_addr.as_u32 == addr.as_u32) + + fib_index = ip4_fib_table_get_index_for_sw_if_index (i->sw_if_index); + if (fib_index != ap->fib_index) { - return 1; + 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 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_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, - int is_add) +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_always_inline snat_fib_entry_reg_t * +nat44_ed_get_fib_entry_reg (ip4_address_t addr, u32 sw_if_index, int *out_idx) +{ + snat_main_t *sm = &snat_main; + snat_fib_entry_reg_t *fe; + int i; + + for (i = 0; i < vec_len (sm->fib_entry_reg); i++) + { + fe = sm->fib_entry_reg + i; + if ((addr.as_u32 == fe->addr.as_u32) && (sw_if_index == fe->sw_if_index)) + { + if (out_idx) + { + *out_idx = i; + } + return fe; + } + } + return NULL; +} + +static void +nat44_ed_add_fib_entry_reg (ip4_address_t addr, u32 sw_if_index) { // Add the external NAT address to the FIB as receive entries. This ensures // that VPP will reply to ARP for this address and we don't need to enable // proxy ARP on the outside interface. - snat_main_t *sm = &snat_main; - fib_prefix_t prefix = { - .fp_len = p_len, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4.as_u32 = addr->as_u32, - }, - }; - u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + snat_fib_entry_reg_t *fe; - if (is_add) + if (!(fe = nat44_ed_get_fib_entry_reg (addr, sw_if_index, 0))) { + fib_prefix_t prefix = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = { + .ip4.as_u32 = addr.as_u32, + }, + }; + u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); fib_table_entry_update_one_path (fib_index, &prefix, sm->fib_src_low, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_EXCLUSIVE), DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); + + vec_add2 (sm->fib_entry_reg, fe, 1); + clib_memset (fe, 0, sizeof (*fe)); + fe->addr.as_u32 = addr.as_u32; + fe->sw_if_index = sw_if_index; } - else + fe->count++; +} + +static void +nat44_ed_del_fib_entry_reg (ip4_address_t addr, u32 sw_if_index) +{ + snat_main_t *sm = &snat_main; + snat_fib_entry_reg_t *fe; + int i; + + if ((fe = nat44_ed_get_fib_entry_reg (addr, sw_if_index, &i))) { - fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low); + fe->count--; + if (0 == fe->count) + { + fib_prefix_t prefix = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = { + .ip4.as_u32 = addr.as_u32, + }, + }; + u32 fib_index = + ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low); + vec_del1 (sm->fib_entry_reg, i); + } } } static void -nat44_ed_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add) +nat44_ed_add_del_interface_fib_reg_entries (ip4_address_t addr, u8 is_add) { snat_main_t *sm = &snat_main; snat_interface_t *i; @@ -345,42 +438,66 @@ nat44_ed_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add) { if (nat44_ed_is_interface_outside (i)) { - nat44_ed_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (addr, i->sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (addr, i->sw_if_index); + } } } pool_foreach (i, sm->output_feature_interfaces) { if (nat44_ed_is_interface_outside (i)) { - nat44_ed_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (addr, i->sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (addr, i->sw_if_index); + } } } } static_always_inline void -nat44_ed_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add) +nat44_ed_add_del_nat_addr_fib_reg_entries (u32 sw_if_index, u8 is_add) { snat_main_t *sm = &snat_main; snat_address_t *ap; vec_foreach (ap, sm->addresses) { - nat44_ed_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (ap->addr, sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (ap->addr, sw_if_index); + } } } static_always_inline void -nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add) +nat44_ed_add_del_sm_fib_reg_entries (u32 sw_if_index, u8 is_add) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; pool_foreach (m, sm->static_mappings) { - if (is_sm_addr_only (m->flags) && !is_sm_identity_nat (m->flags)) + if (is_add) + { + nat44_ed_add_fib_entry_reg (m->external_addr, sw_if_index); + } + else { - nat44_ed_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, - is_add); + nat44_ed_del_fib_entry_reg (m->external_addr, sw_if_index); } } } @@ -417,6 +534,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; @@ -426,24 +544,24 @@ 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_interface_fib_reg_entries (*addr, 1); + nat44_ed_update_outside_if_addresses (ap); + } return 0; } int -nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) +nat44_ed_del_address (ip4_address_t addr, u8 twice_nat) { snat_main_t *sm = &snat_main; snat_address_t *a = 0, *addresses; snat_session_t *ses; u32 *ses_to_be_removed = 0, *ses_index; snat_main_per_thread_data_t *tsm; - snat_static_mapping_t *m; int j; addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses; @@ -462,61 +580,177 @@ nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) return VNET_API_ERROR_NO_SUCH_ENTRY; } - if (delete_sm) + // delete dynamic sessions only + vec_foreach (tsm, sm->per_thread_data) { - pool_foreach (m, sm->static_mappings) + pool_foreach (ses, tsm->sessions) { - if (m->external_addr.as_u32 == addr.as_u32) + if (ses->flags & SNAT_SESSION_FLAG_STATIC_MAPPING) + { + continue; + } + if (ses->out2in.addr.as_u32 == addr.as_u32) { - nat44_ed_del_static_mapping (m->local_addr, m->external_addr, - m->local_port, m->external_port, - ip_proto_to_nat_proto (m->proto), - m->vrf_id, ~0, m->flags); + nat44_ed_free_session_data (sm, ses, tsm - sm->per_thread_data, + 0); + vec_add1 (ses_to_be_removed, ses - tsm->sessions); } } + vec_foreach (ses_index, ses_to_be_removed) + { + ses = pool_elt_at_index (tsm->sessions, ses_index[0]); + nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); + } + vec_free (ses_to_be_removed); + } + + if (!twice_nat) + { + nat44_ed_add_del_interface_fib_reg_entries (addr, 0); + } + + if (a->fib_index != ~0) + { + fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + } + + if (!twice_nat) + { + vec_del1 (sm->addresses, j); } else { - // TODO: why ? - // check if address is used in some static mapping - if (is_snat_address_used_in_static_mapping (sm, addr)) + vec_del1 (sm->twice_nat_addresses, j); + } + + return 0; +} + +vrf_table_t * +nat44_ed_get_vrf_table (u32 table_vrf_id) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + + pool_foreach (t, sm->vrf_tables) + { + if (table_vrf_id == t->table_vrf_id) { - nat_log_err ("address used in static mapping"); - return VNET_API_ERROR_UNSPECIFIED; + return t; } } + return NULL; +} - if (a->fib_index != ~0) +vrf_route_t * +nat44_ed_get_vrf_route (vrf_table_t *t, u32 vrf_id) +{ + vrf_route_t *r; + + pool_foreach (r, t->routes) { - fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + if (vrf_id == r->vrf_id) + { + return r; + } } + return NULL; +} - // delete sessions using address - vec_foreach (tsm, sm->per_thread_data) +int +nat44_ed_add_del_vrf_table (u32 table_vrf_id, bool is_add) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + t = nat44_ed_get_vrf_table (table_vrf_id); + if (t) { - pool_foreach (ses, tsm->sessions) + if (is_add) { - if (ses->out2in.addr.as_u32 == addr.as_u32) - { - nat44_ed_free_session_data (sm, ses, tsm - sm->per_thread_data, - 0); - vec_add1 (ses_to_be_removed, ses - tsm->sessions); - } + return VNET_API_ERROR_VALUE_EXIST; } - vec_foreach (ses_index, ses_to_be_removed) + pool_foreach (r, t->routes) { - ses = pool_elt_at_index (tsm->sessions, ses_index[0]); - nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); } - vec_free (ses_to_be_removed); + fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + + pool_free (t->routes); + pool_put (sm->vrf_tables, t); + } + else + { + if (!is_add) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + pool_get (sm->vrf_tables, t); + clib_memset (t, 0, sizeof (*t)); + t->table_vrf_id = table_vrf_id; + t->table_fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, table_vrf_id, sm->fib_src_low); + } + + return 0; +} + +void +nat44_ed_del_vrf_tables () +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + pool_foreach (t, sm->vrf_tables) + { + pool_foreach (r, t->routes) + { + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + } + fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + pool_free (t->routes); + } + pool_free (sm->vrf_tables); +} + +int +nat44_ed_add_del_vrf_route (u32 table_vrf_id, u32 vrf_id, bool is_add) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + t = nat44_ed_get_vrf_table (table_vrf_id); + if (!t) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + r = nat44_ed_get_vrf_route (t, vrf_id); + if (r) + { + if (is_add) + { + return VNET_API_ERROR_VALUE_EXIST; + } + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + pool_put (t->routes, r); + } + else + { + if (!is_add) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + pool_get (t->routes, r); + clib_memset (r, 0, sizeof (*r)); + r->vrf_id = vrf_id; + r->fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); } - if (!twice_nat) - { - vec_del1 (sm->addresses, j); - nat44_ed_add_del_addr_to_fib_foreach_out_if (&addr, 0); - } - else { vec_del1 (sm->twice_nat_addresses, j); } return 0; } @@ -609,38 +843,18 @@ nat44_ed_sm_i2o_lookup (snat_main_t *sm, ip4_address_t addr, u16 port, return nat44_ed_sm_lookup (sm, &kv); } -void -nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, - ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, - u32 flags, ip4_address_t pool_addr, u8 *tag) -{ - snat_static_map_resolve_t *rp; - snat_main_t *sm = &snat_main; - - vec_add2 (sm->to_resolve, rp, 1); - rp->l_addr.as_u32 = l_addr.as_u32; - rp->l_port = l_port; - rp->e_port = e_port; - rp->sw_if_index = sw_if_index; - rp->vrf_id = vrf_id; - rp->proto = proto; - rp->flags = flags; - rp->pool_addr = pool_addr; - rp->tag = vec_dup (tag); -} - -int +static snat_static_mapping_resolve_t * nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, - u32 flags, int *out) + u32 flags, int *out_idx) { - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; snat_main_t *sm = &snat_main; int i; - for (i = 0; i < vec_len (sm->to_resolve); i++) + for (i = 0; i < vec_len (sm->sm_to_resolve); i++) { - rp = sm->to_resolve + i; + rp = sm->sm_to_resolve + i; if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id) { @@ -669,27 +883,27 @@ nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, { continue; } - if (out) + if (out_idx) { - *out = i; + *out_idx = i; } - return 0; + return rp; } } - return 1; + return NULL; } -int +static int nat44_ed_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags) { snat_main_t *sm = &snat_main; int i; - if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, &i)) + if (nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, &i)) { - vec_del1 (sm->to_resolve, i); + vec_del1 (sm->sm_to_resolve, i); return 0; } return 1; @@ -704,37 +918,87 @@ nat44_ed_validate_sm_input (u32 flags) return VNET_API_ERROR_UNSUPPORTED; } - if (is_sm_twice_nat (flags) || is_sm_self_twice_nat (flags)) + if (is_sm_twice_nat (flags) || is_sm_self_twice_nat (flags)) + { + if (is_sm_addr_only (flags) || is_sm_identity_nat (flags)) + { + return VNET_API_ERROR_UNSUPPORTED; + } + } + return 0; +} + +int +nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag) +{ + snat_static_mapping_resolve_t *rp; + snat_main_t *sm = &snat_main; + int rv; + + if (!sm->enabled) + { + return VNET_API_ERROR_UNSUPPORTED; + } + + rv = nat44_ed_validate_sm_input (flags); + if (rv != 0) { - if (is_sm_addr_only (flags) || is_sm_identity_nat (flags)) + return rv; + } + + // interface bound mapping + if (is_sm_switch_address (flags)) + { + if (nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, 0)) { - return VNET_API_ERROR_UNSUPPORTED; + return VNET_API_ERROR_VALUE_EXIST; + } + + vec_add2 (sm->sm_to_resolve, rp, 1); + rp->l_addr.as_u32 = l_addr.as_u32; + rp->l_port = l_port; + rp->e_port = e_port; + rp->sw_if_index = sw_if_index; + rp->vrf_id = vrf_id; + rp->proto = proto; + rp->flags = flags; + rp->pool_addr = pool_addr; + rp->tag = vec_dup (tag); + rp->is_resolved = 0; + + ip4_address_t *first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); + if (!first_int_addr) + { + return 0; } + + e_addr.as_u32 = first_int_addr->as_u32; + rp->is_resolved = 1; } - return 0; -} -snat_address_t * -nat44_ed_addr_lookup (snat_main_t *sm, u32 addr) -{ - for (int i = 0; i < vec_len (sm->addresses); ++i) + rv = nat44_ed_add_static_mapping_internal (l_addr, e_addr, l_port, e_port, + proto, vrf_id, sw_if_index, flags, + pool_addr, tag); + if ((0 != rv) && is_sm_switch_address (flags)) { - if (sm->addresses[i].addr.as_u32 == addr) - return &sm->addresses[i]; + nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags); } - return NULL; + + return rv; } int -nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, +nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, ip_protocol_t proto, - u32 vrf_id, u32 sw_if_index, u32 flags, - ip4_address_t pool_addr, u8 *tag) + u32 vrf_id, u32 sw_if_index, u32 flags) { snat_main_t *sm = &snat_main; - nat44_lb_addr_port_t *local; - snat_static_mapping_t *m; - u32 fib_index = ~0; int rv; if (!sm->enabled) @@ -748,27 +1012,16 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return rv; } - if (is_sm_addr_only (flags)) - { - e_port = l_port = proto = 0; - } - + // interface bound mapping if (is_sm_switch_address (flags)) { - // this mapping is interface bound - ip4_address_t *first_int_addr; - - // check if this record isn't registered for resolve - if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, 0)) + if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags)) { - return VNET_API_ERROR_VALUE_EXIST; + return VNET_API_ERROR_NO_SUCH_ENTRY; } - // register record for resolve - nat44_ed_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, pool_addr, tag); - first_int_addr = + ip4_address_t *first_int_addr = ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); if (!first_int_addr) { @@ -779,6 +1032,27 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, e_addr.as_u32 = first_int_addr->as_u32; } + return nat44_ed_del_static_mapping_internal (l_addr, e_addr, l_port, e_port, + proto, vrf_id, flags); +} + +static int +nat44_ed_add_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag) +{ + snat_main_t *sm = &snat_main; + nat44_lb_addr_port_t *local; + snat_static_mapping_t *m; + u32 fib_index = ~0; + + if (is_sm_addr_only (flags)) + { + e_port = l_port = proto = 0; + } + if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -788,13 +1062,14 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); if (m) { + // case: + // adding local identity nat record for different vrf table + if (!is_sm_identity_nat (m->flags)) { return VNET_API_ERROR_VALUE_EXIST; } - // case: - // adding local identity nat record for different vrf table pool_foreach (local, m->locals) { if (local->vrf_id == vrf_id) @@ -838,21 +1113,6 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, } } - if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || - sm->static_mapping_only)) - { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) - { - // remove resolve record - if (is_sm_switch_address (flags) && !is_sm_identity_nat (flags)) - { - nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, - vrf_id, sw_if_index, flags); - } - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - } - pool_get (sm->static_mappings, m); clib_memset (m, 0, sizeof (*m)); @@ -860,13 +1120,9 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m->local_addr = l_addr; m->external_addr = e_addr; + m->pool_addr = pool_addr; m->tag = vec_dup (tag); - if (is_sm_exact_address (flags) && is_sm_twice_nat (flags)) - { - m->pool_addr = pool_addr; - } - if (!is_sm_addr_only (flags)) { m->local_port = l_port; @@ -885,12 +1141,6 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, { m->vrf_id = vrf_id; m->fib_index = fib_index; - - // not identity && addr only - if (is_sm_addr_only (flags)) - { - nat44_ed_add_del_addr_to_fib_foreach_out_if (&e_addr, 1); - } } if (!is_sm_out2in_only (flags)) @@ -913,13 +1163,16 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, vec_add1 (m->workers, worker_index); } + nat44_ed_add_del_interface_fib_reg_entries (e_addr, 1); + return 0; } -int -nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, - u32 vrf_id, u32 sw_if_index, u32 flags) +static int +nat44_ed_del_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 flags) { snat_main_per_thread_data_t *tsm; snat_main_t *sm = &snat_main; @@ -927,47 +1180,12 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, nat44_lb_addr_port_t *local; snat_static_mapping_t *m; u32 fib_index = ~0; - int rv; - - if (!sm->enabled) - { - return VNET_API_ERROR_UNSUPPORTED; - } - - rv = nat44_ed_validate_sm_input (flags); - if (rv != 0) - { - return rv; - } if (is_sm_addr_only (flags)) { e_port = l_port = proto = 0; } - if (is_sm_switch_address (flags)) - { - // this mapping is interface bound - ip4_address_t *first_int_addr; - - // delete record registered for resolve - if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags)) - { - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); - if (!first_int_addr) - { - // dhcp resolution required - return 0; - } - - e_addr.as_u32 = first_int_addr->as_u32; - } - if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -976,21 +1194,16 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, // fib index 0 m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); - if (!m) { - if (is_sm_switch_address (flags)) - { - return 0; - } return VNET_API_ERROR_NO_SUCH_ENTRY; } if (is_sm_identity_nat (flags)) { - u8 failure = 1; + u8 found = 0; - if (!is_sm_switch_address (flags)) + if (vrf_id == ~0) { vrf_id = sm->inside_vrf_id; } @@ -1002,11 +1215,11 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, local = pool_elt_at_index (m->locals, local - m->locals); fib_index = local->fib_index; pool_put (m->locals, local); - failure = 0; + found = 1; } } - if (failure) + if (!found) { return VNET_API_ERROR_NO_SUCH_ENTRY; } @@ -1016,32 +1229,24 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, fib_index = m->fib_index; } - if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || - sm->static_mapping_only)) - { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) - { - return VNET_API_ERROR_INVALID_VALUE; - } - } - if (!is_sm_out2in_only (flags)) { nat44_ed_sm_i2o_del (sm, l_addr, l_port, fib_index, proto); } - if (!sm->static_mapping_only || sm->static_mapping_connection_tracking) + // delete sessions for static mapping + if (sm->num_workers > 1) { - // delete sessions for static mapping - if (sm->num_workers > 1) - tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - - nat_ed_static_mapping_del_sessions ( - sm, tsm, m->local_addr, m->local_port, m->proto, fib_index, - is_sm_addr_only (flags), e_addr, e_port); + tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); } + else + { + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + } + + nat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr, m->local_port, + m->proto, fib_index, + is_sm_addr_only (flags), e_addr, e_port); fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); @@ -1055,10 +1260,7 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, vec_free (m->workers); pool_put (sm->static_mappings, m); - if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags)) - { - nat44_ed_add_del_addr_to_fib_foreach_out_if (&e_addr, 0); - } + nat44_ed_add_del_interface_fib_reg_entries (e_addr, 0); } return 0; @@ -1097,7 +1299,7 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, return VNET_API_ERROR_INVALID_VALUE; } - if (!(sm->static_mapping_only || is_sm_out2in_only (flags))) + if (!is_sm_out2in_only (flags)) { /* Find external address in allocated addresses and reserve port for address and port pair mapping when dynamic translations enabled */ @@ -1141,7 +1343,7 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_o2i_add (sm, m, m->external_addr, m->external_port, 0, m->proto)) { - nat_elog_err (sm, "sm o2i key add failed"); + nat_log_err ("sm o2i key add failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1153,7 +1355,7 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, { if (nat44_ed_sm_o2i_add (sm, m, e_addr, e_port, 0, proto)) { - nat_elog_err (sm, "sm o2i key add failed"); + nat_log_err ("sm o2i key add failed"); rc = VNET_API_ERROR_UNSPECIFIED; // here we continue with add operation so that it can be safely // reversed in delete path - otherwise we'd have to track what @@ -1216,7 +1418,7 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_o2i_del (sm, m->external_addr, m->external_port, 0, m->proto)) { - nat_elog_err (sm, "sm o2i key del failed"); + nat_log_err ("sm o2i key del failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1228,7 +1430,7 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_i2o_del (sm, local->addr, local->port, local->fib_index, m->proto)) { - nat_elog_err (sm, "sm i2o key del failed"); + nat_log_err ("sm i2o key del failed"); return VNET_API_ERROR_UNSPECIFIED; } } @@ -1337,7 +1539,7 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_i2o_add (sm, m, l_addr, l_port, local->fib_index, proto)) { - nat_elog_err (sm, "sm i2o key add failed"); + nat_log_err ("sm i2o key add failed"); pool_put (m->locals, local); return VNET_API_ERROR_UNSPECIFIED; } @@ -1358,7 +1560,7 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, { if (nat44_ed_sm_i2o_del (sm, l_addr, l_port, match_local->fib_index, proto)) - nat_elog_err (sm, "sm i2o key del failed"); + nat_log_err ("sm i2o key del failed"); } if (sm->num_workers > 1) @@ -1481,10 +1683,10 @@ update_per_vrf_sessions_vec (u32 fib_index, int is_del) } } -static_always_inline nat_outside_fib_t * -nat44_ed_get_outside_fib (nat_outside_fib_t *outside_fibs, u32 fib_index) +static_always_inline nat_fib_t * +nat44_ed_get_outside_fib (nat_fib_t *outside_fibs, u32 fib_index) { - nat_outside_fib_t *f; + nat_fib_t *f; vec_foreach (f, outside_fibs) { if (f->fib_index == fib_index) @@ -1515,7 +1717,7 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) const char *del_feature_name, *feature_name; snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1597,17 +1799,19 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount++; + outside_fib->ref_count++; } else { vec_add2 (sm->outside_fibs, outside_fib, 1); outside_fib->fib_index = fib_index; - outside_fib->refcount = 1; + outside_fib->ref_count = 1; } - 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_add_del_nat_addr_fib_reg_entries (sw_if_index, 1); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 1); + + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); } else { @@ -1623,7 +1827,7 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside) const char *del_feature_name, *feature_name; snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1708,15 +1912,15 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside) outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount--; - if (!outside_fib->refcount) + outside_fib->ref_count--; + if (!outside_fib->ref_count) { vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); } } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 0); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 0); } return 0; @@ -1727,7 +1931,7 @@ nat44_ed_add_output_interface (u32 sw_if_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1805,17 +2009,19 @@ nat44_ed_add_output_interface (u32 sw_if_index) outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount++; + outside_fib->ref_count++; } else { vec_add2 (sm->outside_fibs, outside_fib, 1); outside_fib->fib_index = fib_index; - outside_fib->refcount = 1; + outside_fib->ref_count = 1; } - 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_add_del_nat_addr_fib_reg_entries (sw_if_index, 1); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 1); + + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); return 0; } @@ -1825,7 +2031,7 @@ nat44_ed_del_output_interface (u32 sw_if_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1893,15 +2099,15 @@ nat44_ed_del_output_interface (u32 sw_if_index) outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount--; - if (!outside_fib->refcount) + outside_fib->ref_count--; + if (!outside_fib->ref_count) { vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); } } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 0); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 0); return 0; } @@ -1937,6 +2143,18 @@ nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts) { fail_if_enabled (); snat_main_t *sm = &snat_main; + + if ((sm->fq_in2out_index != ~0) || (sm->fq_out2in_index != ~0) || + (sm->fq_in2out_output_index != ~0)) + { + // frame queu nelts can be set only before first + // call to nat44_plugin_enable after that it + // doesn't make sense + nat_log_err ("Frame queue was already initialized. " + "Change is not possible"); + return 1; + } + sm->frame_queue_nelts = frame_queue_nelts; return 0; } @@ -1946,7 +2164,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u8 is_add = 1; u8 match = 0; @@ -1958,7 +2176,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, } pool_foreach (i, sm->interfaces) - { + { if (i->sw_if_index == sw_if_index) { if (!(nat44_ed_is_interface_outside (i))) @@ -1968,7 +2186,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, } pool_foreach (i, sm->output_feature_interfaces) - { + { if (i->sw_if_index == sw_if_index) { if (!(nat44_ed_is_interface_outside (i))) @@ -1981,30 +2199,30 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, return; vec_foreach (outside_fib, sm->outside_fibs) - { - if (outside_fib->fib_index == old_fib_index) - { - outside_fib->refcount--; - if (!outside_fib->refcount) - vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); - break; - } - } + { + if (outside_fib->fib_index == old_fib_index) + { + outside_fib->ref_count--; + if (!outside_fib->ref_count) + vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); + break; + } + } vec_foreach (outside_fib, sm->outside_fibs) - { - if (outside_fib->fib_index == new_fib_index) - { - outside_fib->refcount++; - is_add = 0; - break; - } - } + { + if (outside_fib->fib_index == new_fib_index) + { + outside_fib->ref_count++; + is_add = 0; + break; + } + } if (is_add) { vec_add2 (sm->outside_fibs, outside_fib, 1); - outside_fib->refcount = 1; + outside_fib->ref_count = 1; outside_fib->fib_index = new_fib_index; } } @@ -2017,7 +2235,7 @@ static void nat44_ed_add_del_interface_address_cb ( ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete); -static void nat44_ed_add_del_static_mapping_addr_only_cb ( +static void nat44_ed_add_del_static_mapping_cb ( ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete); @@ -2080,21 +2298,6 @@ nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add) VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del); -void -nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm) -{ - vlib_node_t *node; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in"); - sm->out2in_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out"); - sm->in2out_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output"); - sm->in2out_output_node_index = node->index; -} - #define nat_validate_simple_counter(c, i) \ do \ { \ @@ -2142,8 +2345,6 @@ nat_init (vlib_main_t * vm) sm->vnet_main = vnet_get_main (); // convenience sm->ip4_main = &ip4_main; - sm->api_main = vlibapi_get_main (); - sm->ip4_lookup_main = &ip4_main.lookup_main; // frame queue indices used for handoff sm->fq_out2in_index = ~0; @@ -2152,15 +2353,13 @@ nat_init (vlib_main_t * vm) sm->log_level = NAT_LOG_ERROR; - nat44_set_node_indexes (sm, vm); - sm->log_class = vlib_log_register_class ("nat", 0); nat_ipfix_logging_init (vm); nat_init_simple_counter (sm->total_sessions, "total-sessions", "/nat44-ed/total-sessions"); - sm->max_cfg_sessions_gauge = stat_segment_new_entry ( - (u8 *) "/nat44-ed/max-cfg-sessions", STAT_DIR_TYPE_SCALAR_INDEX); + sm->max_cfg_sessions_gauge = + vlib_stats_add_gauge ("/nat44-ed/max-cfg-sessions"); #define _(x) \ nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x, \ @@ -2206,7 +2405,7 @@ nat_init (vlib_main_t * vm) /* callbacks to call when interface address changes. */ cbi.function = nat44_ed_add_del_interface_address_cb; vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi); - cbi.function = nat44_ed_add_del_static_mapping_addr_only_cb; + cbi.function = nat44_ed_add_del_static_mapping_cb; vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi); /* callbacks to call when interface to table biding changes */ @@ -2235,26 +2434,15 @@ nat44_plugin_enable (nat44_config_t c) fail_if_enabled (); - if (c.static_mapping_only && !c.connection_tracking) - { - nat_log_err ("unsupported combination of configuration"); - return 1; - } - - sm->static_mapping_only = c.static_mapping_only; - sm->static_mapping_connection_tracking = c.connection_tracking; - sm->forwarding_enabled = 0; sm->mss_clamping = 0; - sm->pat = (!c.static_mapping_only || - (c.static_mapping_only && c.connection_tracking)); if (!c.sessions) c.sessions = 63 * 1024; sm->max_translations_per_thread = c.sessions; - stat_segment_set_state_counter (sm->max_cfg_sessions_gauge, - sm->max_translations_per_thread); + vlib_stats_set_gauge (sm->max_cfg_sessions_gauge, + sm->max_translations_per_thread); sm->translation_buckets = nat_calc_bihash_buckets (c.sessions); vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread); @@ -2270,6 +2458,8 @@ nat44_plugin_enable (nat44_config_t c) nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets); + nat44_ed_init_tcp_state_stable (sm); + nat_affinity_enable (); nat_reset_timeouts (&sm->timeouts); @@ -2283,101 +2473,199 @@ nat44_plugin_enable (nat44_config_t c) if (sm->num_workers > 1) { + vlib_main_t *vm = vlib_get_main (); + vlib_node_t *node; + if (sm->fq_in2out_index == ~0) { - sm->fq_in2out_index = vlib_frame_queue_main_init ( - sm->in2out_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out"); + sm->fq_in2out_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); } if (sm->fq_out2in_index == ~0) { - sm->fq_out2in_index = vlib_frame_queue_main_init ( - sm->out2in_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in"); + sm->fq_out2in_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); } if (sm->fq_in2out_output_index == ~0) { - sm->fq_in2out_output_index = vlib_frame_queue_main_init ( - sm->in2out_output_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output"); + sm->fq_in2out_output_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); + } + } + + sm->enabled = 1; + sm->rconfig = c; + + return 0; +} + +int +nat44_ed_del_addresses () +{ + snat_main_t *sm = &snat_main; + snat_address_t *a, *vec; + int error = 0; + + vec = vec_dup (sm->addresses); + vec_foreach (a, vec) + { + error = nat44_ed_del_address (a->addr, 0); + if (error) + { + nat_log_err ("error occurred while removing adderess"); + } + } + vec_free (vec); + vec_free (sm->addresses); + sm->addresses = 0; + + vec = vec_dup (sm->twice_nat_addresses); + vec_foreach (a, vec) + { + error = nat44_ed_del_address (a->addr, 1); + if (error) + { + nat_log_err ("error occurred while removing adderess"); + } + } + vec_free (vec); + vec_free (sm->twice_nat_addresses); + sm->twice_nat_addresses = 0; + + vec_free (sm->addr_to_resolve); + sm->addr_to_resolve = 0; + + return error; +} + +int +nat44_ed_del_interfaces () +{ + snat_main_t *sm = &snat_main; + snat_interface_t *i, *pool; + int error = 0; + + pool = pool_dup (sm->interfaces); + pool_foreach (i, pool) + { + if (nat44_ed_is_interface_inside (i)) + { + error = nat44_ed_del_interface (i->sw_if_index, 1); + } + if (nat44_ed_is_interface_outside (i)) + { + error = nat44_ed_del_interface (i->sw_if_index, 0); + } + + if (error) + { + nat_log_err ("error occurred while removing interface"); + } + } + pool_free (pool); + pool_free (sm->interfaces); + sm->interfaces = 0; + return error; +} + +int +nat44_ed_del_output_interfaces () +{ + snat_main_t *sm = &snat_main; + snat_interface_t *i, *pool; + int error = 0; + + pool = pool_dup (sm->output_feature_interfaces); + pool_foreach (i, pool) + { + error = nat44_ed_del_output_interface (i->sw_if_index); + if (error) + { + nat_log_err ("error occurred while removing output interface"); + } + } + pool_free (pool); + pool_free (sm->output_feature_interfaces); + sm->output_feature_interfaces = 0; + return error; +} + +int +nat44_ed_del_static_mappings () +{ + snat_main_t *sm = &snat_main; + snat_static_mapping_t *m, *pool; + int error = 0; + + pool = pool_dup (sm->static_mappings); + pool_foreach (m, pool) + { + error = nat44_ed_del_static_mapping_internal ( + m->local_addr, m->external_addr, m->local_port, m->external_port, + m->proto, m->vrf_id, m->flags); + if (error) + { + nat_log_err ("error occurred while removing mapping"); } } + pool_free (pool); + pool_free (sm->static_mappings); + sm->static_mappings = 0; - sm->enabled = 1; - sm->rconfig = c; - - return 0; -} + vec_free (sm->sm_to_resolve); + sm->sm_to_resolve = 0; -void -nat44_addresses_free (snat_address_t ** addresses) -{ - vec_free (*addresses); - *addresses = 0; + return error; } int nat44_plugin_disable () { + snat_main_per_thread_data_t *tsm; snat_main_t *sm = &snat_main; - snat_interface_t *i, *pool; - int error = 0; + int rc, error = 0; fail_if_disabled (); - pool = pool_dup (sm->interfaces); - pool_foreach (i, pool) - { - if (nat44_ed_is_interface_inside (i)) - { - error = nat44_ed_del_interface (i->sw_if_index, 1); - } - if (nat44_ed_is_interface_outside (i)) - { - error = nat44_ed_del_interface (i->sw_if_index, 0); - } - if (error) - { - nat_log_err ("error occurred while removing interface %u", - i->sw_if_index); - } - } - pool_free (sm->interfaces); - pool_free (pool); - sm->interfaces = 0; + rc = nat44_ed_del_static_mappings (); + if (rc) + error = 1; - pool = pool_dup (sm->output_feature_interfaces); - pool_foreach (i, pool) - { - error = nat44_ed_del_output_interface (i->sw_if_index); - if (error) - { - nat_log_err ("error occurred while removing interface %u", - i->sw_if_index); - } - } - pool_free (sm->output_feature_interfaces); - pool_free (pool); - sm->output_feature_interfaces = 0; + rc = nat44_ed_del_addresses (); + if (rc) + error = 1; + + rc = nat44_ed_del_interfaces (); + if (rc) + error = 1; + + rc = nat44_ed_del_output_interfaces (); + if (rc) + error = 1; + + nat44_ed_del_vrf_tables (); vec_free (sm->max_translations_per_fib); + sm->max_translations_per_fib = 0; - nat44_ed_db_free (); + clib_bihash_free_16_8 (&sm->flow_hash); - nat44_addresses_free (&sm->addresses); - nat44_addresses_free (&sm->twice_nat_addresses); + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ed_worker_db_free (tsm); + } - vec_free (sm->to_resolve); - vec_free (sm->auto_add_sw_if_indices); - vec_free (sm->auto_add_sw_if_indices_twice_nat); + clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig)); - sm->to_resolve = 0; - sm->auto_add_sw_if_indices = 0; - sm->auto_add_sw_if_indices_twice_nat = 0; + nat_affinity_disable (); sm->forwarding_enabled = 0; - sm->enabled = 0; - clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig)); - return 0; + return error; } void @@ -2429,11 +2717,12 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, match_fib_index, 0); if (m) return m; + // default static mapping fib index (based on configuration) if (sm->inside_fib_index != match_fib_index) { m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, @@ -2441,12 +2730,13 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->inside_fib_index, 0); if (m) return m; } + // TODO: this specific use case may be deprecated (needs testing) if (sm->outside_fib_index != match_fib_index) { m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, @@ -2454,7 +2744,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->outside_fib_index, 0); if (m) @@ -2468,7 +2758,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0); if (m) return m; @@ -2477,15 +2767,16 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, } int -snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm, - ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, +snat_static_mapping_match (vlib_main_t *vm, ip4_address_t match_addr, + u16 match_port, u32 match_fib_index, + ip_protocol_t match_protocol, ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, int by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat, snat_static_mapping_t **out) { + snat_main_t *sm = &snat_main; snat_static_mapping_t *m; u32 rand, lo = 0, hi, mid, *tmp = 0, i; nat44_lb_addr_port_t *local; @@ -2629,7 +2920,7 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, if (PREDICT_FALSE (is_output)) { fib_index = sm->outside_fib_index; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; fib_node_index_t fei = FIB_NODE_INDEX_INVALID; fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP4, @@ -2825,7 +3116,7 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, { udp_header_t *udp = ip4_next_header (ip); icmp46_header_t *icmp = (icmp46_header_t *) udp; - icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1); + nat_icmp_echo_header_t *echo = (nat_icmp_echo_header_t *) (icmp + 1); if (!icmp_type_is_error_message (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) port = vnet_buffer (b)->ip.reass.l4_src_port; @@ -2839,13 +3130,13 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, { case IP_PROTOCOL_ICMP: icmp = (icmp46_header_t *) l4_header; - echo = (icmp_echo_header_t *) (icmp + 1); + echo = (nat_icmp_echo_header_t *) (icmp + 1); port = echo->identifier; break; case IP_PROTOCOL_UDP: /* breakthrough */ case IP_PROTOCOL_TCP: - port = ((tcp_udp_header_t *) l4_header)->src_port; + port = ((nat_tcp_udp_header_t *) l4_header)->src_port; break; default: next_worker_index = vlib_get_thread_index (); @@ -2933,8 +3224,8 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id) return 1; sm->max_translations_per_thread = nat44_get_max_session_limit (); - stat_segment_set_state_counter (sm->max_cfg_sessions_gauge, - sm->max_translations_per_thread); + vlib_stats_set_gauge (sm->max_cfg_sessions_gauge, + sm->max_translations_per_thread); sm->translation_buckets = nat_calc_bihash_buckets (sm->max_translations_per_thread); @@ -2992,13 +3283,10 @@ nat44_ed_db_init (u32 translations, u32 translation_buckets) reinit_ed_flow_hash (); - if (sm->pat) + vec_foreach (tsm, sm->per_thread_data) { - vec_foreach (tsm, sm->per_thread_data) - { - nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, - sm->translation_buckets); - } + nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, + sm->translation_buckets); } } @@ -3010,24 +3298,6 @@ nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm) vec_free (tsm->per_vrf_sessions_vec); } -static void -nat44_ed_db_free () -{ - snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm; - - pool_free (sm->static_mappings); - clib_bihash_free_16_8 (&sm->flow_hash); - - if (sm->pat) - { - vec_foreach (tsm, sm->per_thread_data) - { - nat44_ed_worker_db_free (tsm); - } - } -} - void nat44_ed_sessions_clear () { @@ -3036,90 +3306,105 @@ nat44_ed_sessions_clear () reinit_ed_flow_hash (); - if (sm->pat) + vec_foreach (tsm, sm->per_thread_data) { - vec_foreach (tsm, sm->per_thread_data) - { - - nat44_ed_worker_db_free (tsm); - nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, - sm->translation_buckets); - } + nat44_ed_worker_db_free (tsm); + nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, + sm->translation_buckets); } vlib_zero_simple_counter (&sm->total_sessions, 0); } static void -nat44_ed_add_del_static_mapping_addr_only_cb ( - ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, - u32 address_length, u32 if_address_index, u32 is_delete) +nat44_ed_add_del_static_mapping_cb (ip4_main_t *im, uword opaque, + u32 sw_if_index, ip4_address_t *address, + u32 address_length, u32 if_address_index, + u32 is_delete) { - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; snat_main_t *sm = &snat_main; - snat_static_mapping_t *m; - int i, rv = 0, match = 0; + int rv = 0; if (!sm->enabled) { return; } - // find first addr_only resolve record by sw_if_index - for (i = 0; i < vec_len (sm->to_resolve); i++) + vec_foreach (rp, sm->sm_to_resolve) { - rp = sm->to_resolve + i; - if (rp->addr_only && rp->sw_if_index == sw_if_index) + if (sw_if_index == rp->sw_if_index) { - match = 1; - break; + if (is_delete) + { + if (rp->is_resolved) + { + rv = nat44_ed_del_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, + rp->vrf_id, rp->flags); + if (rv) + { + nat_log_err ("ed del static mapping failed"); + } + else + { + rp->is_resolved = 0; + } + } + } + else + { + if (!rp->is_resolved) + { + rv = nat44_ed_add_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, + rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); + if (rv) + { + nat_log_err ("ed add static mapping failed"); + } + else + { + rp->is_resolved = 1; + } + } + } } } - if (!match) - { - return; - } +} - m = nat44_ed_sm_o2i_lookup (sm, *address, rp->addr_only ? 0 : rp->e_port, 0, - rp->proto); +static int +nat44_ed_get_addr_resolve_record (u32 sw_if_index, u8 twice_nat, int *out) +{ + snat_main_t *sm = &snat_main; + snat_address_resolve_t *rp; + int i; - if (is_delete) - { - if (m) - { - rv = nat44_ed_del_static_mapping (rp->l_addr, address[0], rp->l_port, - rp->e_port, rp->proto, rp->vrf_id, - ~0, rp->flags); - } - } - else + for (i = 0; i < vec_len (sm->addr_to_resolve); i++) { - if (!m) + rp = sm->addr_to_resolve + i; + + if ((rp->sw_if_index == sw_if_index) && (rp->is_twice_nat == twice_nat)) { - rv = nat44_ed_add_static_mapping ( - rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); + if (out) + { + *out = i; + } + return 0; } - // else: don't trip over lease renewal, static config - } - if (rv) - { - nat_elog_notice_X1 (sm, "nat44_ed_del_static_mapping returned %d", "i4", - rv); } + return 1; } - -static_always_inline int -is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index) +static int +nat44_ed_del_addr_resolve_record (u32 sw_if_index, u8 twice_nat) { - u32 *i; - vec_foreach (i, sw_if_indices) + snat_main_t *sm = &snat_main; + int i; + if (!nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { - if (*i == sw_if_index) - { - return 1; - } + vec_del1 (sm->addr_to_resolve, i); + return 0; } - return 0; + return 1; } static void @@ -3129,69 +3414,78 @@ nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque, u32 if_address_index, u32 is_delete) { snat_main_t *sm = &snat_main; - snat_static_map_resolve_t *rp; - snat_address_t *addresses = sm->addresses; + snat_address_resolve_t *arp; + snat_address_t *ap; u8 twice_nat = 0; - int rv, i; + int i, rv; if (!sm->enabled) { return; } - if (!is_sw_if_index_reg_for_auto_resolve (sm->auto_add_sw_if_indices, - sw_if_index)) + if (nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { - if (!is_sw_if_index_reg_for_auto_resolve ( - sm->auto_add_sw_if_indices_twice_nat, sw_if_index)) + twice_nat = 1; + if (nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { + 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 - { - addresses = sm->twice_nat_addresses; - twice_nat = 1; - } } + arp = sm->addr_to_resolve + i; + if (!is_delete) { - // don't trip over lease renewal, static config - for (i = 0; i < vec_len (addresses); i++) + if (arp->is_resolved) { - if (addresses[i].addr.as_u32 == address->as_u32) - { - return; - } + return; } - (void) nat44_ed_add_address (address, ~0, twice_nat); - - // scan static mapping switch address resolution record vector - for (i = 0; i < vec_len (sm->to_resolve); i++) + rv = nat44_ed_add_address (address, ~0, arp->is_twice_nat); + if (0 == rv) { - rp = sm->to_resolve + i; - if (rp->addr_only) - { - continue; - } - if (rp->sw_if_index == sw_if_index) - { - rv = nat44_ed_add_static_mapping ( - rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - rp->vrf_id, sw_if_index, rp->flags, rp->pool_addr, rp->tag); - if (rv) - { - nat_elog_notice_X1 (sm, "add_static_mapping returned %d", - "i4", rv); - } - } + arp->is_resolved = 1; } } else { - // remove all static mapping records - (void) nat44_ed_del_address (address[0], 1, twice_nat); + if (!arp->is_resolved) + { + return; + } + + rv = nat44_ed_del_address (address[0], arp->is_twice_nat); + if (0 == rv) + { + arp->is_resolved = 0; + } } } @@ -3201,34 +3495,34 @@ nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat) snat_main_t *sm = &snat_main; ip4_main_t *ip4_main = sm->ip4_main; ip4_address_t *first_int_addr; - u32 *auto_add_sw_if_indices = twice_nat ? - sm->auto_add_sw_if_indices_twice_nat : - sm->auto_add_sw_if_indices; - int i; + snat_address_resolve_t *ap; + int rv; - for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) + if (!sm->enabled) { - if (auto_add_sw_if_indices[i] == sw_if_index) - { - return VNET_API_ERROR_VALUE_EXIST; - } + return VNET_API_ERROR_UNSUPPORTED; } - // add to the auto-address list - if (twice_nat) - { - vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index); - } - else + if (!nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, 0)) { - vec_add1 (sm->auto_add_sw_if_indices, sw_if_index); + return VNET_API_ERROR_VALUE_EXIST; } - // if the address is already bound - or static - add it now + vec_add2 (sm->addr_to_resolve, ap, 1); + ap->sw_if_index = sw_if_index; + ap->is_twice_nat = twice_nat; + ap->is_resolved = 0; + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); if (first_int_addr) { - (void) nat44_ed_add_address (first_int_addr, ~0, twice_nat); + rv = nat44_ed_add_address (first_int_addr, ~0, twice_nat); + if (0 != rv) + { + nat44_ed_del_addr_resolve_record (sw_if_index, twice_nat); + return rv; + } + ap->is_resolved = 1; } return 0; @@ -3240,62 +3534,24 @@ nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat) snat_main_t *sm = &snat_main; ip4_main_t *ip4_main = sm->ip4_main; ip4_address_t *first_int_addr; - snat_static_map_resolve_t *rp; - u32 *indices_to_delete = 0; - int i, j; - u32 *auto_add_sw_if_indices; if (!sm->enabled) { return VNET_API_ERROR_UNSUPPORTED; } - auto_add_sw_if_indices = twice_nat ? sm->auto_add_sw_if_indices_twice_nat : - sm->auto_add_sw_if_indices; - - for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) + if (nat44_ed_del_addr_resolve_record (sw_if_index, twice_nat)) { - if (auto_add_sw_if_indices[i] == sw_if_index) - { - first_int_addr = - ip4_interface_first_address (ip4_main, sw_if_index, 0); - if (first_int_addr) - { - // remove all static mapping records - (void) nat44_ed_del_address (first_int_addr[0], 1, twice_nat); - } - else - { - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - if (rp->sw_if_index == sw_if_index) - { - vec_add1 (indices_to_delete, j); - } - } - if (vec_len (indices_to_delete)) - { - for (j = vec_len (indices_to_delete) - 1; j >= 0; j--) - { - vec_del1 (sm->to_resolve, j); - } - vec_free (indices_to_delete); - } - } + return VNET_API_ERROR_NO_SUCH_ENTRY; + } - if (twice_nat) - { - vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i); - } - else - { - vec_del1 (sm->auto_add_sw_if_indices, i); - } - return 0; - } + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); + if (first_int_addr) + { + return nat44_ed_del_address (first_int_addr[0], twice_nat); } - return VNET_API_ERROR_NO_SUCH_ENTRY; + + return 0; } int @@ -3528,7 +3784,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED; icmp46_header_t *icmp = ip4_next_header (ip); - icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1); + nat_icmp_echo_header_t *echo = (nat_icmp_echo_header_t *) (icmp + 1); if ((!vnet_buffer (b)->ip.reass.is_non_first_fragment)) { @@ -3544,7 +3800,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, { ip_csum_t sum = icmp->checksum; sum = ip_csum_update (sum, echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, + nat_icmp_echo_header_t, identifier /* changed member */); echo->identifier = f->rewrite.icmp_id; icmp->checksum = ip_csum_fold (sum); @@ -3624,6 +3880,9 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, icmp->checksum = new_icmp_sum; break; case IP_PROTOCOL_ICMP: + nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto, + 1 /* is_icmp_inner_ip4 */, + 0 /* skip_saddr_rewrite */); if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) { icmp46_header_t *inner_icmp = ip4_next_header (inner_ip); @@ -3631,19 +3890,21 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, { return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED; } - icmp_echo_header_t *inner_echo = - (icmp_echo_header_t *) (inner_icmp + 1); + nat_icmp_echo_header_t *inner_echo = + (nat_icmp_echo_header_t *) (inner_icmp + 1); if (f->rewrite.icmp_id != inner_echo->identifier) { ip_csum_t sum = icmp->checksum; - sum = ip_csum_update ( - sum, inner_echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, identifier /* changed member */); + sum = ip_csum_update (sum, inner_echo->identifier, + f->rewrite.icmp_id, + nat_icmp_echo_header_t, + identifier /* changed member */); icmp->checksum = ip_csum_fold (sum); ip_csum_t inner_sum = inner_icmp->checksum; inner_sum = ip_csum_update ( sum, inner_echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, identifier /* changed member */); + nat_icmp_echo_header_t, + identifier /* changed member */); inner_icmp->checksum = ip_csum_fold (inner_sum); inner_echo->identifier = f->rewrite.icmp_id; } @@ -3715,110 +3976,7 @@ nat_6t_flow_buf_translate_o2i (vlib_main_t *vm, snat_main_t *sm, 0 /* is_i2o */); } -u8 * -format_nat_6t (u8 *s, va_list *args) -{ - nat_6t_t *t = va_arg (*args, nat_6t_t *); - - s = format (s, "saddr %U sport %u daddr %U dport %u proto %U fib_idx %u", - format_ip4_address, t->saddr.as_u8, - clib_net_to_host_u16 (t->sport), format_ip4_address, - t->daddr.as_u8, clib_net_to_host_u16 (t->dport), - format_ip_protocol, t->proto, t->fib_index); - return s; -} - -u8 * -format_nat_ed_translation_error (u8 *s, va_list *args) -{ - nat_translation_error_e e = va_arg (*args, nat_translation_error_e); - - switch (e) - { - case NAT_ED_TRNSL_ERR_SUCCESS: - s = format (s, "success"); - break; - case NAT_ED_TRNSL_ERR_TRANSLATION_FAILED: - s = format (s, "translation-failed"); - break; - case NAT_ED_TRNSL_ERR_FLOW_MISMATCH: - s = format (s, "flow-mismatch"); - break; - case NAT_ED_TRNSL_ERR_PACKET_TRUNCATED: - s = format (s, "packet-truncated"); - break; - case NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT: - s = format (s, "inner-ip-corrupted"); - break; - case NAT_ED_TRNSL_ERR_INVALID_CSUM: - s = format (s, "invalid-checksum"); - break; - } - return s; -} - -u8 * -format_nat_6t_flow (u8 *s, va_list *args) -{ - nat_6t_flow_t *f = va_arg (*args, nat_6t_flow_t *); - - s = format (s, "match: %U ", format_nat_6t, &f->match); - int r = 0; - if (f->ops & NAT_FLOW_OP_SADDR_REWRITE) - { - s = format (s, "rewrite: saddr %U ", format_ip4_address, - f->rewrite.saddr.as_u8); - r = 1; - } - if (f->ops & NAT_FLOW_OP_SPORT_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "sport %u ", clib_net_to_host_u16 (f->rewrite.sport)); - } - if (f->ops & NAT_FLOW_OP_DADDR_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "daddr %U ", format_ip4_address, f->rewrite.daddr.as_u8); - } - if (f->ops & NAT_FLOW_OP_DPORT_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "dport %u ", clib_net_to_host_u16 (f->rewrite.dport)); - } - if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "icmp-id %u ", clib_net_to_host_u16 (f->rewrite.icmp_id)); - } - if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "txfib %u ", f->rewrite.fib_index); - } - return s; -} - -static inline void +static_always_inline void nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, ip4_address_t *idaddr, u16 idport,