| @@ -66,6 +66,7 @@ · 65 unmodified lines |
| 66 | #include <net/checksum.h> | 66 | #include <net/checksum.h> |
| 67 | #include <net/ip6_checksum.h> | 67 | #include <net/ip6_checksum.h> |
| 68 | #include <net/xfrm.h> | 68 | #include <net/xfrm.h> |
| | 69 | #include <net/mpls.h> |
| 69 | | 70 | |
| 70 | #include <linux/uaccess.h> | 71 | #include <linux/uaccess.h> |
| 71 | #include <trace/events/skb.h> | 72 | #include <trace/events/skb.h> |
| @@ -5425,6 +5426,69 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) · 5353 unmodified lines |
| 5425 | } | 5426 | } |
| 5426 | EXPORT_SYMBOL(skb_vlan_push); | 5427 | EXPORT_SYMBOL(skb_vlan_push); |
| 5427 | | 5428 | |
| | 5429 | /* Update the ethertype of hdr and the skb csum value if required. */ |
| | 5430 | static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr, |
| | 5431 | __be16 ethertype) |
| | 5432 | { |
| | 5433 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| | 5434 | __be16 diff[] = { ~hdr->h_proto, ethertype }; |
| | 5435 | |
| | 5436 | skb->csum = csum_partial((char *)diff, sizeof(diff), skb->csum); |
| | 5437 | } |
| | 5438 | |
| | 5439 | hdr->h_proto = ethertype; |
| | 5440 | } |
| | 5441 | |
| | 5442 | /** |
| | 5443 | * skb_mpls_push() - push a new MPLS header after the mac header |
| | 5444 | * |
| | 5445 | * @skb: buffer |
| | 5446 | * @mpls_lse: MPLS label stack entry to push |
| | 5447 | * @mpls_proto: ethertype of the new MPLS header (expects 0x8847 or 0x8848) |
| | 5448 | * |
| | 5449 | * Expects skb->data at mac header. |
| | 5450 | * |
| | 5451 | * Returns 0 on success, -errno otherwise. |
| | 5452 | */ |
| | 5453 | int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto) |
| | 5454 | { |
| | 5455 | struct mpls_shim_hdr *lse; |
| | 5456 | int err; |
| | 5457 | |
| | 5458 | if (unlikely(!eth_p_mpls(mpls_proto))) |
| | 5459 | return -EINVAL; |
| | 5460 | |
| | 5461 | /* Networking stack does not allow simultaneous Tunnel and MPLS GSO. */ |
| | 5462 | if (skb->encapsulation) |
| | 5463 | return -EINVAL; |
| | 5464 | |
| | 5465 | err = skb_cow_head(skb, MPLS_HLEN); |
| | 5466 | if (unlikely(err)) |
| | 5467 | return err; |
| | 5468 | |
| | 5469 | if (!skb->inner_protocol) { |
| | 5470 | skb_set_inner_network_header(skb, skb->mac_len); |
| | 5471 | skb_set_inner_protocol(skb, skb->protocol); |
| | 5472 | } |
| | 5473 | |
| | 5474 | skb_push(skb, MPLS_HLEN); |
| | 5475 | memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb), |
| | 5476 | skb->mac_len); |
| | 5477 | skb_reset_mac_header(skb); |
| | 5478 | skb_set_network_header(skb, skb->mac_len); |
| | 5479 | |
| | 5480 | lse = mpls_hdr(skb); |
| | 5481 | lse->label_stack_entry = mpls_lse; |
| | 5482 | skb_postpush_rcsum(skb, lse, MPLS_HLEN); |
| | 5483 | |
| | 5484 | if (skb->dev && skb->dev->type == ARPHRD_ETHER) |
| | 5485 | skb_mod_eth_type(skb, eth_hdr(skb), mpls_proto); |
| | 5486 | skb->protocol = mpls_proto; |
| | 5487 | |
| | 5488 | return 0; |
| | 5489 | } |
| | 5490 | EXPORT_SYMBOL_GPL(skb_mpls_push); |
| | 5491 | |
| 5428 | /** | 5492 | /** |
| 5429 | * alloc_skb_with_frags - allocate skb with page frags | 5493 | * alloc_skb_with_frags - allocate skb with page frags |
| 5430 | * | 5494 | * |