4fe4422df13d57d14566a9b8bce396f2ac648a2f
[vpp.git] / src / plugins / nat / dslite / dslite.c
1 /*
2  * Copyright (c) 2017 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 #include <vnet/plugin/plugin.h>
16 #include <nat/dslite/dslite.h>
17 #include <nat/dslite/dslite_dpo.h>
18 #include <vnet/fib/fib_table.h>
19 #include <vpp/app/version.h>
20
21 dslite_main_t dslite_main;
22 fib_source_t nat_fib_src_hi;
23
24 clib_error_t *dslite_api_hookup (vlib_main_t * vm);
25
26 void
27 add_del_dslite_pool_addr_cb (ip4_address_t addr, u8 is_add, void *opaque);
28
29 static clib_error_t *
30 dslite_init (vlib_main_t * vm)
31 {
32   dslite_main_t *dm = &dslite_main;
33   vlib_thread_registration_t *tr;
34   vlib_thread_main_t *tm = vlib_get_thread_main ();
35   uword *p;
36   vlib_node_t *node;
37
38   node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out");
39   dm->dslite_in2out_node_index = node->index;
40
41   node = vlib_get_node_by_name (vm, (u8 *) "dslite-in2out-slowpath");
42   dm->dslite_in2out_slowpath_node_index = node->index;
43
44   node = vlib_get_node_by_name (vm, (u8 *) "dslite-out2in");
45   dm->dslite_out2in_node_index = node->index;
46
47   dm->first_worker_index = 0;
48   dm->num_workers = 0;
49
50   // init nat address pool
51   dm->pool.add_del_pool_addr_cb = add_del_dslite_pool_addr_cb;
52   dm->pool.alloc_addr_and_port_cb = nat_alloc_ip4_addr_and_port_cb_default;
53
54   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
55   if (p)
56     {
57       tr = (vlib_thread_registration_t *) p[0];
58       if (tr)
59         {
60           dm->num_workers = tr->count;
61           dm->first_worker_index = tr->first_index;
62         }
63     }
64
65   if (dm->num_workers)
66     dm->port_per_thread = (0xffff - 1024) / dm->num_workers;
67   else
68     dm->port_per_thread = 0xffff - 1024;
69
70   vec_validate (dm->per_thread_data, tm->n_vlib_mains - 1);
71
72   dm->is_ce = 0;
73   dm->is_enabled = 0;
74
75   /* Init counters */
76   dm->total_b4s.name = "total-b4s";
77   dm->total_b4s.stat_segment_name = "/dslite/total-b4s";
78   vlib_validate_simple_counter (&dm->total_b4s, 0);
79   vlib_zero_simple_counter (&dm->total_b4s, 0);
80   dm->total_sessions.name = "total-sessions";
81   dm->total_sessions.stat_segment_name = "/dslite/total-sessions";
82   vlib_validate_simple_counter (&dm->total_sessions, 0);
83   vlib_zero_simple_counter (&dm->total_sessions, 0);
84
85   dslite_dpo_module_init ();
86
87   nat_fib_src_hi = fib_source_allocate ("dslite-hi",
88                                         FIB_SOURCE_PRIORITY_HI,
89                                         FIB_SOURCE_BH_SIMPLE);
90
91   return dslite_api_hookup (vm);
92 }
93
94 static void
95 dslite_init_datastructures (void)
96 {
97   dslite_main_t *dm = &dslite_main;
98   dslite_per_thread_data_t *td;
99   u32 translation_buckets = 1024;
100   u32 translation_memory_size = 128 << 20;
101   u32 b4_buckets = 128;
102   u32 b4_memory_size = 64 << 20;
103
104   /* *INDENT-OFF* */
105   vec_foreach (td, dm->per_thread_data)
106     {
107       clib_bihash_init_24_8 (&td->in2out, "dslite in2out", translation_buckets,
108                              translation_memory_size);
109
110       clib_bihash_init_8_8 (&td->out2in, "dslite out2in", translation_buckets,
111                             translation_memory_size);
112
113       clib_bihash_init_16_8 (&td->b4_hash, "dslite b4s", b4_buckets, b4_memory_size);
114     }
115   /* *INDENT-ON* */
116   dm->is_enabled = 1;
117 }
118
119 void
120 dslite_set_ce (dslite_main_t * dm, u8 set)
121 {
122   dm->is_ce = (set != 0);
123 }
124
125 static clib_error_t *
126 dslite_config (vlib_main_t * vm, unformat_input_t * input)
127 {
128   dslite_main_t *dm = &dslite_main;
129
130   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
131     {
132       if (unformat (input, "ce"))
133         dslite_set_ce (dm, 1);
134     }
135   return 0;
136 }
137
138 VLIB_CONFIG_FUNCTION (dslite_config, "dslite");
139
140 int
141 dslite_set_aftr_ip6_addr (dslite_main_t * dm, ip6_address_t * addr)
142 {
143   dpo_id_t dpo = DPO_INVALID;
144
145   if (!dm->is_enabled)
146     dslite_init_datastructures ();
147
148   if (dm->is_ce)
149     {
150       dslite_ce_dpo_create (DPO_PROTO_IP4, 0, &dpo);
151       fib_prefix_t pfx = {
152         .fp_proto = FIB_PROTOCOL_IP4,
153         .fp_len = 0,
154         .fp_addr.ip4.as_u32 = 0,
155       };
156       fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
157                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
158     }
159   else
160     {
161       dslite_dpo_create (DPO_PROTO_IP6, 0, &dpo);
162       fib_prefix_t pfx = {
163         .fp_proto = FIB_PROTOCOL_IP6,
164         .fp_len = 128,
165         .fp_addr.ip6.as_u64[0] = addr->as_u64[0],
166         .fp_addr.ip6.as_u64[1] = addr->as_u64[1],
167       };
168       fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
169                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
170     }
171
172   dpo_reset (&dpo);
173
174   dm->aftr_ip6_addr.as_u64[0] = addr->as_u64[0];
175   dm->aftr_ip6_addr.as_u64[1] = addr->as_u64[1];
176   return 0;
177 }
178
179 int
180 dslite_set_aftr_ip4_addr (dslite_main_t * dm, ip4_address_t * addr)
181 {
182   dm->aftr_ip4_addr.as_u32 = addr->as_u32;
183   return 0;
184 }
185
186 int
187 dslite_set_b4_ip6_addr (dslite_main_t * dm, ip6_address_t * addr)
188 {
189   if (!dm->is_enabled)
190     dslite_init_datastructures ();
191
192   if (dm->is_ce)
193     {
194       dpo_id_t dpo = DPO_INVALID;
195
196       dslite_ce_dpo_create (DPO_PROTO_IP6, 0, &dpo);
197       fib_prefix_t pfx = {
198         .fp_proto = FIB_PROTOCOL_IP6,
199         .fp_len = 128,
200         .fp_addr.ip6.as_u64[0] = addr->as_u64[0],
201         .fp_addr.ip6.as_u64[1] = addr->as_u64[1],
202       };
203       fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
204                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
205
206       dpo_reset (&dpo);
207
208       dm->b4_ip6_addr.as_u64[0] = addr->as_u64[0];
209       dm->b4_ip6_addr.as_u64[1] = addr->as_u64[1];
210     }
211   else
212     {
213       return VNET_API_ERROR_FEATURE_DISABLED;
214     }
215
216   return 0;
217 }
218
219 int
220 dslite_set_b4_ip4_addr (dslite_main_t * dm, ip4_address_t * addr)
221 {
222   if (dm->is_ce)
223     {
224       dm->b4_ip4_addr.as_u32 = addr->as_u32;
225     }
226   else
227     {
228       return VNET_API_ERROR_FEATURE_DISABLED;
229     }
230
231   return 0;
232 }
233
234 void
235 add_del_dslite_pool_addr_cb (ip4_address_t addr, u8 is_add, void *opaque)
236 {
237   dpo_id_t dpo_v4 = DPO_INVALID;
238   fib_prefix_t pfx = {
239     .fp_proto = FIB_PROTOCOL_IP4,
240     .fp_len = 32,
241     .fp_addr.ip4.as_u32 = addr.as_u32,
242   };
243
244   if (is_add)
245     {
246       dslite_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
247       fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
248                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
249       dpo_reset (&dpo_v4);
250     }
251   else
252     {
253       fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
254     }
255 }
256
257 u8 *
258 format_dslite_trace (u8 * s, va_list * args)
259 {
260   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
261   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
262   dslite_trace_t *t = va_arg (*args, dslite_trace_t *);
263
264   s =
265     format (s, "next index %d, session %d", t->next_index, t->session_index);
266
267   return s;
268 }
269
270 u8 *
271 format_dslite_ce_trace (u8 * s, va_list * args)
272 {
273   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
274   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
275   dslite_ce_trace_t *t = va_arg (*args, dslite_ce_trace_t *);
276
277   s = format (s, "next index %d", t->next_index);
278
279   return s;
280 }
281
282 VLIB_INIT_FUNCTION (dslite_init);
283
284 /* *INDENT-OFF* */
285 VLIB_PLUGIN_REGISTER () =
286 {
287   .version = VPP_BUILD_VER,
288   .description = "Dual-Stack Lite",
289 };
290 /* *INDENT-ON* */
291
292 /*
293  * fd.io coding-style-patch-verification: ON
294  *
295  * Local Variables:
296  * eval: (c-set-style "gnu")
297  * End:
298  */