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