devices: add support to check host interface offload capabilities
[vpp.git] / src / plugins / af_packet / af_packet.c
1 /*
2  *------------------------------------------------------------------
3  * af_packet.c - linux kernel packet interface
4  *
5  * Copyright (c) 2016 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 <linux/if_ether.h>
21 #include <linux/if_packet.h>
22 #include <linux/ethtool.h>
23 #include <linux/sockios.h>
24 #include <sys/ioctl.h>
25 #include <net/if.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30
31 #include <vppinfra/linux/sysfs.h>
32 #include <vlib/vlib.h>
33 #include <vlib/unix/unix.h>
34 #include <vnet/ip/ip.h>
35 #include <vnet/devices/netlink.h>
36 #include <vnet/ethernet/ethernet.h>
37 #include <vnet/interface/rx_queue_funcs.h>
38 #include <vnet/interface/tx_queue_funcs.h>
39
40 #include <af_packet/af_packet.h>
41
42 af_packet_main_t af_packet_main;
43
44 VNET_HW_INTERFACE_CLASS (af_packet_ip_device_hw_interface_class, static) = {
45   .name = "af-packet-ip-device",
46   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
47 };
48
49 #define AF_PACKET_DEFAULT_TX_FRAMES_PER_BLOCK 1024
50 #define AF_PACKET_DEFAULT_TX_FRAME_SIZE       (2048 * 33) // GSO packet of 64KB
51 #define AF_PACKET_TX_BLOCK_NR           1
52
53 #define AF_PACKET_DEFAULT_RX_FRAMES_PER_BLOCK_V2 1024
54 #define AF_PACKET_DEFAULT_RX_FRAME_SIZE_V2       (2048 * 33) // GSO packet of 64KB
55 #define AF_PACKET_RX_BLOCK_NR_V2                 1
56
57 #define AF_PACKET_DEFAULT_RX_FRAMES_PER_BLOCK 32
58 #define AF_PACKET_DEFAULT_RX_FRAME_SIZE       2048
59 #define AF_PACKET_RX_BLOCK_NR                 160
60
61 /*defined in net/if.h but clashes with dpdk headers */
62 unsigned int if_nametoindex (const char *ifname);
63
64 #define AF_PACKET_OFFLOAD_FLAG_RXCKSUM (1 << 0)
65 #define AF_PACKET_OFFLOAD_FLAG_TXCKSUM (1 << 1)
66 #define AF_PACKET_OFFLOAD_FLAG_SG      (1 << 2)
67 #define AF_PACKET_OFFLOAD_FLAG_TSO     (1 << 3)
68 #define AF_PACKET_OFFLOAD_FLAG_UFO     (1 << 4)
69 #define AF_PACKET_OFFLOAD_FLAG_GSO     (1 << 5)
70 #define AF_PACKET_OFFLOAD_FLAG_GRO     (1 << 6)
71
72 #define AF_PACKET_OFFLOAD_FLAG_MASK                                           \
73   (AF_PACKET_OFFLOAD_FLAG_RXCKSUM | AF_PACKET_OFFLOAD_FLAG_TXCKSUM |          \
74    AF_PACKET_OFFLOAD_FLAG_SG | AF_PACKET_OFFLOAD_FLAG_TSO |                   \
75    AF_PACKET_OFFLOAD_FLAG_UFO | AF_PACKET_OFFLOAD_FLAG_GSO |                  \
76    AF_PACKET_OFFLOAD_FLAG_GRO)
77
78 #define AF_PACKET_IOCTL(fd, a, ...)                                           \
79   if (ioctl (fd, a, __VA_ARGS__) < 0)                                         \
80     {                                                                         \
81       err = clib_error_return_unix (0, "ioctl(" #a ")");                      \
82       vlib_log_err (af_packet_main.log_class, "%U", format_clib_error, err);  \
83       goto done;                                                              \
84     }
85
86 static u32
87 af_packet_get_if_capabilities (u8 *host_if_name)
88 {
89   struct ifreq ifr;
90   struct ethtool_value e; // { __u32 cmd; __u32 data; };
91   clib_error_t *err = 0;
92   int ctl_fd = -1;
93   u32 oflags = 0;
94
95   if ((ctl_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
96     {
97       clib_warning ("Cannot open control socket");
98       goto done;
99     }
100
101   clib_memset (&ifr, 0, sizeof (ifr));
102   clib_memcpy (ifr.ifr_name, host_if_name,
103                strlen ((const char *) host_if_name));
104   ifr.ifr_data = (void *) &e;
105
106   e.cmd = ETHTOOL_GRXCSUM;
107   AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr);
108   if (e.data)
109     oflags |= AF_PACKET_OFFLOAD_FLAG_RXCKSUM;
110
111   e.cmd = ETHTOOL_GTXCSUM;
112   AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr);
113   if (e.data)
114     oflags |= AF_PACKET_OFFLOAD_FLAG_TXCKSUM;
115
116   e.cmd = ETHTOOL_GTSO;
117   AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr);
118   if (e.data)
119     oflags |= AF_PACKET_OFFLOAD_FLAG_TSO;
120
121   e.cmd = ETHTOOL_GGSO;
122   AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr);
123   if (e.data)
124     oflags |= AF_PACKET_OFFLOAD_FLAG_GSO;
125
126   e.cmd = ETHTOOL_GGRO;
127   AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr);
128   if (e.data)
129     oflags |= AF_PACKET_OFFLOAD_FLAG_GRO;
130
131 done:
132   if (ctl_fd != -1)
133     close (ctl_fd);
134
135   return oflags;
136 }
137
138 static clib_error_t *
139 af_packet_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
140                                   u32 frame_size)
141 {
142   clib_error_t *error, *rv;
143   af_packet_main_t *apm = &af_packet_main;
144   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, hi->dev_instance);
145
146   error = vnet_netlink_set_link_mtu (apif->host_if_index,
147                                      frame_size + hi->frame_overhead);
148
149   if (error)
150     {
151       vlib_log_err (apm->log_class, "netlink failed to change MTU: %U",
152                     format_clib_error, error);
153       rv = vnet_error (VNET_ERR_SYSCALL_ERROR_1, "netlink error: %U",
154                        format_clib_error, error);
155       clib_error_free (error);
156       return rv;
157     }
158   else
159     apif->host_mtu = frame_size + hi->frame_overhead;
160   return 0;
161 }
162
163 static int
164 af_packet_read_mtu (af_packet_if_t *apif)
165 {
166   af_packet_main_t *apm = &af_packet_main;
167   clib_error_t *error;
168   error = vnet_netlink_get_link_mtu (apif->host_if_index, &apif->host_mtu);
169   if (error)
170     {
171       vlib_log_err (apm->log_class, "netlink failed to get MTU: %U",
172                     format_clib_error, error);
173       clib_error_free (error);
174       return VNET_API_ERROR_SYSCALL_ERROR_1;
175     }
176   return 0;
177 }
178
179 static clib_error_t *
180 af_packet_fd_read_ready (clib_file_t * uf)
181 {
182   vnet_main_t *vnm = vnet_get_main ();
183
184   /* Schedule the rx node */
185   vnet_hw_if_rx_queue_set_int_pending (vnm, uf->private_data);
186   return 0;
187 }
188
189 static clib_error_t *
190 af_packet_fd_error (clib_file_t *uf)
191 {
192   af_packet_main_t *apm = &af_packet_main;
193   clib_error_t *err = 0;
194   u64 u64;
195
196   int ret = read (uf->file_descriptor, (char *) &u64, sizeof (u64));
197
198   if (ret < 0)
199     {
200       err = clib_error_return_unix (0, "");
201       vlib_log_notice (apm->log_class, "fd %u %U", uf->file_descriptor,
202                        format_clib_error, err);
203       clib_error_free (err);
204     }
205
206   return 0;
207 }
208
209 static int
210 is_bridge (const u8 * host_if_name)
211 {
212   u8 *s;
213   DIR *dir = NULL;
214
215   s = format (0, "/sys/class/net/%s/bridge%c", host_if_name, 0);
216   dir = opendir ((char *) s);
217   vec_free (s);
218
219   if (dir)
220     {
221       closedir (dir);
222       return 0;
223     }
224
225   return -1;
226 }
227
228 static void
229 af_packet_set_rx_queues (vlib_main_t *vm, af_packet_if_t *apif)
230 {
231   vnet_main_t *vnm = vnet_get_main ();
232   af_packet_queue_t *rx_queue;
233
234   vnet_hw_if_set_input_node (vnm, apif->hw_if_index,
235                              af_packet_input_node.index);
236
237   vec_foreach (rx_queue, apif->rx_queues)
238     {
239       rx_queue->queue_index = vnet_hw_if_register_rx_queue (
240         vnm, apif->hw_if_index, rx_queue->queue_id, VNET_HW_IF_RXQ_THREAD_ANY);
241
242       {
243         clib_file_t template = { 0 };
244         template.read_function = af_packet_fd_read_ready;
245         template.error_function = af_packet_fd_error;
246         template.file_descriptor = rx_queue->fd;
247         template.private_data = rx_queue->queue_index;
248         template.description =
249           format (0, "%U queue %u", format_af_packet_device_name,
250                   apif->dev_instance, rx_queue->queue_id);
251         rx_queue->clib_file_index = clib_file_add (&file_main, &template);
252       }
253       vnet_hw_if_set_rx_queue_file_index (vnm, rx_queue->queue_index,
254                                           rx_queue->clib_file_index);
255       vnet_hw_if_set_rx_queue_mode (vnm, rx_queue->queue_index,
256                                     VNET_HW_IF_RX_MODE_INTERRUPT);
257       rx_queue->mode = VNET_HW_IF_RX_MODE_INTERRUPT;
258     }
259   vnet_hw_if_update_runtime_data (vnm, apif->hw_if_index);
260 }
261
262 static void
263 af_packet_set_tx_queues (vlib_main_t *vm, af_packet_if_t *apif)
264 {
265   vnet_main_t *vnm = vnet_get_main ();
266   af_packet_main_t *apm = &af_packet_main;
267   af_packet_queue_t *tx_queue;
268
269   vec_foreach (tx_queue, apif->tx_queues)
270     {
271       tx_queue->queue_index = vnet_hw_if_register_tx_queue (
272         vnm, apif->hw_if_index, tx_queue->queue_id);
273     }
274
275   if (apif->num_txqs == 0)
276     {
277       vlib_log_err (apm->log_class, "Interface %U has 0 txq",
278                     format_vnet_hw_if_index_name, vnm, apif->hw_if_index);
279       return;
280     }
281
282   for (u32 j = 0; j < vlib_get_n_threads (); j++)
283     {
284       u32 qi = apif->tx_queues[j % apif->num_txqs].queue_index;
285       vnet_hw_if_tx_queue_assign_thread (vnm, qi, j);
286     }
287
288   vnet_hw_if_update_runtime_data (vnm, apif->hw_if_index);
289 }
290
291 static int
292 create_packet_sock (int host_if_index, tpacket_req_u_t *rx_req,
293                     tpacket_req_u_t *tx_req, int *fd, af_packet_ring_t *ring,
294                     u32 fanout_id, af_packet_if_flags_t *flags, int ver)
295 {
296   af_packet_main_t *apm = &af_packet_main;
297   struct sockaddr_ll sll;
298   socklen_t req_sz = sizeof (tpacket_req3_t);
299   int ret;
300   u32 ring_sz = 0;
301
302   if ((*fd = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
303     {
304       vlib_log_err (apm->log_class,
305                     "Failed to create AF_PACKET socket: %s (errno %d)",
306                     strerror (errno), errno);
307       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
308       goto error;
309     }
310
311   /* bind before rx ring is cfged so we don't receive packets from other interfaces */
312   clib_memset (&sll, 0, sizeof (sll));
313   sll.sll_family = PF_PACKET;
314   sll.sll_protocol = htons (ETH_P_ALL);
315   sll.sll_ifindex = host_if_index;
316   if (bind (*fd, (struct sockaddr *) &sll, sizeof (sll)) < 0)
317     {
318       vlib_log_err (apm->log_class,
319                     "Failed to bind rx packet socket: %s (errno %d)",
320                     strerror (errno), errno);
321       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
322       goto error;
323     }
324
325   if (setsockopt (*fd, SOL_PACKET, PACKET_VERSION, &ver, sizeof (ver)) < 0)
326     {
327       vlib_log_err (apm->log_class,
328                     "Failed to set rx packet interface version: %s (errno %d)",
329                     strerror (errno), errno);
330       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
331       goto error;
332     }
333
334   int opt = 1;
335   if (setsockopt (*fd, SOL_PACKET, PACKET_LOSS, &opt, sizeof (opt)) < 0)
336     {
337       vlib_log_err (
338         apm->log_class,
339         "Failed to set packet tx ring error handling option: %s (errno %d)",
340         strerror (errno), errno);
341       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
342       goto error;
343     }
344
345   if (*flags & AF_PACKET_IF_FLAGS_CKSUM_GSO)
346     {
347
348       int opt2 = 1;
349       if (setsockopt (*fd, SOL_PACKET, PACKET_VNET_HDR, &opt2, sizeof (opt2)) <
350           0)
351         {
352           // remove the flag
353           *flags &= ~AF_PACKET_IF_FLAGS_CKSUM_GSO;
354           vlib_log_debug (apm->log_class,
355                           "Failed to set packet vnet hdr error handling "
356                           "option: %s (errno %d)",
357                           strerror (errno), errno);
358         }
359     }
360
361 #if defined(PACKET_QDISC_BYPASS)
362   if (*flags & AF_PACKET_IF_FLAGS_QDISC_BYPASS)
363     /* Introduced with Linux 3.14 so the ifdef should eventually be removed  */
364     if (setsockopt (*fd, SOL_PACKET, PACKET_QDISC_BYPASS, &opt, sizeof (opt)) <
365         0)
366       {
367         // remove the flag
368         *flags &= ~AF_PACKET_IF_FLAGS_QDISC_BYPASS;
369         vlib_log_debug (apm->log_class,
370                         "Failed to set qdisc bypass error "
371                         "handling option: %s (errno %d)",
372                         strerror (errno), errno);
373       }
374 #endif
375
376   if (rx_req)
377     {
378       if (*flags & AF_PACKET_IF_FLAGS_FANOUT)
379         {
380           int fanout = ((fanout_id & 0xffff) | ((PACKET_FANOUT_HASH) << 16));
381           if (setsockopt (*fd, SOL_PACKET, PACKET_FANOUT, &fanout,
382                           sizeof (fanout)) < 0)
383             {
384               // remove the flag
385               *flags &= ~AF_PACKET_IF_FLAGS_FANOUT;
386               vlib_log_err (apm->log_class,
387                             "Failed to set fanout options: %s (errno %d)",
388                             strerror (errno), errno);
389               ret = VNET_API_ERROR_SYSCALL_ERROR_1;
390               goto error;
391             }
392         }
393       if (ver == TPACKET_V2)
394         {
395           req_sz = sizeof (tpacket_req_t);
396           ring_sz += rx_req->req.tp_block_size * rx_req->req.tp_block_nr;
397         }
398       else
399         ring_sz += rx_req->req3.tp_block_size * rx_req->req3.tp_block_nr;
400       if (setsockopt (*fd, SOL_PACKET, PACKET_RX_RING, rx_req, req_sz) < 0)
401         {
402           vlib_log_err (apm->log_class,
403                         "Failed to set packet rx ring options: %s (errno %d)",
404                         strerror (errno), errno);
405           ret = VNET_API_ERROR_SYSCALL_ERROR_1;
406           goto error;
407         }
408     }
409
410   if (tx_req)
411     {
412       if (ver == TPACKET_V2)
413         {
414           req_sz = sizeof (tpacket_req_t);
415           ring_sz += tx_req->req.tp_block_size * tx_req->req.tp_block_nr;
416         }
417       else
418         ring_sz += tx_req->req3.tp_block_size * tx_req->req3.tp_block_nr;
419       if (setsockopt (*fd, SOL_PACKET, PACKET_TX_RING, tx_req, req_sz) < 0)
420         {
421           vlib_log_err (apm->log_class,
422                         "Failed to set packet tx ring options: %s (errno %d)",
423                         strerror (errno), errno);
424           ret = VNET_API_ERROR_SYSCALL_ERROR_1;
425           goto error;
426         }
427     }
428   ring->ring_start_addr = mmap (NULL, ring_sz, PROT_READ | PROT_WRITE,
429                                 MAP_SHARED | MAP_LOCKED, *fd, 0);
430   if (ring->ring_start_addr == MAP_FAILED)
431     {
432       vlib_log_err (apm->log_class, "mmap failure: %s (errno %d)",
433                     strerror (errno), errno);
434       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
435       goto error;
436     }
437
438   ring->ring_size = ring_sz;
439
440   return 0;
441 error:
442   if (*fd >= 0)
443     {
444       close (*fd);
445       *fd = -1;
446     }
447   return ret;
448 }
449
450 int
451 af_packet_queue_init (vlib_main_t *vm, af_packet_if_t *apif,
452                       af_packet_create_if_arg_t *arg,
453                       af_packet_queue_t *rx_queue, af_packet_queue_t *tx_queue,
454                       u8 queue_id)
455 {
456   af_packet_main_t *apm = &af_packet_main;
457   tpacket_req_u_t *rx_req = 0;
458   tpacket_req_u_t *tx_req = 0;
459   int ret, fd = -1;
460   af_packet_ring_t ring = { 0 };
461   u8 *ring_addr = 0;
462   u32 rx_frames_per_block, tx_frames_per_block;
463   u32 rx_frame_size, tx_frame_size;
464   u32 i = 0;
465
466   if (rx_queue)
467     {
468       rx_frames_per_block = arg->rx_frames_per_block ?
469                                     arg->rx_frames_per_block :
470                                     ((apif->version == TPACKET_V3) ?
471                                        AF_PACKET_DEFAULT_RX_FRAMES_PER_BLOCK :
472                                        AF_PACKET_DEFAULT_RX_FRAMES_PER_BLOCK_V2);
473
474       rx_frame_size =
475         arg->rx_frame_size ?
476                 arg->rx_frame_size :
477                 ((apif->version == TPACKET_V3) ? AF_PACKET_DEFAULT_RX_FRAME_SIZE :
478                                                  AF_PACKET_DEFAULT_RX_FRAME_SIZE_V2);
479       vec_validate (rx_queue->rx_req, 0);
480       rx_queue->rx_req->req.tp_block_size =
481         rx_frame_size * rx_frames_per_block;
482       rx_queue->rx_req->req.tp_frame_size = rx_frame_size;
483       rx_queue->rx_req->req.tp_block_nr = (apif->version == TPACKET_V3) ?
484                                                   AF_PACKET_RX_BLOCK_NR :
485                                                   AF_PACKET_RX_BLOCK_NR_V2;
486       rx_queue->rx_req->req.tp_frame_nr =
487         rx_queue->rx_req->req.tp_block_nr * rx_frames_per_block;
488       if (apif->version == TPACKET_V3)
489         {
490           rx_queue->rx_req->req3.tp_retire_blk_tov = 1; // 1 ms block timout
491           rx_queue->rx_req->req3.tp_feature_req_word = 0;
492           rx_queue->rx_req->req3.tp_sizeof_priv = 0;
493         }
494       rx_req = rx_queue->rx_req;
495     }
496   if (tx_queue)
497     {
498       tx_frames_per_block = arg->tx_frames_per_block ?
499                                     arg->tx_frames_per_block :
500                                     AF_PACKET_DEFAULT_TX_FRAMES_PER_BLOCK;
501       tx_frame_size = arg->tx_frame_size ? arg->tx_frame_size :
502                                                  AF_PACKET_DEFAULT_TX_FRAME_SIZE;
503
504       vec_validate (tx_queue->tx_req, 0);
505       tx_queue->tx_req->req.tp_block_size =
506         tx_frame_size * tx_frames_per_block;
507       tx_queue->tx_req->req.tp_frame_size = tx_frame_size;
508       tx_queue->tx_req->req.tp_block_nr = AF_PACKET_TX_BLOCK_NR;
509       tx_queue->tx_req->req.tp_frame_nr =
510         AF_PACKET_TX_BLOCK_NR * tx_frames_per_block;
511       if (apif->version == TPACKET_V3)
512         {
513           tx_queue->tx_req->req3.tp_retire_blk_tov = 0;
514           tx_queue->tx_req->req3.tp_sizeof_priv = 0;
515           tx_queue->tx_req->req3.tp_feature_req_word = 0;
516         }
517       tx_req = tx_queue->tx_req;
518     }
519
520   if (rx_queue || tx_queue)
521     {
522       ret =
523         create_packet_sock (apif->host_if_index, rx_req, tx_req, &fd, &ring,
524                             apif->dev_instance, &arg->flags, apif->version);
525
526       if (ret != 0)
527         goto error;
528
529       vec_add1 (apif->fds, fd);
530       vec_add1 (apif->rings, ring);
531       ring_addr = ring.ring_start_addr;
532     }
533
534   if (rx_queue)
535     {
536       rx_queue->fd = fd;
537       vec_validate (rx_queue->rx_ring, rx_queue->rx_req->req.tp_block_nr - 1);
538       vec_foreach_index (i, rx_queue->rx_ring)
539         {
540           rx_queue->rx_ring[i] =
541             ring_addr + i * rx_queue->rx_req->req.tp_block_size;
542         }
543
544       rx_queue->next_rx_block = 0;
545       rx_queue->queue_id = queue_id;
546       rx_queue->is_rx_pending = 0;
547       ring_addr = ring_addr + rx_queue->rx_req->req.tp_block_size *
548                                 rx_queue->rx_req->req.tp_block_nr;
549     }
550
551   if (tx_queue)
552     {
553       tx_queue->fd = fd;
554       vec_validate (tx_queue->tx_ring, tx_queue->tx_req->req.tp_block_nr - 1);
555       vec_foreach_index (i, tx_queue->tx_ring)
556         {
557           tx_queue->tx_ring[i] =
558             ring_addr + i * tx_queue->tx_req->req.tp_block_size;
559         }
560
561       tx_queue->next_tx_frame = 0;
562       tx_queue->queue_id = queue_id;
563       tx_queue->is_tx_pending = 0;
564       clib_spinlock_init (&tx_queue->lockp);
565     }
566
567   return 0;
568 error:
569   vlib_log_err (apm->log_class, "Failed to set queue %u error", queue_id);
570   if (rx_queue)
571     vec_free (rx_queue->rx_req);
572   if (tx_queue)
573     vec_free (tx_queue->tx_req);
574   return ret;
575 }
576
577 int
578 af_packet_device_init (vlib_main_t *vm, af_packet_if_t *apif,
579                        af_packet_create_if_arg_t *args)
580 {
581   af_packet_main_t *apm = &af_packet_main;
582   af_packet_queue_t *rx_queue = 0;
583   af_packet_queue_t *tx_queue = 0;
584   u16 nq = clib_min (args->num_rxqs, args->num_txqs);
585   u16 i = 0;
586   int ret = 0;
587
588   // enable fanout feature for multi-rxqs
589   if (args->num_rxqs > 1)
590     args->flags |= AF_PACKET_IF_FLAGS_FANOUT;
591
592   vec_validate (apif->rx_queues, args->num_rxqs - 1);
593   vec_validate (apif->tx_queues, args->num_txqs - 1);
594
595   for (; i < nq; i++)
596     {
597       rx_queue = vec_elt_at_index (apif->rx_queues, i);
598       tx_queue = vec_elt_at_index (apif->tx_queues, i);
599       ret = af_packet_queue_init (vm, apif, args, rx_queue, tx_queue, i);
600       if (ret != 0)
601         goto error;
602     }
603
604   if (args->num_rxqs > args->num_txqs)
605     {
606       for (; i < args->num_rxqs; i++)
607         {
608           rx_queue = vec_elt_at_index (apif->rx_queues, i);
609           ret = af_packet_queue_init (vm, apif, args, rx_queue, 0, i);
610           if (ret != 0)
611             goto error;
612         }
613     }
614   else if (args->num_txqs > args->num_rxqs)
615     {
616       for (; i < args->num_txqs; i++)
617         {
618           tx_queue = vec_elt_at_index (apif->tx_queues, i);
619           ret = af_packet_queue_init (vm, apif, args, 0, tx_queue, i);
620           if (ret != 0)
621             goto error;
622         }
623     }
624
625   apif->num_rxqs = args->num_rxqs;
626   apif->num_txqs = args->num_txqs;
627
628   return 0;
629 error:
630   vlib_log_err (apm->log_class, "Failed to init device error");
631   return ret;
632 }
633
634 int
635 af_packet_create_if (af_packet_create_if_arg_t *arg)
636 {
637   af_packet_main_t *apm = &af_packet_main;
638   vlib_main_t *vm = vlib_get_main ();
639   int fd2 = -1;
640   struct ifreq ifr;
641   af_packet_if_t *apif = 0;
642   u8 hw_addr[6];
643   vnet_sw_interface_t *sw;
644   vnet_main_t *vnm = vnet_get_main ();
645   vnet_hw_if_caps_t caps = VNET_HW_IF_CAP_INT_MODE;
646   uword *p;
647   uword if_index;
648   u8 *host_if_name_dup = 0;
649   int host_if_index = -1;
650   int ret = 0;
651   u32 oflags = 0, i = 0;
652
653   p = mhash_get (&apm->if_index_by_host_if_name, arg->host_if_name);
654   if (p)
655     {
656       apif = vec_elt_at_index (apm->interfaces, p[0]);
657       arg->sw_if_index = apif->sw_if_index;
658       return VNET_API_ERROR_IF_ALREADY_EXISTS;
659     }
660
661   host_if_name_dup = vec_dup (arg->host_if_name);
662
663   /*
664    * make sure host side of interface is 'UP' before binding AF_PACKET
665    * socket on it.
666    */
667   if ((fd2 = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0)
668     {
669       vlib_log_debug (apm->log_class,
670                       "Failed to create AF_UNIX socket: %s (errno %d)",
671                       strerror (errno), errno);
672       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
673       goto error;
674     }
675
676   clib_memcpy (ifr.ifr_name, (const char *) arg->host_if_name,
677                vec_len (arg->host_if_name));
678   if (ioctl (fd2, SIOCGIFINDEX, &ifr) < 0)
679     {
680       vlib_log_debug (
681         apm->log_class,
682         "Failed to retrieve the interface (%s) index: %s (errno %d)",
683         arg->host_if_name, strerror (errno), errno);
684       ret = VNET_API_ERROR_INVALID_INTERFACE;
685       goto error;
686     }
687
688   host_if_index = ifr.ifr_ifindex;
689   if (ioctl (fd2, SIOCGIFFLAGS, &ifr) < 0)
690     {
691       vlib_log_debug (apm->log_class,
692                       "Failed to get the active flag: %s (errno %d)",
693                       strerror (errno), errno);
694       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
695       goto error;
696     }
697
698   if (!(ifr.ifr_flags & IFF_UP))
699     {
700       ifr.ifr_flags |= IFF_UP;
701       if (ioctl (fd2, SIOCSIFFLAGS, &ifr) < 0)
702         {
703           vlib_log_debug (apm->log_class,
704                           "Failed to set the active flag: %s (errno %d)",
705                           strerror (errno), errno);
706           ret = VNET_API_ERROR_SYSCALL_ERROR_1;
707           goto error;
708         }
709     }
710
711   if (fd2 > -1)
712     {
713       close (fd2);
714       fd2 = -1;
715     }
716
717   // check the host interface capabilities
718   oflags = af_packet_get_if_capabilities (arg->host_if_name);
719
720   ret = is_bridge (arg->host_if_name);
721   if (ret == 0)                 /* is a bridge, ignore state */
722     host_if_index = -1;
723
724   /* So far everything looks good, let's create interface */
725   pool_get (apm->interfaces, apif);
726   if_index = apif - apm->interfaces;
727
728   apif->dev_instance = if_index;
729   apif->host_if_index = host_if_index;
730   apif->host_if_name = host_if_name_dup;
731   apif->per_interface_next_index = ~0;
732   apif->mode = arg->mode;
733   apif->host_interface_oflags = oflags;
734
735   if (arg->is_v2)
736     apif->version = TPACKET_V2;
737   else
738     apif->version = TPACKET_V3;
739
740   ret = af_packet_device_init (vm, apif, arg);
741   if (ret != 0)
742     goto error;
743
744   ret = af_packet_read_mtu (apif);
745   if (ret != 0)
746     goto error;
747
748
749   if (apif->mode != AF_PACKET_IF_MODE_IP)
750     {
751       vnet_eth_interface_registration_t eir = {};
752       /*use configured or generate random MAC address */
753       if (arg->hw_addr)
754         clib_memcpy (hw_addr, arg->hw_addr, 6);
755       else
756         {
757           f64 now = vlib_time_now (vm);
758           u32 rnd;
759           rnd = (u32) (now * 1e6);
760           rnd = random_u32 (&rnd);
761
762           clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
763           hw_addr[0] = 2;
764           hw_addr[1] = 0xfe;
765         }
766
767       eir.dev_class_index = af_packet_device_class.index;
768       eir.dev_instance = apif->dev_instance;
769       eir.address = hw_addr;
770       eir.cb.set_max_frame_size = af_packet_eth_set_max_frame_size;
771       apif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
772     }
773   else
774     {
775       apif->hw_if_index = vnet_register_interface (
776         vnm, af_packet_device_class.index, apif->dev_instance,
777         af_packet_ip_device_hw_interface_class.index, apif->dev_instance);
778     }
779
780   sw = vnet_get_hw_sw_interface (vnm, apif->hw_if_index);
781   apif->sw_if_index = sw->sw_if_index;
782
783   af_packet_set_rx_queues (vm, apif);
784   af_packet_set_tx_queues (vm, apif);
785
786   if (arg->flags & AF_PACKET_IF_FLAGS_FANOUT)
787     apif->is_fanout_enabled = 1;
788
789   apif->is_qdisc_bypass_enabled =
790     (arg->flags & AF_PACKET_IF_FLAGS_QDISC_BYPASS);
791
792   if (arg->flags & AF_PACKET_IF_FLAGS_CKSUM_GSO)
793     {
794       if (apif->host_interface_oflags & AF_PACKET_OFFLOAD_FLAG_TXCKSUM)
795         {
796           apif->is_cksum_gso_enabled = 1;
797           caps |= VNET_HW_IF_CAP_TX_IP4_CKSUM | VNET_HW_IF_CAP_TX_TCP_CKSUM |
798                   VNET_HW_IF_CAP_TX_UDP_CKSUM;
799         }
800
801       if (apif->host_interface_oflags & AF_PACKET_OFFLOAD_FLAG_GSO)
802         {
803           apif->is_cksum_gso_enabled = 1;
804           caps |= VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_IP4_CKSUM |
805                   VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM;
806         }
807     }
808   vnet_hw_if_set_caps (vnm, apif->hw_if_index, caps);
809   vnet_hw_interface_set_flags (vnm, apif->hw_if_index,
810                                VNET_HW_INTERFACE_FLAG_LINK_UP);
811
812   mhash_set_mem (&apm->if_index_by_host_if_name, host_if_name_dup, &if_index,
813                  0);
814   arg->sw_if_index = apif->sw_if_index;
815
816   return 0;
817
818 error:
819   if (fd2 > -1)
820     {
821       close (fd2);
822       fd2 = -1;
823     }
824   vec_foreach_index (i, apif->fds)
825     if (apif->fds[i] != -1)
826       close (apif->fds[i]);
827   vec_free (apif->fds);
828   vec_free (host_if_name_dup);
829   if (apif)
830     {
831       memset (apif, 0, sizeof (*apif));
832       pool_put (apm->interfaces, apif);
833     }
834   return ret;
835 }
836
837 static int
838 af_packet_rx_queue_free (af_packet_if_t *apif, af_packet_queue_t *rx_queue)
839 {
840   clib_file_del_by_index (&file_main, rx_queue->clib_file_index);
841   rx_queue->fd = -1;
842   rx_queue->rx_ring = NULL;
843   vec_free (rx_queue->rx_req);
844   rx_queue->rx_req = NULL;
845   return 0;
846 }
847
848 static int
849 af_packet_tx_queue_free (af_packet_if_t *apif, af_packet_queue_t *tx_queue)
850 {
851   tx_queue->fd = -1;
852   clib_spinlock_free (&tx_queue->lockp);
853   tx_queue->tx_ring = NULL;
854   vec_free (tx_queue->tx_req);
855   tx_queue->tx_req = NULL;
856   return 0;
857 }
858
859 static int
860 af_packet_ring_free (af_packet_if_t *apif, af_packet_ring_t *ring)
861 {
862   af_packet_main_t *apm = &af_packet_main;
863
864   if (ring)
865     {
866       // FIXME: unmap the memory
867       if (munmap (ring->ring_start_addr, ring->ring_size))
868         vlib_log_warn (apm->log_class,
869                        "Host interface %s could not free ring %p of size %u",
870                        apif->host_if_name, ring->ring_start_addr,
871                        ring->ring_size);
872       else
873         ring->ring_start_addr = 0;
874     }
875
876   return 0;
877 }
878
879 int
880 af_packet_delete_if (u8 *host_if_name)
881 {
882   vnet_main_t *vnm = vnet_get_main ();
883   af_packet_main_t *apm = &af_packet_main;
884   af_packet_if_t *apif;
885   af_packet_queue_t *rx_queue;
886   af_packet_queue_t *tx_queue;
887   af_packet_ring_t *ring;
888   uword *p;
889   u32 i = 0;
890
891   p = mhash_get (&apm->if_index_by_host_if_name, host_if_name);
892   if (p == NULL)
893     {
894       vlib_log_warn (apm->log_class, "Host interface %s does not exist",
895                      host_if_name);
896       return VNET_API_ERROR_SYSCALL_ERROR_1;
897     }
898   apif = pool_elt_at_index (apm->interfaces, p[0]);
899
900   /* bring down the interface */
901   vnet_hw_interface_set_flags (vnm, apif->hw_if_index, 0);
902   if (apif->mode != AF_PACKET_IF_MODE_IP)
903     ethernet_delete_interface (vnm, apif->hw_if_index);
904   else
905     vnet_delete_hw_interface (vnm, apif->hw_if_index);
906
907   /* clean up */
908   vec_foreach_index (i, apif->fds)
909     if (apif->fds[i] != -1)
910       close (apif->fds[i]);
911   vec_foreach (rx_queue, apif->rx_queues)
912     af_packet_rx_queue_free (apif, rx_queue);
913   vec_foreach (tx_queue, apif->tx_queues)
914     af_packet_tx_queue_free (apif, tx_queue);
915   vec_foreach (ring, apif->rings)
916     af_packet_ring_free (apif, ring);
917
918   vec_free (apif->fds);
919   apif->fds = NULL;
920   vec_free (apif->rx_queues);
921   apif->rx_queues = NULL;
922   vec_free (apif->tx_queues);
923   apif->tx_queues = NULL;
924   vec_free (apif->rings);
925   apif->rings = NULL;
926
927   vec_free (apif->host_if_name);
928   apif->host_if_name = NULL;
929   apif->host_if_index = -1;
930
931   mhash_unset (&apm->if_index_by_host_if_name, host_if_name, p);
932
933   memset (apif, 0, sizeof (*apif));
934   pool_put (apm->interfaces, apif);
935
936   return 0;
937 }
938
939 int
940 af_packet_enable_disable_qdisc_bypass (u32 sw_if_index, u8 enable_disable)
941 {
942   af_packet_main_t *apm = &af_packet_main;
943   af_packet_if_t *apif;
944   vnet_main_t *vnm = vnet_get_main ();
945   vnet_hw_interface_t *hw;
946   u32 i;
947
948   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
949
950   if (hw->dev_class_index != af_packet_device_class.index)
951     return VNET_API_ERROR_INVALID_INTERFACE;
952
953   apif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
954
955 #if defined(PACKET_QDISC_BYPASS)
956   vec_foreach_index (i, apif->fds)
957     {
958       if (enable_disable)
959         {
960           int opt = 1;
961
962           /* Introduced with Linux 3.14 so the ifdef should eventually be
963            * removed  */
964           if (setsockopt (apif->fds[i], SOL_PACKET, PACKET_QDISC_BYPASS, &opt,
965                           sizeof (opt)) < 0)
966             {
967               vlib_log_err (apm->log_class,
968                             "Failed to enable qdisc bypass error "
969                             "handling option: %s (errno %d)",
970                             strerror (errno), errno);
971             }
972           apif->is_qdisc_bypass_enabled = 1;
973         }
974       else
975         {
976           int opt = 0;
977           if (setsockopt (apif->fds[i], SOL_PACKET, PACKET_QDISC_BYPASS, &opt,
978                           sizeof (opt)) < 0)
979             {
980               vlib_log_err (apm->log_class,
981                             "Failed to disable qdisc bypass error "
982                             "handling option: %s (errno %d)",
983                             strerror (errno), errno);
984             }
985           apif->is_qdisc_bypass_enabled = 0;
986         }
987     }
988
989 #endif
990   return 0;
991 }
992
993 int
994 af_packet_set_l4_cksum_offload (u32 sw_if_index, u8 set)
995 {
996   // deprecated ...
997   return 0;
998 }
999
1000 int
1001 af_packet_dump_ifs (af_packet_if_detail_t ** out_af_packet_ifs)
1002 {
1003   af_packet_main_t *apm = &af_packet_main;
1004   af_packet_if_t *apif;
1005   af_packet_if_detail_t *r_af_packet_ifs = NULL;
1006   af_packet_if_detail_t *af_packet_if = NULL;
1007
1008   pool_foreach (apif, apm->interfaces)
1009      {
1010       vec_add2 (r_af_packet_ifs, af_packet_if, 1);
1011       af_packet_if->sw_if_index = apif->sw_if_index;
1012       if (apif->host_if_name)
1013         {
1014           clib_memcpy (af_packet_if->host_if_name, apif->host_if_name,
1015                        MIN (ARRAY_LEN (af_packet_if->host_if_name) - 1,
1016                        strlen ((const char *) apif->host_if_name)));
1017         }
1018     }
1019
1020   *out_af_packet_ifs = r_af_packet_ifs;
1021
1022   return 0;
1023 }
1024
1025 static clib_error_t *
1026 af_packet_init (vlib_main_t * vm)
1027 {
1028   af_packet_main_t *apm = &af_packet_main;
1029   vlib_thread_main_t *tm = vlib_get_thread_main ();
1030
1031   clib_memset (apm, 0, sizeof (af_packet_main_t));
1032
1033   mhash_init_vec_string (&apm->if_index_by_host_if_name, sizeof (uword));
1034
1035   vec_validate_aligned (apm->rx_buffers, tm->n_vlib_mains - 1,
1036                         CLIB_CACHE_LINE_BYTES);
1037
1038   apm->log_class = vlib_log_register_class ("af_packet", 0);
1039   vlib_log_debug (apm->log_class, "initialized");
1040
1041   return 0;
1042 }
1043
1044 VLIB_INIT_FUNCTION (af_packet_init);
1045
1046 /*
1047  * fd.io coding-style-patch-verification: ON
1048  *
1049  * Local Variables:
1050  * eval: (c-set-style "gnu")
1051  * End:
1052  */