wireguard: add async mode for encryption packets
[vpp.git] / src / plugins / nat / nat66 / nat66.c
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>
23 #include <vnet/ip/reass/ip6_sv_reass.h>
24
25 nat66_main_t nat66_main;
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
41 clib_error_t *nat66_plugin_api_hookup (vlib_main_t * vm);
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 *
68 nat66_init (vlib_main_t * vm)
69 {
70   nat66_main_t *nm = &nat66_main;
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,
81                                             FIB_SOURCE_BH_SIMPLE);
82   return nat66_plugin_api_hookup (vm);
83 }
84
85 int
86 nat66_plugin_enable (u32 outside_vrf)
87 {
88   nat66_main_t *nm = &nat66_main;
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;
101   nm->outside_fib_index = fib_table_find_or_create_and_lock (
102     FIB_PROTOCOL_IP6, outside_vrf, nm->nat_fib_src_hi);
103   nm->enabled = 1;
104   return 0;
105 }
106
107 int
108 nat66_plugin_disable ()
109 {
110   nat66_main_t *nm = &nat66_main;
111   nat66_interface_t *i, *temp;
112   int error = 0;
113
114   temp = pool_dup (nm->interfaces);
115   pool_foreach (i, temp)
116     {
117       if (nat66_interface_is_inside (i))
118         error = nat66_interface_add_del (i->sw_if_index, 1, 0);
119
120       if (nat66_interface_is_outside (i))
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);
129   pool_free (nm->interfaces);
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
147 nat66_validate_counters (nat66_main_t * nm, u32 sw_if_index)
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
156 nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
157 {
158   nat66_main_t *nm = &nat66_main;
159   nat66_interface_t *interface = 0, *i;
160   const char *feature_name;
161
162   fail_if_disabled ();
163
164   pool_foreach (i, nm->interfaces)
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 :
182         NAT66_INTERFACE_FLAG_IS_OUTSIDE;
183       nat66_validate_counters (nm, sw_if_index);
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";
194   int rv = ip6_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
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
202 nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx)
203 {
204   nat66_main_t *nm = &nat66_main;
205   nat66_interface_t *i = 0;
206
207   pool_foreach (i, nm->interfaces)
208    {
209     if (fn (i, ctx))
210       break;
211   }
212 }
213
214 nat66_static_mapping_t *
215 nat66_static_mapping_get (ip6_address_t * addr, u32 fib_index, u8 is_local)
216 {
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;
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 {
242   nat66_main_t *nm = &nat66_main;
243   int rv = 0;
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);
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
267       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
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
320 nat66_static_mappings_walk (nat66_static_mapping_walk_fn_t fn, void *ctx)
321 {
322   nat66_main_t *nm = &nat66_main;
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
332 VLIB_PLUGIN_REGISTER () =
333 {
334  .version = VPP_BUILD_VER,
335  .description = "NAT66",
336 };
337
338 VLIB_INIT_FUNCTION (nat66_init);
339
340 /*
341  * fd.io coding-style-patch-verification: ON
342  *
343  * Local Variables:
344  * eval: (c-set-style "gnu")
345  * End:
346  */