netfilter: flowtable: Support GRE
authorToshiaki Makita <toshiaki.makita1@gmail.com>
Fri, 25 Feb 2022 01:53:07 +0000 (10:53 +0900)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 3 Mar 2022 14:20:51 +0000 (15:20 +0100)
Support GREv0 without NAT.

Signed-off-by: Toshiaki Makita <toshiaki.makita1@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nft_flow_offload.c

index b90eca7a2f22bf8f4f6e4eced7650017c70c041d..e66a375075c97f9a3971d24d87609e675d5a22f3 100644 (file)
@@ -39,8 +39,14 @@ flow_offload_fill_dir(struct flow_offload *flow,
 
        ft->l3proto = ctt->src.l3num;
        ft->l4proto = ctt->dst.protonum;
-       ft->src_port = ctt->src.u.tcp.port;
-       ft->dst_port = ctt->dst.u.tcp.port;
+
+       switch (ctt->dst.protonum) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               ft->src_port = ctt->src.u.tcp.port;
+               ft->dst_port = ctt->dst.u.tcp.port;
+               break;
+       }
 }
 
 struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
index 889cf88d3dba6e10c9efa823d10287bc1eee9576..6e9cacf694dedceac0a02843257345226660b202 100644 (file)
@@ -172,6 +172,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
        struct flow_ports *ports;
        unsigned int thoff;
        struct iphdr *iph;
+       u8 ipproto;
 
        if (!pskb_may_pull(skb, sizeof(*iph) + offset))
                return -1;
@@ -185,13 +186,19 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
 
        thoff += offset;
 
-       switch (iph->protocol) {
+       ipproto = iph->protocol;
+       switch (ipproto) {
        case IPPROTO_TCP:
                *hdrsize = sizeof(struct tcphdr);
                break;
        case IPPROTO_UDP:
                *hdrsize = sizeof(struct udphdr);
                break;
+#ifdef CONFIG_NF_CT_PROTO_GRE
+       case IPPROTO_GRE:
+               *hdrsize = sizeof(struct gre_base_hdr);
+               break;
+#endif
        default:
                return -1;
        }
@@ -202,15 +209,29 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
        if (!pskb_may_pull(skb, thoff + *hdrsize))
                return -1;
 
+       switch (ipproto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
+               tuple->src_port         = ports->source;
+               tuple->dst_port         = ports->dest;
+               break;
+       case IPPROTO_GRE: {
+               struct gre_base_hdr *greh;
+
+               greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
+               if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
+                       return -1;
+               break;
+       }
+       }
+
        iph = (struct iphdr *)(skb_network_header(skb) + offset);
-       ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
 
        tuple->src_v4.s_addr    = iph->saddr;
        tuple->dst_v4.s_addr    = iph->daddr;
-       tuple->src_port         = ports->source;
-       tuple->dst_port         = ports->dest;
        tuple->l3proto          = AF_INET;
-       tuple->l4proto          = iph->protocol;
+       tuple->l4proto          = ipproto;
        tuple->iifidx           = dev->ifindex;
        nf_flow_tuple_encap(skb, tuple);
 
@@ -521,6 +542,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
        struct flow_ports *ports;
        struct ipv6hdr *ip6h;
        unsigned int thoff;
+       u8 nexthdr;
 
        thoff = sizeof(*ip6h) + offset;
        if (!pskb_may_pull(skb, thoff))
@@ -528,13 +550,19 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
 
        ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
 
-       switch (ip6h->nexthdr) {
+       nexthdr = ip6h->nexthdr;
+       switch (nexthdr) {
        case IPPROTO_TCP:
                *hdrsize = sizeof(struct tcphdr);
                break;
        case IPPROTO_UDP:
                *hdrsize = sizeof(struct udphdr);
                break;
+#ifdef CONFIG_NF_CT_PROTO_GRE
+       case IPPROTO_GRE:
+               *hdrsize = sizeof(struct gre_base_hdr);
+               break;
+#endif
        default:
                return -1;
        }
@@ -545,15 +573,29 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
        if (!pskb_may_pull(skb, thoff + *hdrsize))
                return -1;
 
+       switch (nexthdr) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
+               tuple->src_port         = ports->source;
+               tuple->dst_port         = ports->dest;
+               break;
+       case IPPROTO_GRE: {
+               struct gre_base_hdr *greh;
+
+               greh = (struct gre_base_hdr *)(skb_network_header(skb) + thoff);
+               if ((greh->flags & GRE_VERSION) != GRE_VERSION_0)
+                       return -1;
+               break;
+       }
+       }
+
        ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
-       ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
 
        tuple->src_v6           = ip6h->saddr;
        tuple->dst_v6           = ip6h->daddr;
-       tuple->src_port         = ports->source;
-       tuple->dst_port         = ports->dest;
        tuple->l3proto          = AF_INET6;
-       tuple->l4proto          = ip6h->nexthdr;
+       tuple->l4proto          = nexthdr;
        tuple->iifidx           = dev->ifindex;
        nf_flow_tuple_encap(skb, tuple);
 
index b561e0a44a45f36392611d6ed4b94c34f920e29f..99f6db3757ad2b03878ca1b5a9dbc2099f107c92 100644 (file)
@@ -170,6 +170,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
                match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
                break;
        case IPPROTO_UDP:
+       case IPPROTO_GRE:
                break;
        default:
                return -EOPNOTSUPP;
@@ -178,15 +179,22 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
        key->basic.ip_proto = tuple->l4proto;
        mask->basic.ip_proto = 0xff;
 
-       key->tp.src = tuple->src_port;
-       mask->tp.src = 0xffff;
-       key->tp.dst = tuple->dst_port;
-       mask->tp.dst = 0xffff;
-
        match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
                                      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
-                                     BIT(FLOW_DISSECTOR_KEY_BASIC) |
-                                     BIT(FLOW_DISSECTOR_KEY_PORTS);
+                                     BIT(FLOW_DISSECTOR_KEY_BASIC);
+
+       switch (tuple->l4proto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               key->tp.src = tuple->src_port;
+               mask->tp.src = 0xffff;
+               key->tp.dst = tuple->dst_port;
+               mask->tp.dst = 0xffff;
+
+               match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
+               break;
+       }
+
        return 0;
 }
 
index 0af34ad4147966f443c80ce92a36bd16d5e83fea..731b5d87ef453c8fb75e28ba4f0d0c0ec88caf38 100644 (file)
@@ -298,6 +298,19 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
                break;
        case IPPROTO_UDP:
                break;
+#ifdef CONFIG_NF_CT_PROTO_GRE
+       case IPPROTO_GRE: {
+               struct nf_conntrack_tuple *tuple;
+
+               if (ct->status & IPS_NAT_MASK)
+                       goto out;
+               tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+               /* No support for GRE v1 */
+               if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
+                       goto out;
+               break;
+       }
+#endif
        default:
                goto out;
        }