LCOV - code coverage report
Current view: top level - plugins/af_packet - device.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 193 386 50.0 %
Date: 2023-07-05 22:20:52 Functions: 12 22 54.5 %

          Line data    Source code
       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_packet.h>
      21             : #include <sys/socket.h>
      22             : #include <sys/ioctl.h>
      23             : #include <net/if.h>
      24             : #include <net/if_arp.h>
      25             : 
      26             : #include <vlib/vlib.h>
      27             : #include <vlib/unix/unix.h>
      28             : #include <vnet/ip/ip.h>
      29             : #include <vnet/ethernet/ethernet.h>
      30             : #include <vnet/ip/ip4_packet.h>
      31             : #include <vnet/ip/ip6_packet.h>
      32             : #include <vnet/ip/ip_psh_cksum.h>
      33             : #include <vnet/tcp/tcp_packet.h>
      34             : #include <vnet/udp/udp_packet.h>
      35             : 
      36             : #include <af_packet/af_packet.h>
      37             : #include <vnet/devices/virtio/virtio_std.h>
      38             : #include <vnet/devices/netlink.h>
      39             : 
      40             : #define foreach_af_packet_tx_func_error               \
      41             : _(FRAME_NOT_READY, "tx frame not ready")              \
      42             : _(TXRING_EAGAIN,   "tx sendto temporary failure")     \
      43             : _(TXRING_FATAL,    "tx sendto fatal failure")         \
      44             : _(TXRING_OVERRUN,  "tx ring overrun")
      45             : 
      46             : typedef enum
      47             : {
      48             : #define _(f,s) AF_PACKET_TX_ERROR_##f,
      49             :   foreach_af_packet_tx_func_error
      50             : #undef _
      51             :     AF_PACKET_TX_N_ERROR,
      52             : } af_packet_tx_func_error_t;
      53             : 
      54             : static char *af_packet_tx_func_error_strings[] = {
      55             : #define _(n,s) s,
      56             :   foreach_af_packet_tx_func_error
      57             : #undef _
      58             : };
      59             : 
      60             : typedef struct
      61             : {
      62             :   u32 buffer_index;
      63             :   u32 hw_if_index;
      64             :   u16 queue_id;
      65             :   u8 is_v2;
      66             :   union
      67             :   {
      68             :     tpacket2_hdr_t tph2;
      69             :     tpacket3_hdr_t tph3;
      70             :   };
      71             :   vnet_virtio_net_hdr_t vnet_hdr;
      72             :   vlib_buffer_t buffer;
      73             : } af_packet_tx_trace_t;
      74             : 
      75             : #ifndef CLIB_MARCH_VARIANT
      76             : u8 *
      77         504 : format_af_packet_device_name (u8 * s, va_list * args)
      78             : {
      79         504 :   u32 i = va_arg (*args, u32);
      80         504 :   af_packet_main_t *apm = &af_packet_main;
      81         504 :   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, i);
      82             : 
      83         504 :   s = format (s, "host-%s", apif->host_if_name);
      84         504 :   return s;
      85             : }
      86             : #endif /* CLIB_MARCH_VARIANT */
      87             : 
      88             : static u8 *
      89           0 : format_af_packet_device (u8 * s, va_list * args)
      90             : {
      91           0 :   u32 dev_instance = va_arg (*args, u32);
      92           0 :   u32 indent = format_get_indent (s);
      93           0 :   int __clib_unused verbose = va_arg (*args, int);
      94             : 
      95           0 :   af_packet_main_t *apm = &af_packet_main;
      96           0 :   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, dev_instance);
      97           0 :   af_packet_queue_t *rx_queue = 0;
      98           0 :   af_packet_queue_t *tx_queue = 0;
      99             : 
     100           0 :   s = format (s, "Linux PACKET socket interface %s",
     101           0 :               (apif->version == TPACKET_V2) ? "v2" : "v3");
     102           0 :   s = format (s, "\n%UFEATURES:", format_white_space, indent);
     103           0 :   if (apif->is_qdisc_bypass_enabled)
     104           0 :     s = format (s, "\n%Uqdisc-bpass-enabled", format_white_space, indent + 2);
     105           0 :   if (apif->is_cksum_gso_enabled)
     106           0 :     s = format (s, "\n%Ucksum-gso-enabled", format_white_space, indent + 2);
     107           0 :   if (apif->is_fanout_enabled)
     108           0 :     s = format (s, "\n%Ufanout-enabled", format_white_space, indent + 2);
     109             : 
     110           0 :   vec_foreach (rx_queue, apif->rx_queues)
     111             :     {
     112           0 :       u32 rx_block_size = rx_queue->rx_req->req.tp_block_size;
     113           0 :       u32 rx_frame_size = rx_queue->rx_req->req.tp_frame_size;
     114           0 :       u32 rx_frame_nr = rx_queue->rx_req->req.tp_frame_nr;
     115           0 :       u32 rx_block_nr = rx_queue->rx_req->req.tp_block_nr;
     116             : 
     117           0 :       s = format (s, "\n%URX Queue %u:", format_white_space, indent,
     118           0 :                   rx_queue->queue_id);
     119           0 :       s = format (s, "\n%Ublock size:%d nr:%d  frame size:%d nr:%d",
     120             :                   format_white_space, indent + 2, rx_block_size, rx_block_nr,
     121             :                   rx_frame_size, rx_frame_nr);
     122           0 :       if (apif->version == TPACKET_V2)
     123           0 :         s = format (s, " next frame:%d", rx_queue->next_rx_frame);
     124             :       else
     125           0 :         s = format (s, " next block:%d", rx_queue->next_rx_block);
     126           0 :       if (rx_queue->is_rx_pending)
     127             :         {
     128           0 :           s = format (
     129             :             s, "\n%UPending Request: num-rx-pkts:%d next-frame-offset:%d",
     130           0 :             format_white_space, indent + 2, rx_queue->num_rx_pkts,
     131             :             rx_queue->rx_frame_offset);
     132             :         }
     133             :     }
     134             : 
     135           0 :   vec_foreach (tx_queue, apif->tx_queues)
     136             :     {
     137           0 :       clib_spinlock_lock (&tx_queue->lockp);
     138           0 :       u32 tx_block_sz = tx_queue->tx_req->req.tp_block_size;
     139           0 :       u32 tx_frame_sz = tx_queue->tx_req->req.tp_frame_size;
     140           0 :       u32 tx_frame_nr = tx_queue->tx_req->req.tp_frame_nr;
     141           0 :       u32 tx_block_nr = tx_queue->tx_req->req.tp_block_nr;
     142           0 :       int block = 0;
     143           0 :       int n_send_req = 0, n_avail = 0, n_sending = 0, n_tot = 0, n_wrong = 0;
     144           0 :       u8 *tx_block_start = tx_queue->tx_ring[block];
     145           0 :       u32 tx_frame = tx_queue->next_tx_frame;
     146             :       tpacket3_hdr_t *tph3;
     147             :       tpacket2_hdr_t *tph2;
     148             : 
     149           0 :       s = format (s, "\n%UTX Queue %u:", format_white_space, indent,
     150           0 :                   tx_queue->queue_id);
     151           0 :       s = format (s, "\n%Ublock size:%d nr:%d  frame size:%d nr:%d",
     152             :                   format_white_space, indent + 2, tx_block_sz, tx_block_nr,
     153             :                   tx_frame_sz, tx_frame_nr);
     154           0 :       s = format (s, " next frame:%d", tx_queue->next_tx_frame);
     155           0 :       if (apif->version & TPACKET_V3)
     156             :         do
     157             :           {
     158           0 :             tph3 =
     159           0 :               (tpacket3_hdr_t *) (tx_block_start + tx_frame * tx_frame_sz);
     160           0 :             tx_frame = (tx_frame + 1) % tx_frame_nr;
     161           0 :             if (tph3->tp_status == 0)
     162           0 :               n_avail++;
     163           0 :             else if (tph3->tp_status & TP_STATUS_SEND_REQUEST)
     164           0 :               n_send_req++;
     165           0 :             else if (tph3->tp_status & TP_STATUS_SENDING)
     166           0 :               n_sending++;
     167             :             else
     168           0 :               n_wrong++;
     169           0 :             n_tot++;
     170             :           }
     171           0 :         while (tx_frame != tx_queue->next_tx_frame);
     172             :       else
     173             :         do
     174             :           {
     175           0 :             tph2 =
     176           0 :               (tpacket2_hdr_t *) (tx_block_start + tx_frame * tx_frame_sz);
     177           0 :             tx_frame = (tx_frame + 1) % tx_frame_nr;
     178           0 :             if (tph2->tp_status == 0)
     179           0 :               n_avail++;
     180           0 :             else if (tph2->tp_status & TP_STATUS_SEND_REQUEST)
     181           0 :               n_send_req++;
     182           0 :             else if (tph2->tp_status & TP_STATUS_SENDING)
     183           0 :               n_sending++;
     184             :             else
     185           0 :               n_wrong++;
     186           0 :             n_tot++;
     187             :           }
     188           0 :         while (tx_frame != tx_queue->next_tx_frame);
     189             :       s =
     190           0 :         format (s, "\n%Uavailable:%d request:%d sending:%d wrong:%d total:%d",
     191             :                 format_white_space, indent + 2, n_avail, n_send_req, n_sending,
     192             :                 n_wrong, n_tot);
     193           0 :       clib_spinlock_unlock (&tx_queue->lockp);
     194             :     }
     195           0 :   return s;
     196             : }
     197             : 
     198             : static u8 *
     199           0 : format_af_packet_tx_trace (u8 *s, va_list *va)
     200             : {
     201           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     202           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     203           0 :   af_packet_tx_trace_t *t = va_arg (*va, af_packet_tx_trace_t *);
     204           0 :   u32 indent = format_get_indent (s);
     205             : 
     206           0 :   s = format (s, "af_packet: hw_if_index %u tx-queue %u", t->hw_if_index,
     207           0 :               t->queue_id);
     208             : 
     209           0 :   if (t->is_v2)
     210             :     {
     211           0 :       s = format (
     212             :         s,
     213             :         "\n%Utpacket2_hdr:\n%Ustatus 0x%x len %u snaplen %u mac %u net %u"
     214             :         "\n%Usec 0x%x nsec 0x%x vlan %U"
     215             : #ifdef TP_STATUS_VLAN_TPID_VALID
     216             :         " vlan_tpid %u"
     217             : #endif
     218             :         ,
     219             :         format_white_space, indent + 2, format_white_space, indent + 4,
     220           0 :         t->tph2.tp_status, t->tph2.tp_len, t->tph2.tp_snaplen, t->tph2.tp_mac,
     221           0 :         t->tph2.tp_net, format_white_space, indent + 4, t->tph2.tp_sec,
     222           0 :         t->tph2.tp_nsec, format_ethernet_vlan_tci, t->tph2.tp_vlan_tci
     223             : #ifdef TP_STATUS_VLAN_TPID_VALID
     224             :         ,
     225           0 :         t->tph2.tp_vlan_tpid
     226             : #endif
     227             :       );
     228             :     }
     229             :   else
     230             :     {
     231           0 :       s = format (
     232             :         s,
     233             :         "\n%Utpacket3_hdr:\n%Ustatus 0x%x len %u snaplen %u mac %u net %u"
     234             :         "\n%Usec 0x%x nsec 0x%x vlan %U"
     235             : #ifdef TP_STATUS_VLAN_TPID_VALID
     236             :         " vlan_tpid %u"
     237             : #endif
     238             :         ,
     239             :         format_white_space, indent + 2, format_white_space, indent + 4,
     240           0 :         t->tph3.tp_status, t->tph3.tp_len, t->tph3.tp_snaplen, t->tph3.tp_mac,
     241           0 :         t->tph3.tp_net, format_white_space, indent + 4, t->tph3.tp_sec,
     242             :         t->tph3.tp_nsec, format_ethernet_vlan_tci, t->tph3.hv1.tp_vlan_tci
     243             : #ifdef TP_STATUS_VLAN_TPID_VALID
     244             :         ,
     245           0 :         t->tph3.hv1.tp_vlan_tpid
     246             : #endif
     247             :       );
     248             :     }
     249           0 :   s = format (s,
     250             :               "\n%Uvnet-hdr:\n%Uflags 0x%02x gso_type 0x%02x hdr_len %u"
     251             :               "\n%Ugso_size %u csum_start %u csum_offset %u",
     252             :               format_white_space, indent + 2, format_white_space, indent + 4,
     253           0 :               t->vnet_hdr.flags, t->vnet_hdr.gso_type, t->vnet_hdr.hdr_len,
     254           0 :               format_white_space, indent + 4, t->vnet_hdr.gso_size,
     255           0 :               t->vnet_hdr.csum_start, t->vnet_hdr.csum_offset);
     256             : 
     257           0 :   s = format (s, "\n%Ubuffer 0x%x:\n%U%U", format_white_space, indent + 2,
     258             :               t->buffer_index, format_white_space, indent + 4,
     259             :               format_vnet_buffer_no_chain, &t->buffer);
     260           0 :   s = format (s, "\n%U%U", format_white_space, indent + 2,
     261           0 :               format_ethernet_header_with_length, t->buffer.pre_data,
     262             :               sizeof (t->buffer.pre_data));
     263           0 :   return s;
     264             : }
     265             : 
     266             : static void
     267           0 : af_packet_tx_trace (vlib_main_t *vm, vlib_node_runtime_t *node,
     268             :                     vlib_buffer_t *b0, u32 bi, void *tph,
     269             :                     vnet_virtio_net_hdr_t *vnet_hdr, u32 hw_if_index,
     270             :                     u16 queue_id, u8 is_v2)
     271             : {
     272             :   af_packet_tx_trace_t *t;
     273           0 :   t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
     274           0 :   t->hw_if_index = hw_if_index;
     275           0 :   t->queue_id = queue_id;
     276           0 :   t->buffer_index = bi;
     277           0 :   t->is_v2 = is_v2;
     278             : 
     279           0 :   if (is_v2)
     280           0 :     clib_memcpy_fast (&t->tph2, (tpacket2_hdr_t *) tph,
     281             :                       sizeof (tpacket2_hdr_t));
     282             :   else
     283           0 :     clib_memcpy_fast (&t->tph3, (tpacket3_hdr_t *) tph,
     284             :                       sizeof (tpacket3_hdr_t));
     285           0 :   clib_memcpy_fast (&t->vnet_hdr, vnet_hdr, sizeof (*vnet_hdr));
     286           0 :   clib_memcpy_fast (&t->buffer, b0, sizeof (*b0) - sizeof (b0->pre_data));
     287           0 :   clib_memcpy_fast (t->buffer.pre_data, vlib_buffer_get_current (b0),
     288             :                     sizeof (t->buffer.pre_data));
     289           0 : }
     290             : 
     291             : static_always_inline void
     292      697292 : fill_gso_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr)
     293             : {
     294      697292 :   vnet_buffer_oflags_t oflags = vnet_buffer (b0)->oflags;
     295      697292 :   i16 l4_hdr_offset = vnet_buffer (b0)->l4_hdr_offset - b0->current_data;
     296      697292 :   if (b0->flags & VNET_BUFFER_F_IS_IP4)
     297             :     {
     298             :       ip4_header_t *ip4;
     299      374977 :       vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
     300      374977 :       vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size;
     301      374977 :       vnet_hdr->hdr_len = l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz;
     302      374977 :       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
     303      374977 :       vnet_hdr->csum_start = l4_hdr_offset; // 0x22;
     304      374977 :       vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
     305      374977 :       ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
     306      374977 :       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
     307           0 :         ip4->checksum = ip4_header_checksum (ip4);
     308      374977 :       tcp_header_t *tcp =
     309      374977 :         (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     310      374977 :       tcp->checksum = ip4_pseudo_header_cksum (ip4);
     311             :     }
     312      322315 :   else if (b0->flags & VNET_BUFFER_F_IS_IP6)
     313             :     {
     314             :       ip6_header_t *ip6;
     315      322315 :       vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
     316      322315 :       vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size;
     317      322315 :       vnet_hdr->hdr_len = l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz;
     318      322315 :       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
     319      322315 :       vnet_hdr->csum_start = l4_hdr_offset; // 0x36;
     320      322315 :       vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
     321      322315 :       ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
     322      322315 :       tcp_header_t *tcp =
     323      322315 :         (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     324      322315 :       tcp->checksum = ip6_pseudo_header_cksum (ip6);
     325             :     }
     326      697292 : }
     327             : 
     328             : static_always_inline void
     329      623548 : fill_cksum_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr)
     330             : {
     331      623548 :   vnet_buffer_oflags_t oflags = vnet_buffer (b0)->oflags;
     332      623548 :   i16 l4_hdr_offset = vnet_buffer (b0)->l4_hdr_offset - b0->current_data;
     333      623548 :   if (b0->flags & VNET_BUFFER_F_IS_IP4)
     334             :     {
     335             :       ip4_header_t *ip4;
     336      338263 :       ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
     337      338263 :       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
     338           0 :         ip4->checksum = ip4_header_checksum (ip4);
     339      338263 :       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
     340      338263 :       vnet_hdr->csum_start = l4_hdr_offset;
     341      338263 :       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
     342             :         {
     343      338263 :           tcp_header_t *tcp =
     344      338263 :             (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     345      338263 :           tcp->checksum = ip4_pseudo_header_cksum (ip4);
     346      338263 :           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
     347      338263 :           vnet_hdr->hdr_len = l4_hdr_offset + tcp_header_bytes (tcp);
     348             :         }
     349           0 :       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
     350             :         {
     351           0 :           udp_header_t *udp =
     352           0 :             (udp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     353           0 :           udp->checksum = ip4_pseudo_header_cksum (ip4);
     354           0 :           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
     355           0 :           vnet_hdr->hdr_len = l4_hdr_offset + sizeof (udp_header_t);
     356             :         }
     357             :     }
     358      285285 :   else if (b0->flags & VNET_BUFFER_F_IS_IP6)
     359             :     {
     360             :       ip6_header_t *ip6;
     361      285285 :       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
     362      285285 :       vnet_hdr->csum_start = l4_hdr_offset;
     363      285285 :       ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
     364      285285 :       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
     365             :         {
     366      285285 :           tcp_header_t *tcp =
     367      285285 :             (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     368      285285 :           tcp->checksum = ip6_pseudo_header_cksum (ip6);
     369      285285 :           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
     370      285285 :           vnet_hdr->hdr_len = l4_hdr_offset + tcp_header_bytes (tcp);
     371             :         }
     372           0 :       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
     373             :         {
     374           0 :           udp_header_t *udp =
     375           0 :             (udp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset);
     376           0 :           udp->checksum = ip6_pseudo_header_cksum (ip6);
     377           0 :           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
     378           0 :           vnet_hdr->hdr_len = l4_hdr_offset + sizeof (udp_header_t);
     379             :         }
     380             :     }
     381      623548 : }
     382             : 
     383      817322 : VNET_DEVICE_CLASS_TX_FN (af_packet_device_class) (vlib_main_t * vm,
     384             :                                                   vlib_node_runtime_t * node,
     385             :                                                   vlib_frame_t * frame)
     386             : {
     387      815086 :   af_packet_main_t *apm = &af_packet_main;
     388      815086 :   vnet_hw_if_tx_frame_t *tf = vlib_frame_scalar_args (frame);
     389      815086 :   u32 *buffers = vlib_frame_vector_args (frame);
     390      815086 :   u32 n_left = frame->n_vectors;
     391      815086 :   u32 n_sent = 0;
     392      815086 :   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
     393      815086 :   af_packet_if_t *apif =
     394      815086 :     pool_elt_at_index (apm->interfaces, rd->dev_instance);
     395      815086 :   u16 queue_id = tf->queue_id;
     396      815086 :   af_packet_queue_t *tx_queue = vec_elt_at_index (apif->tx_queues, queue_id);
     397      815086 :   u32 block = 0, frame_size = 0, frame_num = 0, tx_frame = 0;
     398      815086 :   u8 *block_start = 0;
     399      815086 :   tpacket3_hdr_t *tph3 = 0;
     400      815086 :   tpacket2_hdr_t *tph2 = 0;
     401      815086 :   u32 frame_not_ready = 0;
     402      815086 :   u8 is_cksum_gso_enabled = (apif->is_cksum_gso_enabled == 1) ? 1 : 0;
     403      815086 :   u32 tpacket_align = 0;
     404      815086 :   u8 is_v2 = (apif->version == TPACKET_V2) ? 1 : 0;
     405             : 
     406      815086 :   if (tf->shared_queue)
     407           0 :     clib_spinlock_lock (&tx_queue->lockp);
     408             : 
     409      815086 :   frame_size = tx_queue->tx_req->req.tp_frame_size;
     410      815086 :   frame_num = tx_queue->tx_req->req.tp_frame_nr;
     411      815086 :   block_start = tx_queue->tx_ring[block];
     412      815086 :   tx_frame = tx_queue->next_tx_frame;
     413      815086 :   if (is_v2)
     414             :     {
     415      271212 :       tpacket_align = TPACKET_ALIGN (sizeof (tpacket2_hdr_t));
     416     6264150 :       while (n_left)
     417             :         {
     418             :           u32 len;
     419     5992940 :           vnet_virtio_net_hdr_t *vnet_hdr = 0;
     420     5992940 :           u32 offset = 0;
     421     5992940 :           vlib_buffer_t *b0 = 0, *b0_first = 0;
     422             :           u32 bi, bi_first;
     423             : 
     424     5992940 :           bi = bi_first = buffers[0];
     425     5992940 :           n_left--;
     426     5992940 :           buffers++;
     427             : 
     428     5992940 :           tph2 = (tpacket2_hdr_t *) (block_start + tx_frame * frame_size);
     429     5992940 :           if (PREDICT_FALSE (tph2->tp_status &
     430             :                              (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)))
     431             :             {
     432           0 :               frame_not_ready++;
     433           0 :               goto nextv2;
     434             :             }
     435             : 
     436     5992940 :           b0_first = b0 = vlib_get_buffer (vm, bi);
     437             : 
     438     5992940 :           if (PREDICT_TRUE (is_cksum_gso_enabled))
     439             :             {
     440     3968290 :               vnet_hdr =
     441     3968290 :                 (vnet_virtio_net_hdr_t *) ((u8 *) tph2 + tpacket_align);
     442             : 
     443     3968290 :               clib_memset_u8 (vnet_hdr, 0, sizeof (vnet_virtio_net_hdr_t));
     444     3968290 :               offset = sizeof (vnet_virtio_net_hdr_t);
     445             : 
     446     3968290 :               if (b0->flags & VNET_BUFFER_F_GSO)
     447      516765 :                 fill_gso_offload (b0, vnet_hdr);
     448     3451530 :               else if (b0->flags & VNET_BUFFER_F_OFFLOAD)
     449      411179 :                 fill_cksum_offload (b0, vnet_hdr);
     450             :             }
     451             : 
     452     5992940 :           len = b0->current_length;
     453     5992940 :           clib_memcpy_fast ((u8 *) tph2 + tpacket_align + offset,
     454     5992940 :                             vlib_buffer_get_current (b0), len);
     455     5992940 :           offset += len;
     456             : 
     457    24344300 :           while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
     458             :             {
     459    18351300 :               b0 = vlib_get_buffer (vm, b0->next_buffer);
     460    18351300 :               len = b0->current_length;
     461    18351300 :               clib_memcpy_fast ((u8 *) tph2 + tpacket_align + offset,
     462    18351300 :                                 vlib_buffer_get_current (b0), len);
     463    18351300 :               offset += len;
     464             :             }
     465             : 
     466     5992940 :           tph2->tp_len = tph2->tp_snaplen = offset;
     467     5992940 :           tph2->tp_status = TP_STATUS_SEND_REQUEST;
     468     5992940 :           n_sent++;
     469             : 
     470     5992940 :           if (PREDICT_FALSE (b0_first->flags & VLIB_BUFFER_IS_TRACED))
     471             :             {
     472           0 :               if (PREDICT_TRUE (is_cksum_gso_enabled))
     473           0 :                 af_packet_tx_trace (vm, node, b0_first, bi_first, tph2,
     474             :                                     vnet_hdr, apif->hw_if_index, queue_id, 1);
     475             :               else
     476             :                 {
     477           0 :                   vnet_virtio_net_hdr_t vnet_hdr2 = {};
     478           0 :                   af_packet_tx_trace (vm, node, b0_first, bi_first, tph2,
     479             :                                       &vnet_hdr2, apif->hw_if_index, queue_id,
     480             :                                       1);
     481             :                 }
     482             :             }
     483     5992940 :           tx_frame = (tx_frame + 1) % frame_num;
     484             : 
     485     5992940 :         nextv2:
     486             :           /* check if we've exhausted the ring */
     487     5992940 :           if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num))
     488           0 :             break;
     489             :         }
     490             :     }
     491             :   else
     492             :     {
     493      543874 :       tpacket_align = TPACKET_ALIGN (sizeof (tpacket3_hdr_t));
     494             : 
     495     9495590 :       while (n_left)
     496             :         {
     497             :           u32 len;
     498     8951710 :           vnet_virtio_net_hdr_t *vnet_hdr = 0;
     499     8951710 :           u32 offset = 0;
     500     8951710 :           vlib_buffer_t *b0 = 0, *b0_first = 0;
     501             :           u32 bi, bi_first;
     502             : 
     503     8951710 :           bi = bi_first = buffers[0];
     504     8951710 :           n_left--;
     505     8951710 :           buffers++;
     506             : 
     507     8951710 :           tph3 = (tpacket3_hdr_t *) (block_start + tx_frame * frame_size);
     508     8951710 :           if (PREDICT_FALSE (tph3->tp_status &
     509             :                              (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)))
     510             :             {
     511           0 :               frame_not_ready++;
     512           0 :               goto nextv3;
     513             :             }
     514             : 
     515     8951710 :           b0_first = b0 = vlib_get_buffer (vm, bi);
     516             : 
     517     8951710 :           if (PREDICT_TRUE (is_cksum_gso_enabled))
     518             :             {
     519     1163250 :               vnet_hdr =
     520     1163250 :                 (vnet_virtio_net_hdr_t *) ((u8 *) tph3 + tpacket_align);
     521             : 
     522     1163250 :               clib_memset_u8 (vnet_hdr, 0, sizeof (vnet_virtio_net_hdr_t));
     523     1163250 :               offset = sizeof (vnet_virtio_net_hdr_t);
     524             : 
     525     1163250 :               if (b0->flags & VNET_BUFFER_F_GSO)
     526      180527 :                 fill_gso_offload (b0, vnet_hdr);
     527      982725 :               else if (b0->flags & VNET_BUFFER_F_OFFLOAD)
     528      212369 :                 fill_cksum_offload (b0, vnet_hdr);
     529             :             }
     530             : 
     531     8951710 :           len = b0->current_length;
     532     8951710 :           clib_memcpy_fast ((u8 *) tph3 + tpacket_align + offset,
     533     8951710 :                             vlib_buffer_get_current (b0), len);
     534     8951710 :           offset += len;
     535             : 
     536    17471800 :           while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
     537             :             {
     538     8520090 :               b0 = vlib_get_buffer (vm, b0->next_buffer);
     539     8520090 :               len = b0->current_length;
     540     8520090 :               clib_memcpy_fast ((u8 *) tph3 + tpacket_align + offset,
     541     8520090 :                                 vlib_buffer_get_current (b0), len);
     542     8520090 :               offset += len;
     543             :             }
     544             : 
     545     8951710 :           tph3->tp_len = tph3->tp_snaplen = offset;
     546     8951710 :           tph3->tp_status = TP_STATUS_SEND_REQUEST;
     547     8951710 :           n_sent++;
     548             : 
     549     8951710 :           if (PREDICT_FALSE (b0_first->flags & VLIB_BUFFER_IS_TRACED))
     550             :             {
     551           0 :               if (PREDICT_TRUE (is_cksum_gso_enabled))
     552           0 :                 af_packet_tx_trace (vm, node, b0_first, bi_first, tph3,
     553             :                                     vnet_hdr, apif->hw_if_index, queue_id, 0);
     554             :               else
     555             :                 {
     556           0 :                   vnet_virtio_net_hdr_t vnet_hdr2 = {};
     557           0 :                   af_packet_tx_trace (vm, node, b0_first, bi_first, tph3,
     558             :                                       &vnet_hdr2, apif->hw_if_index, queue_id,
     559             :                                       0);
     560             :                 }
     561             :             }
     562     8951710 :           tx_frame = (tx_frame + 1) % frame_num;
     563             : 
     564     8951710 :         nextv3:
     565             :           /* check if we've exhausted the ring */
     566     8951710 :           if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num))
     567           0 :             break;
     568             :         }
     569             :     }
     570      815086 :   CLIB_MEMORY_BARRIER ();
     571             : 
     572      815086 :   if (PREDICT_TRUE (n_sent || tx_queue->is_tx_pending))
     573             :     {
     574      815086 :       tx_queue->next_tx_frame = tx_frame;
     575      815086 :       tx_queue->is_tx_pending = 0;
     576             : 
     577      815086 :       if (PREDICT_FALSE (
     578             :             sendto (tx_queue->fd, NULL, 0, MSG_DONTWAIT, NULL, 0) == -1))
     579             :         {
     580             :           /* Uh-oh, drop & move on, but count whether it was fatal or not.
     581             :            * Note that we have no reliable way to properly determine the
     582             :            * disposition of the packets we just enqueued for delivery.
     583             :            */
     584             :           uword counter;
     585             : 
     586           0 :           if (unix_error_is_fatal (errno))
     587             :             {
     588           0 :               counter = AF_PACKET_TX_ERROR_TXRING_FATAL;
     589             :             }
     590             :           else
     591             :             {
     592           0 :               counter = AF_PACKET_TX_ERROR_TXRING_EAGAIN;
     593             :               /* non-fatal error: kick again next time
     594             :                * note that you could still end up in a deadlock: if you do not
     595             :                * try to send new packets (ie reschedule this tx node), eg.
     596             :                * because your peer is waiting for the unsent packets to reply
     597             :                * to you but your waiting for its reply etc., you are not going
     598             :                * to kick again, and everybody is waiting for the other to talk
     599             :                * 1st... */
     600           0 :               tx_queue->is_tx_pending = 1;
     601             :             }
     602             : 
     603           0 :           vlib_error_count (vm, node->node_index, counter, 1);
     604             :         }
     605             :     }
     606             : 
     607      815086 :   if (tf->shared_queue)
     608           0 :     clib_spinlock_unlock (&tx_queue->lockp);
     609             : 
     610      815086 :   if (PREDICT_FALSE (frame_not_ready))
     611           0 :     vlib_error_count (vm, node->node_index,
     612             :                       AF_PACKET_TX_ERROR_FRAME_NOT_READY, frame_not_ready);
     613             : 
     614      815086 :   if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num))
     615           0 :     vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_TXRING_OVERRUN,
     616             :                       n_left);
     617             : 
     618      815086 :   vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
     619      815086 :   return frame->n_vectors;
     620             : }
     621             : 
     622             : static void
     623           0 : af_packet_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
     624             :                                    u32 node_index)
     625             : {
     626           0 :   af_packet_main_t *apm = &af_packet_main;
     627           0 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
     628           0 :   af_packet_if_t *apif =
     629           0 :     pool_elt_at_index (apm->interfaces, hw->dev_instance);
     630             : 
     631             :   /* Shut off redirection */
     632           0 :   if (node_index == ~0)
     633             :     {
     634           0 :       apif->per_interface_next_index = node_index;
     635           0 :       return;
     636             :     }
     637             : 
     638           0 :   apif->per_interface_next_index =
     639           0 :     vlib_node_add_next (vlib_get_main (), af_packet_input_node.index,
     640             :                         node_index);
     641             : }
     642             : 
     643             : static void
     644           0 : af_packet_clear_hw_interface_counters (u32 instance)
     645             : {
     646             :   /* Nothing for now */
     647           0 : }
     648             : 
     649             : static clib_error_t *
     650         504 : af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     651             :                                    u32 flags)
     652             : {
     653         504 :   af_packet_main_t *apm = &af_packet_main;
     654         504 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
     655         504 :   af_packet_if_t *apif =
     656         504 :     pool_elt_at_index (apm->interfaces, hw->dev_instance);
     657             :   u32 hw_flags;
     658             : 
     659         504 :   if (apif->host_if_index < 0)
     660           0 :     return 0; /* no error */
     661             : 
     662         504 :   apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
     663             : 
     664         504 :   if (apif->is_admin_up)
     665             :     {
     666         252 :       hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP;
     667         252 :       vnet_netlink_set_link_state (apif->host_if_index, 1);
     668             :     }
     669             :   else
     670             :     {
     671         252 :       hw_flags = 0;
     672         252 :       vnet_netlink_set_link_state (apif->host_if_index, 0);
     673             :     }
     674             : 
     675         504 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     676             : 
     677         504 :   return 0;                     /* no error */
     678             : }
     679             : 
     680             : static clib_error_t *
     681           0 : af_packet_subif_add_del_function (vnet_main_t * vnm,
     682             :                                   u32 hw_if_index,
     683             :                                   struct vnet_sw_interface_t *st, int is_add)
     684             : {
     685             :   /* Nothing for now */
     686           0 :   return 0;
     687             : }
     688             : 
     689           0 : static clib_error_t *af_packet_set_mac_address_function
     690             :   (struct vnet_hw_interface_t *hi, const u8 * old_address, const u8 * address)
     691             : {
     692           0 :   af_packet_main_t *apm = &af_packet_main;
     693           0 :   af_packet_if_t *apif =
     694           0 :     pool_elt_at_index (apm->interfaces, hi->dev_instance);
     695             :   int rv, fd;
     696             :   struct ifreq ifr;
     697             : 
     698           0 :   if (apif->mode == AF_PACKET_IF_MODE_IP)
     699             :     {
     700           0 :       vlib_log_warn (apm->log_class, "af_packet_%s interface is in IP mode",
     701             :                      apif->host_if_name);
     702           0 :       return clib_error_return (0,
     703             :                                 " MAC update failed, interface is in IP mode");
     704             :     }
     705             : 
     706           0 :   fd = socket (AF_UNIX, SOCK_DGRAM, 0);
     707           0 :   if (0 > fd)
     708             :     {
     709           0 :       vlib_log_warn (apm->log_class, "af_packet_%s could not open socket",
     710             :                      apif->host_if_name);
     711           0 :       return 0;
     712             :     }
     713             : 
     714             :   /* if interface is a bridge ignore */
     715           0 :   if (apif->host_if_index < 0)
     716           0 :     goto error;                 /* no error */
     717             : 
     718             :   /* use host_if_index in case host name has changed */
     719           0 :   ifr.ifr_ifindex = apif->host_if_index;
     720           0 :   if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0)
     721             :     {
     722           0 :       vlib_log_warn
     723             :         (apm->log_class,
     724             :          "af_packet_%s ioctl could not retrieve eth name, error: %d",
     725             :          apif->host_if_name, rv);
     726           0 :       goto error;
     727             :     }
     728             : 
     729           0 :   clib_memcpy (ifr.ifr_hwaddr.sa_data, address, 6);
     730           0 :   ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
     731             : 
     732           0 :   if ((rv = ioctl (fd, SIOCSIFHWADDR, &ifr)) < 0)
     733             :     {
     734           0 :       vlib_log_warn (apm->log_class,
     735             :                      "af_packet_%s ioctl could not set mac, error: %d",
     736             :                      apif->host_if_name, rv);
     737           0 :       goto error;
     738             :     }
     739             : 
     740           0 : error:
     741             : 
     742           0 :   if (0 <= fd)
     743           0 :     close (fd);
     744             : 
     745           0 :   return 0;                     /* no error */
     746             : }
     747             : 
     748             : static clib_error_t *
     749         252 : af_packet_interface_rx_mode_change (vnet_main_t *vnm, u32 hw_if_index, u32 qid,
     750             :                                     vnet_hw_if_rx_mode mode)
     751             : {
     752         252 :   af_packet_main_t *apm = &af_packet_main;
     753         252 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
     754             :   af_packet_if_t *apif;
     755             : 
     756         252 :   apif = vec_elt_at_index (apm->interfaces, hw->dev_instance);
     757             : 
     758         252 :   if (mode == VNET_HW_IF_RX_MODE_ADAPTIVE)
     759             :     {
     760           0 :       vlib_log_err (apm->log_class,
     761             :                     "af_packet_%s adaptive mode is not supported",
     762             :                     apif->host_if_name);
     763           0 :       return clib_error_return (
     764             :         0, "af_packet_%s adaptive mode is not supported", apif->host_if_name);
     765             :     }
     766             : 
     767         252 :   af_packet_queue_t *rx_queue = vec_elt_at_index (apif->rx_queues, qid);
     768             : 
     769         252 :   if (rx_queue->mode != mode)
     770             :     {
     771         252 :       rx_queue->mode = mode;
     772             : 
     773         252 :       if (mode == VNET_HW_IF_RX_MODE_POLLING)
     774           0 :         apm->polling_count++;
     775         252 :       else if (mode == VNET_HW_IF_RX_MODE_INTERRUPT && apm->polling_count > 0)
     776           0 :         apm->polling_count--;
     777             :     }
     778             : 
     779         252 :   return 0;
     780             : }
     781             : 
     782       10639 : VNET_DEVICE_CLASS (af_packet_device_class) = {
     783             :   .name = "af-packet",
     784             :   .format_device_name = format_af_packet_device_name,
     785             :   .format_device = format_af_packet_device,
     786             :   .format_tx_trace = format_af_packet_tx_trace,
     787             :   .tx_function_n_errors = AF_PACKET_TX_N_ERROR,
     788             :   .tx_function_error_strings = af_packet_tx_func_error_strings,
     789             :   .rx_redirect_to_node = af_packet_set_interface_next_node,
     790             :   .clear_counters = af_packet_clear_hw_interface_counters,
     791             :   .admin_up_down_function = af_packet_interface_admin_up_down,
     792             :   .subif_add_del_function = af_packet_subif_add_del_function,
     793             :   .mac_addr_change_function = af_packet_set_mac_address_function,
     794             :   .rx_mode_change_function = af_packet_interface_rx_mode_change,
     795             : };
     796             : 
     797             : /*
     798             :  * fd.io coding-style-patch-verification: ON
     799             :  *
     800             :  * Local Variables:
     801             :  * eval: (c-set-style "gnu")
     802             :  * End:
     803             :  */

Generated by: LCOV version 1.14