diff options
author | Patrick McHardy <kaber@trash.net> | 2013-04-18 22:04:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-19 14:46:06 -0400 |
commit | 8ad227ff89a7e6f05d07cd0acfd95ed3a24450ca (patch) | |
tree | 90cb532df2523a011e47844434cc423664441d71 /net/core | |
parent | 86a9bad3ab6b6f858fd4443b48738cabbb6d094c (diff) |
net: vlan: add 802.1ad support
Add support for 802.1ad VLAN devices. This mainly consists of checking for
ETH_P_8021AD in addition to ETH_P_8021Q in a couple of places and check
offloading capabilities based on the used protocol.
Configuration is done using "ip link":
# ip link add link eth0 eth0.1000 \
type vlan proto 802.1ad id 1000
# ip link add link eth0.1000 eth0.1000.1000 \
type vlan proto 802.1q id 1000
52:54:00:12:34:56 > 92:b1:54:28:e4:8c, ethertype 802.1Q (0x8100), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
20.1.0.2 > 20.1.0.1: ICMP echo request, id 3003, seq 8, length 64
92:b1:54:28:e4:8c > 52:54:00:12:34:56, ethertype 802.1Q-QinQ (0x88a8), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 47944, offset 0, flags [none], proto ICMP (1), length 84)
20.1.0.1 > 20.1.0.2: ICMP echo reply, id 3003, seq 8, length 64
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 3a12ee132b59..fad4c385f7a1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2212,7 +2212,7 @@ __be16 skb_network_protocol(struct sk_buff *skb) | |||
2212 | __be16 type = skb->protocol; | 2212 | __be16 type = skb->protocol; |
2213 | int vlan_depth = ETH_HLEN; | 2213 | int vlan_depth = ETH_HLEN; |
2214 | 2214 | ||
2215 | while (type == htons(ETH_P_8021Q)) { | 2215 | while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { |
2216 | struct vlan_hdr *vh; | 2216 | struct vlan_hdr *vh; |
2217 | 2217 | ||
2218 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) | 2218 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) |
@@ -2428,20 +2428,22 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) | |||
2428 | if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) | 2428 | if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) |
2429 | features &= ~NETIF_F_GSO_MASK; | 2429 | features &= ~NETIF_F_GSO_MASK; |
2430 | 2430 | ||
2431 | if (protocol == htons(ETH_P_8021Q)) { | 2431 | if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) { |
2432 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; | 2432 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; |
2433 | protocol = veh->h_vlan_encapsulated_proto; | 2433 | protocol = veh->h_vlan_encapsulated_proto; |
2434 | } else if (!vlan_tx_tag_present(skb)) { | 2434 | } else if (!vlan_tx_tag_present(skb)) { |
2435 | return harmonize_features(skb, protocol, features); | 2435 | return harmonize_features(skb, protocol, features); |
2436 | } | 2436 | } |
2437 | 2437 | ||
2438 | features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX); | 2438 | features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | |
2439 | NETIF_F_HW_VLAN_STAG_TX); | ||
2439 | 2440 | ||
2440 | if (protocol != htons(ETH_P_8021Q)) { | 2441 | if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) { |
2441 | return harmonize_features(skb, protocol, features); | 2442 | return harmonize_features(skb, protocol, features); |
2442 | } else { | 2443 | } else { |
2443 | features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | | 2444 | features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | |
2444 | NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX; | 2445 | NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | |
2446 | NETIF_F_HW_VLAN_STAG_TX; | ||
2445 | return harmonize_features(skb, protocol, features); | 2447 | return harmonize_features(skb, protocol, features); |
2446 | } | 2448 | } |
2447 | } | 2449 | } |
@@ -3360,6 +3362,7 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb) | |||
3360 | case __constant_htons(ETH_P_IP): | 3362 | case __constant_htons(ETH_P_IP): |
3361 | case __constant_htons(ETH_P_IPV6): | 3363 | case __constant_htons(ETH_P_IPV6): |
3362 | case __constant_htons(ETH_P_8021Q): | 3364 | case __constant_htons(ETH_P_8021Q): |
3365 | case __constant_htons(ETH_P_8021AD): | ||
3363 | return true; | 3366 | return true; |
3364 | default: | 3367 | default: |
3365 | return false; | 3368 | return false; |
@@ -3400,7 +3403,8 @@ another_round: | |||
3400 | 3403 | ||
3401 | __this_cpu_inc(softnet_data.processed); | 3404 | __this_cpu_inc(softnet_data.processed); |
3402 | 3405 | ||
3403 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { | 3406 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || |
3407 | skb->protocol == cpu_to_be16(ETH_P_8021AD)) { | ||
3404 | skb = vlan_untag(skb); | 3408 | skb = vlan_untag(skb); |
3405 | if (unlikely(!skb)) | 3409 | if (unlikely(!skb)) |
3406 | goto unlock; | 3410 | goto unlock; |