diff options
author | Pedro Garcia <pedro.netdev@dondevamos.com> | 2010-07-18 18:38:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-18 18:38:44 -0400 |
commit | ad1afb00393915a51c21b1ae8704562bf036855f (patch) | |
tree | 68ead91b78624a66f4aabb9699f4b414b914a762 /net/8021q/vlan_dev.c | |
parent | 01893c82b4e6949f4e3a453c4faea34970359d76 (diff) |
vlan_dev: VLAN 0 should be treated as "no vlan tag" (802.1p packet)
- Without the 8021q module loaded in the kernel, all 802.1p packets
(VLAN 0 but QoS tagging) are silently discarded (as expected, as
the protocol is not loaded).
- Without this patch in 8021q module, these packets are forwarded to
the module, but they are discarded also if VLAN 0 is not configured,
which should not be the default behaviour, as VLAN 0 is not really
a VLANed packet but a 802.1p packet. Defining VLAN 0 makes it almost
impossible to communicate with mixed 802.1p and non 802.1p devices on
the same network due to arp table issues.
- Changed logic to skip vlan specific code in vlan_skb_recv if VLAN
is 0 and we have not defined a VLAN with ID 0, but we accept the
packet with the encapsulated proto and pass it later to netif_rx.
- In the vlan device event handler, added some logic to add VLAN 0
to HW filter in devices that support it (this prevented any traffic
in VLAN 0 to reach the stack in e1000e with HW filter under 2.6.35,
and probably also with other HW filtered cards, so we fix it here).
- In the vlan unregister logic, prevent the elimination of VLAN 0
in devices with HW filter.
- The default behaviour is to ignore the VLAN 0 tagging and accept
the packet as if it was not tagged, but we can still define a
VLAN 0 if desired (so it is backwards compatible).
Signed-off-by: Pedro Garcia <pedro.netdev@dondevamos.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 103 |
1 files changed, 60 insertions, 43 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 7cb285f96b99..3d59c9bf8feb 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -142,6 +142,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
142 | { | 142 | { |
143 | struct vlan_hdr *vhdr; | 143 | struct vlan_hdr *vhdr; |
144 | struct vlan_rx_stats *rx_stats; | 144 | struct vlan_rx_stats *rx_stats; |
145 | struct net_device *vlan_dev; | ||
145 | u16 vlan_id; | 146 | u16 vlan_id; |
146 | u16 vlan_tci; | 147 | u16 vlan_tci; |
147 | 148 | ||
@@ -157,55 +158,71 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
157 | vlan_id = vlan_tci & VLAN_VID_MASK; | 158 | vlan_id = vlan_tci & VLAN_VID_MASK; |
158 | 159 | ||
159 | rcu_read_lock(); | 160 | rcu_read_lock(); |
160 | skb->dev = __find_vlan_dev(dev, vlan_id); | 161 | vlan_dev = __find_vlan_dev(dev, vlan_id); |
161 | if (!skb->dev) { | ||
162 | pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", | ||
163 | __func__, vlan_id, dev->name); | ||
164 | goto err_unlock; | ||
165 | } | ||
166 | |||
167 | rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats, | ||
168 | smp_processor_id()); | ||
169 | u64_stats_update_begin(&rx_stats->syncp); | ||
170 | rx_stats->rx_packets++; | ||
171 | rx_stats->rx_bytes += skb->len; | ||
172 | |||
173 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
174 | |||
175 | skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); | ||
176 | 162 | ||
177 | pr_debug("%s: priority: %u for TCI: %hu\n", | 163 | /* If the VLAN device is defined, we use it. |
178 | __func__, skb->priority, vlan_tci); | 164 | * If not, and the VID is 0, it is a 802.1p packet (not |
179 | 165 | * really a VLAN), so we will just netif_rx it later to the | |
180 | switch (skb->pkt_type) { | 166 | * original interface, but with the skb->proto set to the |
181 | case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ | 167 | * wrapped proto: we do nothing here. |
182 | /* stats->broadcast ++; // no such counter :-( */ | 168 | */ |
183 | break; | ||
184 | |||
185 | case PACKET_MULTICAST: | ||
186 | rx_stats->rx_multicast++; | ||
187 | break; | ||
188 | 169 | ||
189 | case PACKET_OTHERHOST: | 170 | if (!vlan_dev) { |
190 | /* Our lower layer thinks this is not local, let's make sure. | 171 | if (vlan_id) { |
191 | * This allows the VLAN to have a different MAC than the | 172 | pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", |
192 | * underlying device, and still route correctly. | 173 | __func__, vlan_id, dev->name); |
193 | */ | 174 | goto err_unlock; |
194 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, | 175 | } |
195 | skb->dev->dev_addr)) | 176 | rx_stats = NULL; |
196 | skb->pkt_type = PACKET_HOST; | 177 | } else { |
197 | break; | 178 | skb->dev = vlan_dev; |
198 | default: | 179 | |
199 | break; | 180 | rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats, |
181 | smp_processor_id()); | ||
182 | u64_stats_update_begin(&rx_stats->syncp); | ||
183 | rx_stats->rx_packets++; | ||
184 | rx_stats->rx_bytes += skb->len; | ||
185 | |||
186 | skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); | ||
187 | |||
188 | pr_debug("%s: priority: %u for TCI: %hu\n", | ||
189 | __func__, skb->priority, vlan_tci); | ||
190 | |||
191 | switch (skb->pkt_type) { | ||
192 | case PACKET_BROADCAST: | ||
193 | /* Yeah, stats collect these together.. */ | ||
194 | /* stats->broadcast ++; // no such counter :-( */ | ||
195 | break; | ||
196 | |||
197 | case PACKET_MULTICAST: | ||
198 | rx_stats->rx_multicast++; | ||
199 | break; | ||
200 | |||
201 | case PACKET_OTHERHOST: | ||
202 | /* Our lower layer thinks this is not local, let's make | ||
203 | * sure. | ||
204 | * This allows the VLAN to have a different MAC than the | ||
205 | * underlying device, and still route correctly. | ||
206 | */ | ||
207 | if (!compare_ether_addr(eth_hdr(skb)->h_dest, | ||
208 | skb->dev->dev_addr)) | ||
209 | skb->pkt_type = PACKET_HOST; | ||
210 | break; | ||
211 | default: | ||
212 | break; | ||
213 | } | ||
214 | u64_stats_update_end(&rx_stats->syncp); | ||
200 | } | 215 | } |
201 | u64_stats_update_end(&rx_stats->syncp); | ||
202 | 216 | ||
217 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
203 | vlan_set_encap_proto(skb, vhdr); | 218 | vlan_set_encap_proto(skb, vhdr); |
204 | 219 | ||
205 | skb = vlan_check_reorder_header(skb); | 220 | if (vlan_dev) { |
206 | if (!skb) { | 221 | skb = vlan_check_reorder_header(skb); |
207 | rx_stats->rx_errors++; | 222 | if (!skb) { |
208 | goto err_unlock; | 223 | rx_stats->rx_errors++; |
224 | goto err_unlock; | ||
225 | } | ||
209 | } | 226 | } |
210 | 227 | ||
211 | netif_rx(skb); | 228 | netif_rx(skb); |