Dedicated SW Interface Event
[vpp.git] / src / vnet / unix / tuntap.c
1 /* 
2  *------------------------------------------------------------------
3  * tuntap.c - kernel stack (reverse) punt/inject path
4  *
5  * Copyright (c) 2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 /**
20  * @file
21  * @brief  TunTap Kernel stack (reverse) punt/inject path.
22  *
23  * This driver runs in one of two distinct modes:
24  * - "punt/inject" mode, where we send pkts not otherwise processed
25  * by the forwarding to the Linux kernel stack, and
26  *
27  * - "normal interface" mode, where we treat the Linux kernel stack
28  * as a peer.
29  *
30  * By default, we select punt/inject mode.
31  */
32
33 #include <fcntl.h>              /* for open */
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>            /* for iovec */
39 #include <netinet/in.h>
40
41 #include <linux/if_arp.h>
42 #include <linux/if_tun.h>
43
44 #include <vlib/vlib.h>
45 #include <vlib/unix/unix.h>
46
47 #include <vnet/ip/ip.h>
48 #include <vnet/fib/fib_table.h>
49
50 #include <vnet/ethernet/ethernet.h>
51 #include <vnet/devices/devices.h>
52 #include <vnet/feature/feature.h>
53
54 static vnet_device_class_t tuntap_dev_class;
55 static vnet_hw_interface_class_t tuntap_interface_class;
56
57 static void tuntap_punt_frame (vlib_main_t * vm,
58                                vlib_node_runtime_t * node,
59                                vlib_frame_t * frame);
60 static void tuntap_nopunt_frame (vlib_main_t * vm,
61                                  vlib_node_runtime_t * node,
62                                  vlib_frame_t * frame);
63
64 typedef struct {
65   u32 sw_if_index;
66   u8 is_v6;
67   u8 addr[16];
68 } subif_address_t;
69
70 /**
71  * @brief TUNTAP node main state
72  */
73 typedef struct {
74   /** Vector of iovecs for readv/writev calls. */
75   struct iovec * iovecs;
76
77   /** Vector of VLIB rx buffers to use.  We allocate them in blocks
78      of VLIB_FRAME_SIZE (256). */
79   u32 * rx_buffers;
80
81   /** File descriptors for /dev/net/tun and provisioning socket. */
82   int dev_net_tun_fd, dev_tap_fd;
83
84   /** Create a "tap" [ethernet] encaps device */
85   int is_ether;
86
87   /** 1 if a "normal" routed intfc, 0 if a punt/inject interface */
88
89   int have_normal_interface;
90
91   /** tap device destination MAC address. Required, or Linux drops pkts */
92   u8 ether_dst_mac[6];
93
94   /** Interface MTU in bytes and # of default sized buffers. */
95   u32 mtu_bytes, mtu_buffers;
96
97   /** Linux interface name for tun device. */
98   char * tun_name;
99
100   /** Pool of subinterface addresses */
101   subif_address_t *subifs;
102
103   /** Hash for subif addresses */
104   mhash_t subif_mhash;
105
106   /** Unix file index */
107   u32 unix_file_index;
108
109   /** For the "normal" interface, if configured */
110   u32 hw_if_index, sw_if_index;
111
112 } tuntap_main_t;
113
114 static tuntap_main_t tuntap_main = {
115   .tun_name = "vnet",
116
117   /** Suitable defaults for an Ethernet-like tun/tap device */
118   .mtu_bytes = 4096 + 256,
119 };
120
121 /**
122  * @brief tuntap_tx
123  * @node tuntap-tx
124  *
125  * Output node, writes the buffers comprising the incoming frame
126  * to the tun/tap device, aka hands them to the Linux kernel stack.
127  *
128  * @param *vm - vlib_main_t
129  * @param *node - vlib_node_runtime_t
130  * @param *frame - vlib_frame_t
131  *
132  * @return rc - uword
133  *
134  */
135 static uword
136 tuntap_tx (vlib_main_t * vm,
137            vlib_node_runtime_t * node,
138            vlib_frame_t * frame)
139 {
140   u32 * buffers = vlib_frame_args (frame);
141   uword n_packets = frame->n_vectors;
142   tuntap_main_t * tm = &tuntap_main;
143   vnet_main_t *vnm = vnet_get_main ();
144   vnet_interface_main_t *im = &vnm->interface_main;
145   u32 n_bytes = 0;
146   int i;
147
148   for (i = 0; i < n_packets; i++)
149     {
150       struct iovec * iov;
151       vlib_buffer_t * b;
152       uword l;
153
154       b = vlib_get_buffer (vm, buffers[i]);
155
156       if (tm->is_ether && (!tm->have_normal_interface))
157         {
158           vlib_buffer_reset(b);
159           clib_memcpy (vlib_buffer_get_current (b), tm->ether_dst_mac, 6);
160         }
161
162       /* Re-set iovecs if present. */
163       if (tm->iovecs)
164         _vec_len (tm->iovecs) = 0;
165
166       /** VLIB buffer chain -> Unix iovec(s). */
167       vec_add2 (tm->iovecs, iov, 1);
168       iov->iov_base = b->data + b->current_data;
169       iov->iov_len = l = b->current_length;
170
171       if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NEXT_PRESENT))
172         {
173           do {
174             b = vlib_get_buffer (vm, b->next_buffer);
175
176             vec_add2 (tm->iovecs, iov, 1);
177
178             iov->iov_base = b->data + b->current_data;
179             iov->iov_len = b->current_length;
180             l += b->current_length;
181           } while (b->flags & VLIB_BUFFER_NEXT_PRESENT);
182         }
183
184       if (writev (tm->dev_net_tun_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
185         clib_unix_warning ("writev");
186
187       n_bytes += l;
188     }
189
190   /* Update tuntap interface output stats. */
191   vlib_increment_combined_counter (im->combined_sw_if_counters
192                                    + VNET_INTERFACE_COUNTER_TX,
193                                    vm->thread_index,
194                                    tm->sw_if_index, n_packets, n_bytes);
195
196
197   /** The normal interface path flattens the buffer chain */
198   if (tm->have_normal_interface)
199     vlib_buffer_free_no_next (vm, buffers, n_packets);
200   else
201     vlib_buffer_free (vm, buffers, n_packets);
202
203   return n_packets;
204 }
205
206 VLIB_REGISTER_NODE (tuntap_tx_node,static) = {
207   .function = tuntap_tx,
208   .name = "tuntap-tx",
209   .type = VLIB_NODE_TYPE_INTERNAL,
210   .vector_size = 4,
211 };
212
213 /**
214  * @brief TUNTAP receive node
215  * @node tuntap-rx
216  *
217  * @param *vm - vlib_main_t
218  * @param *node - vlib_node_runtime_t
219  * @param *frame - vlib_frame_t
220  *
221  * @return rc - uword
222  *
223  */
224 static uword
225 tuntap_rx (vlib_main_t * vm,
226            vlib_node_runtime_t * node,
227            vlib_frame_t * frame)
228 {
229   tuntap_main_t * tm = &tuntap_main;
230   vlib_buffer_t * b;
231   u32 bi;
232   const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
233
234   /** Make sure we have some RX buffers. */
235   {
236     uword n_left = vec_len (tm->rx_buffers);
237     uword n_alloc;
238
239     if (n_left < VLIB_FRAME_SIZE / 2)
240       {
241         if (! tm->rx_buffers)
242           vec_alloc (tm->rx_buffers, VLIB_FRAME_SIZE);
243
244         n_alloc = vlib_buffer_alloc (vm, tm->rx_buffers + n_left, VLIB_FRAME_SIZE - n_left);
245         _vec_len (tm->rx_buffers) = n_left + n_alloc;
246       }
247   }
248
249   /** Allocate RX buffers from end of rx_buffers.
250      Turn them into iovecs to pass to readv. */
251   {
252     uword i_rx = vec_len (tm->rx_buffers) - 1;
253     vlib_buffer_t * b;
254     word i, n_bytes_left, n_bytes_in_packet;
255
256     /** We should have enough buffers left for an MTU sized packet. */
257     ASSERT (vec_len (tm->rx_buffers) >= tm->mtu_buffers);
258
259     vec_validate (tm->iovecs, tm->mtu_buffers - 1);
260     for (i = 0; i < tm->mtu_buffers; i++)
261       {
262         b = vlib_get_buffer (vm, tm->rx_buffers[i_rx - i]);
263         tm->iovecs[i].iov_base = b->data;
264         tm->iovecs[i].iov_len = buffer_size;
265       }
266
267     n_bytes_left = readv (tm->dev_net_tun_fd, tm->iovecs, tm->mtu_buffers);
268     n_bytes_in_packet = n_bytes_left;
269     if (n_bytes_left <= 0)
270       {
271         if (errno != EAGAIN)
272           clib_unix_warning ("readv %d", n_bytes_left);
273         return 0;
274       }
275
276     bi = tm->rx_buffers[i_rx];
277
278     while (1)
279       {
280         b = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
281         b->flags = 0;
282         b->current_data = 0;
283         b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size;
284
285         n_bytes_left -= buffer_size;
286
287         if (n_bytes_left <= 0)
288           {
289             break;
290           }
291
292         i_rx--;
293         b->flags |= VLIB_BUFFER_NEXT_PRESENT;
294         b->next_buffer = tm->rx_buffers[i_rx];
295       }
296
297     /** Interface counters for tuntap interface. */
298     vlib_increment_combined_counter
299         (vnet_main.interface_main.combined_sw_if_counters
300          + VNET_INTERFACE_COUNTER_RX,
301          vlib_get_thread_index(),
302          tm->sw_if_index,
303          1, n_bytes_in_packet);
304
305     _vec_len (tm->rx_buffers) = i_rx;
306   }
307
308   b = vlib_get_buffer (vm, bi);
309
310   {
311     u32 next_index;
312     uword n_trace = vlib_get_trace_count (vm, node);
313
314     vnet_buffer (b)->sw_if_index[VLIB_RX] = tm->sw_if_index;
315     vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32)~0;
316
317     /*
318      * Turn this on if you run into
319      * "bad monkey" contexts, and you want to know exactly
320      * which nodes they've visited...
321      */
322     if (VLIB_BUFFER_TRACE_TRAJECTORY)
323         b->pre_data[0] = 0;
324
325     b->error = node->errors[0];
326
327     if (tm->is_ether)
328       {
329         next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
330       }
331     else
332       switch (b->data[0] & 0xf0)
333         {
334         case 0x40:
335           next_index = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
336           break;
337         case 0x60:
338           next_index = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
339           break;
340         default:
341           next_index = VNET_DEVICE_INPUT_NEXT_DROP;
342           break;
343         }
344
345     /* The linux kernel couldn't care less if our interface is up */
346     if (tm->have_normal_interface)
347       {
348         vnet_main_t *vnm = vnet_get_main();
349         vnet_sw_interface_t * si;
350         si = vnet_get_sw_interface (vnm, tm->sw_if_index);
351         if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
352           next_index = VNET_DEVICE_INPUT_NEXT_DROP;
353       }
354
355     vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b);
356
357     vlib_set_next_frame_buffer (vm, node, next_index, bi);
358
359     if (n_trace > 0)
360       {
361         vlib_trace_buffer (vm, node, next_index,
362                            b, /* follow_chain */ 1);
363         vlib_set_trace_count (vm, node, n_trace - 1);
364       }
365   }
366
367   return 1;
368 }
369
370 /**
371  * @brief TUNTAP_RX error strings
372  */
373 static char * tuntap_rx_error_strings[] = {
374   "unknown packet type",
375 };
376
377 VLIB_REGISTER_NODE (tuntap_rx_node,static) = {
378   .function = tuntap_rx,
379   .name = "tuntap-rx",
380   .sibling_of = "device-input",
381   .type = VLIB_NODE_TYPE_INPUT,
382   .state = VLIB_NODE_STATE_INTERRUPT,
383   .vector_size = 4,
384   .n_errors = 1,
385   .error_strings = tuntap_rx_error_strings,
386 };
387
388 /**
389  * @brief Gets called when file descriptor is ready from epoll.
390  *
391  * @param *uf - unix_file_t
392  *
393  * @return error - clib_error_t
394  */
395 static clib_error_t * tuntap_read_ready (unix_file_t * uf)
396 {
397   vlib_main_t * vm = vlib_get_main();
398   vlib_node_set_interrupt_pending (vm, tuntap_rx_node.index);
399   return 0;
400 }
401
402 /**
403  * @brief Clean up the tun/tap device
404  *
405  * @param *vm - vlib_main_t
406  *
407  * @return error - clib_error_t
408  *
409  */
410 static clib_error_t *
411 tuntap_exit (vlib_main_t * vm)
412 {
413   tuntap_main_t *tm = &tuntap_main;
414   struct ifreq ifr;
415   int sfd;
416
417   /* Not present. */
418   if (! tm->dev_net_tun_fd || tm->dev_net_tun_fd < 0)
419     return 0;
420
421   sfd = socket (AF_INET, SOCK_STREAM, 0);
422   if (sfd < 0)
423     clib_unix_warning("provisioning socket");
424
425   memset(&ifr, 0, sizeof (ifr));
426   strncpy (ifr.ifr_name, tm->tun_name, sizeof (ifr.ifr_name)-1);
427
428   /* get flags, modify to bring down interface... */
429   if (ioctl (sfd, SIOCGIFFLAGS, &ifr) < 0)
430     clib_unix_warning ("SIOCGIFFLAGS");
431
432   ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
433
434   if (ioctl (sfd, SIOCSIFFLAGS, &ifr) < 0)
435     clib_unix_warning ("SIOCSIFFLAGS");
436
437   /* Turn off persistence */
438   if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 0) < 0)
439     clib_unix_warning ("TUNSETPERSIST");
440   close(tm->dev_tap_fd);
441   if (tm->dev_net_tun_fd >= 0)
442     close(tm->dev_net_tun_fd);
443   if (sfd >= 0)
444     close (sfd);
445
446   return 0;
447 }
448
449 VLIB_MAIN_LOOP_EXIT_FUNCTION (tuntap_exit);
450
451 /**
452  * @brief CLI function for tun/tap config
453  *
454  * @param *vm - vlib_main_t
455  * @param *input - unformat_input_t
456  *
457  * @return error - clib_error_t
458  *
459  */
460 static clib_error_t *
461 tuntap_config (vlib_main_t * vm, unformat_input_t * input)
462 {
463   tuntap_main_t *tm = &tuntap_main;
464   clib_error_t * error = 0;
465   struct ifreq ifr;
466   u8 * name;
467   int flags = IFF_TUN | IFF_NO_PI;
468   int is_enabled = 0, is_ether = 0, have_normal_interface = 0;
469   const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
470
471   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
472     {
473       if (unformat (input, "mtu %d", &tm->mtu_bytes))
474         ;
475       else if (unformat (input, "enable"))
476         is_enabled = 1;
477       else if (unformat (input, "disable"))
478         is_enabled = 0;
479       else if (unformat (input, "ethernet") ||
480                unformat (input, "ether"))
481         is_ether = 1;
482       else if (unformat (input, "have-normal-interface") ||
483                unformat (input, "have-normal"))
484         have_normal_interface = 1;
485       else if (unformat (input, "name %s", &name))
486         tm->tun_name = (char *) name;
487       else
488         return clib_error_return (0, "unknown input `%U'",
489                                   format_unformat_error, input);
490     }
491
492   tm->dev_net_tun_fd = -1;
493   tm->dev_tap_fd = -1;
494
495   if (is_enabled == 0)
496     return 0;
497
498   if (geteuid()) 
499     {
500       clib_warning ("tuntap disabled: must be superuser");
501       return 0;
502     }    
503
504   tm->is_ether = is_ether;
505   tm->have_normal_interface = have_normal_interface;
506
507   if (is_ether)
508     flags = IFF_TAP | IFF_NO_PI;
509
510   if ((tm->dev_net_tun_fd = open ("/dev/net/tun", O_RDWR)) < 0)
511     {
512       error = clib_error_return_unix (0, "open /dev/net/tun");
513       goto done;
514     }
515
516   memset (&ifr, 0, sizeof (ifr));
517   strncpy(ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
518   ifr.ifr_flags = flags;
519   if (ioctl (tm->dev_net_tun_fd, TUNSETIFF, (void *)&ifr) < 0)
520     {
521       error = clib_error_return_unix (0, "ioctl TUNSETIFF");
522       goto done;
523     }
524     
525   /* Make it persistent, at least until we split. */
526   if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 1) < 0)
527     {
528       error = clib_error_return_unix (0, "TUNSETPERSIST");
529       goto done;
530     }
531
532   /* Open a provisioning socket */
533   if ((tm->dev_tap_fd = socket(PF_PACKET, SOCK_RAW,
534                                htons(ETH_P_ALL))) < 0 )
535     {
536       error = clib_error_return_unix (0, "socket");
537       goto done;
538     }
539
540   /* Find the interface index. */
541   {
542     struct ifreq ifr;
543     struct sockaddr_ll sll;
544
545     memset (&ifr, 0, sizeof(ifr));
546     strncpy (ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
547     if (ioctl (tm->dev_tap_fd, SIOCGIFINDEX, &ifr) < 0 )
548       {
549         error = clib_error_return_unix (0, "ioctl SIOCGIFINDEX");
550         goto done;
551       }
552
553     /* Bind the provisioning socket to the interface. */
554     memset(&sll, 0, sizeof(sll));
555     sll.sll_family   = AF_PACKET;
556     sll.sll_ifindex  = ifr.ifr_ifindex;
557     sll.sll_protocol = htons(ETH_P_ALL);
558
559     if (bind(tm->dev_tap_fd, (struct sockaddr*) &sll, sizeof(sll)) < 0)
560       {
561         error = clib_error_return_unix (0, "bind");
562         goto done;
563       }
564   }
565
566   /* non-blocking I/O on /dev/tapX */
567   {
568     int one = 1;
569     if (ioctl (tm->dev_net_tun_fd, FIONBIO, &one) < 0)
570       {
571         error = clib_error_return_unix (0, "ioctl FIONBIO");
572         goto done;
573       }
574   }
575
576   tm->mtu_buffers = (tm->mtu_bytes + (buffer_size - 1)) / buffer_size;
577
578   ifr.ifr_mtu = tm->mtu_bytes;
579   if (ioctl (tm->dev_tap_fd, SIOCSIFMTU, &ifr) < 0)
580     {
581       error = clib_error_return_unix (0, "ioctl SIOCSIFMTU");
582       goto done;
583     }
584
585   /* get flags, modify to bring up interface... */
586   if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
587     {
588       error = clib_error_return_unix (0, "ioctl SIOCGIFFLAGS");
589       goto done;
590     }
591
592   ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
593
594   if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
595     {
596       error = clib_error_return_unix (0, "ioctl SIOCSIFFLAGS");
597       goto done;
598     }
599
600   if (is_ether)
601     {
602       if (ioctl (tm->dev_tap_fd, SIOCGIFHWADDR, &ifr) < 0)
603         {
604           error = clib_error_return_unix (0, "ioctl SIOCGIFHWADDR");
605           goto done;
606         }
607       else
608         clib_memcpy (tm->ether_dst_mac, ifr.ifr_hwaddr.sa_data, 6);
609     }
610
611   if (have_normal_interface)
612     {
613       vnet_main_t *vnm = vnet_get_main();
614       error = ethernet_register_interface
615         (vnm,
616          tuntap_dev_class.index,
617          0 /* device instance */,
618          tm->ether_dst_mac /* ethernet address */,
619          &tm->hw_if_index, 
620          0 /* flag change */);
621       if (error)
622         clib_error_report (error);
623       tm->sw_if_index = tm->hw_if_index;
624       vm->os_punt_frame = tuntap_nopunt_frame;
625     }
626   else
627     {
628       vnet_main_t *vnm = vnet_get_main();
629       vnet_hw_interface_t * hi;
630       
631       vm->os_punt_frame = tuntap_punt_frame;
632       
633       tm->hw_if_index = vnet_register_interface
634         (vnm,
635          tuntap_dev_class.index, 0 /* device instance */,
636          tuntap_interface_class.index, 0);
637       hi = vnet_get_hw_interface (vnm, tm->hw_if_index);
638       tm->sw_if_index = hi->sw_if_index;
639       
640       /* Interface is always up. */
641       vnet_hw_interface_set_flags (vnm, tm->hw_if_index, 
642                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
643       vnet_sw_interface_set_flags (vnm, tm->sw_if_index, 
644                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
645     }
646
647   {
648     unix_file_t template = {0};
649     template.read_function = tuntap_read_ready;
650     template.file_descriptor = tm->dev_net_tun_fd;
651     tm->unix_file_index = unix_file_add (&unix_main, &template);
652   }
653
654  done:
655   if (error)
656     {
657       if (tm->dev_net_tun_fd >= 0)
658         close (tm->dev_net_tun_fd);
659       if (tm->dev_tap_fd >= 0)
660         close (tm->dev_tap_fd);
661     }
662
663   return error;
664 }
665
666 VLIB_CONFIG_FUNCTION (tuntap_config, "tuntap");
667
668 /**
669  * @brief Add or Del IP4 address to tun/tap interface
670  *
671  * @param *im - ip4_main_t
672  * @param opaque - uword
673  * @param sw_if_index - u32
674  * @param *address - ip4_address_t
675  * @param is_delete - u32
676  *
677  */
678 void
679 tuntap_ip4_add_del_interface_address (ip4_main_t * im,
680                                       uword opaque,
681                                       u32 sw_if_index,
682                                       ip4_address_t * address,
683                                       u32 address_length,
684                                       u32 if_address_index,
685                                       u32 is_delete)
686 {
687   tuntap_main_t * tm = &tuntap_main;
688   struct ifreq ifr;
689   subif_address_t subif_addr, * ap;
690   uword * p;
691
692   /** Tuntap disabled, or using a "normal" interface. */
693   if (tm->have_normal_interface ||  tm->dev_tap_fd < 0)
694     return;
695
696   /* if the address is being applied to an interface that is not in
697    * the same table/VRF as this tap, then ignore it.
698    * If we don't do this overlapping address spaces in the diferent tables
699    * breaks the linux host's routing tables */
700   if (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
701                                           sw_if_index) !=
702       fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
703                                           tm->sw_if_index))
704       return;
705
706   /** See if we already know about this subif */
707   memset (&subif_addr, 0, sizeof (subif_addr));
708   subif_addr.sw_if_index = sw_if_index;
709   clib_memcpy (&subif_addr.addr, address, sizeof (*address));
710
711   p = mhash_get (&tm->subif_mhash, &subif_addr);
712
713   if (p)
714     ap = pool_elt_at_index (tm->subifs, p[0]);
715   else
716     {
717       pool_get (tm->subifs, ap);
718       *ap = subif_addr;
719       mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
720     }
721
722   /* Use subif pool index to select alias device. */
723   memset (&ifr, 0, sizeof (ifr));
724   snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), 
725             "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
726
727   /* the tuntap punt/inject is enabled for IPv4 RX so long as
728    * any vpp interface has an IPv4 address.
729    * this is also ref counted.
730    */
731   ip4_sw_interface_enable_disable (tm->sw_if_index, !is_delete);
732
733   if (! is_delete)
734     {
735       struct sockaddr_in * sin;
736
737       sin = (struct sockaddr_in *)&ifr.ifr_addr;
738
739       /* Set ipv4 address, netmask. */
740       sin->sin_family = AF_INET;
741       clib_memcpy (&sin->sin_addr.s_addr, address, 4);
742       if (ioctl (tm->dev_tap_fd, SIOCSIFADDR, &ifr) < 0)
743         clib_unix_warning ("ioctl SIOCSIFADDR");
744     
745       sin->sin_addr.s_addr = im->fib_masks[address_length];
746       if (ioctl (tm->dev_tap_fd, SIOCSIFNETMASK, &ifr) < 0)
747         clib_unix_warning ("ioctl SIOCSIFNETMASK");
748     }
749   else
750     {
751       mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
752       pool_put (tm->subifs, ap);
753     }
754
755   /* get flags, modify to bring up interface... */
756   if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
757     clib_unix_warning ("ioctl SIOCGIFFLAGS");
758
759   if (is_delete)
760     ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
761   else
762     ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
763
764   if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
765     clib_unix_warning ("ioctl SIOCSIFFLAGS");
766 }
767
768 /**
769  * @brief workaround for a known include file bug.
770  * including @c <linux/ipv6.h> causes multiple definitions if
771  * @c <netinet/in.h is also included.
772  */
773 struct in6_ifreq {
774         struct in6_addr ifr6_addr;
775         u32             ifr6_prefixlen;
776         int             ifr6_ifindex;
777 };
778
779 /**
780  * @brief Add or Del tun/tap interface address.
781  *
782  * Both the v6 interface address API and the way ifconfig
783  * displays subinterfaces differ from their v4 couterparts.
784  * The code given here seems to work but YMMV.
785  *
786  * @param *im - ip6_main_t
787  * @param opaque - uword
788  * @param sw_if_index - u32
789  * @param *address - ip6_address_t
790  * @param address_length - u32
791  * @param if_address_index - u32
792  * @param is_delete - u32
793  */
794 void
795 tuntap_ip6_add_del_interface_address (ip6_main_t * im,
796                                       uword opaque,
797                                       u32 sw_if_index,
798                                       ip6_address_t * address,
799                                       u32 address_length,
800                                       u32 if_address_index,
801                                       u32 is_delete)
802 {
803   tuntap_main_t * tm = &tuntap_main;
804   struct ifreq ifr;
805   struct in6_ifreq ifr6;
806   subif_address_t subif_addr, * ap;
807   uword * p;
808
809   /* Tuntap disabled, or using a "normal" interface. */
810   if (tm->have_normal_interface ||  tm->dev_tap_fd < 0)
811     return;
812
813   /* if the address is being applied to an interface that is not in
814    * the same table/VRF as this tap, then ignore it.
815    * If we don't do this overlapping address spaces in the diferent tables
816    * breaks the linux host's routing tables */
817   if (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP6,
818                                           sw_if_index) !=
819       fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP6,
820                                           tm->sw_if_index))
821       return;
822
823   /* See if we already know about this subif */
824   memset (&subif_addr, 0, sizeof (subif_addr));
825   subif_addr.sw_if_index = sw_if_index;
826   subif_addr.is_v6 = 1;
827   clib_memcpy (&subif_addr.addr, address, sizeof (*address));
828
829   p = mhash_get (&tm->subif_mhash, &subif_addr);
830
831   if (p)
832     ap = pool_elt_at_index (tm->subifs, p[0]);
833   else
834     {
835       pool_get (tm->subifs, ap);
836       *ap = subif_addr;
837       mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
838     }
839
840   /* Use subif pool index to select alias device. */
841   memset (&ifr, 0, sizeof (ifr));
842   memset (&ifr6, 0, sizeof (ifr6));
843   snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), 
844             "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
845
846   /* the tuntap punt/inject is enabled for IPv6 RX so long as
847    * any vpp interface has an IPv6 address.
848    * this is also ref counted.
849    */
850   ip6_sw_interface_enable_disable (tm->sw_if_index, !is_delete);
851
852   if (! is_delete)
853     {
854       int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
855       if (sockfd < 0)
856         clib_unix_warning ("get ifindex socket");
857
858       if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
859         clib_unix_warning ("get ifindex");
860
861       ifr6.ifr6_ifindex = ifr.ifr_ifindex;
862       ifr6.ifr6_prefixlen = address_length;
863       clib_memcpy (&ifr6.ifr6_addr, address, 16);
864
865       if (ioctl (sockfd, SIOCSIFADDR, &ifr6) < 0)
866         clib_unix_warning ("set address");
867
868       if (sockfd >= 0)
869         close (sockfd);
870     }
871   else
872     {
873       int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
874       if (sockfd < 0)
875         clib_unix_warning ("get ifindex socket");
876
877       if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
878         clib_unix_warning ("get ifindex");
879
880       ifr6.ifr6_ifindex = ifr.ifr_ifindex;
881       ifr6.ifr6_prefixlen = address_length;
882       clib_memcpy (&ifr6.ifr6_addr, address, 16);
883
884       if (ioctl (sockfd, SIOCDIFADDR, &ifr6) < 0)
885         clib_unix_warning ("del address");
886
887       if (sockfd >= 0)
888         close (sockfd);
889
890       mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
891       pool_put (tm->subifs, ap);
892     }
893 }
894
895 /**
896  * @brief TX the tun/tap frame
897  *
898  * @param *vm - vlib_main_t
899  * @param *node - vlib_node_runtime_t
900  * @param *frame - vlib_frame_t
901  *
902  */
903 static void
904 tuntap_punt_frame (vlib_main_t * vm,
905                    vlib_node_runtime_t * node,
906                    vlib_frame_t * frame)
907 {
908   tuntap_tx (vm, node, frame);
909   vlib_frame_free (vm, node, frame);
910 }
911
912 /**
913  * @brief Free the tun/tap frame
914  *
915  * @param *vm - vlib_main_t
916  * @param *node - vlib_node_runtime_t
917  * @param *frame - vlib_frame_t
918  *
919  */
920 static void
921 tuntap_nopunt_frame (vlib_main_t * vm,
922                    vlib_node_runtime_t * node,
923                    vlib_frame_t * frame)
924 {
925   u32 * buffers = vlib_frame_args (frame);
926   uword n_packets = frame->n_vectors;
927   vlib_buffer_free (vm, buffers, n_packets);
928   vlib_frame_free (vm, node, frame);
929 }
930
931 VNET_HW_INTERFACE_CLASS (tuntap_interface_class,static) = {
932   .name = "tuntap",
933   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
934 };
935
936 /**
937  * @brief Format tun/tap interface name
938  *
939  * @param *s - u8 - formatter string
940  * @param *args - va_list
941  *
942  * @return *s - u8 - formatted string
943  *
944  */
945 static u8 * format_tuntap_interface_name (u8 * s, va_list * args)
946 {
947   u32 i = va_arg (*args, u32);
948
949   s = format (s, "tuntap-%d", i);
950   return s;
951 }
952
953 /**
954  * @brief TX packet out tun/tap
955  *
956  * @param *vm - vlib_main_t
957  * @param *node - vlib_node_runtime_t
958  * @param *frame - vlib_frame_t
959  *
960  * @return n_buffers - uword - Packets transmitted
961  *
962  */
963 static uword
964 tuntap_intfc_tx (vlib_main_t * vm,
965                  vlib_node_runtime_t * node,
966                  vlib_frame_t * frame)
967 {
968   tuntap_main_t * tm = &tuntap_main;
969   u32 * buffers = vlib_frame_args (frame);
970   uword n_buffers = frame->n_vectors;
971
972   /* Normal interface transmit happens only on the normal interface... */
973   if (tm->have_normal_interface)
974     return tuntap_tx (vm, node, frame);
975
976   vlib_buffer_free (vm, buffers, n_buffers);
977   return n_buffers;
978 }
979
980 VNET_DEVICE_CLASS (tuntap_dev_class,static) = {
981   .name = "tuntap",
982   .tx_function = tuntap_intfc_tx,
983   .format_device_name = format_tuntap_interface_name,
984 };
985
986 /**
987  * @brief tun/tap node init
988  *
989  * @param *vm - vlib_main_t
990  *
991  * @return error - clib_error_t
992  *
993  */
994 static clib_error_t *
995 tuntap_init (vlib_main_t * vm)
996 {
997   clib_error_t * error;
998   ip4_main_t * im4 = &ip4_main;
999   ip6_main_t * im6 = &ip6_main;
1000   ip4_add_del_interface_address_callback_t cb4;
1001   ip6_add_del_interface_address_callback_t cb6;
1002   tuntap_main_t * tm = &tuntap_main;
1003
1004   error = vlib_call_init_function (vm, ip4_init);
1005   if (error)
1006     return error;
1007
1008   mhash_init (&tm->subif_mhash, sizeof (u32), sizeof(subif_address_t));
1009
1010   cb4.function = tuntap_ip4_add_del_interface_address;
1011   cb4.function_opaque = 0;
1012   vec_add1 (im4->add_del_interface_address_callbacks, cb4);
1013
1014   cb6.function = tuntap_ip6_add_del_interface_address;
1015   cb6.function_opaque = 0;
1016   vec_add1 (im6->add_del_interface_address_callbacks, cb6);
1017
1018   return 0;
1019 }
1020
1021 VLIB_INIT_FUNCTION (tuntap_init);