Parcourir la source

[intel] Strip spurious VLAN tags received by virtual function NICs

The physical function may be configured to transparently insert a VLAN
tag into all transmitted packets.  Unfortunately, it does not
equivalently strip this same VLAN tag from all received packets.  This
behaviour may be observed in some Amazon EC2 instances with Enhanced
Networking enabled: transmissions work as expected but all packets
received by iPXE appear to have a spurious VLAN tag.

We can configure the receive queue to strip VLAN tags via the
RXDCTL.VME bit.  We need to find out from the PF driver whether or not
we should do so.

There exists a "get queue configuration" mailbox message which
contains a field labelled IXGBE_VF_TRANS_VLAN in the Linux driver.

A comment in the Linux PF driver describes this field as "notify VF of
need for VLAN tag stripping, and correct queue".  It will be filled
with a non-zero value if the PF is enforcing the use of a single VLAN
tag.  It will also be filled with a non-zero value if the PF is using
multiple traffic classes.

The Linux VF driver seems to treat this field as being simply the
number of traffic classes, and gives it no VLAN-related
interpretation.  The Linux VF driver instead handles the VLAN tag
stripping by simply assuming that any unrecognised VLAN tag ought to
be silently dropped.

We choose to strip and ignore the VLAN tag if the IXGBE_VF_TRANS_VLAN
field has a non-zero value.

Reported-by: Leonid Vasetsky <leonidv@velostrata.com>
Tested-by: Leonid Vasetsky <leonidv@velostrata.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown il y a 8 ans
Parent
révision
db3443608f
4 fichiers modifiés avec 144 ajouts et 0 suppressions
  1. 41
    0
      src/drivers/net/intelvf.c
  2. 43
    0
      src/drivers/net/intelvf.h
  3. 3
    0
      src/drivers/net/intelx.h
  4. 57
    0
      src/drivers/net/intelxvf.c

+ 41
- 0
src/drivers/net/intelvf.c Voir le fichier

@@ -338,3 +338,44 @@ int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
338 338
 
339 339
 	return 0;
340 340
 }
341
+
342
+/**
343
+ * Get queue configuration
344
+ *
345
+ * @v intel		Intel device
346
+ * @v vlan_thing	VLAN hand-waving thing to fill in
347
+ * @ret rc		Return status code
348
+ */
349
+int intelvf_mbox_queues ( struct intel_nic *intel, int *vlan_thing ) {
350
+	union intelvf_msg msg;
351
+	int rc;
352
+
353
+	/* Send queue configuration message */
354
+	memset ( &msg, 0, sizeof ( msg ) );
355
+	msg.hdr = INTELVF_MSG_TYPE_GET_QUEUES;
356
+	if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
357
+		DBGC ( intel, "INTEL %p get queue configuration failed: %s\n",
358
+		       intel, strerror ( rc ) );
359
+		return rc;
360
+	}
361
+
362
+	/* Check response */
363
+	if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) !=INTELVF_MSG_TYPE_GET_QUEUES){
364
+		DBGC ( intel, "INTEL %p get queue configuration unexpected "
365
+		       "response:\n", intel );
366
+		DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
367
+		return -EPROTO;
368
+	}
369
+
370
+	/* Check that we were allowed to get the queue configuration */
371
+	if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
372
+		DBGC ( intel, "INTEL %p get queue configuration refused\n",
373
+		       intel );
374
+		return -EPERM;
375
+	}
376
+
377
+	/* Extract VLAN hand-waving thing */
378
+	*vlan_thing = msg.queues.vlan_thing;
379
+
380
+	return 0;
381
+}

+ 43
- 0
src/drivers/net/intelvf.h Voir le fichier

@@ -37,6 +37,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
37 37
 /** Set MTU mailbox message */
38 38
 #define INTELVF_MSG_TYPE_SET_MTU 0x00000005UL
39 39
 
40
+/** Get queue configuration message */
41
+#define INTELVF_MSG_TYPE_GET_QUEUES 0x00000009UL
42
+
40 43
 /** Control ("ping") mailbox message */
41 44
 #define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
42 45
 
@@ -78,6 +81,44 @@ struct intelvf_msg_mtu {
78 81
 	uint32_t mtu;
79 82
 } __attribute__ (( packed ));
80 83
 
84
+/** Queue configuration mailbox message (API v1.1+ only) */
85
+struct intelvf_msg_queues {
86
+	/** Message header */
87
+	uint32_t hdr;
88
+	/** Maximum number of transmit queues */
89
+	uint32_t tx;
90
+	/** Maximum number of receive queues */
91
+	uint32_t rx;
92
+	/** VLAN hand-waving thing
93
+	 *
94
+	 * This is labelled IXGBE_VF_TRANS_VLAN in the Linux driver.
95
+	 *
96
+	 * A comment in the Linux PF driver describes it as "notify VF
97
+	 * of need for VLAN tag stripping, and correct queue".  It
98
+	 * will be filled with a non-zero value if the PF is enforcing
99
+	 * the use of a single VLAN tag.  It will also be filled with
100
+	 * a non-zero value if the PF is using multiple traffic
101
+	 * classes.
102
+	 *
103
+	 * The Linux VF driver seems to treat this field as being
104
+	 * simply the number of traffic classes, and gives it no
105
+	 * VLAN-related interpretation.
106
+	 *
107
+	 * If the PF is enforcing the use of a single VLAN tag for the
108
+	 * VF, then the VLAN tag will be transparently inserted in
109
+	 * transmitted packets (via the PFVMVIR register) but will
110
+	 * still be visible in received packets.  The Linux VF driver
111
+	 * handles this unexpected VLAN tag by simply ignoring any
112
+	 * unrecognised VLAN tags.
113
+	 *
114
+	 * We choose to strip and ignore the VLAN tag if this field
115
+	 * has a non-zero value.
116
+	 */
117
+	uint32_t vlan_thing;
118
+	/** Default queue */
119
+	uint32_t dflt;
120
+} __attribute__ (( packed ));
121
+
81 122
 /** Mailbox message */
