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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @brief NAT66 implementation
20 #include <nat/nat66/nat66.h>
21 #include <vpp/app/version.h>
22 #include <vnet/plugin/plugin.h>
23 #include <vnet/ip/reass/ip6_sv_reass.h>
25 nat66_main_t nat66_main;
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"),
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"),
41 clib_error_t *nat66_plugin_api_hookup (vlib_main_t * vm);
43 #define fail_if_enabled() \
46 nat66_main_t *nm = &nat66_main; \
47 if (PREDICT_FALSE (nm->enabled)) \
49 nat66_elog_warn ("plugin enabled"); \
55 #define fail_if_disabled() \
58 nat66_main_t *nm = &nat66_main; \
59 if (PREDICT_FALSE (!nm->enabled)) \
61 nat66_elog_warn ("plugin disabled"); \
68 nat66_init (vlib_main_t * vm)
70 nat66_main_t *nm = &nat66_main;
72 clib_memset (nm, 0, sizeof (*nm));
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";
80 nm->nat_fib_src_hi = fib_source_allocate ("nat66-hi", FIB_SOURCE_PRIORITY_HI,
81 FIB_SOURCE_BH_SIMPLE);
82 return nat66_plugin_api_hookup (vm);
86 nat66_plugin_enable (u32 outside_vrf)
88 nat66_main_t *nm = &nat66_main;
90 u32 static_mapping_buckets = 1024;
91 uword static_mapping_memory_size = 64 << 20;
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);
100 nm->outside_vrf_id = outside_vrf;
101 nm->outside_fib_index = fib_table_find_or_create_and_lock (
102 FIB_PROTOCOL_IP6, outside_vrf, nm->nat_fib_src_hi);
108 nat66_plugin_disable ()
110 nat66_main_t *nm = &nat66_main;
111 nat66_interface_t *i, *temp;
114 temp = pool_dup (nm->interfaces);
115 pool_foreach (i, temp)
117 if (nat66_interface_is_inside (i))
118 error = nat66_interface_add_del (i->sw_if_index, 1, 0);
120 if (nat66_interface_is_outside (i))
121 error = nat66_interface_add_del (i->sw_if_index, 0, 0);
125 nat66_elog_warn ("error occurred while removing interface");
129 pool_free (nm->interfaces);
132 clib_bihash_free_24_8 (&nm->sm_l);
133 clib_bihash_free_24_8 (&nm->sm_e);
138 vlib_clear_combined_counters (&nm->session_counters);
139 vlib_clear_simple_counters (&nm->in2out_packets);
140 vlib_clear_simple_counters (&nm->out2in_packets);
147 nat66_validate_counters (nat66_main_t * nm, u32 sw_if_index)
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);
156 nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
158 nat66_main_t *nm = &nat66_main;
159 nat66_interface_t *interface = 0, *i;
160 const char *feature_name;
164 pool_foreach (i, nm->interfaces)
166 if (i->sw_if_index == sw_if_index)
176 return VNET_API_ERROR_VALUE_EXIST;
178 pool_get (nm->interfaces, interface);
179 interface->sw_if_index = sw_if_index;
181 is_inside ? NAT66_INTERFACE_FLAG_IS_INSIDE :
182 NAT66_INTERFACE_FLAG_IS_OUTSIDE;
183 nat66_validate_counters (nm, sw_if_index);
188 return VNET_API_ERROR_NO_SUCH_ENTRY;
190 pool_put (nm->interfaces, interface);
193 feature_name = is_inside ? "nat66-in2out" : "nat66-out2in";
194 int rv = ip6_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
197 return vnet_feature_enable_disable ("ip6-unicast", feature_name,
198 sw_if_index, is_add, 0, 0);
202 nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx)
204 nat66_main_t *nm = &nat66_main;
205 nat66_interface_t *i = 0;
207 pool_foreach (i, nm->interfaces)
214 nat66_static_mapping_t *
215 nat66_static_mapping_get (ip6_address_t * addr, u32 fib_index, u8 is_local)
217 nat66_main_t *nm = &nat66_main;
218 nat66_static_mapping_t *sm = 0;
219 nat66_sm_key_t sm_key;
220 clib_bihash_kv_24_8_t kv, value;
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;
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];
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);
239 nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
240 u32 vrf_id, u8 is_add)
242 nat66_main_t *nm = &nat66_main;
244 nat66_static_mapping_t *sm = 0;
245 nat66_sm_key_t sm_key;
246 clib_bihash_kv_24_8_t kv, value;
247 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, vrf_id);
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;
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];
259 if (!clib_bihash_search_24_8 (&nm->sm_l, &kv, &value))
260 sm = pool_elt_at_index (nm->sm, value.value);
265 return VNET_API_ERROR_VALUE_EXIST;
267 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
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;
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");
293 vlib_validate_combined_counter (&nm->session_counters, kv.value);
294 vlib_zero_combined_counter (&nm->session_counters, kv.value);
299 return VNET_API_ERROR_NO_SUCH_ENTRY;
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);
320 nat66_static_mappings_walk (nat66_static_mapping_walk_fn_t fn, void *ctx)
322 nat66_main_t *nm = &nat66_main;
323 nat66_static_mapping_t *sm = 0;
325 pool_foreach (sm, nm->sm)
332 VLIB_PLUGIN_REGISTER () =
334 .version = VPP_BUILD_VER,
335 .description = "NAT66",
338 VLIB_INIT_FUNCTION (nat66_init);
341 * fd.io coding-style-patch-verification: ON
344 * eval: (c-set-style "gnu")