f7f006ebd7fdbea478af986350fce1618ac791d0
[vpp.git] / src / vnet / devices / af_packet / device.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_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 <vnet/devices/af_packet/af_packet.h>
37 #include <vnet/devices/virtio/virtio_std.h>
38
39 #define foreach_af_packet_tx_func_error               \
40 _(FRAME_NOT_READY, "tx frame not ready")              \
41 _(TXRING_EAGAIN,   "tx sendto temporary failure")     \
42 _(TXRING_FATAL,    "tx sendto fatal failure")         \
43 _(TXRING_OVERRUN,  "tx ring overrun")
44
45 typedef enum
46 {
47 #define _(f,s) AF_PACKET_TX_ERROR_##f,
48   foreach_af_packet_tx_func_error
49 #undef _
50     AF_PACKET_TX_N_ERROR,
51 } af_packet_tx_func_error_t;
52
53 static char *af_packet_tx_func_error_strings[] = {
54 #define _(n,s) s,
55   foreach_af_packet_tx_func_error
56 #undef _
57 };
58
59 typedef struct
60 {
61   u32 buffer_index;
62   u32 hw_if_index;
63   tpacket3_hdr_t tph;
64   vnet_virtio_net_hdr_t vnet_hdr;
65   vlib_buffer_t buffer;
66 } af_packet_tx_trace_t;
67
68 #ifndef CLIB_MARCH_VARIANT
69 u8 *
70 format_af_packet_device_name (u8 * s, va_list * args)
71 {
72   u32 i = va_arg (*args, u32);
73   af_packet_main_t *apm = &af_packet_main;
74   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, i);
75
76   s = format (s, "host-%s", apif->host_if_name);
77   return s;
78 }
79 #endif /* CLIB_MARCH_VARIANT */
80
81 static u8 *
82 format_af_packet_device (u8 * s, va_list * args)
83 {
84   u32 dev_instance = va_arg (*args, u32);
85   u32 indent = format_get_indent (s);
86   int __clib_unused verbose = va_arg (*args, int);
87
88   af_packet_main_t *apm = &af_packet_main;
89   af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, dev_instance);
90   clib_spinlock_lock_if_init (&apif->lockp);
91   u32 tx_block_sz = apif->tx_req->tp_block_size;
92   u32 tx_frame_sz = apif->tx_req->tp_frame_size;
93   u32 tx_frame_nr = apif->tx_req->tp_frame_nr;
94   u32 tx_block_nr = apif->tx_req->tp_block_nr;
95   u32 rx_block_size = apif->rx_req->tp_block_size;
96   u32 rx_frame_size = apif->rx_req->tp_frame_size;
97   u32 rx_frame_nr = apif->rx_req->tp_frame_nr;
98   u32 rx_block_nr = apif->rx_req->tp_block_nr;
99   int block = 0;
100   u8 *tx_block_start = apif->tx_ring[block];
101   u32 tx_frame = apif->next_tx_frame;
102   tpacket3_hdr_t *tph;
103
104   s = format (s, "Linux PACKET socket interface\n");
105   s = format (s, "%UTX block size:%d nr:%d  TX frame size:%d nr:%d\n",
106               format_white_space, indent, tx_block_sz, tx_block_nr,
107               tx_frame_sz, tx_frame_nr);
108   s = format (s, "%URX block size:%d nr:%d  RX frame size:%d nr:%d\n",
109               format_white_space, indent, rx_block_size, rx_block_nr,
110               rx_frame_size, rx_frame_nr);
111   s = format (s, "%Unext frame:%d\n", format_white_space, indent,
112               apif->next_tx_frame);
113
114   int n_send_req = 0, n_avail = 0, n_sending = 0, n_tot = 0, n_wrong = 0;
115   do
116     {
117       tph = (tpacket3_hdr_t *) (tx_block_start + tx_frame * tx_frame_sz);
118       tx_frame = (tx_frame + 1) % tx_frame_nr;
119       if (tph->tp_status == 0)
120         n_avail++;
121       else if (tph->tp_status & TP_STATUS_SEND_REQUEST)
122         n_send_req++;
123       else if (tph->tp_status & TP_STATUS_SENDING)
124         n_sending++;
125       else
126         n_wrong++;
127       n_tot++;
128     }
129   while (tx_frame != apif->next_tx_frame);
130   s = format (s, "%Uavailable:%d request:%d sending:%d wrong:%d total:%d\n",
131               format_white_space, indent, n_avail, n_send_req, n_sending,
132               n_wrong, n_tot);
133
134   clib_spinlock_unlock_if_init (&apif->lockp);
135   return s;
136 }
137
138 static u8 *
139 format_af_packet_tx_trace (u8 *s, va_list *va)
140 {
141   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
142   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
143   af_packet_tx_trace_t *t = va_arg (*va, af_packet_tx_trace_t *);
144   u32 indent = format_get_indent (s);
145
146   s = format (s, "af_packet: hw_if_index %u", t->hw_if_index);
147
148   s =
149     format (s,
150             "\n%Utpacket3_hdr:\n%Ustatus 0x%x len %u snaplen %u mac %u net %u"
151             "\n%Usec 0x%x nsec 0x%x vlan %U"
152 #ifdef TP_STATUS_VLAN_TPID_VALID
153             " vlan_tpid %u"
154 #endif
155             ,
156             format_white_space, indent + 2, format_white_space, indent + 4,
157             t->tph.tp_status, t->tph.tp_len, t->tph.tp_snaplen, t->tph.tp_mac,
158             t->tph.tp_net, format_white_space, indent + 4, t->tph.tp_sec,
159             t->tph.tp_nsec, format_ethernet_vlan_tci, t->tph.hv1.tp_vlan_tci
160 #ifdef TP_STATUS_VLAN_TPID_VALID
161             ,
162             t->tph.hv1.tp_vlan_tpid
163 #endif
164     );
165
166   s = format (s,
167               "\n%Uvnet-hdr:\n%Uflags 0x%02x gso_type 0x%02x hdr_len %u"
168               "\n%Ugso_size %u csum_start %u csum_offset %u",
169               format_white_space, indent + 2, format_white_space, indent + 4,
170               t->vnet_hdr.flags, t->vnet_hdr.gso_type, t->vnet_hdr.hdr_len,
171               format_white_space, indent + 4, t->vnet_hdr.gso_size,
172               t->vnet_hdr.csum_start, t->vnet_hdr.csum_offset);
173
174   s = format (s, "\n%Ubuffer 0x%x:\n%U%U", format_white_space, indent + 2,
175               t->buffer_index, format_white_space, indent + 4,
176               format_vnet_buffer_no_chain, &t->buffer);
177   s = format (s, "\n%U%U", format_white_space, indent + 2,
178               format_ethernet_header_with_length, t->buffer.pre_data,
179               sizeof (t->buffer.pre_data));
180   return s;
181 }
182
183 static void
184 af_packet_tx_trace (vlib_main_t *vm, vlib_node_runtime_t *node,
185                     vlib_buffer_t *b0, u32 bi, tpacket3_hdr_t *tph,
186                     vnet_virtio_net_hdr_t *vnet_hdr, u32 hw_if_index)
187 {
188   af_packet_tx_trace_t *t;
189   t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
190   t->hw_if_index = hw_if_index;
191   t->buffer_index = bi;
192
193   clib_memcpy_fast (&t->tph, tph, sizeof (*tph));
194   clib_memcpy_fast (&t->vnet_hdr, vnet_hdr, sizeof (*vnet_hdr));
195   clib_memcpy_fast (&t->buffer, b0, sizeof (*b0) - sizeof (b0->pre_data));
196   clib_memcpy_fast (t->buffer.pre_data, vlib_buffer_get_current (b0),
197                     sizeof (t->buffer.pre_data));
198 }
199
200 static_always_inline void
201 fill_gso_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr)
202 {
203   vnet_buffer_oflags_t oflags = vnet_buffer (b0)->oflags;
204   if (b0->flags & VNET_BUFFER_F_IS_IP4)
205     {
206       ip4_header_t *ip4;
207       vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
208       vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size;
209       vnet_hdr->hdr_len =
210         vnet_buffer (b0)->l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz;
211       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
212       vnet_hdr->csum_start = vnet_buffer (b0)->l4_hdr_offset; // 0x22;
213       vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
214       ip4 = (ip4_header_t *) (vlib_buffer_get_current (b0) +
215                               vnet_buffer (b0)->l3_hdr_offset);
216       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
217         ip4->checksum = ip4_header_checksum (ip4);
218     }
219   else if (b0->flags & VNET_BUFFER_F_IS_IP6)
220     {
221       vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
222       vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size;
223       vnet_hdr->hdr_len =
224         vnet_buffer (b0)->l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz;
225       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
226       vnet_hdr->csum_start = vnet_buffer (b0)->l4_hdr_offset; // 0x36;
227       vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
228     }
229 }
230
231 static_always_inline void
232 fill_cksum_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr)
233 {
234   vnet_buffer_oflags_t oflags = vnet_buffer (b0)->oflags;
235   if (b0->flags & VNET_BUFFER_F_IS_IP4)
236     {
237       ip4_header_t *ip4;
238       ip4 = (ip4_header_t *) (vlib_buffer_get_current (b0) +
239                               vnet_buffer (b0)->l3_hdr_offset);
240       if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
241         ip4->checksum = ip4_header_checksum (ip4);
242       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
243       vnet_hdr->csum_start = 0x22;
244       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
245         {
246           tcp_header_t *tcp =
247             (tcp_header_t *) (vlib_buffer_get_current (b0) +
248                               vnet_buffer (b0)->l4_hdr_offset);
249           tcp->checksum = ip4_pseudo_header_cksum (ip4);
250           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
251         }
252       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
253         {
254           udp_header_t *udp =
255             (udp_header_t *) (vlib_buffer_get_current (b0) +
256                               vnet_buffer (b0)->l4_hdr_offset);
257           udp->checksum = ip4_pseudo_header_cksum (ip4);
258           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
259         }
260     }
261   else if (b0->flags & VNET_BUFFER_F_IS_IP6)
262     {
263       ip6_header_t *ip6;
264       vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
265       vnet_hdr->csum_start = 0x36;
266       ip6 = (ip6_header_t *) (vlib_buffer_get_current (b0) +
267                               vnet_buffer (b0)->l3_hdr_offset);
268       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
269         {
270           tcp_header_t *tcp =
271             (tcp_header_t *) (vlib_buffer_get_current (b0) +
272                               vnet_buffer (b0)->l4_hdr_offset);
273           tcp->checksum = ip6_pseudo_header_cksum (ip6);
274           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
275         }
276       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
277         {
278           udp_header_t *udp =
279             (udp_header_t *) (vlib_buffer_get_current (b0) +
280                               vnet_buffer (b0)->l4_hdr_offset);
281           udp->checksum = ip6_pseudo_header_cksum (ip6);
282           vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
283         }
284     }
285 }
286
287 VNET_DEVICE_CLASS_TX_FN (af_packet_device_class) (vlib_main_t * vm,
288                                                   vlib_node_runtime_t * node,
289                                                   vlib_frame_t * frame)
290 {
291   af_packet_main_t *apm = &af_packet_main;
292   u32 *buffers = vlib_frame_vector_args (frame);
293   u32 n_left = frame->n_vectors;
294   u32 n_sent = 0;
295   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
296   af_packet_if_t *apif =
297     pool_elt_at_index (apm->interfaces, rd->dev_instance);
298   clib_spinlock_lock_if_init (&apif->lockp);
299   u32 block = 0;
300   u32 frame_size = apif->tx_req->tp_frame_size;
301   u32 frame_num = apif->tx_req->tp_frame_nr;
302   u8 *block_start = apif->tx_ring[block];
303   u32 tx_frame = apif->next_tx_frame;
304   tpacket3_hdr_t *tph;
305   u32 frame_not_ready = 0;
306   u8 is_cksum_gso_enabled = (apif->is_cksum_gso_enabled == 1) ? 1 : 0;
307
308   while (n_left)
309     {
310       u32 len;
311       vnet_virtio_net_hdr_t *vnet_hdr = 0;
312       u32 offset = 0;
313       vlib_buffer_t *b0 = 0, *b0_first = 0;
314       u32 bi, bi_first;
315
316       bi = bi_first = buffers[0];
317       n_left--;
318       buffers++;
319
320       tph = (tpacket3_hdr_t *) (block_start + tx_frame * frame_size);
321       if (PREDICT_FALSE (tph->tp_status &
322                          (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)))
323         {
324           frame_not_ready++;
325           goto next;
326         }
327
328       b0_first = b0 = vlib_get_buffer (vm, bi);
329
330       if (PREDICT_TRUE (is_cksum_gso_enabled))
331         {
332           vnet_hdr =
333             (vnet_virtio_net_hdr_t *) ((u8 *) tph + TPACKET_ALIGN (sizeof (
334                                                       tpacket3_hdr_t)));
335
336           clib_memset_u8 (vnet_hdr, 0, sizeof (vnet_virtio_net_hdr_t));
337           offset = sizeof (vnet_virtio_net_hdr_t);
338
339           if (b0->flags & VNET_BUFFER_F_GSO)
340             fill_gso_offload (b0, vnet_hdr);
341           else if (b0->flags & VNET_BUFFER_F_OFFLOAD)
342             fill_cksum_offload (b0, vnet_hdr);
343         }
344
345       len = b0->current_length;
346       clib_memcpy_fast ((u8 *) tph + TPACKET_ALIGN (sizeof (tpacket3_hdr_t)) +
347                           offset,
348                         vlib_buffer_get_current (b0), len);
349       offset += len;
350
351       while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
352         {
353           b0 = vlib_get_buffer (vm, b0->next_buffer);
354           len = b0->current_length;
355           clib_memcpy_fast ((u8 *) tph +
356                               TPACKET_ALIGN (sizeof (tpacket3_hdr_t)) + offset,
357                             vlib_buffer_get_current (b0), len);
358           offset += len;
359         }
360
361       tph->tp_len = tph->tp_snaplen = offset;
362       tph->tp_status = TP_STATUS_SEND_REQUEST;
363       n_sent++;
364
365       if (PREDICT_FALSE (b0_first->flags & VLIB_BUFFER_IS_TRACED))
366         {
367           if (PREDICT_TRUE (is_cksum_gso_enabled))
368             af_packet_tx_trace (vm, node, b0_first, bi_first, tph, vnet_hdr,
369                                 apif->hw_if_index);
370           else
371             {
372               vnet_virtio_net_hdr_t vnet_hdr2 = {};
373               af_packet_tx_trace (vm, node, b0_first, bi_first, tph,
374                                   &vnet_hdr2, apif->hw_if_index);
375             }
376         }
377       tx_frame = (tx_frame + 1) % frame_num;
378
379     next:
380       /* check if we've exhausted the ring */
381       if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num))
382         break;
383     }
384
385   CLIB_MEMORY_BARRIER ();
386
387   if (PREDICT_TRUE (n_sent))
388     {
389       apif->next_tx_frame = tx_frame;
390
391       if (PREDICT_FALSE (sendto (apif->fd, NULL, 0, MSG_DONTWAIT, NULL, 0) ==
392                          -1))
393         {
394           /* Uh-oh, drop & move on, but count whether it was fatal or not.
395            * Note that we have no reliable way to properly determine the
396            * disposition of the packets we just enqueued for delivery.
397            */
398           vlib_error_count (vm, node->node_index,
399                             unix_error_is_fatal (errno) ?
400                               AF_PACKET_TX_ERROR_TXRING_FATAL :
401                               AF_PACKET_TX_ERROR_TXRING_EAGAIN,
402                             n_sent);
403         }
404     }
405
406   clib_spinlock_unlock_if_init (&apif->lockp);
407
408   if (PREDICT_FALSE (frame_not_ready))
409     vlib_error_count (vm, node->node_index,
410                       AF_PACKET_TX_ERROR_FRAME_NOT_READY, frame_not_ready);
411
412   if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num))
413     vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_TXRING_OVERRUN,
414                       n_left);
415
416   vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
417   return frame->n_vectors;
418 }
419
420 static void
421 af_packet_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
422                                    u32 node_index)
423 {
424   af_packet_main_t *apm = &af_packet_main;
425   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
426   af_packet_if_t *apif =
427     pool_elt_at_index (apm->interfaces, hw->dev_instance);
428
429   /* Shut off redirection */
430   if (node_index == ~0)
431     {
432       apif->per_interface_next_index = node_index;
433       return;
434     }
435
436   apif->per_interface_next_index =
437     vlib_node_add_next (vlib_get_main (), af_packet_input_node.index,
438                         node_index);
439 }
440
441 static void
442 af_packet_clear_hw_interface_counters (u32 instance)
443 {
444   /* Nothing for now */
445 }
446
447 static clib_error_t *
448 af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
449                                    u32 flags)
450 {
451   af_packet_main_t *apm = &af_packet_main;
452   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
453   af_packet_if_t *apif =
454     pool_elt_at_index (apm->interfaces, hw->dev_instance);
455   u32 hw_flags;
456   int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0);
457   struct ifreq ifr;
458
459   if (0 > fd)
460     {
461       vlib_log_warn (apm->log_class, "af_packet_%s could not open socket",
462                      apif->host_if_name);
463       return 0;
464     }
465
466   /* if interface is a bridge ignore */
467   if (apif->host_if_index < 0)
468     goto error;                 /* no error */
469
470   /* use host_if_index in case host name has changed */
471   ifr.ifr_ifindex = apif->host_if_index;
472   if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0)
473     {
474       vlib_log_warn (apm->log_class,
475                      "af_packet_%s ioctl could not retrieve eth name",
476                      apif->host_if_name);
477       goto error;
478     }
479
480   apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
481
482   if ((rv = ioctl (fd, SIOCGIFFLAGS, &ifr)) < 0)
483     {
484       vlib_log_warn (apm->log_class, "af_packet_%s error: %d",
485                      apif->is_admin_up ? "up" : "down", rv);
486       goto error;
487     }
488
489   if (apif->is_admin_up)
490     {
491       hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP;
492       ifr.ifr_flags |= IFF_UP;
493     }
494   else
495     {
496       hw_flags = 0;
497       ifr.ifr_flags &= ~IFF_UP;
498     }
499
500   if ((rv = ioctl (fd, SIOCSIFFLAGS, &ifr)) < 0)
501     {
502       vlib_log_warn (apm->log_class, "af_packet_%s error: %d",
503                      apif->is_admin_up ? "up" : "down", rv);
504       goto error;
505     }
506
507   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
508
509 error:
510   if (0 <= fd)
511     close (fd);
512
513   return 0;                     /* no error */
514 }
515
516 static clib_error_t *
517 af_packet_subif_add_del_function (vnet_main_t * vnm,
518                                   u32 hw_if_index,
519                                   struct vnet_sw_interface_t *st, int is_add)
520 {
521   /* Nothing for now */
522   return 0;
523 }
524
525 static clib_error_t *af_packet_set_mac_address_function
526   (struct vnet_hw_interface_t *hi, const u8 * old_address, const u8 * address)
527 {
528   af_packet_main_t *apm = &af_packet_main;
529   af_packet_if_t *apif =
530     pool_elt_at_index (apm->interfaces, hi->dev_instance);
531   int rv, fd;
532   struct ifreq ifr;
533
534   if (apif->mode == AF_PACKET_IF_MODE_IP)
535     {
536       vlib_log_warn (apm->log_class, "af_packet_%s interface is in IP mode",
537                      apif->host_if_name);
538       return clib_error_return (0,
539                                 " MAC update failed, interface is in IP mode");
540     }
541
542   fd = socket (AF_UNIX, SOCK_DGRAM, 0);
543   if (0 > fd)
544     {
545       vlib_log_warn (apm->log_class, "af_packet_%s could not open socket",
546                      apif->host_if_name);
547       return 0;
548     }
549
550   /* if interface is a bridge ignore */
551   if (apif->host_if_index < 0)
552     goto error;                 /* no error */
553
554   /* use host_if_index in case host name has changed */
555   ifr.ifr_ifindex = apif->host_if_index;
556   if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0)
557     {
558       vlib_log_warn
559         (apm->log_class,
560          "af_packet_%s ioctl could not retrieve eth name, error: %d",
561          apif->host_if_name, rv);
562       goto error;
563     }
564
565   clib_memcpy (ifr.ifr_hwaddr.sa_data, address, 6);
566   ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
567
568   if ((rv = ioctl (fd, SIOCSIFHWADDR, &ifr)) < 0)
569     {
570       vlib_log_warn (apm->log_class,
571                      "af_packet_%s ioctl could not set mac, error: %d",
572                      apif->host_if_name, rv);
573       goto error;
574     }
575
576 error:
577
578   if (0 <= fd)
579     close (fd);
580
581   return 0;                     /* no error */
582 }
583
584 VNET_DEVICE_CLASS (af_packet_device_class) = {
585   .name = "af-packet",
586   .format_device_name = format_af_packet_device_name,
587   .format_device = format_af_packet_device,
588   .format_tx_trace = format_af_packet_tx_trace,
589   .tx_function_n_errors = AF_PACKET_TX_N_ERROR,
590   .tx_function_error_strings = af_packet_tx_func_error_strings,
591   .rx_redirect_to_node = af_packet_set_interface_next_node,
592   .clear_counters = af_packet_clear_hw_interface_counters,
593   .admin_up_down_function = af_packet_interface_admin_up_down,
594   .subif_add_del_function = af_packet_subif_add_del_function,
595   .mac_addr_change_function = af_packet_set_mac_address_function,
596 };
597
598 /*
599  * fd.io coding-style-patch-verification: ON
600  *
601  * Local Variables:
602  * eval: (c-set-style "gnu")
603  * End:
604  */