ethernet: fix DMAC check and skip unnecessary ones (VPP-1868)
[vpp.git] / src / vnet / devices / 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 <sys/ioctl.h>
23 #include <net/if.h>
24 #include <dirent.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28
29 #include <vppinfra/linux/sysfs.h>
30 #include <vlib/vlib.h>
31 #include <vlib/unix/unix.h>
32 #include <vnet/ip/ip.h>
33 #include <vnet/ethernet/ethernet.h>
34
35 #include <vnet/devices/af_packet/af_packet.h>
36
37 af_packet_main_t af_packet_main;
38
39 #define AF_PACKET_TX_FRAMES_PER_BLOCK   1024
40 #define AF_PACKET_TX_FRAME_SIZE         (2048 * 5)
41 #define AF_PACKET_TX_BLOCK_NR           1
42 #define AF_PACKET_TX_FRAME_NR           (AF_PACKET_TX_BLOCK_NR * \
43                                          AF_PACKET_TX_FRAMES_PER_BLOCK)
44 #define AF_PACKET_TX_BLOCK_SIZE         (AF_PACKET_TX_FRAME_SIZE * \
45                                          AF_PACKET_TX_FRAMES_PER_BLOCK)
46
47 #define AF_PACKET_RX_FRAMES_PER_BLOCK   1024
48 #define AF_PACKET_RX_FRAME_SIZE         (2048 * 5)
49 #define AF_PACKET_RX_BLOCK_NR           1
50 #define AF_PACKET_RX_FRAME_NR           (AF_PACKET_RX_BLOCK_NR * \
51                                          AF_PACKET_RX_FRAMES_PER_BLOCK)
52 #define AF_PACKET_RX_BLOCK_SIZE         (AF_PACKET_RX_FRAME_SIZE * \
53                                          AF_PACKET_RX_FRAMES_PER_BLOCK)
54
55 /*defined in net/if.h but clashes with dpdk headers */
56 unsigned int if_nametoindex (const char *ifname);
57
58 typedef struct tpacket_req tpacket_req_t;
59
60 static u32
61 af_packet_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
62                            u32 flags)
63 {
64   clib_error_t *error;
65   u8 *s;
66   af_packet_main_t *apm = &af_packet_main;
67   af_packet_if_t *apif =
68     pool_elt_at_index (apm->interfaces, hi->dev_instance);
69
70   if (flags == ETHERNET_INTERFACE_FLAG_MTU)
71     {
72       s = format (0, "/sys/class/net/%s/mtu%c", apif->host_if_name, 0);
73
74       error = clib_sysfs_write ((char *) s, "%d", hi->max_packet_bytes);
75       vec_free (s);
76
77       if (error)
78         {
79           vlib_log_err (apm->log_class,
80                         "sysfs write failed to change MTU: %U",
81                         format_clib_error, error);
82           clib_error_free (error);
83           return VNET_API_ERROR_SYSCALL_ERROR_1;
84         }
85     }
86
87   return 0;
88 }
89
90 static clib_error_t *
91 af_packet_fd_read_ready (clib_file_t * uf)
92 {
93   af_packet_main_t *apm = &af_packet_main;
94   vnet_main_t *vnm = vnet_get_main ();
95   u32 idx = uf->private_data;
96   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, idx);
97
98   apm->pending_input_bitmap =
99     clib_bitmap_set (apm->pending_input_bitmap, idx, 1);
100
101   /* Schedule the rx node */
102   vnet_device_input_set_interrupt_pending (vnm, apif->hw_if_index, 0);
103
104   return 0;
105 }
106
107 static int
108 is_bridge (const u8 * host_if_name)
109 {
110   u8 *s;
111   DIR *dir = NULL;
112
113   s = format (0, "/sys/class/net/%s/bridge%c", host_if_name, 0);
114   dir = opendir ((char *) s);
115   vec_free (s);
116
117   if (dir)
118     {
119       closedir (dir);
120       return 0;
121     }
122
123   return -1;
124 }
125
126 static int
127 create_packet_v2_sock (int host_if_index, tpacket_req_t * rx_req,
128                        tpacket_req_t * tx_req, int *fd, u8 ** ring)
129 {
130   af_packet_main_t *apm = &af_packet_main;
131   int ret;
132   struct sockaddr_ll sll;
133   int ver = TPACKET_V2;
134   socklen_t req_sz = sizeof (struct tpacket_req);
135   u32 ring_sz = rx_req->tp_block_size * rx_req->tp_block_nr +
136     tx_req->tp_block_size * tx_req->tp_block_nr;
137
138   if ((*fd = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
139     {
140       vlib_log_debug (apm->log_class,
141                       "Failed to create AF_PACKET socket: %s (errno %d)",
142                       strerror (errno), errno);
143       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
144       goto error;
145     }
146
147   /* bind before rx ring is cfged so we don't receive packets from other interfaces */
148   clib_memset (&sll, 0, sizeof (sll));
149   sll.sll_family = PF_PACKET;
150   sll.sll_protocol = htons (ETH_P_ALL);
151   sll.sll_ifindex = host_if_index;
152   if (bind (*fd, (struct sockaddr *) &sll, sizeof (sll)) < 0)
153     {
154       vlib_log_debug (apm->log_class,
155                       "Failed to bind rx packet socket: %s (errno %d)",
156                       strerror (errno), errno);
157       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
158       goto error;
159     }
160
161   if (setsockopt (*fd, SOL_PACKET, PACKET_VERSION, &ver, sizeof (ver)) < 0)
162     {
163       vlib_log_debug (apm->log_class,
164                       "Failed to set rx packet interface version: %s (errno %d)",
165                       strerror (errno), errno);
166       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
167       goto error;
168     }
169
170   int opt = 1;
171   if (setsockopt (*fd, SOL_PACKET, PACKET_LOSS, &opt, sizeof (opt)) < 0)
172     {
173       vlib_log_debug (apm->log_class,
174                       "Failed to set packet tx ring error handling option: %s (errno %d)",
175                       strerror (errno), errno);
176       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
177       goto error;
178     }
179
180   if (setsockopt (*fd, SOL_PACKET, PACKET_RX_RING, rx_req, req_sz) < 0)
181     {
182       vlib_log_debug (apm->log_class,
183                       "Failed to set packet rx ring options: %s (errno %d)",
184                       strerror (errno), errno);
185       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
186       goto error;
187     }
188
189   if (setsockopt (*fd, SOL_PACKET, PACKET_TX_RING, tx_req, req_sz) < 0)
190     {
191       vlib_log_debug (apm->log_class,
192                       "Failed to set packet tx ring options: %s (errno %d)",
193                       strerror (errno), errno);
194       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
195       goto error;
196     }
197
198   *ring =
199     mmap (NULL, ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, *fd,
200           0);
201   if (*ring == MAP_FAILED)
202     {
203       vlib_log_debug (apm->log_class, "mmap failure: %s (errno %d)",
204                       strerror (errno), errno);
205       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
206       goto error;
207     }
208
209   return 0;
210 error:
211   if (*fd >= 0)
212     {
213       close (*fd);
214       *fd = -1;
215     }
216   return ret;
217 }
218
219 int
220 af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set,
221                      u32 * sw_if_index)
222 {
223   af_packet_main_t *apm = &af_packet_main;
224   int ret, fd = -1, fd2 = -1;
225   struct tpacket_req *rx_req = 0;
226   struct tpacket_req *tx_req = 0;
227   struct ifreq ifr;
228   u8 *ring = 0;
229   af_packet_if_t *apif = 0;
230   u8 hw_addr[6];
231   clib_error_t *error;
232   vnet_sw_interface_t *sw;
233   vnet_hw_interface_t *hw;
234   vlib_thread_main_t *tm = vlib_get_thread_main ();
235   vnet_main_t *vnm = vnet_get_main ();
236   uword *p;
237   uword if_index;
238   u8 *host_if_name_dup = 0;
239   int host_if_index = -1;
240
241   p = mhash_get (&apm->if_index_by_host_if_name, host_if_name);
242   if (p)
243     {
244       apif = vec_elt_at_index (apm->interfaces, p[0]);
245       *sw_if_index = apif->sw_if_index;
246       return VNET_API_ERROR_IF_ALREADY_EXISTS;
247     }
248
249   host_if_name_dup = vec_dup (host_if_name);
250
251   vec_validate (rx_req, 0);
252   rx_req->tp_block_size = AF_PACKET_RX_BLOCK_SIZE;
253   rx_req->tp_frame_size = AF_PACKET_RX_FRAME_SIZE;
254   rx_req->tp_block_nr = AF_PACKET_RX_BLOCK_NR;
255   rx_req->tp_frame_nr = AF_PACKET_RX_FRAME_NR;
256
257   vec_validate (tx_req, 0);
258   tx_req->tp_block_size = AF_PACKET_TX_BLOCK_SIZE;
259   tx_req->tp_frame_size = AF_PACKET_TX_FRAME_SIZE;
260   tx_req->tp_block_nr = AF_PACKET_TX_BLOCK_NR;
261   tx_req->tp_frame_nr = AF_PACKET_TX_FRAME_NR;
262
263   /*
264    * make sure host side of interface is 'UP' before binding AF_PACKET
265    * socket on it.
266    */
267   if ((fd2 = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0)
268     {
269       vlib_log_debug (apm->log_class,
270                       "Failed to create AF_UNIX socket: %s (errno %d)",
271                       strerror (errno), errno);
272       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
273       goto error;
274     }
275
276   clib_memcpy (ifr.ifr_name, (const char *) host_if_name,
277                vec_len (host_if_name));
278   if (ioctl (fd2, SIOCGIFINDEX, &ifr) < 0)
279     {
280       vlib_log_debug (apm->log_class,
281                       "Failed to retrieve the interface (%s) index: %s (errno %d)",
282                       host_if_name, strerror (errno), errno);
283       ret = VNET_API_ERROR_INVALID_INTERFACE;
284       goto error;
285     }
286
287   host_if_index = ifr.ifr_ifindex;
288   if (ioctl (fd2, SIOCGIFFLAGS, &ifr) < 0)
289     {
290       vlib_log_debug (apm->log_class,
291                       "Failed to get the active flag: %s (errno %d)",
292                       strerror (errno), errno);
293       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
294       goto error;
295     }
296
297   if (!(ifr.ifr_flags & IFF_UP))
298     {
299       ifr.ifr_flags |= IFF_UP;
300       if (ioctl (fd2, SIOCSIFFLAGS, &ifr) < 0)
301         {
302           vlib_log_debug (apm->log_class,
303                           "Failed to set the active flag: %s (errno %d)",
304                           strerror (errno), errno);
305           ret = VNET_API_ERROR_SYSCALL_ERROR_1;
306           goto error;
307         }
308     }
309
310   if (fd2 > -1)
311     {
312       close (fd2);
313       fd2 = -1;
314     }
315
316   ret = create_packet_v2_sock (host_if_index, rx_req, tx_req, &fd, &ring);
317
318   if (ret != 0)
319     goto error;
320
321   ret = is_bridge (host_if_name);
322
323   if (ret == 0)                 /* is a bridge, ignore state */
324     host_if_index = -1;
325
326   /* So far everything looks good, let's create interface */
327   pool_get (apm->interfaces, apif);
328   if_index = apif - apm->interfaces;
329
330   apif->host_if_index = host_if_index;
331   apif->fd = fd;
332   apif->rx_ring = ring;
333   apif->tx_ring = ring + rx_req->tp_block_size * rx_req->tp_block_nr;
334   apif->rx_req = rx_req;
335   apif->tx_req = tx_req;
336   apif->host_if_name = host_if_name_dup;
337   apif->per_interface_next_index = ~0;
338   apif->next_tx_frame = 0;
339   apif->next_rx_frame = 0;
340
341   if (tm->n_vlib_mains > 1)
342     clib_spinlock_init (&apif->lockp);
343
344   {
345     clib_file_t template = { 0 };
346     template.read_function = af_packet_fd_read_ready;
347     template.file_descriptor = fd;
348     template.private_data = if_index;
349     template.flags = UNIX_FILE_EVENT_EDGE_TRIGGERED;
350     template.description = format (0, "%U", format_af_packet_device_name,
351                                    if_index);
352     apif->clib_file_index = clib_file_add (&file_main, &template);
353   }
354
355   /*use configured or generate random MAC address */
356   if (hw_addr_set)
357     clib_memcpy (hw_addr, hw_addr_set, 6);
358   else
359     {
360       f64 now = vlib_time_now (vm);
361       u32 rnd;
362       rnd = (u32) (now * 1e6);
363       rnd = random_u32 (&rnd);
364
365       clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
366       hw_addr[0] = 2;
367       hw_addr[1] = 0xfe;
368     }
369
370   error = ethernet_register_interface (vnm, af_packet_device_class.index,
371                                        if_index, hw_addr, &apif->hw_if_index,
372                                        af_packet_eth_flag_change);
373
374   if (error)
375     {
376       clib_memset (apif, 0, sizeof (*apif));
377       pool_put (apm->interfaces, apif);
378       vlib_log_err (apm->log_class, "Unable to register interface: %U",
379                     format_clib_error, error);
380       clib_error_free (error);
381       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
382       goto error;
383     }
384
385   sw = vnet_get_hw_sw_interface (vnm, apif->hw_if_index);
386   hw = vnet_get_hw_interface (vnm, apif->hw_if_index);
387   apif->sw_if_index = sw->sw_if_index;
388   vnet_hw_interface_set_input_node (vnm, apif->hw_if_index,
389                                     af_packet_input_node.index);
390
391   vnet_hw_interface_assign_rx_thread (vnm, apif->hw_if_index, 0,        /* queue */
392                                       ~0 /* any cpu */ );
393
394   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
395   vnet_hw_interface_set_flags (vnm, apif->hw_if_index,
396                                VNET_HW_INTERFACE_FLAG_LINK_UP);
397
398   vnet_hw_interface_set_rx_mode (vnm, apif->hw_if_index, 0,
399                                  VNET_HW_INTERFACE_RX_MODE_INTERRUPT);
400
401   mhash_set_mem (&apm->if_index_by_host_if_name, host_if_name_dup, &if_index,
402                  0);
403   if (sw_if_index)
404     *sw_if_index = apif->sw_if_index;
405
406   return 0;
407
408 error:
409   if (fd2 > -1)
410     {
411       close (fd2);
412       fd2 = -1;
413     }
414   vec_free (host_if_name_dup);
415   vec_free (rx_req);
416   vec_free (tx_req);
417   return ret;
418 }
419
420 int
421 af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name)
422 {
423   vnet_main_t *vnm = vnet_get_main ();
424   af_packet_main_t *apm = &af_packet_main;
425   af_packet_if_t *apif;
426   uword *p;
427   uword if_index;
428   u32 ring_sz;
429
430   p = mhash_get (&apm->if_index_by_host_if_name, host_if_name);
431   if (p == NULL)
432     {
433       vlib_log_warn (apm->log_class, "Host interface %s does not exist",
434                      host_if_name);
435       return VNET_API_ERROR_SYSCALL_ERROR_1;
436     }
437   apif = pool_elt_at_index (apm->interfaces, p[0]);
438   if_index = apif - apm->interfaces;
439
440   /* bring down the interface */
441   vnet_hw_interface_set_flags (vnm, apif->hw_if_index, 0);
442   vnet_hw_interface_unassign_rx_thread (vnm, apif->hw_if_index, 0);
443
444   /* clean up */
445   if (apif->clib_file_index != ~0)
446     {
447       clib_file_del (&file_main, file_main.file_pool + apif->clib_file_index);
448       apif->clib_file_index = ~0;
449     }
450   else
451     close (apif->fd);
452
453   ring_sz = apif->rx_req->tp_block_size * apif->rx_req->tp_block_nr +
454     apif->tx_req->tp_block_size * apif->tx_req->tp_block_nr;
455   if (munmap (apif->rx_ring, ring_sz))
456     vlib_log_warn (apm->log_class,
457                    "Host interface %s could not free rx/tx ring",
458                    host_if_name);
459   apif->rx_ring = NULL;
460   apif->tx_ring = NULL;
461   apif->fd = -1;
462
463   vec_free (apif->rx_req);
464   apif->rx_req = NULL;
465   vec_free (apif->tx_req);
466   apif->tx_req = NULL;
467
468   vec_free (apif->host_if_name);
469   apif->host_if_name = NULL;
470   apif->host_if_index = -1;
471
472   mhash_unset (&apm->if_index_by_host_if_name, host_if_name, &if_index);
473
474   ethernet_delete_interface (vnm, apif->hw_if_index);
475
476   pool_put (apm->interfaces, apif);
477
478   return 0;
479 }
480
481 int
482 af_packet_set_l4_cksum_offload (vlib_main_t * vm, u32 sw_if_index, u8 set)
483 {
484   vnet_main_t *vnm = vnet_get_main ();
485   vnet_hw_interface_t *hw;
486
487   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
488
489   if (hw->dev_class_index != af_packet_device_class.index)
490     return VNET_API_ERROR_INVALID_INTERFACE;
491
492   if (set)
493     hw->flags &= ~VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD;
494   else
495     hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD;
496
497   return 0;
498 }
499
500 int
501 af_packet_dump_ifs (af_packet_if_detail_t ** out_af_packet_ifs)
502 {
503   af_packet_main_t *apm = &af_packet_main;
504   af_packet_if_t *apif;
505   af_packet_if_detail_t *r_af_packet_ifs = NULL;
506   af_packet_if_detail_t *af_packet_if = NULL;
507
508   /* *INDENT-OFF* */
509   pool_foreach (apif, apm->interfaces,
510     ({
511       vec_add2 (r_af_packet_ifs, af_packet_if, 1);
512       af_packet_if->sw_if_index = apif->sw_if_index;
513       if (apif->host_if_name)
514         {
515           clib_memcpy (af_packet_if->host_if_name, apif->host_if_name,
516                        MIN (ARRAY_LEN (af_packet_if->host_if_name) - 1,
517                        strlen ((const char *) apif->host_if_name)));
518         }
519     }));
520   /* *INDENT-ON* */
521
522   *out_af_packet_ifs = r_af_packet_ifs;
523
524   return 0;
525 }
526
527 static clib_error_t *
528 af_packet_init (vlib_main_t * vm)
529 {
530   af_packet_main_t *apm = &af_packet_main;
531   vlib_thread_main_t *tm = vlib_get_thread_main ();
532
533   clib_memset (apm, 0, sizeof (af_packet_main_t));
534
535   mhash_init_vec_string (&apm->if_index_by_host_if_name, sizeof (uword));
536
537   vec_validate_aligned (apm->rx_buffers, tm->n_vlib_mains - 1,
538                         CLIB_CACHE_LINE_BYTES);
539
540   apm->log_class = vlib_log_register_class ("af_packet", 0);
541   vlib_log_debug (apm->log_class, "initialized");
542
543   return 0;
544 }
545
546 VLIB_INIT_FUNCTION (af_packet_init);
547
548 /*
549  * fd.io coding-style-patch-verification: ON
550  *
551  * Local Variables:
552  * eval: (c-set-style "gnu")
553  * End:
554  */