Skip to content

Commit ef7baf5

Browse files
williamtudavem330
authored andcommitted
ip6_gre: add ip6 erspan collect_md mode
Similar to ip6 gretap and ip4 gretap, the patch allows erspan tunnel to operate in collect metadata mode. bpf_skb_[gs]et_tunnel_key() helpers can make use of it right away. Signed-off-by: William Tu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 92425c4 commit ef7baf5

File tree

1 file changed

+85
-25
lines changed

1 file changed

+85
-25
lines changed

net/ipv6/ip6_gre.c

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,37 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
524524
false, false) < 0)
525525
return PACKET_REJECT;
526526

527-
tunnel->parms.index = ntohl(index);
528-
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
527+
if (tunnel->parms.collect_md) {
528+
struct metadata_dst *tun_dst;
529+
struct ip_tunnel_info *info;
530+
struct erspan_metadata *md;
531+
__be64 tun_id;
532+
__be16 flags;
533+
534+
tpi->flags |= TUNNEL_KEY;
535+
flags = tpi->flags;
536+
tun_id = key32_to_tunnel_id(tpi->key);
537+
538+
tun_dst = ipv6_tun_rx_dst(skb, flags, tun_id,
539+
sizeof(*md));
540+
if (!tun_dst)
541+
return PACKET_REJECT;
542+
543+
info = &tun_dst->u.tun_info;
544+
md = ip_tunnel_info_opts(info);
545+
if (!md)
546+
return PACKET_REJECT;
547+
548+
md->index = index;
549+
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
550+
info->options_len = sizeof(*md);
551+
552+
ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
553+
554+
} else {
555+
tunnel->parms.index = ntohl(index);
556+
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
557+
}
529558

530559
return PACKET_RCVD;
531560
}
@@ -857,42 +886,73 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
857886
if (gre_handle_offloads(skb, false))
858887
goto tx_err;
859888

860-
switch (skb->protocol) {
861-
case htons(ETH_P_IP):
862-
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
863-
prepare_ip6gre_xmit_ipv4(skb, dev, &fl6,
864-
&dsfield, &encap_limit);
865-
break;
866-
case htons(ETH_P_IPV6):
867-
if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
868-
goto tx_err;
869-
if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6,
870-
&dsfield, &encap_limit))
871-
goto tx_err;
872-
break;
873-
default:
874-
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
875-
break;
876-
}
877-
878889
if (skb->len > dev->mtu + dev->hard_header_len) {
879890
pskb_trim(skb, dev->mtu + dev->hard_header_len);
880891
truncate = true;
881892
}
882893

883-
erspan_build_header(skb, t->parms.o_key, t->parms.index,
884-
truncate, false);
885894
t->parms.o_flags &= ~TUNNEL_KEY;
886-
887895
IPCB(skb)->flags = 0;
888-
fl6.daddr = t->parms.raddr;
896+
897+
/* For collect_md mode, derive fl6 from the tunnel key,
898+
* for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}.
899+
*/
900+
if (t->parms.collect_md) {
901+
struct ip_tunnel_info *tun_info;
902+
const struct ip_tunnel_key *key;
903+
struct erspan_metadata *md;
904+
905+
tun_info = skb_tunnel_info(skb);
906+
if (unlikely(!tun_info ||
907+
!(tun_info->mode & IP_TUNNEL_INFO_TX) ||
908+
ip_tunnel_info_af(tun_info) != AF_INET6))
909+
return -EINVAL;
910+
911+
key = &tun_info->key;
912+
memset(&fl6, 0, sizeof(fl6));
913+
fl6.flowi6_proto = IPPROTO_GRE;
914+
fl6.daddr = key->u.ipv6.dst;
915+
fl6.flowlabel = key->label;
916+
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
917+
918+
dsfield = key->tos;
919+
md = ip_tunnel_info_opts(tun_info);
920+
if (!md)
921+
goto tx_err;
922+
923+
erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
924+
ntohl(md->index), truncate, false);
925+
926+
} else {
927+
switch (skb->protocol) {
928+
case htons(ETH_P_IP):
929+
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
930+
prepare_ip6gre_xmit_ipv4(skb, dev, &fl6,
931+
&dsfield, &encap_limit);
932+
break;
933+
case htons(ETH_P_IPV6):
934+
if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
935+
goto tx_err;
936+
if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6,
937+
&dsfield, &encap_limit))
938+
goto tx_err;
939+
break;
940+
default:
941+
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
942+
break;
943+
}
944+
945+
erspan_build_header(skb, t->parms.o_key, t->parms.index,
946+
truncate, false);
947+
fl6.daddr = t->parms.raddr;
948+
}
889949

890950
/* Push GRE header. */
891951
gre_build_header(skb, 8, TUNNEL_SEQ,
892952
htons(ETH_P_ERSPAN), 0, htonl(t->o_seqno++));
893953

894954
/* TooBig packet may have updated dst->dev's mtu */
895-
if (dst && dst_mtu(dst) > dst->dev->mtu)
955+
if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu)
896956
dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu);
897957

898958
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,

0 commit comments

Comments
 (0)