4421ffb918d3fef8f59087131290c5a67c8563c4
[vpp.git] / vnet / vnet / unix / tapcli.c
1 /* 
2  *------------------------------------------------------------------
3  * tapcli.c - dynamic tap interface hookup
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 #include <vnet/unix/tapcli.h>
43
44 static vnet_device_class_t tapcli_dev_class;
45 static vnet_hw_interface_class_t tapcli_interface_class;
46
47 static void tapcli_nopunt_frame (vlib_main_t * vm,
48                                  vlib_node_runtime_t * node,
49                                  vlib_frame_t * frame);
50 typedef struct {
51   u32 unix_fd;
52   u32 unix_file_index;
53   u32 provision_fd;
54   u32 sw_if_index;              /* for counters */
55   u32 hw_if_index;
56   u32 is_promisc;
57   struct ifreq ifr;
58   u32 per_interface_next_index;
59   u8 active;                    /* for delete */
60 } tapcli_interface_t;
61
62 typedef struct {
63   /* Vector of iovecs for readv/writev calls. */
64   struct iovec * iovecs;
65
66   /* Vector of VLIB rx buffers to use.  We allocate them in blocks
67      of VLIB_FRAME_SIZE (256). */
68   u32 * rx_buffers;
69
70   /* tap device destination MAC address. Required, or Linux drops pkts */
71   u8 ether_dst_mac[6];
72
73   /* Interface MTU in bytes and # of default sized buffers. */
74   u32 mtu_bytes, mtu_buffers;
75
76   /* Vector of tap interfaces */
77   tapcli_interface_t * tapcli_interfaces;
78
79   /* Vector of deleted tap interfaces */
80   u32 * tapcli_inactive_interfaces;
81
82   /* Bitmap of tap interfaces with pending reads */
83   uword * pending_read_bitmap;
84
85   /* Hash table to find tapcli interface given hw_if_index */
86   uword * tapcli_interface_index_by_sw_if_index;
87   
88   /* Hash table to find tapcli interface given unix fd */
89   uword * tapcli_interface_index_by_unix_fd;
90
91   /* renumbering table */
92   u32 * show_dev_instance_by_real_dev_instance;
93
94   /* 1 => disable CLI */
95   int is_disabled;
96
97   /* convenience */
98   vlib_main_t * vlib_main;
99   vnet_main_t * vnet_main;
100   unix_main_t * unix_main;
101 } tapcli_main_t;
102
103 static tapcli_main_t tapcli_main;
104
105 /*
106  * tapcli_tx
107  * Output node, writes the buffers comprising the incoming frame 
108  * to the tun/tap device, aka hands them to the Linux kernel stack.
109  * 
110  */
111 static uword
112 tapcli_tx (vlib_main_t * vm,
113            vlib_node_runtime_t * node,
114            vlib_frame_t * frame)
115 {
116   u32 * buffers = vlib_frame_args (frame);
117   uword n_packets = frame->n_vectors;
118   tapcli_main_t * tm = &tapcli_main;
119   tapcli_interface_t * ti;
120   int i;
121
122   for (i = 0; i < n_packets; i++)
123     {
124       struct iovec * iov;
125       vlib_buffer_t * b;
126       uword l;
127       vnet_hw_interface_t * hw;
128       uword * p;
129       u32 tx_sw_if_index;
130
131       b = vlib_get_buffer (vm, buffers[i]);
132
133       tx_sw_if_index = vnet_buffer(b)->sw_if_index[VLIB_TX];
134       if (tx_sw_if_index == (u32)~0)
135         tx_sw_if_index = vnet_buffer(b)->sw_if_index[VLIB_RX];
136         
137       ASSERT(tx_sw_if_index != (u32)~0);
138
139       /* Use the sup intfc to finesse vlan subifs */
140       hw = vnet_get_sup_hw_interface (tm->vnet_main, tx_sw_if_index);
141       tx_sw_if_index = hw->sw_if_index;
142
143       p = hash_get (tm->tapcli_interface_index_by_sw_if_index, 
144                     tx_sw_if_index);
145       if (p == 0)
146         {
147           clib_warning ("sw_if_index %d unknown", tx_sw_if_index);
148           /* $$$ leak, but this should never happen... */
149           continue;
150         }
151       else
152         ti = vec_elt_at_index (tm->tapcli_interfaces, p[0]);
153
154       /* Re-set iovecs if present. */
155       if (tm->iovecs)
156         _vec_len (tm->iovecs) = 0;
157
158       /* VLIB buffer chain -> Unix iovec(s). */
159       vec_add2 (tm->iovecs, iov, 1);
160       iov->iov_base = b->data + b->current_data;
161       iov->iov_len = l = b->current_length;
162
163       if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NEXT_PRESENT))
164         {
165           do {
166             b = vlib_get_buffer (vm, b->next_buffer);
167
168             vec_add2 (tm->iovecs, iov, 1);
169
170             iov->iov_base = b->data + b->current_data;
171             iov->iov_len = b->current_length;
172             l += b->current_length;
173           } while (b->flags & VLIB_BUFFER_NEXT_PRESENT);
174         }
175
176       if (writev (ti->unix_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
177         clib_unix_warning ("writev");
178     }
179     
180   vlib_buffer_free(vm, vlib_frame_vector_args(frame), frame->n_vectors);
181     
182   return n_packets;
183 }
184
185 VLIB_REGISTER_NODE (tapcli_tx_node,static) = {
186   .function = tapcli_tx,
187   .name = "tapcli-tx",
188   .type = VLIB_NODE_TYPE_INTERNAL,
189   .vector_size = 4,
190 };
191
192 enum {
193   TAPCLI_RX_NEXT_IP4_INPUT, 
194   TAPCLI_RX_NEXT_IP6_INPUT, 
195   TAPCLI_RX_NEXT_ETHERNET_INPUT,
196   TAPCLI_RX_NEXT_DROP,
197   TAPCLI_RX_N_NEXT,
198 };
199
200 static uword
201 tapcli_rx (vlib_main_t * vm,
202            vlib_node_runtime_t * node,
203            vlib_frame_t * frame)
204 {
205   tapcli_main_t * tm = &tapcli_main;
206   vlib_buffer_t *b_first;
207   u32 bi;
208   vlib_buffer_free_list_t *fl;
209   const uword buffer_size = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES;
210   static u32 * ready_interface_indices;
211   tapcli_interface_t * ti;
212   int i;
213   word n_bytes_in_packet;
214
215   vec_reset_length (ready_interface_indices);
216
217   clib_bitmap_foreach (i, tm->pending_read_bitmap, 
218   ({
219     vec_add1 (ready_interface_indices, i);
220   }));
221
222   if (vec_len (ready_interface_indices) == 0)
223     return 1;
224
225   fl = vlib_buffer_get_free_list(vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
226
227   for (i = 0; i < vec_len(ready_interface_indices); i++)
228     {
229       /* Clear the "interrupt" bit */
230       tm->pending_read_bitmap = 
231         clib_bitmap_set (tm->pending_read_bitmap,
232                          ready_interface_indices[i], 0);
233       
234       ti = vec_elt_at_index (tm->tapcli_interfaces, ready_interface_indices[i]);
235
236       /* Make sure we have some RX buffers. */
237       {
238         uword n_left = vec_len (tm->rx_buffers);
239         uword n_alloc;
240         if (n_left < VLIB_FRAME_SIZE / 2) {
241           vec_validate(tm->rx_buffers, VLIB_FRAME_SIZE + n_left - 1);
242           n_alloc = vlib_buffer_alloc(vm, &tm->rx_buffers[n_left], VLIB_FRAME_SIZE);
243           n_left += n_alloc;
244           _vec_len (tm->rx_buffers) = n_left;
245         }
246       }
247
248       /* Allocate RX buffers from end of rx_buffers.
249          Turn them into iovecs to pass to readv. */
250       {
251         uword i_rx = vec_len (tm->rx_buffers) - 1;
252         vlib_buffer_t * b, *prev = 0;
253         word j, n_bytes_left;
254
255         /* We need enough buffers left for an MTU sized packet. */
256         if (PREDICT_FALSE(vec_len (tm->rx_buffers) < tm->mtu_buffers))
257           {
258             clib_bitmap_set (tm->pending_read_bitmap,
259                              ready_interface_indices[i], 1);
260             clib_warning ("buffer allocation failure");
261             continue;
262           }
263
264         vec_validate (tm->iovecs, tm->mtu_buffers - 1);
265         for (j = 0; j < tm->mtu_buffers; j++)
266           {
267             b = vlib_get_buffer (vm, tm->rx_buffers[i_rx - j]);
268             vlib_buffer_init_for_free_list (b, fl);
269             tm->iovecs[j].iov_base = b->data;
270             tm->iovecs[j].iov_len = buffer_size;
271           }
272
273         n_bytes_left = readv (ti->unix_fd, tm->iovecs, tm->mtu_buffers);
274         n_bytes_in_packet = n_bytes_left;
275         if (n_bytes_left <= 0)
276           {
277             if (errno != EAGAIN)
278               clib_unix_warning ("readv %d", n_bytes_left);
279             return 0;
280           }
281         
282         bi = tm->rx_buffers[i_rx];
283         b = b_first = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
284
285         while (1) {
286           u32 bi;
287
288           vlib_buffer_init_for_free_list(b, fl);
289
290           b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size;
291           n_bytes_left -= buffer_size;
292
293           if (prev) {
294             prev->next_buffer = bi;
295             prev->flags |= VLIB_BUFFER_NEXT_PRESENT;
296           }
297           prev = b;
298
299           /* last segment */
300           if (n_bytes_left <= 0) break;
301
302           i_rx--;
303           bi = tm->rx_buffers[i_rx];
304           b = vlib_get_buffer (vm, bi);
305         }
306
307         /* Interface counters for tapcli interface. */
308         vlib_increment_combined_counter 
309           (vnet_main.interface_main.combined_sw_if_counters
310            + VNET_INTERFACE_COUNTER_RX,
311            os_get_cpu_number(),
312            ti->sw_if_index,
313            1, n_bytes_in_packet);
314
315         _vec_len (tm->rx_buffers) = i_rx;
316       }
317
318       b_first->total_length_not_including_first_buffer = (n_bytes_in_packet > buffer_size) ? n_bytes_in_packet - buffer_size : 0;
319       b_first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
320
321       /* Ensure mbufs are updated */
322       vlib_buffer_chain_validate(vm, b_first);
323
324       /*
325        * Turn this on if you run into
326        * "bad monkey" contexts, and you want to know exactly
327        * which nodes they've visited... See .../vlib/vlib/buffer.h
328        */
329       VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b_first);
330
331       {
332         u32 next_index;
333         uword n_trace = vlib_get_trace_count (vm, node);
334
335         vnet_buffer (b_first)->sw_if_index[VLIB_RX] = ti->sw_if_index;
336         vnet_buffer (b_first)->sw_if_index[VLIB_TX] = (u32)~0;
337
338         b_first->error = node->errors[0];
339
340         {
341           next_index = TAPCLI_RX_NEXT_ETHERNET_INPUT;
342
343           next_index = (ti->per_interface_next_index != ~0) ? 
344             ti->per_interface_next_index : next_index;
345         }
346         {
347           vnet_main_t *vnm = vnet_get_main();
348           vnet_sw_interface_t * si;
349           si = vnet_get_sw_interface (vnm, ti->sw_if_index);
350           if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
351             next_index = TAPCLI_RX_NEXT_DROP;
352         }
353
354         vlib_set_next_frame_buffer (vm, node, next_index, bi);
355         
356         if (n_trace > 0)
357           {
358             vlib_trace_buffer (vm, node, next_index,
359                                b_first, /* follow_chain */ 1);
360             vlib_set_trace_count (vm, node, n_trace - 1);
361           }
362       }
363     }
364
365   return 1;
366 }
367
368 static char * tapcli_rx_error_strings[] = {
369   "Interface down",
370 };
371
372 VLIB_REGISTER_NODE (tapcli_rx_node,static) = {
373   .function = tapcli_rx,
374   .name = "tapcli-rx",
375   .type = VLIB_NODE_TYPE_INPUT,
376   .state = VLIB_NODE_STATE_INTERRUPT,
377   .vector_size = 4,
378   .n_errors = 1,
379   .error_strings = tapcli_rx_error_strings,
380
381   .n_next_nodes = TAPCLI_RX_N_NEXT,
382   .next_nodes = {
383     [TAPCLI_RX_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
384     [TAPCLI_RX_NEXT_IP6_INPUT] = "ip6-input",
385     [TAPCLI_RX_NEXT_DROP] = "error-drop",
386     [TAPCLI_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
387   },
388 };
389
390 /* Gets called when file descriptor is ready from epoll. */
391 static clib_error_t * tapcli_read_ready (unix_file_t * uf)
392 {
393   vlib_main_t * vm = vlib_get_main();
394   tapcli_main_t * tm = &tapcli_main;
395   uword * p;
396   
397   /* Schedule the rx node */
398   vlib_node_set_interrupt_pending (vm, tapcli_rx_node.index);
399
400   p = hash_get (tm->tapcli_interface_index_by_unix_fd, uf->file_descriptor);
401
402   /* Mark the specific tap interface ready-to-read */
403   if (p)
404     tm->pending_read_bitmap = clib_bitmap_set (tm->pending_read_bitmap,
405                                                p[0], 1);
406   else
407     clib_warning ("fd %d not in hash table", uf->file_descriptor);
408
409   return 0;
410 }
411
412 static clib_error_t *
413 tapcli_config (vlib_main_t * vm, unformat_input_t * input)
414 {
415   tapcli_main_t *tm = &tapcli_main;
416   const uword buffer_size = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES;
417
418   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
419     {
420       if (unformat (input, "mtu %d", &tm->mtu_bytes))
421         ;
422       else if (unformat (input, "disable"))
423         tm->is_disabled = 1;
424       else
425           return clib_error_return (0, "unknown input `%U'",
426                                     format_unformat_error, input);
427     }
428
429   if (tm->is_disabled)
430     return 0;
431
432   if (geteuid()) 
433     {
434       clib_warning ("tapcli disabled: must be superuser");
435       tm->is_disabled = 1;
436       return 0;
437     }    
438
439   tm->mtu_buffers = (tm->mtu_bytes + (buffer_size - 1)) / buffer_size;
440   
441   return 0;
442 }
443
444 static int tap_name_renumber (vnet_hw_interface_t * hi,
445                               u32 new_dev_instance)
446 {
447   tapcli_main_t *tm = &tapcli_main;
448
449   vec_validate_init_empty (tm->show_dev_instance_by_real_dev_instance,
450                            hi->dev_instance, ~0);
451
452   tm->show_dev_instance_by_real_dev_instance [hi->dev_instance] =
453     new_dev_instance;
454
455   return 0;
456 }
457
458 VLIB_CONFIG_FUNCTION (tapcli_config, "tapcli");
459
460 static void
461 tapcli_nopunt_frame (vlib_main_t * vm,
462                    vlib_node_runtime_t * node,
463                    vlib_frame_t * frame)
464 {
465   u32 * buffers = vlib_frame_args (frame);
466   uword n_packets = frame->n_vectors;
467   vlib_buffer_free (vm, buffers, n_packets);
468   vlib_frame_free (vm, node, frame);
469 }
470
471 VNET_HW_INTERFACE_CLASS (tapcli_interface_class,static) = {
472   .name = "tapcli",
473 };
474
475 static u8 * format_tapcli_interface_name (u8 * s, va_list * args)
476 {
477   u32 i = va_arg (*args, u32);
478   u32 show_dev_instance = ~0;
479   tapcli_main_t * tm = &tapcli_main;
480
481   if (i < vec_len (tm->show_dev_instance_by_real_dev_instance))
482     show_dev_instance = tm->show_dev_instance_by_real_dev_instance[i];
483
484   if (show_dev_instance != ~0)
485     i = show_dev_instance;
486
487   s = format (s, "tap-%d", i);
488   return s;
489 }
490
491 static u32 tapcli_flag_change (vnet_main_t * vnm, 
492                                vnet_hw_interface_t * hw,
493                                u32 flags)
494 {
495   tapcli_main_t *tm = &tapcli_main;
496   tapcli_interface_t *ti;
497   struct ifreq ifr;
498   u32 want_promisc;
499
500   ti = vec_elt_at_index (tm->tapcli_interfaces, hw->dev_instance);
501
502   memcpy (&ifr, &ti->ifr, sizeof (ifr));
503
504   /* get flags, modify to bring up interface... */
505   if (ioctl (ti->provision_fd, SIOCGIFFLAGS, &ifr) < 0)
506     {
507       clib_unix_warning ("Couldn't get interface flags for %s", hw->name);
508       return 0;
509     }
510
511   want_promisc = (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
512
513   if (want_promisc == ti->is_promisc)
514     return 0;
515
516
517   if (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL)
518     ifr.ifr_flags |= IFF_PROMISC;
519   else
520     ifr.ifr_flags &= ~(IFF_PROMISC);
521
522   /* get flags, modify to bring up interface... */
523   if (ioctl (ti->provision_fd, SIOCSIFFLAGS, &ifr) < 0)
524     {
525       clib_unix_warning ("Couldn't set interface flags for %s", hw->name);
526       return 0;
527     }
528
529   ti->is_promisc = want_promisc;
530
531   return 0;
532 }
533
534 static void tapcli_set_interface_next_node (vnet_main_t *vnm, 
535                                             u32 hw_if_index,
536                                             u32 node_index)
537 {
538   tapcli_main_t *tm = &tapcli_main;
539   tapcli_interface_t *ti;
540   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
541
542   ti = vec_elt_at_index (tm->tapcli_interfaces, hw->dev_instance);
543   
544   /* Shut off redirection */
545   if (node_index == ~0)
546     {
547       ti->per_interface_next_index = node_index;
548       return;
549     }
550   
551   ti->per_interface_next_index = 
552     vlib_node_add_next (tm->vlib_main, tapcli_rx_node.index, node_index);
553 }
554
555 /* 
556  * Mainly exists to set link_state == admin_state
557  * otherwise, e.g. ip6 neighbor discovery breaks
558  */
559 static clib_error_t * 
560 tapcli_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
561 {
562   uword is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
563   u32 hw_flags;
564   u32 speed_duplex = VNET_HW_INTERFACE_FLAG_FULL_DUPLEX 
565     | VNET_HW_INTERFACE_FLAG_SPEED_1G;
566     
567   if (is_admin_up)
568     hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP | speed_duplex;
569   else
570     hw_flags = speed_duplex;
571   
572   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
573   return 0;
574 }
575
576 VNET_DEVICE_CLASS (tapcli_dev_class,static) = {
577   .name = "tapcli",
578   .tx_function = tapcli_tx,
579   .format_device_name = format_tapcli_interface_name,
580   .rx_redirect_to_node = tapcli_set_interface_next_node,
581   .name_renumber = tap_name_renumber,
582   .admin_up_down_function = tapcli_interface_admin_up_down,
583   .no_flatten_output_chains = 1,
584 };
585
586 int vnet_tap_dump_ifs (tapcli_interface_details_t **out_tapids)
587 {
588   tapcli_main_t * tm = &tapcli_main;
589   tapcli_interface_t * ti;
590
591   tapcli_interface_details_t * r_tapids = NULL;
592   tapcli_interface_details_t * tapid = NULL;
593
594   vec_foreach (ti, tm->tapcli_interfaces) {
595     if (!ti->active)
596         continue;
597     vec_add2(r_tapids, tapid, 1);
598     tapid->sw_if_index = ti->sw_if_index;
599     strncpy((char *)tapid->dev_name, ti->ifr.ifr_name, sizeof (ti->ifr.ifr_name)-1);
600   }
601
602   *out_tapids = r_tapids;
603
604   return 0;
605 }
606
607 /* get tap interface from inactive interfaces or create new */
608 static tapcli_interface_t *tapcli_get_new_tapif()
609 {
610   tapcli_main_t * tm = &tapcli_main;
611   tapcli_interface_t *ti = NULL;
612
613   int inactive_cnt = vec_len(tm->tapcli_inactive_interfaces);
614   // if there are any inactive ifaces
615   if (inactive_cnt > 0) {
616     // take last
617     u32 ti_idx = tm->tapcli_inactive_interfaces[inactive_cnt - 1];
618     if (vec_len(tm->tapcli_interfaces) > ti_idx) {
619       ti = vec_elt_at_index (tm->tapcli_interfaces, ti_idx);
620       clib_warning("reusing tap interface");
621     }
622     // "remove" from inactive list
623     _vec_len(tm->tapcli_inactive_interfaces) -= 1;
624   }
625
626   // ti was not retrieved from inactive ifaces - create new
627   if (!ti)
628     vec_add2 (tm->tapcli_interfaces, ti, 1);
629
630   return ti;
631 }
632
633 int vnet_tap_connect (vlib_main_t * vm, u8 * intfc_name, u8 *hwaddr_arg,
634                       u32 * sw_if_indexp)
635 {
636   tapcli_main_t * tm = &tapcli_main;
637   tapcli_interface_t * ti = NULL;
638   struct ifreq ifr;
639   int flags;
640   int dev_net_tun_fd;
641   int dev_tap_fd = -1;
642   clib_error_t * error;
643   u8 hwaddr [6];
644   int rv = 0;
645
646   if (tm->is_disabled)
647     {
648       return VNET_API_ERROR_FEATURE_DISABLED;
649     }
650
651   flags = IFF_TAP | IFF_NO_PI;
652
653   if ((dev_net_tun_fd = open ("/dev/net/tun", O_RDWR)) < 0)
654     return VNET_API_ERROR_SYSCALL_ERROR_1;
655   
656   memset (&ifr, 0, sizeof (ifr));
657   strncpy(ifr.ifr_name, (char *) intfc_name, sizeof (ifr.ifr_name)-1);
658   ifr.ifr_flags = flags;
659   if (ioctl (dev_net_tun_fd, TUNSETIFF, (void *)&ifr) < 0)
660     {
661       rv = VNET_API_ERROR_SYSCALL_ERROR_2;
662       goto error;
663     }
664     
665   /* Open a provisioning socket */
666   if ((dev_tap_fd = socket(PF_PACKET, SOCK_RAW,
667                            htons(ETH_P_ALL))) < 0 )
668     {
669       rv = VNET_API_ERROR_SYSCALL_ERROR_3;
670       goto error;
671     }
672
673   /* Find the interface index. */
674   {
675     struct ifreq ifr;
676     struct sockaddr_ll sll;
677
678     memset (&ifr, 0, sizeof(ifr));
679     strncpy (ifr.ifr_name, (char *) intfc_name, sizeof (ifr.ifr_name)-1);
680     if (ioctl (dev_tap_fd, SIOCGIFINDEX, &ifr) < 0 )
681       {
682         rv = VNET_API_ERROR_SYSCALL_ERROR_4;
683         goto error;
684       }
685
686     /* Bind the provisioning socket to the interface. */
687     memset(&sll, 0, sizeof(sll));
688     sll.sll_family   = AF_PACKET;
689     sll.sll_ifindex  = ifr.ifr_ifindex;
690     sll.sll_protocol = htons(ETH_P_ALL);
691
692     if (bind(dev_tap_fd, (struct sockaddr*) &sll, sizeof(sll)) < 0)
693       {
694         rv = VNET_API_ERROR_SYSCALL_ERROR_5;
695         goto error;
696       }
697   }
698
699   /* non-blocking I/O on /dev/tapX */
700   {
701     int one = 1;
702     if (ioctl (dev_net_tun_fd, FIONBIO, &one) < 0)
703       {
704         rv = VNET_API_ERROR_SYSCALL_ERROR_6;
705         goto error;
706       }
707   }
708   ifr.ifr_mtu = tm->mtu_bytes;
709   if (ioctl (dev_tap_fd, SIOCSIFMTU, &ifr) < 0)
710     {
711       rv = VNET_API_ERROR_SYSCALL_ERROR_7;
712       goto error;
713     }
714
715   /* get flags, modify to bring up interface... */
716   if (ioctl (dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
717     {
718       rv = VNET_API_ERROR_SYSCALL_ERROR_8;
719       goto error;
720     }
721
722   ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
723
724   if (ioctl (dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
725     {
726       rv = VNET_API_ERROR_SYSCALL_ERROR_9;
727       goto error;
728     }
729
730   if (ioctl (dev_tap_fd, SIOCGIFHWADDR, &ifr) < 0)
731     {
732       rv = VNET_API_ERROR_SYSCALL_ERROR_1;
733       goto error;
734     }
735
736   ti = tapcli_get_new_tapif();
737
738   if (hwaddr_arg != 0)
739     memcpy(hwaddr, hwaddr_arg, 6);
740
741   error = ethernet_register_interface
742         (tm->vnet_main,
743          tapcli_dev_class.index,
744          ti - tm->tapcli_interfaces /* device instance */,
745          hwaddr_arg != 0 ? hwaddr :
746          (u8 *) ifr.ifr_hwaddr.sa_data /* ethernet address */,
747          &ti->hw_if_index, 
748          tapcli_flag_change);
749
750   if (error)
751     {
752       clib_error_report (error);
753       rv = VNET_API_ERROR_INVALID_REGISTRATION;
754       goto error;
755     }
756
757   {
758     unix_file_t template = {0};
759     template.read_function = tapcli_read_ready;
760     template.file_descriptor = dev_net_tun_fd;
761     ti->unix_file_index = unix_file_add (&unix_main, &template);
762     ti->unix_fd = dev_net_tun_fd;
763     ti->provision_fd = dev_tap_fd;
764     memcpy (&ti->ifr, &ifr, sizeof (ifr));
765   }
766   
767   {
768     vnet_hw_interface_t * hw;
769     hw = vnet_get_hw_interface (tm->vnet_main, ti->hw_if_index);
770     hw->max_l3_packet_bytes[VLIB_RX] = hw->max_l3_packet_bytes[VLIB_TX] = tm->mtu_bytes - sizeof(ethernet_header_t);
771     ti->sw_if_index = hw->sw_if_index;
772     if (sw_if_indexp)
773       *sw_if_indexp = hw->sw_if_index;
774   }
775
776   ti->active = 1;
777   
778   hash_set (tm->tapcli_interface_index_by_sw_if_index, ti->sw_if_index,
779             ti - tm->tapcli_interfaces);
780   
781   hash_set (tm->tapcli_interface_index_by_unix_fd, ti->unix_fd,
782             ti - tm->tapcli_interfaces);
783   
784   return rv;
785
786  error:
787   close (dev_net_tun_fd);
788   close (dev_tap_fd);
789
790   return rv;
791 }
792
793 int vnet_tap_connect_renumber (vlib_main_t * vm, u8 * intfc_name,
794                                u8 *hwaddr_arg, u32 * sw_if_indexp,
795                                u8 renumber, u32 custom_dev_instance)
796 {
797     int rv = vnet_tap_connect(vm, intfc_name, hwaddr_arg, sw_if_indexp);
798
799     if (!rv && renumber)
800         vnet_interface_name_renumber (*sw_if_indexp, custom_dev_instance);
801
802     return rv;
803 }
804
805 static int tapcli_tap_disconnect (tapcli_interface_t *ti)
806 {
807   int rv = 0;
808   vnet_main_t * vnm = vnet_get_main();
809   tapcli_main_t * tm = &tapcli_main;
810   u32 sw_if_index = ti->sw_if_index;
811
812   // bring interface down
813   vnet_sw_interface_set_flags (vnm, sw_if_index, 0);
814
815   if (ti->unix_file_index != ~0) {
816     unix_file_del (&unix_main, unix_main.file_pool + ti->unix_file_index);
817     ti->unix_file_index = ~0;
818   }
819
820   hash_unset (tm->tapcli_interface_index_by_unix_fd, ti->unix_fd);
821   hash_unset (tm->tapcli_interface_index_by_sw_if_index, ti->sw_if_index);
822   close(ti->unix_fd);
823   close(ti->provision_fd);
824   ti->unix_fd = -1;
825   ti->provision_fd = -1;
826
827   return rv;
828 }
829
830 int vnet_tap_delete(vlib_main_t *vm, u32 sw_if_index)
831 {
832   int rv = 0;
833   tapcli_main_t * tm = &tapcli_main;
834   tapcli_interface_t *ti;
835   uword *p = NULL;
836
837   p = hash_get (tm->tapcli_interface_index_by_sw_if_index,
838                 sw_if_index);
839   if (p == 0) {
840     clib_warning ("sw_if_index %d unknown", sw_if_index);
841     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
842   }
843   ti = vec_elt_at_index (tm->tapcli_interfaces, p[0]);
844
845   // inactive
846   ti->active = 0;
847   tapcli_tap_disconnect(ti);
848   // add to inactive list
849   vec_add1(tm->tapcli_inactive_interfaces, ti - tm->tapcli_interfaces);
850
851   // reset renumbered iface
852   if (p[0] < vec_len (tm->show_dev_instance_by_real_dev_instance))
853     tm->show_dev_instance_by_real_dev_instance[p[0]] = ~0;
854
855   ethernet_delete_interface (tm->vnet_main, ti->hw_if_index);
856   return rv;
857 }
858
859 static clib_error_t *
860 tap_delete_command_fn (vlib_main_t * vm,
861                  unformat_input_t * input,
862                  vlib_cli_command_t * cmd)
863 {
864   tapcli_main_t * tm = &tapcli_main;
865   u32 sw_if_index = ~0;
866
867   if (tm->is_disabled)
868     {
869       return clib_error_return (0, "device disabled...");
870     }
871
872   if (unformat (input, "%U", unformat_vnet_sw_interface, tm->vnet_main,
873                 &sw_if_index))
874       ;
875   else
876     return clib_error_return (0, "unknown input `%U'",
877                               format_unformat_error, input);
878
879
880   int rc = vnet_tap_delete (vm, sw_if_index);
881
882   if (!rc) {
883     vlib_cli_output (vm, "Deleted.");
884   } else {
885     vlib_cli_output (vm, "Error during deletion of tap interface. (rc: %d)", rc);
886   }
887
888   return 0;
889 }
890
891 VLIB_CLI_COMMAND (tap_delete_command, static) = {
892     .path = "tap delete",
893     .short_help = "tap delete <vpp-tap-intfc-name>",
894     .function = tap_delete_command_fn,
895 };
896
897 /* modifies tap interface - can result in new interface being created */
898 int vnet_tap_modify (vlib_main_t * vm, u32 orig_sw_if_index,
899                      u8 * intfc_name, u8 *hwaddr_arg, 
900                      u32 * sw_if_indexp,
901                      u8 renumber, u32 custom_dev_instance)
902 {
903     int rv = vnet_tap_delete (vm, orig_sw_if_index);
904
905     if (rv)
906         return rv;
907
908     rv = vnet_tap_connect_renumber(vm, intfc_name, hwaddr_arg, sw_if_indexp,
909             renumber, custom_dev_instance);
910
911     return rv;
912 }
913
914 static clib_error_t *
915 tap_modify_command_fn (vlib_main_t * vm,
916                  unformat_input_t * input,
917                  vlib_cli_command_t * cmd)
918 {
919   u8 * intfc_name;
920   tapcli_main_t * tm = &tapcli_main;
921   u32 sw_if_index = ~0;
922   u32 new_sw_if_index = ~0;
923   int user_hwaddr = 0;
924   u8 hwaddr[6];
925     
926   if (tm->is_disabled)
927     {
928       return clib_error_return (0, "device disabled...");
929     }
930
931   if (unformat (input, "%U", unformat_vnet_sw_interface, tm->vnet_main,
932                 &sw_if_index))
933       ;
934   else
935     return clib_error_return (0, "unknown input `%U'",
936                               format_unformat_error, input);
937
938   if (unformat (input, "%s", &intfc_name))
939     ;
940   else
941     return clib_error_return (0, "unknown input `%U'",
942                               format_unformat_error, input);
943   
944   if (unformat(input, "hwaddr %U", unformat_ethernet_address,
945                &hwaddr))
946     user_hwaddr = 1;
947
948
949   int rc = vnet_tap_modify (vm, sw_if_index, intfc_name,
950                             (user_hwaddr == 1 ? hwaddr : 0),
951                             &new_sw_if_index, 0, 0);
952
953   if (!rc) {
954     vlib_cli_output (vm, "Modified %U for Linux tap '%s'",
955                    format_vnet_sw_if_index_name, tm->vnet_main, 
956                    new_sw_if_index, intfc_name);
957   } else {
958     vlib_cli_output (vm, "Error during modification of tap interface. (rc: %d)", rc);
959   }
960
961   return 0;
962 }
963
964 VLIB_CLI_COMMAND (tap_modify_command, static) = {
965     .path = "tap modify",
966     .short_help = "tap modify <vpp-tap-intfc-name> <linux-intfc-name> [hwaddr [<addr> | random]]",
967     .function = tap_modify_command_fn,
968 };
969
970 static clib_error_t *
971 tap_connect_command_fn (vlib_main_t * vm,
972                  unformat_input_t * input,
973                  vlib_cli_command_t * cmd)
974 {
975   u8 * intfc_name;
976   tapcli_main_t * tm = &tapcli_main;
977   tapcli_interface_t * ti;
978   struct ifreq ifr;
979   int flags;
980   int dev_net_tun_fd;
981   int dev_tap_fd = -1;
982   clib_error_t * error;
983   int user_hwaddr = 0;
984   u8 hwaddr[6];
985
986   if (tm->is_disabled)
987     {
988       return clib_error_return (0, "device disabled...");
989     }
990
991   if (unformat (input, "%s", &intfc_name))
992     ;
993   else
994     return clib_error_return (0, "unknown input `%U'",
995                               format_unformat_error, input);
996   
997   if (unformat(input, "hwaddr %U", unformat_ethernet_address,
998                &hwaddr))
999     user_hwaddr = 1;
1000
1001   flags = IFF_TAP | IFF_NO_PI;
1002
1003   if ((dev_net_tun_fd = open ("/dev/net/tun", O_RDWR)) < 0)
1004     {
1005       vlib_cli_output (vm, "Couldn't open /dev/net/tun");
1006       return 0;
1007     }
1008   
1009   memset (&ifr, 0, sizeof (ifr));
1010   strncpy(ifr.ifr_name, (char *) intfc_name, sizeof (ifr.ifr_name)-1);
1011   ifr.ifr_flags = flags;
1012   if (ioctl (dev_net_tun_fd, TUNSETIFF, (void *)&ifr) < 0)
1013     {
1014       vlib_cli_output (vm, "Error setting flags on '%s'", intfc_name);
1015       goto error;
1016     }
1017     
1018   /* Open a provisioning socket */
1019   if ((dev_tap_fd = socket(PF_PACKET, SOCK_RAW,
1020                            htons(ETH_P_ALL))) < 0 )
1021     {
1022       vlib_cli_output (vm, "Couldn't open provisioning socket");
1023       goto error;
1024     }
1025
1026   /* Find the interface index. */
1027   {
1028     struct ifreq ifr;
1029     struct sockaddr_ll sll;
1030
1031     memset (&ifr, 0, sizeof(ifr));
1032     strncpy (ifr.ifr_name, (char *) intfc_name, sizeof (ifr.ifr_name)-1);
1033     if (ioctl (dev_tap_fd, SIOCGIFINDEX, &ifr) < 0 )
1034       {
1035         vlib_cli_output (vm, "Couldn't get if_index");
1036         goto error;
1037       }
1038
1039     /* Bind the provisioning socket to the interface. */
1040     memset(&sll, 0, sizeof(sll));
1041     sll.sll_family   = AF_PACKET;
1042     sll.sll_ifindex  = ifr.ifr_ifindex;
1043     sll.sll_protocol = htons(ETH_P_ALL);
1044
1045     if (bind(dev_tap_fd, (struct sockaddr*) &sll, sizeof(sll)) < 0)
1046       {
1047         vlib_cli_output (vm, "Couldn't bind provisioning socket");
1048         goto error;
1049       }
1050   }
1051
1052   /* non-blocking I/O on /dev/tapX */
1053   {
1054     int one = 1;
1055     if (ioctl (dev_net_tun_fd, FIONBIO, &one) < 0)
1056       {
1057         vlib_cli_output (0, "Couldn't set device non-blocking flag");
1058         goto error;
1059       }
1060   }
1061   ifr.ifr_mtu = tm->mtu_bytes;
1062   if (ioctl (dev_tap_fd, SIOCSIFMTU, &ifr) < 0)
1063     {
1064       vlib_cli_output (0, "Couldn't set device MTU");
1065       goto error;
1066     }
1067
1068   /* get flags, modify to bring up interface... */
1069   if (ioctl (dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
1070     {
1071       vlib_cli_output (0, "Couldn't get interface flags");
1072       goto error;
1073     }
1074
1075   ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
1076
1077   if (ioctl (dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
1078     {
1079       vlib_cli_output (0, "Couldn't set intfc admin state up");
1080       goto error;
1081     }
1082
1083   if (ioctl (dev_tap_fd, SIOCGIFHWADDR, &ifr) < 0)
1084     {
1085       vlib_cli_output (0, "Couldn't get intfc MAC address");
1086       goto error;
1087     }
1088
1089   ti = tapcli_get_new_tapif();
1090   ti->per_interface_next_index = ~0;
1091
1092   if (unformat(input, "hwaddr random"))
1093     {
1094       f64 now = vlib_time_now(vm);
1095       u32 rnd;
1096       rnd = (u32) (now * 1e6);
1097       rnd = random_u32 (&rnd);
1098
1099       memcpy (hwaddr+2, &rnd, sizeof(rnd));
1100       hwaddr[0] = 2;
1101       hwaddr[1] = 0xfe;
1102       user_hwaddr = 1;
1103     }
1104   
1105   error = ethernet_register_interface
1106         (tm->vnet_main,
1107          tapcli_dev_class.index,
1108          ti - tm->tapcli_interfaces /* device instance */,
1109          user_hwaddr ? hwaddr : 
1110          (u8 *) ifr.ifr_hwaddr.sa_data /* ethernet address */,
1111          &ti->hw_if_index, 
1112          tapcli_flag_change);
1113
1114   if (error)
1115     clib_error_report (error);
1116
1117   {
1118     unix_file_t template = {0};
1119     template.read_function = tapcli_read_ready;
1120     template.file_descriptor = dev_net_tun_fd;
1121     ti->unix_file_index = unix_file_add (&unix_main, &template);
1122     ti->unix_fd = dev_net_tun_fd;
1123     ti->provision_fd = dev_tap_fd;
1124     memcpy (&ti->ifr, &ifr, sizeof (ifr));
1125   }
1126   
1127   {
1128     vnet_hw_interface_t * hw;
1129     hw = vnet_get_hw_interface (tm->vnet_main, ti->hw_if_index);
1130     ti->sw_if_index = hw->sw_if_index;
1131     hw->max_l3_packet_bytes[VLIB_RX] = hw->max_l3_packet_bytes[VLIB_TX] = tm->mtu_bytes - sizeof(ethernet_header_t);
1132   }
1133
1134   ti->active = 1;
1135
1136   hash_set (tm->tapcli_interface_index_by_sw_if_index, ti->sw_if_index,
1137             ti - tm->tapcli_interfaces);
1138
1139   hash_set (tm->tapcli_interface_index_by_unix_fd, ti->unix_fd,
1140             ti - tm->tapcli_interfaces);
1141
1142   vlib_cli_output (vm, "Created %U for Linux tap '%s'",
1143                    format_vnet_sw_if_index_name, tm->vnet_main, 
1144                    ti->sw_if_index, intfc_name);
1145                    
1146   return 0;
1147
1148  error:
1149   close (dev_net_tun_fd);
1150   close (dev_tap_fd);
1151
1152   return 0;
1153 }
1154
1155 VLIB_CLI_COMMAND (tap_connect_command, static) = {
1156     .path = "tap connect",
1157     .short_help = "tap connect <intfc-name> [hwaddr [<addr> | random]]",
1158     .function = tap_connect_command_fn,
1159 };
1160
1161 clib_error_t *
1162 tapcli_init (vlib_main_t * vm)
1163 {
1164   tapcli_main_t * tm = &tapcli_main;
1165
1166   tm->vlib_main = vm;
1167   tm->vnet_main = vnet_get_main();
1168   tm->unix_main = &unix_main;
1169   tm->mtu_bytes = 4096 + 256;
1170   tm->tapcli_interface_index_by_sw_if_index = hash_create (0, sizeof(uword));
1171   tm->tapcli_interface_index_by_unix_fd = hash_create (0, sizeof (uword));
1172   vm->os_punt_frame = tapcli_nopunt_frame;
1173
1174   return 0;
1175 }
1176
1177 VLIB_INIT_FUNCTION (tapcli_init);