~ubuntu-branches/debian/experimental/linux-2.6/experimental

« back to all changes in this revision

Viewing changes to debian/patches/features/x86/hyperv/0070-net-hyperv-Add-support-for-vlan-trunking-from-guests.patch

  • Committer: Package Import Robot
  • Author(s): maximilian attems, maximilian attems, Ben Hutchings
  • Date: 2012-06-06 10:25:57 UTC
  • mfrom: (1.2.38)
  • Revision ID: package-import@ubuntu.com-20120606102557-b9j3506wcwrqrnx8
Tags: 3.4.1-1~experimental.1
* New upstream release: http://kernelnewbies.org/Linux_3.4
* New upstream stable update:
  http://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.4.1

[ maximilian attems ]
* Enable DM_VERITY, NF_CONNTRACK_TIMEOUT, NF_CT_NETLINK_TIMEOUT,
  IP_NF_MATCH_RPFILTER, IP6_NF_MATCH_RPFILTER, NETFILTER_NETLINK_ACCT,
  NETFILTER_XT_MATCH_NFACCT, NET_SCH_PLUG, SCSI_UFSHCD, SCSI_VIRTIO,
  NET_TEAM, ATH6KL.

[ Ben Hutchings ]
* DFSG: Remove the new vs6624 driver, which contains non-free firmware
* aufs: Update to aufs3.4-20120521
* [rt] Update to 3.4-rt8 and reenable

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
From: Haiyang Zhang <haiyangz@microsoft.com>
2
 
Date: Mon, 12 Mar 2012 10:20:50 +0000
3
 
Subject: [PATCH 70/77] net/hyperv: Add support for vlan trunking from guests
4
 
 
5
 
commit 1f5f3a75e216fe771b8d6805e0bb2f43595a6ee1 upstream.
6
 
 
7
 
With this feature, a Linux guest can now configure multiple vlans through
8
 
a single synthetic NIC on Win8 Hyper-V host.
9
 
 
10
 
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
11
 
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
12
 
Signed-off-by: David S. Miller <davem@davemloft.net>
13
 
---
14
 
 drivers/net/hyperv/hyperv_net.h   |   34 ++++++++++++++++++++-
15
 
 drivers/net/hyperv/netvsc.c       |    3 +-
16
 
 drivers/net/hyperv/netvsc_drv.c   |    8 +++--
17
 
 drivers/net/hyperv/rndis_filter.c |   60 +++++++++++++++++++++++++++++++++++++
18
 
 4 files changed, 101 insertions(+), 4 deletions(-)
19
 
 
20
 
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
21
 
index dec5836..c358245 100644
22
 
--- a/drivers/net/hyperv/hyperv_net.h
23
 
+++ b/drivers/net/hyperv/hyperv_net.h
24
 
@@ -49,6 +49,7 @@ struct hv_netvsc_packet {
25
 
 
26
 
        struct hv_device *device;
27
 
        bool is_data_pkt;
28
 
+       u16 vlan_tci;
29
 
 
30
 
        /*
31
 
         * Valid only for receives when we break a xfer page packet
32
 
@@ -926,9 +927,40 @@ struct rndis_oobd {
33
 
 struct rndis_per_packet_info {
34
 
        u32 size;
35
 
        u32 type;
36
 
-       u32 per_pkt_info_offset;
37
 
+       u32 ppi_offset;
38
 
+};
39
 
+
40
 
+enum ndis_per_pkt_info_type {
41
 
+       TCPIP_CHKSUM_PKTINFO,
42
 
+       IPSEC_PKTINFO,
43
 
+       TCP_LARGESEND_PKTINFO,
44
 
+       CLASSIFICATION_HANDLE_PKTINFO,
45
 
+       NDIS_RESERVED,
46
 
+       SG_LIST_PKTINFO,
47
 
+       IEEE_8021Q_INFO,
48
 
+       ORIGINAL_PKTINFO,
49
 
+       PACKET_CANCEL_ID,
50
 
+       ORIGINAL_NET_BUFLIST,
51
 
+       CACHED_NET_BUFLIST,
52
 
+       SHORT_PKT_PADINFO,
53
 
+       MAX_PER_PKT_INFO
54
 
+};
55
 
+
56
 
+struct ndis_pkt_8021q_info {
57
 
+       union {
58
 
+               struct {
59
 
+                       u32 pri:3; /* User Priority */
60
 
+                       u32 cfi:1; /* Canonical Format ID */
61
 
+                       u32 vlanid:12; /* VLAN ID */
62
 
+                       u32 reserved:16;
63
 
+               };
64
 
