xfrm: use gre key as flow upper protocol info
Timo Teräs [Wed, 3 Nov 2010 04:41:38 +0000 (04:41 +0000)]
The GRE Key field is intended to be used for identifying an individual
traffic flow within a tunnel. It is useful to be able to have XFRM
policy selector matches to have different policies for different
GRE tunnels.

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/net/flow.h
include/net/xfrm.h
net/ipv4/ip_gre.c
net/ipv4/xfrm4_policy.c

index 0ac3fb5..7196e68 100644 (file)
@@ -67,6 +67,7 @@ struct flowi {
                } dnports;
 
                __be32          spi;
+               __be32          gre_key;
 
                struct {
                        __u8    type;
@@ -78,6 +79,7 @@ struct flowi {
 #define fl_icmp_code   uli_u.icmpt.code
 #define fl_ipsec_spi   uli_u.spi
 #define fl_mh_type     uli_u.mht.type
+#define fl_gre_key     uli_u.gre_key
        __u32           secid;  /* used by xfrm; see secid.txt */
 } __attribute__((__aligned__(BITS_PER_LONG/8)));
 
index bcfb6b2..54b2832 100644 (file)
@@ -805,6 +805,9 @@ __be16 xfrm_flowi_sport(struct flowi *fl)
        case IPPROTO_MH:
                port = htons(fl->fl_mh_type);
                break;
+       case IPPROTO_GRE:
+               port = htonl(fl->fl_gre_key) >> 16;
+               break;
        default:
                port = 0;       /*XXX*/
        }
@@ -826,6 +829,9 @@ __be16 xfrm_flowi_dport(struct flowi *fl)
        case IPPROTO_ICMPV6:
                port = htons(fl->fl_icmp_code);
                break;
+       case IPPROTO_GRE:
+               port = htonl(fl->fl_gre_key) & 0xffff;
+               break;
        default:
                port = 0;       /*XXX*/
        }
index cab2057..aace653 100644 (file)
@@ -779,9 +779,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                                        .tos = RT_TOS(tos)
                                }
                        },
-                       .proto = IPPROTO_GRE
-               }
-;
+                       .proto = IPPROTO_GRE,
+                       .fl_gre_key = tunnel->parms.o_key
+               };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
                        dev->stats.tx_carrier_errors++;
                        goto tx_error;
@@ -958,7 +958,8 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
                                        .tos = RT_TOS(iph->tos)
                                }
                        },
-                       .proto = IPPROTO_GRE
+                       .proto = IPPROTO_GRE,
+                       .fl_gre_key = tunnel->parms.o_key
                };
                struct rtable *rt;
 
@@ -1223,7 +1224,8 @@ static int ipgre_open(struct net_device *dev)
                                        .tos = RT_TOS(t->parms.iph.tos)
                                }
                        },
-                       .proto = IPPROTO_GRE
+                       .proto = IPPROTO_GRE,
+                       .fl_gre_key = t->parms.o_key
                };
                struct rtable *rt;
 
index dd1fd8c..4a8c533 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/inetdevice.h>
+#include <linux/if_tunnel.h>
 #include <net/dst.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
@@ -154,6 +155,20 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                                fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
                        }
                        break;
+
+               case IPPROTO_GRE:
+                       if (pskb_may_pull(skb, xprth + 12 - skb->data)) {
+                               __be16 *greflags = (__be16 *)xprth;
+                               __be32 *gre_hdr = (__be32 *)xprth;
+
+                               if (greflags[0] & GRE_KEY) {
+                                       if (greflags[0] & GRE_CSUM)
+                                               gre_hdr++;
+                                       fl->fl_gre_key = gre_hdr[1];
+                               }
+                       }
+                       break;
+
                default:
                        fl->fl_ipsec_spi = 0;
                        break;