gre: add sequence number for collect md mode.
authorWilliam Tu <u9012063@gmail.com>
Thu, 1 Mar 2018 21:49:57 +0000 (13:49 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 4 Mar 2018 23:35:02 +0000 (18:35 -0500)
Currently GRE sequence number can only be used in native
tunnel mode.  This patch adds sequence number support for
gre collect metadata mode.  RFC2890 defines GRE sequence
number to be specific to the traffic flow identified by the
key.  However, this patch does not implement per-key seqno.
The sequence number is shared in the same tunnel device.
That is, different tunnel keys using the same collect_md
tunnel share single sequence number.

Signed-off-by: William Tu <u9012063@gmail.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/bpf.h
net/core/filter.c
net/ipv4/ip_gre.c
net/ipv6/ip6_gre.c

index db6bdc3751268351da3126f57566639fce355b12..2a66769e58753f802c5f2df8c92d131e0ed5edd9 100644 (file)
@@ -800,6 +800,7 @@ enum bpf_func_id {
 /* BPF_FUNC_skb_set_tunnel_key flags. */
 #define BPF_F_ZERO_CSUM_TX             (1ULL << 1)
 #define BPF_F_DONT_FRAGMENT            (1ULL << 2)
+#define BPF_F_SEQ_NUMBER               (1ULL << 3)
 
 /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
  * BPF_FUNC_perf_event_read_value flags.
index 0c121adbdbaaac5ed1f48a8e618cc0a2af2039d6..33edfa8372fd5e011f2b67df4039c21c46ca2448 100644 (file)
@@ -2991,7 +2991,7 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb,
        struct ip_tunnel_info *info;
 
        if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX |
-                              BPF_F_DONT_FRAGMENT)))
+                              BPF_F_DONT_FRAGMENT | BPF_F_SEQ_NUMBER)))
                return -EINVAL;
        if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
                switch (size) {
@@ -3025,6 +3025,8 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb,
                info->key.tun_flags |= TUNNEL_DONT_FRAGMENT;
        if (flags & BPF_F_ZERO_CSUM_TX)
                info->key.tun_flags &= ~TUNNEL_CSUM;
+       if (flags & BPF_F_SEQ_NUMBER)
+               info->key.tun_flags |= TUNNEL_SEQ;
 
        info->key.tun_id = cpu_to_be64(from->tunnel_id);
        info->key.tos = from->tunnel_tos;
index 0fe1d69b5df41e6470b2aa8997bf0bc979afbe4f..95fd225f402e746b83945c617089abefae9b16e0 100644 (file)
@@ -522,6 +522,7 @@ err_free_skb:
 static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
                        __be16 proto)
 {
+       struct ip_tunnel *tunnel = netdev_priv(dev);
        struct ip_tunnel_info *tun_info;
        const struct ip_tunnel_key *key;
        struct rtable *rt = NULL;
@@ -545,9 +546,11 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
        if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
                goto err_free_rt;
 
-       flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
+       flags = tun_info->key.tun_flags &
+               (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
        gre_build_header(skb, tunnel_hlen, flags, proto,
-                        tunnel_id_to_key32(tun_info->key.tun_id), 0);
+                        tunnel_id_to_key32(tun_info->key.tun_id),
+                        (flags | TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) : 0);
 
        df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
 
index 83c7766c8c756eefa4bcf138272d0be78f100ea5..18a3dfbd0300dae769fb67aabe8ff0ff3a831e93 100644 (file)
@@ -695,9 +695,6 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
        else
                fl6->daddr = tunnel->parms.raddr;
 
-       if (tunnel->parms.o_flags & TUNNEL_SEQ)
-               tunnel->o_seqno++;
-
        /* Push GRE header. */
        protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
 
@@ -720,14 +717,20 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
                fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
 
                dsfield = key->tos;
-               flags = key->tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
+               flags = key->tun_flags &
+                       (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
                tunnel->tun_hlen = gre_calc_hlen(flags);
 
                gre_build_header(skb, tunnel->tun_hlen,
                                 flags, protocol,
-                                tunnel_id_to_key32(tun_info->key.tun_id), 0);
+                                tunnel_id_to_key32(tun_info->key.tun_id),
+                                (flags | TUNNEL_SEQ) ? htonl(tunnel->o_seqno++)
+                                                     : 0);
 
        } else {
+               if (tunnel->parms.o_flags & TUNNEL_SEQ)
+                       tunnel->o_seqno++;
+
                gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
                                 protocol, tunnel->parms.o_key,
                                 htonl(tunnel->o_seqno));