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