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