+               u32 value;
65
 
+       };
66
 
 };
67
 
 
68
 
+#define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
69
 
+               sizeof(struct ndis_pkt_8021q_info))
70
 
+
71
 
 /* Format of Information buffer passed in a SetRequest for the OID */
72
 
 /* OID_GEN_RNDIS_CONFIG_PARAMETER. */
73
 
 struct rndis_config_parameter_info {
74
 
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
75
 
index 8965b45..d025c83 100644
76
 
--- a/drivers/net/hyperv/netvsc.c
77
 
+++ b/drivers/net/hyperv/netvsc.c
78
 
@@ -300,6 +300,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
79
 
        memset(init_packet, 0, sizeof(struct nvsp_message));
80
 
        init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
81
 
        init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
82
 
+       init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
83
 
 
84
 
        ret = vmbus_sendpacket(device->channel, init_packet,
85
 
                                sizeof(struct nvsp_message),
86
 
@@ -341,7 +342,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
87
 
        /* Send the ndis version */
88
 
        memset(init_packet, 0, sizeof(struct nvsp_message));
89
 
 
90
 
-       ndis_version = 0x00050000;
91
 
+       ndis_version = 0x00050001;
92
 
 
93
 
        init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
94
 
        init_packet->msg.v1_msg.
95
 
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
96
 
index 217dfed..0f8e834 100644
97
 
--- a/drivers/net/hyperv/netvsc_drv.c
98
 
+++ b/drivers/net/hyperv/netvsc_drv.c
99
 
@@ -159,7 +159,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
100
 
        /* Allocate a netvsc packet based on # of frags. */
101
 
        packet = kzalloc(sizeof(struct hv_netvsc_packet) +
102
 
                         (num_pages * sizeof(struct hv_page_buffer)) +
103
 
-                        sizeof(struct rndis_filter_packet), GFP_ATOMIC);
104
 
+                        sizeof(struct rndis_filter_packet) +
105
 
+                        NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
106
 
        if (!packet) {
107
 
                /* out of memory, drop packet */
108
 
                netdev_err(net, "unable to allocate hv_netvsc_packet\n");
109
 
@@ -169,6 +170,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
110
 
                return NETDEV_TX_BUSY;
111
 
        }
112
 
 
113
 
+       packet->vlan_tci = skb->vlan_tci;
114
 
+
115
 
        packet->extension = (void *)(unsigned long)packet +
116
 
                                sizeof(struct hv_netvsc_packet) +
117
 
                                    (num_pages * sizeof(struct hv_page_buffer));
118
 
@@ -293,6 +296,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
119
 
 
120
 
        skb->protocol = eth_type_trans(skb, net);
121
 
        skb->ip_summed = CHECKSUM_NONE;
122
 
+       skb->vlan_tci = packet->vlan_tci;
123
 
 
124
 
        net->stats.rx_packets++;
125
 
        net->stats.rx_bytes += packet->total_data_buflen;
126
 
@@ -407,7 +411,7 @@ static int netvsc_probe(struct hv_device *dev,
127
 
 
128
 
        /* TODO: Add GSO and Checksum offload */
129
 
        net->hw_features = NETIF_F_SG;
130
 
-       net->features = NETIF_F_SG;
131
 
+       net->features = NETIF_F_SG | NETIF_F_HW_VLAN_TX;
132
 
 
133
 
        SET_ETHTOOL_OPS(net, &ethtool_ops);
134
 
        SET_NETDEV_DEV(net, &dev->device);
135
 
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
136
 
index 0c3d7d9..d6be64b 100644
137
 
--- a/drivers/net/hyperv/rndis_filter.c
138
 
+++ b/drivers/net/hyperv/rndis_filter.c
139
 
@@ -26,6 +26,7 @@
140
 
 #include <linux/io.h>
141
 
 #include <linux/if_ether.h>
142
 
 #include <linux/netdevice.h>
143
 
+#include <linux/if_vlan.h>
144
 
 
145
 
 #include "hyperv_net.h"
146
 
 
147
 
@@ -303,12 +304,39 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
148
 
        }
149
 
 }
150
 
 
151
 
+/*
152
 
+ * Get the Per-Packet-Info with the specified type
153
 
+ * return NULL if not found.
154
 
+ */
155
 
+static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
156
 
+{
157
 
+       struct rndis_per_packet_info *ppi;
158
 
+       int len;
159
 
+
160
 
+       if (rpkt->per_pkt_info_offset == 0)
161
 
+               return NULL;
162
 
+
163
 
+       ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
164
 
+               rpkt->per_pkt_info_offset);
165
 
+       len = rpkt->per_pkt_info_len;
166
 
+
167
 
+       while (len > 0) {
168
 
+               if (ppi->type == type)
169
 
+                       return (void *)((ulong)ppi + ppi->ppi_offset);
170
 
+               len -= ppi->size;
171
 
+               ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
172
 
+       }
173
 
+
174
 
+       return NULL;
175
 
+}
176
 
