Browse 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 8 years ago
parent
commit
db3443608f
4 changed files with 144 additions and 0 deletions
  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 View File

338
 
338
 
339
 	return 0;
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 View File

37
 /** Set MTU mailbox message */
37
 /** Set MTU mailbox message */
38
 #define INTELVF_MSG_TYPE_SET_MTU 0x00000005UL
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
 /** Control ("ping") mailbox message */
43
 /** Control ("ping") mailbox message */
41
 #define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
44
 #define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
42
 
45
 
78
 	uint32_t mtu;
81
 	uint32_t mtu;
79
 } __attribute__ (( packed ));
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
 /** Mailbox message */
122
 /** Mailbox message */
82
 union intelvf_msg {
123
 union intelvf_msg {
83
 	/** Message header */
124
 	/** Message header */
88
 	struct intelvf_msg_version version;
129
 	struct intelvf_msg_version version;
89
 	/** MTU message */
130
 	/** MTU message */
90
 	struct intelvf_msg_mtu mtu;
131
 	struct intelvf_msg_mtu mtu;
132
+	/** Queue configuration message */
133
+	struct intelvf_msg_queues queues;
91
 	/** Raw dwords */
134
 	/** Raw dwords */
92
 	uint32_t dword[0];
135
 	uint32_t dword[0];
93
 };
136
 };

+ 3
- 0
src/drivers/net/intelx.h View File

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

+ 57
- 0
src/drivers/net/intelxvf.c View File

30
 #include <ipxe/pci.h>
30
 #include <ipxe/pci.h>
31
 #include <ipxe/netdevice.h>
31
 #include <ipxe/netdevice.h>
32
 #include <ipxe/ethernet.h>
32
 #include <ipxe/ethernet.h>
33
+#include "intelx.h"
33
 #include "intelxvf.h"
34
 #include "intelxvf.h"
34
 
35
 
35
 /** @file
36
 /** @file
156
 	return 0;
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
  * Network device interface
203
  * Network device interface
171
  */
213
  */
172
 static int intelxvf_open ( struct net_device *netdev ) {
214
 static int intelxvf_open ( struct net_device *netdev ) {
173
 	struct intel_nic *intel = netdev->priv;
215
 	struct intel_nic *intel = netdev->priv;
216
+	uint32_t rxdctl;
174
 	uint32_t srrctl;
217
 	uint32_t srrctl;
175
 	uint32_t dca_rxctrl;
218
 	uint32_t dca_rxctrl;
219
+	int vlan_thing;
176
 	int rc;
220
 	int rc;
177
 
221
 
178
 	/* Reset the function */
222
 	/* Reset the function */
208
 		goto err_mbox_set_mtu;
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
 	/* Create transmit descriptor ring */
268
 	/* Create transmit descriptor ring */
212
 	if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
269
 	if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
213
 		goto err_create_tx;
270
 		goto err_create_tx;

Loading…
Cancel
Save