FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
nat66.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT66 implementation
18  */
19 
20 #include <nat/nat66/nat66.h>
21 #include <vpp/app/version.h>
22 #include <vnet/plugin/plugin.h>
24 
26 
27 /* Hook up input features */
28 VNET_FEATURE_INIT (nat66_in2out, static) = {
29  .arc_name = "ip6-unicast",
30  .node_name = "nat66-in2out",
31  .runs_before = VNET_FEATURES ("ip6-lookup"),
32  .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
33 };
34 VNET_FEATURE_INIT (nat66_out2in, static) = {
35  .arc_name = "ip6-unicast",
36  .node_name = "nat66-out2in",
37  .runs_before = VNET_FEATURES ("ip6-lookup"),
38  .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
39 };
40 
42 
43 #define fail_if_enabled() \
44  do \
45  { \
46  nat66_main_t *nm = &nat66_main; \
47  if (PREDICT_FALSE (nm->enabled)) \
48  { \
49  nat66_elog_warn ("plugin enabled"); \
50  return 1; \
51  } \
52  } \
53  while (0)
54 
55 #define fail_if_disabled() \
56  do \
57  { \
58  nat66_main_t *nm = &nat66_main; \
59  if (PREDICT_FALSE (!nm->enabled)) \
60  { \
61  nat66_elog_warn ("plugin disabled"); \
62  return 1; \
63  } \
64  } \
65  while (0)
66 
67 static clib_error_t *
69 {
71 
72  clib_memset (nm, 0, sizeof (*nm));
73 
74  nm->session_counters.name = "session counters";
75  nm->in2out_packets.name = "in2out";
76  nm->in2out_packets.stat_segment_name = "/nat64/in2out";
77  nm->out2in_packets.name = "out2in";
78  nm->out2in_packets.stat_segment_name = "/nat64/out2in";
79 
80  nm->nat_fib_src_hi = fib_source_allocate ("nat66-hi", FIB_SOURCE_PRIORITY_HI,
82  return nat66_plugin_api_hookup (vm);
83 }
84 
85 int
86 nat66_plugin_enable (u32 outside_vrf)
87 {
89 
90  u32 static_mapping_buckets = 1024;
91  uword static_mapping_memory_size = 64 << 20;
92 
93  fail_if_enabled ();
94 
95  clib_bihash_init_24_8 (&nm->sm_l, "nat66-static-map-by-local",
96  static_mapping_buckets, static_mapping_memory_size);
97  clib_bihash_init_24_8 (&nm->sm_e, "nat66-static-map-by-external",
98  static_mapping_buckets, static_mapping_memory_size);
99 
100  nm->outside_vrf_id = outside_vrf;
102  FIB_PROTOCOL_IP6, outside_vrf, nm->nat_fib_src_hi);
103  nm->enabled = 1;
104  return 0;
105 }
106 
107 int
109 {
111  nat66_interface_t *i, *temp;
112  int error = 0;
113 
114  temp = pool_dup (nm->interfaces);
115  pool_foreach (i, temp)
116  {
118  error = nat66_interface_add_del (i->sw_if_index, 1, 0);
119 
121  error = nat66_interface_add_del (i->sw_if_index, 0, 0);
122 
123  if (error)
124  {
125  nat66_elog_warn ("error occurred while removing interface");
126  }
127  }
128  pool_free (temp);
130 
131  pool_free (nm->sm);
132  clib_bihash_free_24_8 (&nm->sm_l);
133  clib_bihash_free_24_8 (&nm->sm_e);
134 
135  nm->interfaces = 0;
136  nm->sm = 0;
137 
138  vlib_clear_combined_counters (&nm->session_counters);
139  vlib_clear_simple_counters (&nm->in2out_packets);
140  vlib_clear_simple_counters (&nm->out2in_packets);
141 
142  nm->enabled = 0;
143  return error;
144 }
145 
146 static void
148 {
149  vlib_validate_simple_counter (&nm->in2out_packets, sw_if_index);
150  vlib_zero_simple_counter (&nm->in2out_packets, sw_if_index);
151  vlib_validate_simple_counter (&nm->out2in_packets, sw_if_index);
152  vlib_zero_simple_counter (&nm->out2in_packets, sw_if_index);
153 }
154 
155 int
157 {
159  nat66_interface_t *interface = 0, *i;
160  const char *feature_name;
161 
162  fail_if_disabled ();
163 
165  {
166  if (i->sw_if_index == sw_if_index)
167  {
168  interface = i;
169  break;
170  }
171  }
172 
173  if (is_add)
174  {
175  if (interface)
176  return VNET_API_ERROR_VALUE_EXIST;
177 
178  pool_get (nm->interfaces, interface);
179  interface->sw_if_index = sw_if_index;
180  interface->flags =
181  is_inside ? NAT66_INTERFACE_FLAG_IS_INSIDE :
184  }
185  else
186  {
187  if (!interface)
188  return VNET_API_ERROR_NO_SUCH_ENTRY;
189 
190  pool_put (nm->interfaces, interface);
191  }
192 
193  feature_name = is_inside ? "nat66-in2out" : "nat66-out2in";
195  if (rv)
196  return rv;
197  return vnet_feature_enable_disable ("ip6-unicast", feature_name,
198  sw_if_index, is_add, 0, 0);
199 }
200 
201 void
203 {
205  nat66_interface_t *i = 0;
206 
208  {
209  if (fn (i, ctx))
210  break;
211  }
212 }
213 
215 nat66_static_mapping_get (ip6_address_t * addr, u32 fib_index, u8 is_local)
216 {
218  nat66_static_mapping_t *sm = 0;
219  nat66_sm_key_t sm_key;
221 
222  sm_key.addr.as_u64[0] = addr->as_u64[0];
223  sm_key.addr.as_u64[1] = addr->as_u64[1];
224  sm_key.fib_index = fib_index;
225  sm_key.rsvd = 0;
226 
227  kv.key[0] = sm_key.as_u64[0];
228  kv.key[1] = sm_key.as_u64[1];
229  kv.key[2] = sm_key.as_u64[2];
230 
231  if (!clib_bihash_search_24_8
232  (is_local ? &nm->sm_l : &nm->sm_e, &kv, &value))
233  sm = pool_elt_at_index (nm->sm, value.value);
234 
235  return sm;
236 }
237 
238 int
239 nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
240  u32 vrf_id, u8 is_add)
241 {
243  int rv = 0;
244  nat66_static_mapping_t *sm = 0;
245  nat66_sm_key_t sm_key;
247  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, vrf_id);
248 
249  fail_if_disabled ();
250 
251  sm_key.addr.as_u64[0] = l_addr->as_u64[0];
252  sm_key.addr.as_u64[1] = l_addr->as_u64[1];
253  sm_key.fib_index = fib_index;
254  sm_key.rsvd = 0;
255  kv.key[0] = sm_key.as_u64[0];
256  kv.key[1] = sm_key.as_u64[1];
257  kv.key[2] = sm_key.as_u64[2];
258 
259  if (!clib_bihash_search_24_8 (&nm->sm_l, &kv, &value))
260  sm = pool_elt_at_index (nm->sm, value.value);
261 
262  if (is_add)
263  {
264  if (sm)
265  return VNET_API_ERROR_VALUE_EXIST;
266 
268  nm->nat_fib_src_hi);
269  pool_get (nm->sm, sm);
270  clib_memset (sm, 0, sizeof (*sm));
271  sm->l_addr.as_u64[0] = l_addr->as_u64[0];
272  sm->l_addr.as_u64[1] = l_addr->as_u64[1];
273  sm->e_addr.as_u64[0] = e_addr->as_u64[0];
274  sm->e_addr.as_u64[1] = e_addr->as_u64[1];
275  sm->fib_index = fib_index;
276 
277  sm_key.fib_index = fib_index;
278  kv.key[0] = sm_key.as_u64[0];
279  kv.key[1] = sm_key.as_u64[1];
280  kv.key[2] = sm_key.as_u64[2];
281  kv.value = sm - nm->sm;
282  if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 1))
283  nat66_elog_warn ("nat66-static-map-by-local add key failed");
284  sm_key.addr.as_u64[0] = e_addr->as_u64[0];
285  sm_key.addr.as_u64[1] = e_addr->as_u64[1];
286  sm_key.fib_index = 0;
287  kv.key[0] = sm_key.as_u64[0];
288  kv.key[1] = sm_key.as_u64[1];
289  kv.key[2] = sm_key.as_u64[2];
290  if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 1))
291  nat66_elog_warn ("nat66-static-map-by-external add key failed");
292 
293  vlib_validate_combined_counter (&nm->session_counters, kv.value);
294  vlib_zero_combined_counter (&nm->session_counters, kv.value);
295  }
296  else
297  {
298  if (!sm)
299  return VNET_API_ERROR_NO_SUCH_ENTRY;
300 
301  kv.value = sm - nm->sm;
302  if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 0))
303  nat66_elog_warn ("nat66-static-map-by-local delete key failed");
304  sm_key.addr.as_u64[0] = e_addr->as_u64[0];
305  sm_key.addr.as_u64[1] = e_addr->as_u64[1];
306  sm_key.fib_index = 0;
307  kv.key[0] = sm_key.as_u64[0];
308  kv.key[1] = sm_key.as_u64[1];
309  kv.key[2] = sm_key.as_u64[2];
310  if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 0))
311  nat66_elog_warn ("nat66-static-map-by-external delete key failed");
312  fib_table_unlock (sm->fib_index, FIB_PROTOCOL_IP6, nm->nat_fib_src_hi);
313  pool_put (nm->sm, sm);
314  }
315 
316  return rv;
317 }
318 
319 void
321 {
323  nat66_static_mapping_t *sm = 0;
324 
325  pool_foreach (sm, nm->sm)
326  {
327  if (fn (sm, ctx))
328  break;
329  }
330 }
331 
333 {
334  .version = VPP_BUILD_VER,
335  .description = "NAT66",
336 };
337 
339 
340 /*
341  * fd.io coding-style-patch-verification: ON
342  *
343  * Local Variables:
344  * eval: (c-set-style "gnu")
345  * End:
346  */
nat66_static_mapping_get
nat66_static_mapping_t * nat66_static_mapping_get(ip6_address_t *addr, u32 fib_index, u8 is_local)
Definition: nat66.c:215
nat66_interface_add_del
int nat66_interface_add_del(u32 sw_if_index, u8 is_inside, u8 is_add)
Definition: nat66.c:156
nat66_static_mapping_t::e_addr
ip6_address_t e_addr
Definition: nat66.h:29
nat66_plugin_api_hookup
clib_error_t * nat66_plugin_api_hookup(vlib_main_t *vm)
Definition: nat66_api.c:189
VLIB_PLUGIN_REGISTER
VLIB_PLUGIN_REGISTER()
nat66_interfaces_walk
void nat66_interfaces_walk(nat66_interface_walk_fn_t fn, void *ctx)
Definition: nat66.c:202
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:549
nat66_static_mapping_t::l_addr
ip6_address_t l_addr
Definition: nat66.h:28
vlib_clear_combined_counters
void vlib_clear_combined_counters(vlib_combined_counter_main_t *cm)
Clear a collection of combined counters.
Definition: counter.c:61
nat44_ei_main_s::interfaces
nat44_ei_interface_t * interfaces
Definition: nat44_ei.h:340
nat66_sm_key_t::rsvd
u32 rsvd
Definition: nat66.h:41
nat66_plugin_enable
int nat66_plugin_enable(u32 outside_vrf)
Definition: nat66.c:86
clib_bihash_kv_24_8_t
Definition: bihash_24_8.h:40
nat66_static_mapping_t::fib_index
u32 fib_index
Definition: nat66.h:30
vlib_validate_combined_counter
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:119
nat66_static_mapping_walk_fn_t
int(* nat66_static_mapping_walk_fn_t)(nat66_static_mapping_t *sm, void *ctx)
Definition: nat66.h:110
pool_put
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
ip6_sv_reass_enable_disable_with_refcnt
int ip6_sv_reass_enable_disable_with_refcnt(u32 sw_if_index, int is_enable)
Definition: ip6_sv_reass.c:1301
nat66_static_mappings_walk
void nat66_static_mappings_walk(nat66_static_mapping_walk_fn_t fn, void *ctx)
Definition: nat66.c:320
NAT66_INTERFACE_FLAG_IS_INSIDE
#define NAT66_INTERFACE_FLAG_IS_INSIDE
Definition: nat66.h:53
nat66_elog_warn
#define nat66_elog_warn(nat_elog_str)
Definition: nat66.h:99
nat66_sm_key_t
Definition: nat66.h:33
NAT66_INTERFACE_FLAG_IS_OUTSIDE
#define NAT66_INTERFACE_FLAG_IS_OUTSIDE
Definition: nat66.h:54
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
error
Definition: cJSON.c:88
nat66_interface_is_outside
#define nat66_interface_is_outside(i)
Definition: nat66.h:56
nat66_sm_key_t::addr
ip6_address_t addr
Definition: nat66.h:39
nat66_interface_walk_fn_t
int(* nat66_interface_walk_fn_t)(nat66_interface_t *i, void *ctx)
Definition: nat66.h:107
nat66_static_mapping_add_del
int nat66_static_mapping_add_del(ip6_address_t *l_addr, ip6_address_t *e_addr, u32 vrf_id, u8 is_add)
Definition: nat66.c:239
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
ip6_sv_reass.h
IPv6 shallow virtual reassembly.
nat44_ei_main_s::enabled
u8 enabled
Definition: nat44_ei.h:471
fib_table_find_or_create_and_lock
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1170
uword
u64 uword
Definition: types.h:112
vlib_zero_combined_counter
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread counters.
Definition: counter.h:298
nat44_ei_main_s::outside_fib_index
u32 outside_fib_index
Definition: nat44_ei.h:354
clib_bihash_kv_24_8_t::value
u64 value
Definition: bihash_24_8.h:43
nat66_sm_key_t::as_u64
u64 as_u64[3]
Definition: nat66.h:43
pool_get
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
nat66_main_t
Definition: nat66.h:58
fib_source_allocate
fib_source_t fib_source_allocate(const char *name, fib_source_priority_t prio, fib_source_behaviour_t bh)
Definition: fib_source.c:118
plugin.h
nat44_ei_main_s::outside_vrf_id
u32 outside_vrf_id
Definition: nat44_ei.h:353
FIB_SOURCE_PRIORITY_HI
#define FIB_SOURCE_PRIORITY_HI
Some priority values that plugins might use when they are not to concerned where in the list they'll ...
Definition: fib_source.h:284
nat66_validate_counters
static void nat66_validate_counters(nat66_main_t *nm, u32 sw_if_index)
Definition: nat66.c:147
nat66_plugin_disable
int nat66_plugin_disable()
Definition: nat66.c:108
vlib_zero_simple_counter
static void vlib_zero_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
Clear a simple counter Clears the set of per-thread u16 counters, and the u64 counter.
Definition: counter.h:154
fail_if_enabled
#define fail_if_enabled()
Definition: nat66.c:43
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
vlib_validate_simple_counter
void vlib_validate_simple_counter(vlib_simple_counter_main_t *cm, u32 index)
validate a simple counter
Definition: counter.c:79
FIB_PROTOCOL_IP6
@ FIB_PROTOCOL_IP6
Definition: fib_types.h:37
nat66_interface_is_inside
#define nat66_interface_is_inside(i)
Definition: nat66.h:55
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
clib_bihash_kv_24_8_t::key
u64 key[3]
Definition: bihash_24_8.h:42
fail_if_disabled
#define fail_if_disabled()
Definition: nat66.c:55
nat66_main
nat66_main_t nat66_main
Definition: nat66.c:25
nm
nat44_ei_main_t * nm
Definition: nat44_ei_hairpinning.c:413
value
u8 value
Definition: qos.api:54
vnet_feature_enable_disable
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: pnat_test_stubs.h:50
nat66_init
static clib_error_t * nat66_init(vlib_main_t *vm)
Definition: nat66.c:68
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
VNET_FEATURES
#define VNET_FEATURES(...)
Definition: feature.h:470
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
pool_dup
#define pool_dup(P)
Return copy of pool without alignment.
Definition: pool.h:405
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
fib_table_unlock
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1342
FIB_SOURCE_BH_SIMPLE
@ FIB_SOURCE_BH_SIMPLE
add paths without path extensions
Definition: fib_source.h:210
i
int i
Definition: flowhash_template.h:376
pool_free
#define pool_free(p)
Free a pool.
Definition: pool.h:447
rv
int __clib_unused rv
Definition: application.c:491
nat66_interface_t
Definition: nat66.h:47
vrf_id
u32 vrf_id
Definition: nat44_ed.api:1053
nat66.h
NAT66 global declarations.
is_local
bool is_local
Definition: ikev2_types.api:33
fib_table_find
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1111
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_clear_simple_counters
void vlib_clear_simple_counters(vlib_simple_counter_main_t *cm)
Clear a collection of simple counters.
Definition: counter.c:44
nat66_static_mapping_t
Definition: nat66.h:26
VNET_FEATURE_INIT
VNET_FEATURE_INIT(nat66_in2out, static)
nat66_sm_key_t::fib_index
u32 fib_index
Definition: nat66.h:40