Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: erspan: refactor existing erspan code

The patch refactors the existing erspan implementation in order
to support erspan version 2, which has additional metadata. So, in
stead of having one 'struct erspanhdr' holding erspan version 1,
breaks it into 'struct erspan_base_hdr' and 'struct erspan_metadata'.

Signed-off-by: William Tu <u9012063@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

William Tu and committed by
David S. Miller
1d7e2ed2 4650b751

+61 -33
+24 -10
include/net/erspan.h
··· 15 15 * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The 16 16 * other fields are set to zero, so only a sequence number follows. 17 17 * 18 - * ERSPAN Type II header (8 octets [42:49]) 18 + * ERSPAN Version 1 (Type II) header (8 octets [42:49]) 19 19 * 0 1 2 3 20 20 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 21 21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ··· 27 27 * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB 28 28 */ 29 29 30 - #define ERSPAN_VERSION 0x1 30 + #define ERSPAN_VERSION 0x1 /* ERSPAN type II */ 31 31 32 32 #define VER_MASK 0xf000 33 33 #define VLAN_MASK 0x0fff ··· 44 44 ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */ 45 45 }; 46 46 47 + #define ERSPAN_V1_MDSIZE 4 48 + #define ERSPAN_V2_MDSIZE 8 47 49 struct erspan_metadata { 48 - __be32 index; /* type II */ 50 + union { 51 + __be32 index; /* Version 1 (type II)*/ 52 + } u; 49 53 }; 50 54 51 - struct erspanhdr { 55 + struct erspan_base_hdr { 52 56 __be16 ver_vlan; 53 57 #define VER_OFFSET 12 54 58 __be16 session_id; 55 59 #define COS_OFFSET 13 56 60 #define EN_OFFSET 11 57 61 #define T_OFFSET 10 58 - struct erspan_metadata md; 59 62 }; 63 + 64 + static inline int erspan_hdr_len(int version) 65 + { 66 + return sizeof(struct erspan_base_hdr) + 67 + (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE); 68 + } 60 69 61 70 static inline u8 tos_to_cos(u8 tos) 62 71 { ··· 82 73 { 83 74 struct ethhdr *eth = eth_hdr(skb); 84 75 enum erspan_encap_type enc_type; 85 - struct erspanhdr *ershdr; 76 + struct erspan_base_hdr *ershdr; 77 + struct erspan_metadata *ersmd; 86 78 struct qtag_prefix { 87 79 __be16 eth_type; 88 80 __be16 tci; ··· 106 96 enc_type = ERSPAN_ENCAP_INFRAME; 107 97 } 108 98 109 - skb_push(skb, sizeof(*ershdr)); 110 - ershdr = (struct erspanhdr *)skb->data; 111 - memset(ershdr, 0, sizeof(*ershdr)); 99 + skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); 100 + ershdr = (struct erspan_base_hdr *)skb->data; 101 + memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); 112 102 103 + /* Build base header */ 113 104 ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | 114 105 (ERSPAN_VERSION << VER_OFFSET)); 115 106 ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | 116 107 ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | 117 108 (enc_type << EN_OFFSET & EN_MASK) | 118 109 ((truncate << T_OFFSET) & T_MASK)); 119 - ershdr->md.index = htonl(index & INDEX_MASK); 110 + 111 + /* Build metadata */ 112 + ersmd = (struct erspan_metadata *)(ershdr + 1); 113 + ersmd->u.index = htonl(index & INDEX_MASK); 120 114 } 121 115 122 116 #endif
+17 -10
net/ipv4/ip_gre.c
··· 256 256 { 257 257 struct net *net = dev_net(skb->dev); 258 258 struct metadata_dst *tun_dst = NULL; 259 + struct erspan_base_hdr *ershdr; 260 + struct erspan_metadata *pkt_md; 259 261 struct ip_tunnel_net *itn; 260 262 struct ip_tunnel *tunnel; 261 - struct erspanhdr *ershdr; 262 263 const struct iphdr *iph; 263 - __be32 index; 264 + int ver; 264 265 int len; 265 266 266 267 itn = net_generic(net, erspan_net_id); 267 268 len = gre_hdr_len + sizeof(*ershdr); 268 269 270 + /* Check based hdr len */ 269 271 if (unlikely(!pskb_may_pull(skb, len))) 270 272 return -ENOMEM; 271 273 272 274 iph = ip_hdr(skb); 273 - ershdr = (struct erspanhdr *)(skb->data + gre_hdr_len); 275 + ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); 276 + ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; 274 277 275 278 /* The original GRE header does not have key field, 276 279 * Use ERSPAN 10-bit session ID as key. 277 280 */ 278 281 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 279 - index = ershdr->md.index; 282 + pkt_md = (struct erspan_metadata *)(ershdr + 1); 280 283 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, 281 284 tpi->flags | TUNNEL_KEY, 282 285 iph->saddr, iph->daddr, tpi->key); 283 286 284 287 if (tunnel) { 288 + len = gre_hdr_len + erspan_hdr_len(ver); 289 + if (unlikely(!pskb_may_pull(skb, len))) 290 + return -ENOMEM; 291 + 285 292 if (__iptunnel_pull_header(skb, 286 - gre_hdr_len + sizeof(*ershdr), 293 + len, 287 294 htons(ETH_P_TEB), 288 295 false, false) < 0) 289 296 goto drop; ··· 314 307 if (!md) 315 308 return PACKET_REJECT; 316 309 317 - md->index = index; 310 + memcpy(md, pkt_md, sizeof(*md)); 318 311 info = &tun_dst->u.tun_info; 319 312 info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 320 313 info->options_len = sizeof(*md); 321 314 } else { 322 - tunnel->index = ntohl(index); 315 + tunnel->index = ntohl(pkt_md->u.index); 323 316 } 324 317 325 318 skb_reset_mac_header(skb); ··· 578 571 key = &tun_info->key; 579 572 580 573 /* ERSPAN has fixed 8 byte GRE header */ 581 - tunnel_hlen = 8 + sizeof(struct erspanhdr); 574 + tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; 582 575 583 576 rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); 584 577 if (!rt) ··· 597 590 goto err_free_rt; 598 591 599 592 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 600 - ntohl(md->index), truncate, true); 593 + ntohl(md->u.index), truncate, true); 601 594 602 595 gre_build_header(skb, 8, TUNNEL_SEQ, 603 596 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); ··· 1245 1238 tunnel->tun_hlen = 8; 1246 1239 tunnel->parms.iph.protocol = IPPROTO_GRE; 1247 1240 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1248 - sizeof(struct erspanhdr); 1241 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; 1249 1242 t_hlen = tunnel->hlen + sizeof(struct iphdr); 1250 1243 1251 1244 dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
+16 -9
net/ipv6/ip6_gre.c
··· 501 501 static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, 502 502 struct tnl_ptk_info *tpi) 503 503 { 504 + struct erspan_base_hdr *ershdr; 505 + struct erspan_metadata *pkt_md; 504 506 const struct ipv6hdr *ipv6h; 505 - struct erspanhdr *ershdr; 506 507 struct ip6_tnl *tunnel; 507 - __be32 index; 508 + u8 ver; 508 509 509 510 ipv6h = ipv6_hdr(skb); 510 - ershdr = (struct erspanhdr *)skb->data; 511 + ershdr = (struct erspan_base_hdr *)skb->data; 511 512 512 513 if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) 513 514 return PACKET_REJECT; 514 515 516 + ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; 515 517 tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); 516 - index = ershdr->md.index; 518 + pkt_md = (struct erspan_metadata *)(ershdr + 1); 517 519 518 520 tunnel = ip6gre_tunnel_lookup(skb->dev, 519 521 &ipv6h->saddr, &ipv6h->daddr, tpi->key, 520 522 tpi->proto); 521 523 if (tunnel) { 522 - if (__iptunnel_pull_header(skb, sizeof(*ershdr), 524 + int len = erspan_hdr_len(ver); 525 + 526 + if (unlikely(!pskb_may_pull(skb, len))) 527 + return -ENOMEM; 528 + 529 + if (__iptunnel_pull_header(skb, len, 523 530 htons(ETH_P_TEB), 524 531 false, false) < 0) 525 532 return PACKET_REJECT; ··· 552 545 if (!md) 553 546 return PACKET_REJECT; 554 547 555 - md->index = index; 548 + memcpy(md, pkt_md, sizeof(*md)); 556 549 info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 557 550 info->options_len = sizeof(*md); 558 551 559 552 ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 560 553 561 554 } else { 562 - tunnel->parms.index = ntohl(index); 555 + tunnel->parms.index = ntohl(pkt_md->u.index); 563 556 ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error); 564 557 } 565 558 ··· 928 921 goto tx_err; 929 922 930 923 erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), 931 - ntohl(md->index), truncate, false); 924 + ntohl(md->u.index), truncate, false); 932 925 933 926 } else { 934 927 switch (skb->protocol) { ··· 1664 1657 1665 1658 tunnel->tun_hlen = 8; 1666 1659 tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1667 - sizeof(struct erspanhdr); 1660 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; 1668 1661 t_hlen = tunnel->hlen + sizeof(struct ipv6hdr); 1669 1662 1670 1663 dev->hard_header_len = LL_MAX_HEADER + t_hlen;
+4 -4
net/openvswitch/flow_netlink.c
··· 644 644 BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); 645 645 646 646 memset(&opts, 0, sizeof(opts)); 647 - opts.index = nla_get_be32(attr); 647 + opts.u.index = nla_get_be32(attr); 648 648 649 649 /* Index has only 20-bit */ 650 - if (ntohl(opts.index) & ~INDEX_MASK) { 650 + if (ntohl(opts.u.index) & ~INDEX_MASK) { 651 651 OVS_NLERR(log, "ERSPAN index number %x too large.", 652 - ntohl(opts.index)); 652 + ntohl(opts.u.index)); 653 653 return -EINVAL; 654 654 } 655 655 ··· 907 907 return -EMSGSIZE; 908 908 else if (output->tun_flags & TUNNEL_ERSPAN_OPT && 909 909 nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, 910 - ((struct erspan_metadata *)tun_opts)->index)) 910 + ((struct erspan_metadata *)tun_opts)->u.index)) 911 911 return -EMSGSIZE; 912 912 } 913 913