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