+
177
 
 static void rndis_filter_receive_data(struct rndis_device *dev,
178
 
                                   struct rndis_message *msg,
179
 
                                   struct hv_netvsc_packet *pkt)
180
 
 {
181
 
        struct rndis_packet *rndis_pkt;
182
 
        u32 data_offset;
183
 
+       struct ndis_pkt_8021q_info *vlan;
184
 
 
185
 
        rndis_pkt = &msg->msg.pkt;
186
 
 
187
 
@@ -344,6 +372,14 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
188
 
 
189
 
        pkt->is_data_pkt = true;
190
 
 
191
 
+       vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
192
 
+       if (vlan) {
193
 
+               pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
194
 
+                       (vlan->pri << VLAN_PRIO_SHIFT);
195
 
+       } else {
196
 
+               pkt->vlan_tci = 0;
197
 
+       }
198
 
+
199
 
        netvsc_recv_callback(dev->net_dev->dev, pkt);
200
 
 }
201
 
 
202
 
@@ -759,12 +795,15 @@ int rndis_filter_send(struct hv_device *dev,
203
 
        struct rndis_message *rndis_msg;
204
 
        struct rndis_packet *rndis_pkt;
205
 
        u32 rndis_msg_size;
206
 
+       bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
207
 
 
208
 
        /* Add the rndis header */
209
 
        filter_pkt = (struct rndis_filter_packet *)pkt->extension;
210
 
 
211
 
        rndis_msg = &filter_pkt->msg;
212
 
        rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
213
 
+       if (isvlan)
214
 
+               rndis_msg_size += NDIS_VLAN_PPI_SIZE;
215
 
 
216
 
        rndis_msg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
217
 
        rndis_msg->msg_len = pkt->total_data_buflen +
218
 
@@ -772,8 +811,29 @@ int rndis_filter_send(struct hv_device *dev,
219
 
 
220
 
        rndis_pkt = &rndis_msg->msg.pkt;
221
 
        rndis_pkt->data_offset = sizeof(struct rndis_packet);
222
 
+       if (isvlan)
223
 
+               rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
224
 
        rndis_pkt->data_len = pkt->total_data_buflen;
225
 
 
226
 
+       if (isvlan) {
227
 
+               struct rndis_per_packet_info *ppi;
228
 
+               struct ndis_pkt_8021q_info *vlan;
229
 
+
230
 
+               rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
231
 
+               rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
232
 
+
233
 
+               ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
234
 
+                       rndis_pkt->per_pkt_info_offset);
235
 
+               ppi->size = NDIS_VLAN_PPI_SIZE;
236
 
+               ppi->type = IEEE_8021Q_INFO;
237
 
+               ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
238
 
+
239
 
+               vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
240
 
+                       ppi->ppi_offset);
241
 
+               vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
242
 
+               vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
243
 
+       }
244
 
+
245
 
        pkt->is_data_pkt = true;
246
 
        pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
247
 
        pkt->page_buf[0].offset =
248
 
1.7.9.5
249