82 123
 union intelvf_msg {
83 124
 	/** Message header */
@@ -88,6 +129,8 @@ union intelvf_msg {
88 129
 	struct intelvf_msg_version version;
89 130
 	/** MTU message */
90 131
 	struct intelvf_msg_mtu mtu;
132
+	/** Queue configuration message */
133
+	struct intelvf_msg_queues queues;
91 134
 	/** Raw dwords */
92 135
 	uint32_t dword[0];
93 136
 };

+ 3
- 0
src/drivers/net/intelx.h Voir le fichier

@@ -71,6 +71,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
71 71
 /** Receive Descriptor register block */
72 72
 #define INTELX_RD 0x01000UL
73 73
 
74
+/** Receive Descriptor Control Register */
75
+#define INTELX_RXDCTL_VME	0x40000000UL	/**< Strip VLAN tag */
76
+
74 77
 /** Split Receive Control Register */
75 78
 #define INTELX_SRRCTL 0x02100UL
76 79
 #define INTELX_SRRCTL_BSIZE(kb)	( (kb) << 0 )	/**< Receive buffer size */

+ 57
- 0
src/drivers/net/intelxvf.c Voir le fichier

@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
30 30
 #include <ipxe/pci.h>
31 31
 #include <ipxe/netdevice.h>
32 32
 #include <ipxe/ethernet.h>
33
+#include "intelx.h"
33 34
 #include "intelxvf.h"
34 35
 
35 36
 /** @file
@@ -156,6 +157,47 @@ static int intelxvf_mbox_version ( struct intel_nic *intel,
156 157
 	return 0;
157 158
 }
158 159
 
160
+/**
161
+ * Get queue configuration
162
+ *
163
+ * @v intel		Intel device
164
+ * @v vlan_thing	VLAN hand-waving thing to fill in
165
+ * @ret rc		Return status code
166
+ */
167
+static int intelxvf_mbox_queues ( struct intel_nic *intel, int *vlan_thing ) {
168
+	union intelvf_msg msg;
169
+	int rc;
170
+
171
+	/* Send queue configuration message */
172
+	memset ( &msg, 0, sizeof ( msg ) );
173
+	msg.hdr = INTELVF_MSG_TYPE_GET_QUEUES;
174
+	if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
175
+		DBGC ( intel, "INTEL %p get queue configuration failed: %s\n",
176
+		       intel, strerror ( rc ) );
177
+		return rc;
178
+	}
179
+
180
+	/* Check response */
181
+	if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) !=INTELVF_MSG_TYPE_GET_QUEUES){
182
+		DBGC ( intel, "INTEL %p get queue configuration unexpected "
183
+		       "response:\n", intel );
184
+		DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
185
+		return -EPROTO;
186
+	}
187
+
188
+	/* Check that we were allowed to get the queue configuration */
189
+	if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
190
+		DBGC ( intel, "INTEL %p get queue configuration refused\n",
191
+		       intel );
192
+		return -EPERM;
193
+	}
194
+
195
+	/* Extract VLAN hand-waving thing */
196
+	*vlan_thing = msg.queues.vlan_thing;
197
+
198
+	return 0;
199
+}
200
+
159 201
 /******************************************************************************
160 202
  *
161 203
  * Network device interface
@@ -171,8 +213,10 @@ static int intelxvf_mbox_version ( struct intel_nic *intel,
171 213
  */
172 214
 static int intelxvf_open ( struct net_device *netdev ) {
173 215
 	struct intel_nic *intel = netdev->priv;
216
+	uint32_t rxdctl;
174 217
 	uint32_t srrctl;
175 218
 	uint32_t dca_rxctrl;
219
+	int vlan_thing;
176 220
 	int rc;
177 221
 
178 222
 	/* Reset the function */
@@ -208,6 +252,19 @@ static int intelxvf_open ( struct net_device *netdev ) {
208 252
 		goto err_mbox_set_mtu;
209 253
 	}
210 254
 
255
+	/* Get queue configuration.  Ignore failures, since the host
256
+	 * may not support this message.
257
+	 */
258
+	vlan_thing = 0;
259
+	intelxvf_mbox_queues ( intel, &vlan_thing );
260
+	if ( vlan_thing ) {
261
+		DBGC ( intel, "INTEL %p stripping VLAN tags (thing=%d)\n",
262
+		       intel, vlan_thing );
263
+		rxdctl = readl ( intel->regs + INTELXVF_RD + INTEL_xDCTL );
264
+		rxdctl |= INTELX_RXDCTL_VME;
265
+		writel ( rxdctl, intel->regs + INTELXVF_RD + INTEL_xDCTL );
266
+	}
267
+
211 268
 	/* Create transmit descriptor ring */
212 269
 	if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
213 270
 		goto err_create_tx;

Chargement…
Annuler
Enregistrer