Line data Source code
1 : /*
2 : * l2tp.c : L2TPv3 tunnel support
3 : *
4 : * Copyright (c) 2013 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vppinfra/error.h>
19 : #include <vppinfra/hash.h>
20 : #include <vnet/vnet.h>
21 : #include <vnet/ip/ip.h>
22 : #include <vnet/l2/l2_input.h>
23 : #include <vnet/ethernet/ethernet.h>
24 : #include <l2tp/l2tp.h>
25 :
26 : l2t_main_t l2t_main;
27 :
28 : /* packet trace format function */
29 : u8 *
30 1 : format_l2t_trace (u8 * s, va_list * args)
31 : {
32 1 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
33 1 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
34 1 : l2t_trace_t *t = va_arg (*args, l2t_trace_t *);
35 :
36 1 : if (t->is_user_to_network)
37 1 : s = format (s, "L2T: %U (client) -> %U (our) session %d",
38 : format_ip6_address, &t->client_address,
39 : format_ip6_address, &t->our_address, t->session_index);
40 : else
41 0 : s = format (s, "L2T: %U (our) -> %U (client) session %d)",
42 : format_ip6_address, &t->our_address,
43 : format_ip6_address, &t->client_address, t->session_index);
44 1 : return s;
45 : }
46 :
47 : u8 *
48 0 : format_l2t_session (u8 * s, va_list * args)
49 : {
50 0 : l2t_session_t *session = va_arg (*args, l2t_session_t *);
51 0 : l2t_main_t *lm = &l2t_main;
52 : u32 counter_index;
53 : vlib_counter_t v;
54 :
55 0 : s = format (s, "[%d] %U (our) %U (client) %U (sw_if_index %d)\n",
56 0 : session - lm->sessions,
57 : format_ip6_address, &session->our_address,
58 : format_ip6_address, &session->client_address,
59 : format_vnet_sw_interface_name, lm->vnet_main,
60 : vnet_get_sw_interface (lm->vnet_main, session->sw_if_index),
61 : session->sw_if_index);
62 :
63 0 : s = format (s, " local cookies %016llx %016llx remote cookie %016llx\n",
64 : clib_net_to_host_u64 (session->local_cookie[0]),
65 : clib_net_to_host_u64 (session->local_cookie[1]),
66 : clib_net_to_host_u64 (session->remote_cookie));
67 :
68 0 : s = format (s, " local session-id %d remote session-id %d\n",
69 : clib_net_to_host_u32 (session->local_session_id),
70 : clib_net_to_host_u32 (session->remote_session_id));
71 :
72 0 : s = format (s, " l2 specific sublayer %s\n",
73 0 : session->l2_sublayer_present ? "preset" : "absent");
74 :
75 : counter_index =
76 0 : session_index_to_counter_index (session - lm->sessions,
77 : SESSION_COUNTER_USER_TO_NETWORK);
78 :
79 0 : vlib_get_combined_counter (&lm->counter_main, counter_index, &v);
80 0 : if (v.packets != 0)
81 0 : s = format (s, " user-to-net: %llu pkts %llu bytes\n",
82 : v.packets, v.bytes);
83 :
84 0 : vlib_get_combined_counter (&lm->counter_main, counter_index + 1, &v);
85 :
86 0 : if (v.packets != 0)
87 0 : s = format (s, " net-to-user: %llu pkts %llu bytes\n",
88 : v.packets, v.bytes);
89 0 : return s;
90 : }
91 :
92 : static clib_error_t *
93 0 : show_l2tp_command_fn (vlib_main_t * vm,
94 : unformat_input_t * input, vlib_cli_command_t * cmd)
95 : {
96 : l2t_session_t *session;
97 0 : l2t_main_t *lm = &l2t_main;
98 0 : char *keystr = 0;
99 0 : int verbose = 0;
100 :
101 0 : if (unformat (input, "verbose") || unformat (input, "v"))
102 0 : verbose = 1;
103 :
104 0 : if (pool_elts (lm->sessions) == 0)
105 0 : vlib_cli_output (vm, "No l2tp sessions...");
106 : else
107 0 : vlib_cli_output (vm, "%u l2tp sessions...", pool_elts (lm->sessions));
108 :
109 0 : if (verbose)
110 : {
111 0 : switch (lm->lookup_type)
112 : {
113 0 : case L2T_LOOKUP_SRC_ADDRESS:
114 0 : keystr = "src address";
115 0 : break;
116 :
117 0 : case L2T_LOOKUP_DST_ADDRESS:
118 0 : keystr = "dst address";
119 0 : break;
120 :
121 0 : case L2T_LOOKUP_SESSION_ID:
122 0 : keystr = "session id";
123 0 : break;
124 :
125 0 : default:
126 0 : keystr = "BOGUS!";
127 0 : break;
128 : }
129 :
130 0 : vlib_cli_output (vm, "L2tp session lookup on %s", keystr);
131 :
132 : /* *INDENT-OFF* */
133 0 : pool_foreach (session, lm->sessions)
134 : {
135 0 : vlib_cli_output (vm, "%U", format_l2t_session, session);
136 : }
137 : /* *INDENT-ON* */
138 : }
139 :
140 0 : return 0;
141 : }
142 :
143 : /* *INDENT-OFF* */
144 172087 : VLIB_CLI_COMMAND (show_session_detail_command, static) = {
145 : .path = "show l2tpv3",
146 : .short_help = "show l2tpv3 [verbose]",
147 : .function = show_l2tp_command_fn,
148 : };
149 : /* *INDENT-ON* */
150 :
151 : static clib_error_t *
152 0 : test_counters_command_fn (vlib_main_t * vm,
153 : unformat_input_t * input, vlib_cli_command_t * cmd)
154 : {
155 : l2t_session_t *session;
156 0 : l2t_main_t *lm = &l2t_main;
157 : u32 session_index;
158 : u32 counter_index;
159 0 : u32 nincr = 0;
160 0 : u32 thread_index = vm->thread_index;
161 :
162 : /* *INDENT-OFF* */
163 0 : pool_foreach (session, lm->sessions)
164 : {
165 0 : session_index = session - lm->sessions;
166 : counter_index =
167 0 : session_index_to_counter_index (session_index,
168 : SESSION_COUNTER_USER_TO_NETWORK);
169 0 : vlib_increment_combined_counter (&lm->counter_main,
170 : thread_index,
171 : counter_index,
172 : 1/*pkt*/, 1111 /*bytes*/);
173 0 : vlib_increment_combined_counter (&lm->counter_main,
174 : thread_index,
175 : counter_index+1,
176 : 1/*pkt*/, 2222 /*bytes*/);
177 0 : nincr++;
178 :
179 : }
180 : /* *INDENT-ON* */
181 0 : vlib_cli_output (vm, "Incremented %d active counters\n", nincr);
182 :
183 0 : return 0;
184 : }
185 :
186 : /* *INDENT-OFF* */
187 172087 : VLIB_CLI_COMMAND (test_counters_command, static) = {
188 : .path = "test lt2p counters",
189 : .short_help = "increment all active counters",
190 : .function = test_counters_command_fn,
191 : };
192 : /* *INDENT-ON* */
193 :
194 : static clib_error_t *
195 0 : clear_counters_command_fn (vlib_main_t * vm,
196 : unformat_input_t * input, vlib_cli_command_t * cmd)
197 : {
198 : l2t_session_t *session;
199 0 : l2t_main_t *lm = &l2t_main;
200 : u32 session_index;
201 : u32 counter_index;
202 0 : u32 nincr = 0;
203 :
204 : /* *INDENT-OFF* */
205 0 : pool_foreach (session, lm->sessions)
206 : {
207 0 : session_index = session - lm->sessions;
208 : counter_index =
209 0 : session_index_to_counter_index (session_index,
210 : SESSION_COUNTER_USER_TO_NETWORK);
211 0 : vlib_zero_combined_counter (&lm->counter_main, counter_index);
212 0 : vlib_zero_combined_counter (&lm->counter_main, counter_index+1);
213 0 : nincr++;
214 : }
215 : /* *INDENT-ON* */
216 0 : vlib_cli_output (vm, "Cleared %d active counters\n", nincr);
217 :
218 0 : return 0;
219 : }
220 :
221 : /* *INDENT-OFF* */
222 172087 : VLIB_CLI_COMMAND (clear_counters_command, static) = {
223 : .path = "clear l2tp counters",
224 : .short_help = "clear all active counters",
225 : .function = clear_counters_command_fn,
226 : };
227 : /* *INDENT-ON* */
228 :
229 : static u8 *
230 2 : format_l2tpv3_name (u8 * s, va_list * args)
231 : {
232 2 : l2t_main_t *lm = &l2t_main;
233 2 : u32 i = va_arg (*args, u32);
234 2 : u32 show_dev_instance = ~0;
235 :
236 2 : if (i < vec_len (lm->dev_inst_by_real))
237 0 : show_dev_instance = lm->dev_inst_by_real[i];
238 :
239 2 : if (show_dev_instance != ~0)
240 0 : i = show_dev_instance;
241 :
242 2 : return format (s, "l2tpv3_tunnel%d", i);
243 : }
244 :
245 : static int
246 0 : l2tpv3_name_renumber (vnet_hw_interface_t * hi, u32 new_dev_instance)
247 : {
248 0 : l2t_main_t *lm = &l2t_main;
249 :
250 0 : vec_validate_init_empty (lm->dev_inst_by_real, hi->dev_instance, ~0);
251 :
252 0 : lm->dev_inst_by_real[hi->dev_instance] = new_dev_instance;
253 :
254 0 : return 0;
255 : }
256 :
257 : /* *INDENT-OFF* */
258 7279 : VNET_DEVICE_CLASS (l2tpv3_device_class,static) = {
259 : .name = "L2TPv3",
260 : .format_device_name = format_l2tpv3_name,
261 : .name_renumber = l2tpv3_name_renumber,
262 : };
263 : /* *INDENT-ON* */
264 :
265 : static u8 *
266 0 : format_l2tp_header_with_length (u8 * s, va_list * args)
267 : {
268 0 : u32 dev_instance = va_arg (*args, u32);
269 0 : s = format (s, "unimplemented dev %u", dev_instance);
270 0 : return s;
271 : }
272 :
273 : /* *INDENT-OFF* */
274 3919 : VNET_HW_INTERFACE_CLASS (l2tpv3_hw_class) = {
275 : .name = "L2TPV3",
276 : .format_header = format_l2tp_header_with_length,
277 : .build_rewrite = default_build_rewrite,
278 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
279 : };
280 : /* *INDENT-ON* */
281 :
282 : int
283 1 : create_l2tpv3_ipv6_tunnel (l2t_main_t * lm,
284 : ip6_address_t * client_address,
285 : ip6_address_t * our_address,
286 : u32 local_session_id,
287 : u32 remote_session_id,
288 : u64 local_cookie,
289 : u64 remote_cookie,
290 : int l2_sublayer_present,
291 : u32 encap_fib_index, u32 * sw_if_index)
292 : {
293 1 : l2t_session_t *s = 0;
294 1 : vnet_main_t *vnm = lm->vnet_main;
295 : vnet_hw_interface_t *hi;
296 1 : uword *p = (uword *) ~ 0;
297 : u32 hw_if_index;
298 : l2tpv3_header_t l2tp_hdr;
299 : ip6_address_t *dst_address_copy, *src_address_copy;
300 : u32 counter_index;
301 :
302 1 : remote_session_id = clib_host_to_net_u32 (remote_session_id);
303 1 : local_session_id = clib_host_to_net_u32 (local_session_id);
304 :
305 1 : switch (lm->lookup_type)
306 : {
307 0 : case L2T_LOOKUP_SRC_ADDRESS:
308 0 : p = hash_get_mem (lm->session_by_src_address, client_address);
309 0 : break;
310 :
311 1 : case L2T_LOOKUP_DST_ADDRESS:
312 1 : p = hash_get_mem (lm->session_by_dst_address, our_address);
313 1 : break;
314 :
315 0 : case L2T_LOOKUP_SESSION_ID:
316 0 : p = hash_get (lm->session_by_session_id, local_session_id);
317 0 : break;
318 :
319 0 : default:
320 0 : ASSERT (0);
321 : }
322 :
323 : /* adding a session: session must not already exist */
324 1 : if (p)
325 0 : return VNET_API_ERROR_INVALID_VALUE;
326 :
327 1 : pool_get (lm->sessions, s);
328 1 : clib_memset (s, 0, sizeof (*s));
329 1 : clib_memcpy (&s->our_address, our_address, sizeof (s->our_address));
330 1 : clib_memcpy (&s->client_address, client_address,
331 : sizeof (s->client_address));
332 1 : s->local_cookie[0] = clib_host_to_net_u64 (local_cookie);
333 1 : s->remote_cookie = clib_host_to_net_u64 (remote_cookie);
334 1 : s->local_session_id = local_session_id;
335 1 : s->remote_session_id = remote_session_id;
336 1 : s->l2_sublayer_present = l2_sublayer_present;
337 : /* precompute l2tp header size */
338 1 : s->l2tp_hdr_size = l2_sublayer_present ?
339 : sizeof (l2tpv3_header_t) :
340 : sizeof (l2tpv3_header_t) - sizeof (l2tp_hdr.l2_specific_sublayer);
341 1 : s->admin_up = 0;
342 1 : s->encap_fib_index = encap_fib_index;
343 :
344 : /* Setup hash table entries */
345 1 : switch (lm->lookup_type)
346 : {
347 0 : case L2T_LOOKUP_SRC_ADDRESS:
348 0 : src_address_copy = clib_mem_alloc (sizeof (*src_address_copy));
349 0 : clib_memcpy (src_address_copy, client_address,
350 : sizeof (*src_address_copy));
351 0 : hash_set_mem (lm->session_by_src_address, src_address_copy,
352 : s - lm->sessions);
353 0 : break;
354 1 : case L2T_LOOKUP_DST_ADDRESS:
355 1 : dst_address_copy = clib_mem_alloc (sizeof (*dst_address_copy));
356 1 : clib_memcpy (dst_address_copy, our_address, sizeof (*dst_address_copy));
357 2 : hash_set_mem (lm->session_by_dst_address, dst_address_copy,
358 : s - lm->sessions);
359 1 : break;
360 0 : case L2T_LOOKUP_SESSION_ID:
361 0 : hash_set (lm->session_by_session_id, local_session_id,
362 : s - lm->sessions);
363 0 : break;
364 :
365 0 : default:
366 0 : ASSERT (0);
367 : }
368 :
369 : /* validate counters */
370 : counter_index =
371 1 : session_index_to_counter_index (s - lm->sessions,
372 : SESSION_COUNTER_USER_TO_NETWORK);
373 1 : vlib_validate_combined_counter (&lm->counter_main, counter_index);
374 1 : vlib_validate_combined_counter (&lm->counter_main, counter_index + 1);
375 :
376 1 : if (vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) > 0)
377 : {
378 0 : hw_if_index = lm->free_l2tpv3_tunnel_hw_if_indices
379 0 : [vec_len (lm->free_l2tpv3_tunnel_hw_if_indices) - 1];
380 0 : vec_dec_len (lm->free_l2tpv3_tunnel_hw_if_indices, 1);
381 :
382 0 : hi = vnet_get_hw_interface (vnm, hw_if_index);
383 0 : hi->dev_instance = s - lm->sessions;
384 0 : hi->hw_instance = hi->dev_instance;
385 : }
386 : else
387 : {
388 1 : hw_if_index = vnet_register_interface
389 1 : (vnm, l2tpv3_device_class.index, s - lm->sessions,
390 1 : l2tpv3_hw_class.index, s - lm->sessions);
391 1 : hi = vnet_get_hw_interface (vnm, hw_if_index);
392 1 : hi->output_node_index = l2t_encap_node.index;
393 : /* $$$$ initialize custom dispositions, if needed */
394 : }
395 :
396 1 : s->hw_if_index = hw_if_index;
397 1 : s->sw_if_index = hi->sw_if_index;
398 :
399 1 : if (sw_if_index)
400 1 : *sw_if_index = hi->sw_if_index;
401 :
402 1 : if (!lm->proto_registered)
403 : {
404 1 : ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_local_node.index);
405 1 : lm->proto_registered = true;
406 : }
407 :
408 1 : return 0;
409 : }
410 :
411 : static clib_error_t *
412 0 : create_l2tpv3_tunnel_command_fn (vlib_main_t * vm,
413 : unformat_input_t * input,
414 : vlib_cli_command_t * cmd)
415 : {
416 : ip6_address_t client_address, our_address;
417 0 : unformat_input_t _line_input, *line_input = &_line_input;
418 0 : l2t_main_t *lm = &l2t_main;
419 0 : u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0;
420 0 : u32 local_session_id = 1, remote_session_id = 1;
421 0 : int our_address_set = 0, client_address_set = 0;
422 0 : int l2_sublayer_present = 0;
423 : int rv;
424 : u32 sw_if_index;
425 0 : u32 encap_fib_id = ~0;
426 0 : u32 encap_fib_index = ~0;
427 0 : clib_error_t *error = NULL;
428 :
429 : /* Get a line of input. */
430 0 : if (!unformat_user (input, unformat_line_input, line_input))
431 0 : return 0;
432 :
433 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
434 : {
435 0 : if (unformat (line_input, "client %U",
436 : unformat_ip6_address, &client_address))
437 0 : client_address_set = 1;
438 0 : else if (unformat (line_input, "our %U",
439 : unformat_ip6_address, &our_address))
440 0 : our_address_set = 1;
441 0 : else if (unformat (line_input, "local-cookie %llx", &local_cookie))
442 : ;
443 0 : else if (unformat (line_input, "remote-cookie %llx", &remote_cookie))
444 : ;
445 0 : else if (unformat (line_input, "local-session-id %d",
446 : &local_session_id))
447 : ;
448 0 : else if (unformat (line_input, "remote-session-id %d",
449 : &remote_session_id))
450 : ;
451 0 : else if (unformat (line_input, "fib-id %d", &encap_fib_id))
452 : ;
453 0 : else if (unformat (line_input, "l2-sublayer-present"))
454 0 : l2_sublayer_present = 1;
455 : else
456 : {
457 0 : error = clib_error_return (0, "parse error: '%U'",
458 : format_unformat_error, line_input);
459 0 : goto done;
460 : }
461 : }
462 :
463 0 : if (encap_fib_id != ~0)
464 : {
465 : uword *p;
466 0 : ip6_main_t *im = &ip6_main;
467 0 : if (!(p = hash_get (im->fib_index_by_table_id, encap_fib_id)))
468 : {
469 0 : error = clib_error_return (0, "No fib with id %d", encap_fib_id);
470 0 : goto done;
471 : }
472 0 : encap_fib_index = p[0];
473 : }
474 : else
475 : {
476 0 : encap_fib_index = ~0;
477 : }
478 :
479 0 : if (our_address_set == 0)
480 : {
481 0 : error = clib_error_return (0, "our address not specified");
482 0 : goto done;
483 : }
484 0 : if (client_address_set == 0)
485 : {
486 0 : error = clib_error_return (0, "client address not specified");
487 0 : goto done;
488 : }
489 :
490 0 : rv = create_l2tpv3_ipv6_tunnel (lm, &client_address, &our_address,
491 : local_session_id, remote_session_id,
492 : local_cookie, remote_cookie,
493 : l2_sublayer_present,
494 : encap_fib_index, &sw_if_index);
495 0 : switch (rv)
496 : {
497 0 : case 0:
498 0 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
499 : vnet_get_main (), sw_if_index);
500 0 : break;
501 0 : case VNET_API_ERROR_INVALID_VALUE:
502 0 : error = clib_error_return (0, "session already exists...");
503 0 : goto done;
504 :
505 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
506 0 : error = clib_error_return (0, "session does not exist...");
507 0 : goto done;
508 :
509 0 : default:
510 0 : error = clib_error_return (0, "l2tp_session_add_del returned %d", rv);
511 0 : goto done;
512 : }
513 :
514 0 : done:
515 0 : unformat_free (line_input);
516 :
517 0 : return error;
518 : }
519 :
520 : /* *INDENT-OFF* */
521 172087 : VLIB_CLI_COMMAND (create_l2tpv3_tunnel_command, static) =
522 : {
523 : .path = "create l2tpv3 tunnel",
524 : .short_help =
525 : "create l2tpv3 tunnel client <ip6> our <ip6> local-cookie <hex> remote-cookie <hex> local-session <dec> remote-session <dec>",
526 : .function = create_l2tpv3_tunnel_command_fn,
527 : };
528 : /* *INDENT-ON* */
529 :
530 : int
531 0 : l2tpv3_set_tunnel_cookies (l2t_main_t * lm,
532 : u32 sw_if_index,
533 : u64 new_local_cookie, u64 new_remote_cookie)
534 : {
535 : l2t_session_t *s;
536 : vnet_hw_interface_t *hi;
537 0 : vnet_main_t *vnm = vnet_get_main ();
538 0 : hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
539 :
540 0 : if (pool_is_free_index (lm->sessions, hi->dev_instance))
541 0 : return VNET_API_ERROR_INVALID_VALUE;
542 :
543 0 : s = pool_elt_at_index (lm->sessions, hi->dev_instance);
544 :
545 0 : s->local_cookie[1] = s->local_cookie[0];
546 0 : s->local_cookie[0] = clib_host_to_net_u64 (new_local_cookie);
547 0 : s->remote_cookie = clib_host_to_net_u64 (new_remote_cookie);
548 :
549 0 : return 0;
550 : }
551 :
552 :
553 : static clib_error_t *
554 0 : set_l2tp_tunnel_cookie_command_fn (vlib_main_t * vm,
555 : unformat_input_t * input,
556 : vlib_cli_command_t * cmd)
557 : {
558 0 : l2t_main_t *lm = &l2t_main;
559 0 : vnet_main_t *vnm = vnet_get_main ();
560 0 : u32 sw_if_index = ~0;
561 0 : u64 local_cookie = (u64) ~ 0, remote_cookie = (u64) ~ 0;
562 :
563 : int rv;
564 :
565 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
566 : {
567 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
568 : &sw_if_index))
569 : ;
570 0 : else if (unformat (input, "local %llx", &local_cookie))
571 : ;
572 0 : else if (unformat (input, "remote %llx", &remote_cookie))
573 : ;
574 : else
575 0 : break;
576 : }
577 0 : if (sw_if_index == ~0)
578 0 : return clib_error_return (0, "unknown interface");
579 0 : if (local_cookie == ~0)
580 0 : return clib_error_return (0, "local cookie required");
581 0 : if (remote_cookie == ~0)
582 0 : return clib_error_return (0, "remote cookie required");
583 :
584 0 : rv = l2tpv3_set_tunnel_cookies (lm, sw_if_index,
585 : local_cookie, remote_cookie);
586 :
587 0 : switch (rv)
588 : {
589 0 : case 0:
590 0 : break;
591 :
592 0 : case VNET_API_ERROR_INVALID_SW_IF_INDEX:
593 0 : return clib_error_return (0, "invalid interface");
594 :
595 0 : default:
596 0 : return clib_error_return (0, "l2tp_session_set_cookies returned %d",
597 : rv);
598 : }
599 :
600 0 : return 0;
601 : }
602 :
603 : /* *INDENT-OFF* */
604 172087 : VLIB_CLI_COMMAND (set_l2tp_tunnel_cookie_command, static) =
605 : {
606 : .path = "set l2tpv3 tunnel cookie",
607 : .short_help =
608 : "set l2tpv3 tunnel cookie <intfc> local <hex> remote <hex>",
609 : .function = set_l2tp_tunnel_cookie_command_fn,
610 : };
611 : /* *INDENT-ON* */
612 :
613 : int
614 0 : l2tpv3_interface_enable_disable (vnet_main_t * vnm,
615 : u32 sw_if_index, int enable_disable)
616 : {
617 :
618 0 : if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
619 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
620 :
621 0 : vnet_feature_enable_disable ("ip6-unicast", "l2tp-decap", sw_if_index,
622 : enable_disable, 0, 0);
623 0 : return 0;
624 : }
625 :
626 : /* Enable/disable L2TPv3 intercept on IP6 forwarding path */
627 : static clib_error_t *
628 0 : set_ip6_l2tpv3 (vlib_main_t * vm,
629 : unformat_input_t * input, vlib_cli_command_t * cmd)
630 : {
631 0 : u32 sw_if_index = ~0;
632 0 : int is_add = 1;
633 : int rv;
634 0 : vnet_main_t *vnm = vnet_get_main ();
635 :
636 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
637 : {
638 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
639 : &sw_if_index))
640 : ;
641 0 : else if (unformat (input, "del"))
642 0 : is_add = 0;
643 : else
644 0 : break;
645 : }
646 :
647 0 : if (sw_if_index == ~0)
648 0 : return clib_error_return (0, "interface required");
649 :
650 0 : rv = l2tpv3_interface_enable_disable (vnm, sw_if_index, is_add);
651 :
652 0 : switch (rv)
653 : {
654 0 : case 0:
655 0 : break;
656 :
657 0 : case VNET_API_ERROR_INVALID_SW_IF_INDEX:
658 0 : return clib_error_return (0, "invalid interface");
659 :
660 0 : default:
661 0 : return clib_error_return (0,
662 : "l2tp_interface_enable_disable returned %d",
663 : rv);
664 : }
665 0 : return 0;
666 : }
667 :
668 : /* *INDENT-OFF* */
669 172087 : VLIB_CLI_COMMAND (set_interface_ip6_l2tpv3, static) =
670 : {
671 : .path = "set interface ip6 l2tpv3",
672 : .function = set_ip6_l2tpv3,
673 : .short_help = "set interface ip6 l2tpv3 <intfc> [del]",
674 : };
675 : /* *INDENT-ON* */
676 :
677 : static clib_error_t *
678 559 : l2tp_config (vlib_main_t * vm, unformat_input_t * input)
679 : {
680 559 : l2t_main_t *lm = &l2t_main;
681 :
682 559 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
683 : {
684 0 : if (unformat (input, "lookup-v6-src"))
685 0 : lm->lookup_type = L2T_LOOKUP_SRC_ADDRESS;
686 0 : else if (unformat (input, "lookup-v6-dst"))
687 0 : lm->lookup_type = L2T_LOOKUP_DST_ADDRESS;
688 0 : else if (unformat (input, "lookup-session-id"))
689 0 : lm->lookup_type = L2T_LOOKUP_SESSION_ID;
690 : else
691 0 : return clib_error_return (0, "unknown input `%U'",
692 : format_unformat_error, input);
693 : }
694 559 : return 0;
695 : }
696 :
697 2826 : VLIB_CONFIG_FUNCTION (l2tp_config, "l2tp");
698 :
699 :
700 : clib_error_t *
701 13268 : l2tp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
702 : {
703 13268 : l2t_main_t *lm = &l2t_main;
704 13268 : vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
705 13268 : if (hi->hw_class_index != l2tpv3_hw_class.index)
706 13268 : return 0;
707 :
708 0 : u32 session_index = hi->dev_instance;
709 0 : l2t_session_t *s = pool_elt_at_index (lm->sessions, session_index);
710 0 : s->admin_up = ! !(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
711 0 : return 0;
712 : }
713 :
714 2241 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2tp_sw_interface_up_down);
715 :
716 : clib_error_t *
717 559 : l2tp_init (vlib_main_t * vm)
718 : {
719 559 : l2t_main_t *lm = &l2t_main;
720 559 : ip_main_t *im = &ip_main;
721 : ip_protocol_info_t *pi;
722 :
723 559 : lm->vnet_main = vnet_get_main ();
724 559 : lm->vlib_main = vm;
725 559 : lm->lookup_type = L2T_LOOKUP_DST_ADDRESS;
726 :
727 559 : lm->session_by_src_address = hash_create_mem
728 : (0, sizeof (ip6_address_t) /* key bytes */ ,
729 : sizeof (u32) /* value bytes */ );
730 559 : lm->session_by_dst_address = hash_create_mem
731 : (0, sizeof (ip6_address_t) /* key bytes */ ,
732 : sizeof (u32) /* value bytes */ );
733 559 : lm->session_by_session_id = hash_create (0, sizeof (uword));
734 :
735 559 : pi = ip_get_protocol_info (im, IP_PROTOCOL_L2TP);
736 559 : pi->unformat_pg_edit = unformat_pg_l2tp_header;
737 :
738 559 : lm->proto_registered = false;
739 :
740 : /* insure these nodes are included in build */
741 559 : l2tp_encap_init (vm);
742 :
743 559 : return 0;
744 : }
745 :
746 1119 : VLIB_INIT_FUNCTION (l2tp_init);
747 :
748 : clib_error_t *
749 54 : l2tp_worker_init (vlib_main_t * vm)
750 : {
751 54 : l2tp_encap_init (vm);
752 :
753 54 : return 0;
754 : }
755 :
756 1119 : VLIB_WORKER_INIT_FUNCTION (l2tp_worker_init);
757 :
758 : /*
759 : * fd.io coding-style-patch-verification: ON
760 : *
761 : * Local Variables:
762 : * eval: (c-set-style "gnu")
763 : * End:
764 : */
|