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