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