Merge branch 'lwt-ipv6'
authorDavid S. Miller <davem@davemloft.net>
Thu, 20 Aug 2015 22:42:38 +0000 (15:42 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 20 Aug 2015 22:42:38 +0000 (15:42 -0700)
Jiri Benc says:

====================
lwtunnel: per route ipv6 support for vxlan

v3: Moved LWTUNNEL_ENCAP_IP6 definition in patch 13.
v2: Fixed issues in patch 4 pointed out by Alexei.

This series enables IPv6 tunnels based on lwtunnel infrastructure. Only
vxlan is supported for now.

Tested in all combinations of IPv4 over IPv6, IPv6 over IPv4 and IPv6 over
IPv6.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
30 files changed:
drivers/net/vrf.c
drivers/net/vxlan.c
include/net/dst.h
include/net/dst_metadata.h
include/net/flow.h
include/net/ip6_fib.h
include/net/ip_tunnels.h
include/net/lwtunnel.h
include/net/ndisc.h
include/net/route.h
include/net/vxlan.h
include/uapi/linux/lwtunnel.h
net/core/dst.c
net/core/filter.c
net/core/lwtunnel.c
net/ipv4/ip_gre.c
net/ipv4/ip_tunnel_core.c
net/ipv4/route.c
net/ipv6/addrconf.c
net/ipv6/ila.c
net/ipv6/ip6_fib.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/mpls/mpls_iptunnel.c
net/openvswitch/flow_netlink.c
net/openvswitch/flow_table.c
net/openvswitch/vport-geneve.c
net/openvswitch/vport-netdev.c
net/openvswitch/vport.c
net/openvswitch/vport.h

index dbeffe7..b3d9c55 100644 (file)
@@ -295,7 +295,6 @@ static struct rtable *vrf_rtable_create(struct net_device *dev)
                rth->rt_uses_gateway = 0;
                INIT_LIST_HEAD(&rth->rt_uncached);
                rth->rt_uncached_list = NULL;
-               rth->rt_lwtstate = NULL;
        }
 
        return rth;
index ad51dac..54615bb 100644 (file)
@@ -236,7 +236,7 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
 
        hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
                if (inet_sk(vs->sock->sk)->inet_sport == port &&
-                   inet_sk(vs->sock->sk)->sk.sk_family == family &&
+                   vxlan_get_sk_family(vs) == family &&
                    vs->flags == flags)
                        return vs;
        }
@@ -625,7 +625,7 @@ static void vxlan_notify_add_rx_port(struct vxlan_sock *vs)
        struct net_device *dev;
        struct sock *sk = vs->sock->sk;
        struct net *net = sock_net(sk);
-       sa_family_t sa_family = sk->sk_family;
+       sa_family_t sa_family = vxlan_get_sk_family(vs);
        __be16 port = inet_sk(sk)->inet_sport;
        int err;
 
@@ -650,7 +650,7 @@ static void vxlan_notify_del_rx_port(struct vxlan_sock *vs)
        struct net_device *dev;
        struct sock *sk = vs->sock->sk;
        struct net *net = sock_net(sk);
-       sa_family_t sa_family = sk->sk_family;
+       sa_family_t sa_family = vxlan_get_sk_family(vs);
        __be16 port = inet_sk(sk)->inet_sport;
 
        rcu_read_lock();
@@ -1269,17 +1269,27 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        }
 
        if (vxlan_collect_metadata(vs)) {
-               const struct iphdr *iph = ip_hdr(skb);
-
                tun_dst = metadata_dst_alloc(sizeof(*md), GFP_ATOMIC);
                if (!tun_dst)
                        goto drop;
 
                info = &tun_dst->u.tun_info;
-               info->key.ipv4_src = iph->saddr;
-               info->key.ipv4_dst = iph->daddr;
-               info->key.ipv4_tos = iph->tos;
-               info->key.ipv4_ttl = iph->ttl;
+               if (vxlan_get_sk_family(vs) == AF_INET) {
+                       const struct iphdr *iph = ip_hdr(skb);
+
+                       info->key.u.ipv4.src = iph->saddr;
+                       info->key.u.ipv4.dst = iph->daddr;
+                       info->key.tos = iph->tos;
+                       info->key.ttl = iph->ttl;
+               } else {
+                       const struct ipv6hdr *ip6h = ipv6_hdr(skb);
+
+                       info->key.u.ipv6.src = ip6h->saddr;
+                       info->key.u.ipv6.dst = ip6h->daddr;
+                       info->key.tos = ipv6_get_dsfield(ip6h);
+                       info->key.ttl = ip6h->hop_limit;
+               }
+
                info->key.tp_src = udp_hdr(skb)->source;
                info->key.tp_dst = udp_hdr(skb)->dest;
 
@@ -1894,6 +1904,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        struct ip_tunnel_info *info;
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct sock *sk = vxlan->vn_sock->sock->sk;
+       unsigned short family = vxlan_get_sk_family(vxlan->vn_sock);
        struct rtable *rt = NULL;
        const struct iphdr *old_iph;
        struct flowi4 fl4;
@@ -1908,8 +1919,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        int err;
        u32 flags = vxlan->flags;
 
-       /* FIXME: Support IPv6 */
-       info = skb_tunnel_info(skb, AF_INET);
+       info = skb_tunnel_info(skb);
 
        if (rdst) {
                dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
@@ -1924,8 +1934,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 
                dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
                vni = be64_to_cpu(info->key.tun_id);
-               remote_ip.sin.sin_family = AF_INET;
-               remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst;
+               remote_ip.sa.sa_family = family;
+               if (family == AF_INET)
+                       remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst;
+               else
+                       remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
                dst = &remote_ip;
        }
 
@@ -1951,23 +1964,24 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
                                     vxlan->cfg.port_max, true);
 
+       if (info) {
+               if (info->key.tun_flags & TUNNEL_CSUM)
+                       flags |= VXLAN_F_UDP_CSUM;
+               else
+                       flags &= ~VXLAN_F_UDP_CSUM;
+
+               ttl = info->key.ttl;
+               tos = info->key.tos;
+
+               if (info->options_len)
+                       md = ip_tunnel_info_opts(info, sizeof(*md));
+       } else {
+               md->gbp = skb->mark;
+       }
+
        if (dst->sa.sa_family == AF_INET) {
-               if (info) {
-                       if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
-                               df = htons(IP_DF);
-                       if (info->key.tun_flags & TUNNEL_CSUM)
-                               flags |= VXLAN_F_UDP_CSUM;
-                       else
-                               flags &= ~VXLAN_F_UDP_CSUM;
-
-                       ttl = info->key.ipv4_ttl;
-                       tos = info->key.ipv4_tos;
-
-                       if (info->options_len)
-                               md = ip_tunnel_info_opts(info, sizeof(*md));
-               } else {
-                       md->gbp = skb->mark;
-               }
+               if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT))
+                       df = htons(IP_DF);
 
                memset(&fl4, 0, sizeof(fl4));
                fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0;
@@ -2025,7 +2039,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        } else {
                struct dst_entry *ndst;
                struct flowi6 fl6;
-               u32 flags;
+               u32 rt6i_flags;
 
                memset(&fl6, 0, sizeof(fl6));
                fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0;
@@ -2050,9 +2064,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                }
 
                /* Bypass encapsulation if the destination is local */
-               flags = ((struct rt6_info *)ndst)->rt6i_flags;
-               if (flags & RTF_LOCAL &&
-                   !(flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
+               rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
+               if (rt6i_flags & RTF_LOCAL &&
+                   !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
                        struct vxlan_dev *dst_vxlan;
 
                        dst_release(ndst);
@@ -2066,12 +2080,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                }
 
                ttl = ttl ? : ip6_dst_hoplimit(ndst);
-               md->gbp = skb->mark;
-
                err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr,
                                      0, ttl, src_port, dst_port, htonl(vni << 8), md,
                                      !net_eq(vxlan->net, dev_net(vxlan->dev)),
-                                     vxlan->flags);
+                                     flags);
 #endif
        }
 
@@ -2104,8 +2116,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
        struct vxlan_rdst *rdst, *fdst = NULL;
        struct vxlan_fdb *f;
 
-       /* FIXME: Support IPv6 */
-       info = skb_tunnel_info(skb, AF_INET);
+       info = skb_tunnel_info(skb);
 
        skb_reset_mac_header(skb);
        eth = eth_hdr(skb);
@@ -2390,7 +2401,7 @@ void vxlan_get_rx_port(struct net_device *dev)
        for (i = 0; i < PORT_HASH_SIZE; ++i) {
                hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
                        port = inet_sk(vs->sock->sk)->inet_sport;
-                       sa_family = vs->sock->sk->sk_family;
+                       sa_family = vxlan_get_sk_family(vs);
                        dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
                                                            port);
                }
index 2578811..0a9a723 100644 (file)
@@ -44,6 +44,7 @@ struct dst_entry {
 #else
        void                    *__pad1;
 #endif
+       struct lwtunnel_state   *lwtstate;
        int                     (*input)(struct sk_buff *);
        int                     (*output)(struct sock *sk, struct sk_buff *skb);
 
@@ -89,7 +90,7 @@ struct dst_entry {
         * (L1_CACHE_SIZE would be too much)
         */
 #ifdef CONFIG_64BIT
-       long                    __pad_to_align_refcnt[2];
+       long                    __pad_to_align_refcnt[1];
 #endif
        /*
         * __refcnt wants to be on a different cache line from
index 075f523..2cb52d5 100644 (file)
@@ -23,22 +23,17 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb)
        return NULL;
 }
 
-static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb,
-                                                    int family)
+static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb)
 {
        struct metadata_dst *md_dst = skb_metadata_dst(skb);
-       struct rtable *rt;
+       struct dst_entry *dst;
 
        if (md_dst)
                return &md_dst->u.tun_info;
 
-       switch (family) {
-       case AF_INET:
-               rt = (struct rtable *)skb_dst(skb);
-               if (rt && rt->rt_lwtstate)
-                       return lwt_tun_info(rt->rt_lwtstate);
-               break;
-       }
+       dst = skb_dst(skb);
+       if (dst && dst->lwtstate)
+               return lwt_tun_info(dst->lwtstate);
 
        return NULL;
 }
index f305588..9e0297c 100644 (file)
@@ -130,6 +130,7 @@ struct flowi6 {
 #define flowi6_proto           __fl_common.flowic_proto
 #define flowi6_flags           __fl_common.flowic_flags
 #define flowi6_secid           __fl_common.flowic_secid
+#define flowi6_tun_key         __fl_common.flowic_tun_key
        struct in6_addr         daddr;
        struct in6_addr         saddr;
        __be32                  flowlabel;
index 276328e..063d304 100644 (file)
@@ -133,7 +133,6 @@ struct rt6_info {
        /* more non-fragment space at head required */
        unsigned short                  rt6i_nfheader_len;
        u8                              rt6i_protocol;
-       struct lwtunnel_state           *rt6i_lwtstate;
 };
 
 static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
index 984dbfa..224e4ec 100644 (file)
 #define IPTUNNEL_ERR_TIMEO     (30*HZ)
 
 /* Used to memset ip_tunnel padding. */
-#define IP_TUNNEL_KEY_SIZE                                     \
-       (offsetof(struct ip_tunnel_key, tp_dst) +               \
-        FIELD_SIZEOF(struct ip_tunnel_key, tp_dst))
+#define IP_TUNNEL_KEY_SIZE     offsetofend(struct ip_tunnel_key, tp_dst)
+
+/* Used to memset ipv4 address padding. */
+#define IP_TUNNEL_KEY_IPV4_PAD offsetofend(struct ip_tunnel_key, u.ipv4.dst)
+#define IP_TUNNEL_KEY_IPV4_PAD_LEN                             \
+       (FIELD_SIZEOF(struct ip_tunnel_key, u) -                \
+        FIELD_SIZEOF(struct ip_tunnel_key, u.ipv4))
 
 struct ip_tunnel_key {
        __be64                  tun_id;
-       __be32                  ipv4_src;
-       __be32                  ipv4_dst;
+       union {
+               struct {
+                       __be32  src;
+                       __be32  dst;
+               } ipv4;
+               struct {
+                       struct in6_addr src;
+                       struct in6_addr dst;
+               } ipv6;
+       } u;
        __be16                  tun_flags;
-       __u8                    ipv4_tos;
-       __u8                    ipv4_ttl;
+       u8                      tos;            /* TOS for IPv4, TC for IPv6 */
+       u8                      ttl;            /* TTL for IPv4, HL for IPv6 */
        __be16                  tp_src;
        __be16                  tp_dst;
-} __packed __aligned(4); /* Minimize padding. */
+};
 
 /* Indicates whether the tunnel info structure represents receive
  * or transmit tunnel parameters.
@@ -64,8 +76,8 @@ struct ip_tunnel_6rd_parm {
 #endif
 
 struct ip_tunnel_encap {
-       __u16                   type;
-       __u16                   flags;
+       u16                     type;
+       u16                     flags;
        __be16                  sport;
        __be16                  dport;
 };
@@ -95,8 +107,8 @@ struct ip_tunnel {
                                         * arrived */
 
        /* These four fields used only by GRE */
-       __u32           i_seqno;        /* The last seen seqno  */
-       __u32           o_seqno;        /* The last output seqno */
+       u32             i_seqno;        /* The last seen seqno  */
+       u32             o_seqno;        /* The last output seqno */
        int             tun_hlen;       /* Precalculated header length */
        int             mlink;
 
@@ -179,10 +191,12 @@ static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
                                         const void *opts, u8 opts_len)
 {
        tun_info->key.tun_id = tun_id;
-       tun_info->key.ipv4_src = saddr;
-       tun_info->key.ipv4_dst = daddr;
-       tun_info->key.ipv4_tos = tos;
-       tun_info->key.ipv4_ttl = ttl;
+       tun_info->key.u.ipv4.src = saddr;
+       tun_info->key.u.ipv4.dst = daddr;
+       memset((unsigned char *)&tun_info->key + IP_TUNNEL_KEY_IPV4_PAD,
+              0, IP_TUNNEL_KEY_IPV4_PAD_LEN);
+       tun_info->key.tos = tos;
+       tun_info->key.ttl = ttl;
        tun_info->key.tun_flags = tun_flags;
 
        /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
@@ -273,8 +287,8 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
 
 int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto);
 int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
-                 __be32 src, __be32 dst, __u8 proto,
-                 __u8 tos, __u8 ttl, __be16 df, bool xnet);
+                 __be32 src, __be32 dst, u8 proto,
+                 u8 tos, u8 ttl, __be16 df, bool xnet);
 
 struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum,
                                         int gso_type_mask);
index cfee539..8434898 100644 (file)
@@ -87,9 +87,7 @@ int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
 struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
 int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
 int lwtunnel_output(struct sock *sk, struct sk_buff *skb);
-int lwtunnel_output6(struct sock *sk, struct sk_buff *skb);
 int lwtunnel_input(struct sk_buff *skb);
-int lwtunnel_input6(struct sk_buff *skb);
 
 #else
 
@@ -164,21 +162,11 @@ static inline int lwtunnel_output(struct sock *sk, struct sk_buff *skb)
        return -EOPNOTSUPP;
 }
 
-static inline int lwtunnel_output6(struct sock *sk, struct sk_buff *skb)
-{
-       return -EOPNOTSUPP;
-}
-
 static inline int lwtunnel_input(struct sk_buff *skb)
 {
        return -EOPNOTSUPP;
 }
 
-static inline int lwtunnel_input6(struct sk_buff *skb)
-{
-       return -EOPNOTSUPP;
-}
-
 #endif
 
 #endif /* __NET_LWTUNNEL_H */
index b3a7751..aba5695 100644 (file)
@@ -182,7 +182,8 @@ int ndisc_rcv(struct sk_buff *skb);
 
 void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                   const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr);
+                  const struct in6_addr *daddr, const struct in6_addr *saddr,
+                  struct sk_buff *oskb);
 
 void ndisc_send_rs(struct net_device *dev,
                   const struct in6_addr *saddr, const struct in6_addr *daddr);
index 6dda2c1..395d79b 100644 (file)
@@ -66,7 +66,6 @@ struct rtable {
 
        struct list_head        rt_uncached;
        struct uncached_list    *rt_uncached_list;
-       struct lwtunnel_state   *rt_lwtstate;
 };
 
 static inline bool rt_is_input_route(const struct rtable *rt)
index e4534f1..43677e6 100644 (file)
@@ -241,3 +241,8 @@ static inline void vxlan_get_rx_port(struct net_device *netdev)
 }
 #endif
 #endif
+
+static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs)
+{
+       return vs->sock->sk->sk_family;
+}
index aa84ca3..34141a5 100644 (file)
@@ -8,6 +8,7 @@ enum lwtunnel_encap_types {
        LWTUNNEL_ENCAP_MPLS,
        LWTUNNEL_ENCAP_IP,
        LWTUNNEL_ENCAP_ILA,
+       LWTUNNEL_ENCAP_IP6,
        __LWTUNNEL_ENCAP_MAX,
 };
 
@@ -28,4 +29,19 @@ enum lwtunnel_ip_t {
 
 #define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1)
 
+enum lwtunnel_ip6_t {
+       LWTUNNEL_IP6_UNSPEC,
+       LWTUNNEL_IP6_ID,
+       LWTUNNEL_IP6_DST,
+       LWTUNNEL_IP6_SRC,
+       LWTUNNEL_IP6_HOPLIMIT,
+       LWTUNNEL_IP6_TC,
+       LWTUNNEL_IP6_SPORT,
+       LWTUNNEL_IP6_DPORT,
+       LWTUNNEL_IP6_FLAGS,
+       __LWTUNNEL_IP6_MAX,
+};
+
+#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1)
+
 #endif /* _UAPI_LWTUNNEL_H_ */
index f8694d1..50dcdbb 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/net_namespace.h>
 #include <linux/sched.h>
 #include <linux/prefetch.h>
+#include <net/lwtunnel.h>
 
 #include <net/dst.h>
 #include <net/dst_metadata.h>
@@ -184,6 +185,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
 #ifdef CONFIG_IP_ROUTE_CLASSID
        dst->tclassid = 0;
 #endif
+       dst->lwtstate = NULL;
        atomic_set(&dst->__refcnt, initial_ref);
        dst->__use = 0;
        dst->lastuse = jiffies;
@@ -264,6 +266,7 @@ again:
                kfree(dst);
        else
                kmem_cache_free(dst->ops->kmem_cachep, dst);
+       lwtstate_put(dst->lwtstate);
 
        dst = child;
        if (dst) {
index 83f08ce..b4adc96 100644 (file)
@@ -1489,13 +1489,13 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
 {
        struct sk_buff *skb = (struct sk_buff *) (long) r1;
        struct bpf_tunnel_key *to = (struct bpf_tunnel_key *) (long) r2;
-       struct ip_tunnel_info *info = skb_tunnel_info(skb, AF_INET);
+       struct ip_tunnel_info *info = skb_tunnel_info(skb);
 
        if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info))
                return -EINVAL;
 
        to->tunnel_id = be64_to_cpu(info->key.tun_id);
-       to->remote_ipv4 = be32_to_cpu(info->key.ipv4_src);
+       to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
 
        return 0;
 }
@@ -1529,7 +1529,7 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        info = &md->u.tun_info;
        info->mode = IP_TUNNEL_INFO_TX;
        info->key.tun_id = cpu_to_be64(from->tunnel_id);
-       info->key.ipv4_dst = cpu_to_be32(from->remote_ipv4);
+       info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4);
 
        return 0;
 }
index 3331585..e924c2e 100644 (file)
@@ -179,14 +179,16 @@ int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
 }
 EXPORT_SYMBOL(lwtunnel_cmp_encap);
 
-int __lwtunnel_output(struct sock *sk, struct sk_buff *skb,
-                     struct lwtunnel_state *lwtstate)
+int lwtunnel_output(struct sock *sk, struct sk_buff *skb)
 {
+       struct dst_entry *dst = skb_dst(skb);
        const struct lwtunnel_encap_ops *ops;
+       struct lwtunnel_state *lwtstate;
        int ret = -EINVAL;
 
-       if (!lwtstate)
+       if (!dst)
                goto drop;
+       lwtstate = dst->lwtstate;
 
        if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
            lwtstate->type > LWTUNNEL_ENCAP_MAX)
@@ -209,47 +211,18 @@ drop:
 
        return ret;
 }
-
-int lwtunnel_output6(struct sock *sk, struct sk_buff *skb)
-{
-       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-       struct lwtunnel_state *lwtstate = NULL;
-
-       if (rt) {
-               lwtstate = rt->rt6i_lwtstate;
-               skb->dev = rt->dst.dev;
-       }
-
-       skb->protocol = htons(ETH_P_IPV6);
-
-       return __lwtunnel_output(sk, skb, lwtstate);
-}
-EXPORT_SYMBOL(lwtunnel_output6);
-
-int lwtunnel_output(struct sock *sk, struct sk_buff *skb)
-{
-       struct rtable *rt = (struct rtable *)skb_dst(skb);
-       struct lwtunnel_state *lwtstate = NULL;
-
-       if (rt) {
-               lwtstate = rt->rt_lwtstate;
-               skb->dev = rt->dst.dev;
-       }
-
-       skb->protocol = htons(ETH_P_IP);
-
-       return __lwtunnel_output(sk, skb, lwtstate);
-}
 EXPORT_SYMBOL(lwtunnel_output);
 
-int __lwtunnel_input(struct sk_buff *skb,
-                    struct lwtunnel_state *lwtstate)
+int lwtunnel_input(struct sk_buff *skb)
 {
+       struct dst_entry *dst = skb_dst(skb);
        const struct lwtunnel_encap_ops *ops;
+       struct lwtunnel_state *lwtstate;
        int ret = -EINVAL;
 
-       if (!lwtstate)
+       if (!dst)
                goto drop;
+       lwtstate = dst->lwtstate;
 
        if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
            lwtstate->type > LWTUNNEL_ENCAP_MAX)
@@ -272,27 +245,4 @@ drop:
 
        return ret;
 }
-
-int lwtunnel_input6(struct sk_buff *skb)
-{
-       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-       struct lwtunnel_state *lwtstate = NULL;
-
-       if (rt)
-               lwtstate = rt->rt6i_lwtstate;
-
-       return __lwtunnel_input(skb, lwtstate);
-}
-EXPORT_SYMBOL(lwtunnel_input6);
-
-int lwtunnel_input(struct sk_buff *skb)
-{
-       struct rtable *rt = (struct rtable *)skb_dst(skb);
-       struct lwtunnel_state *lwtstate = NULL;
-
-       if (rt)
-               lwtstate = rt->rt_lwtstate;
-
-       return __lwtunnel_input(skb, lwtstate);
-}
 EXPORT_SYMBOL(lwtunnel_input);
index fb44d69..1bf3281 100644 (file)
@@ -407,10 +407,10 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
                                return PACKET_REJECT;
 
                        info = &tun_dst->u.tun_info;
-                       info->key.ipv4_src = iph->saddr;
-                       info->key.ipv4_dst = iph->daddr;
-                       info->key.ipv4_tos = iph->tos;
-                       info->key.ipv4_ttl = iph->ttl;
+                       info->key.u.ipv4.src = iph->saddr;
+                       info->key.u.ipv4.dst = iph->daddr;
+                       info->key.tos = iph->tos;
+                       info->key.ttl = iph->ttl;
 
                        info->mode = IP_TUNNEL_INFO_RX;
                        info->key.tun_flags = tpi->flags &
@@ -521,15 +521,15 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
        __be16 df, flags;
        int err;
 
-       tun_info = skb_tunnel_info(skb, AF_INET);
+       tun_info = skb_tunnel_info(skb);
        if (unlikely(!tun_info || tun_info->mode != IP_TUNNEL_INFO_TX))
                goto err_free_skb;
 
        key = &tun_info->key;
        memset(&fl, 0, sizeof(fl));
-       fl.daddr = key->ipv4_dst;
-       fl.saddr = key->ipv4_src;
-       fl.flowi4_tos = RT_TOS(key->ipv4_tos);
+       fl.daddr = key->u.ipv4.dst;
+       fl.saddr = key->u.ipv4.src;
+       fl.flowi4_tos = RT_TOS(key->tos);
        fl.flowi4_mark = skb->mark;
        fl.flowi4_proto = IPPROTO_GRE;
 
@@ -564,8 +564,8 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
 
        df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
        err = iptunnel_xmit(skb->sk, rt, skb, fl.saddr,
-                           key->ipv4_dst, IPPROTO_GRE,
-                           key->ipv4_tos, key->ipv4_ttl, df, false);
+                           key->u.ipv4.dst, IPPROTO_GRE,
+                           key->tos, key->ttl, df, false);
        iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
        return;
 
index 1c2389d..289b6c2 100644 (file)
@@ -227,16 +227,16 @@ static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
                tun_info->key.tun_id = nla_get_u64(tb[LWTUNNEL_IP_ID]);
 
        if (tb[LWTUNNEL_IP_DST])
-               tun_info->key.ipv4_dst = nla_get_be32(tb[LWTUNNEL_IP_DST]);
+               tun_info->key.u.ipv4.dst = nla_get_be32(tb[LWTUNNEL_IP_DST]);
 
        if (tb[LWTUNNEL_IP_SRC])
-               tun_info->key.ipv4_src = nla_get_be32(tb[LWTUNNEL_IP_SRC]);
+               tun_info->key.u.ipv4.src = nla_get_be32(tb[LWTUNNEL_IP_SRC]);
 
        if (tb[LWTUNNEL_IP_TTL])
-               tun_info->key.ipv4_ttl = nla_get_u8(tb[LWTUNNEL_IP_TTL]);
+               tun_info->key.ttl = nla_get_u8(tb[LWTUNNEL_IP_TTL]);
 
        if (tb[LWTUNNEL_IP_TOS])
-               tun_info->key.ipv4_tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
+               tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
 
        if (tb[LWTUNNEL_IP_SPORT])
                tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP_SPORT]);
@@ -262,10 +262,10 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb,
        struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate);
 
        if (nla_put_u64(skb, LWTUNNEL_IP_ID, tun_info->key.tun_id) ||
-           nla_put_be32(skb, LWTUNNEL_IP_DST, tun_info->key.ipv4_dst) ||
-           nla_put_be32(skb, LWTUNNEL_IP_SRC, tun_info->key.ipv4_src) ||
-           nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.ipv4_tos) ||
-           nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ipv4_ttl) ||
+           nla_put_be32(skb, LWTUNNEL_IP_DST, tun_info->key.u.ipv4.dst) ||
+           nla_put_be32(skb, LWTUNNEL_IP_SRC, tun_info->key.u.ipv4.src) ||
+           nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.tos) ||
+           nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ttl) ||
            nla_put_u16(skb, LWTUNNEL_IP_SPORT, tun_info->key.tp_src) ||
            nla_put_u16(skb, LWTUNNEL_IP_DPORT, tun_info->key.tp_dst) ||
            nla_put_u16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags))
@@ -299,9 +299,111 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = {
        .cmp_encap = ip_tun_cmp_encap,
 };
 
+static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
+       [LWTUNNEL_IP6_ID]               = { .type = NLA_U64 },
+       [LWTUNNEL_IP6_DST]              = { .len = sizeof(struct in6_addr) },
+       [LWTUNNEL_IP6_SRC]              = { .len = sizeof(struct in6_addr) },
+       [LWTUNNEL_IP6_HOPLIMIT]         = { .type = NLA_U8 },
+       [LWTUNNEL_IP6_TC]               = { .type = NLA_U8 },
+       [LWTUNNEL_IP6_SPORT]            = { .type = NLA_U16 },
+       [LWTUNNEL_IP6_DPORT]            = { .type = NLA_U16 },
+       [LWTUNNEL_IP6_FLAGS]            = { .type = NLA_U16 },
+};
+
+static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr,
+                              struct lwtunnel_state **ts)
+{
+       struct ip_tunnel_info *tun_info;
+       struct lwtunnel_state *new_state;
+       struct nlattr *tb[LWTUNNEL_IP6_MAX + 1];
+       int err;
+
+       err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, attr, ip6_tun_policy);
+       if (err < 0)
+               return err;
+
+       new_state = lwtunnel_state_alloc(sizeof(*tun_info));
+       if (!new_state)
+               return -ENOMEM;
+
+       new_state->type = LWTUNNEL_ENCAP_IP6;
+
+       tun_info = lwt_tun_info(new_state);
+
+       if (tb[LWTUNNEL_IP6_ID])
+               tun_info->key.tun_id = nla_get_u64(tb[LWTUNNEL_IP6_ID]);
+
+       if (tb[LWTUNNEL_IP6_DST])
+               tun_info->key.u.ipv6.dst = nla_get_in6_addr(tb[LWTUNNEL_IP6_DST]);
+
+       if (tb[LWTUNNEL_IP6_SRC])
+               tun_info->key.u.ipv6.src = nla_get_in6_addr(tb[LWTUNNEL_IP6_SRC]);
+
+       if (tb[LWTUNNEL_IP6_HOPLIMIT])
+               tun_info->key.ttl = nla_get_u8(tb[LWTUNNEL_IP6_HOPLIMIT]);
+
+       if (tb[LWTUNNEL_IP6_TC])
+               tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP6_TC]);
+
+       if (tb[LWTUNNEL_IP6_SPORT])
+               tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP6_SPORT]);
+
+       if (tb[LWTUNNEL_IP6_DPORT])
+               tun_info->key.tp_dst = nla_get_be16(tb[LWTUNNEL_IP6_DPORT]);
+
+       if (tb[LWTUNNEL_IP6_FLAGS])
+               tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]);
+
+       tun_info->mode = IP_TUNNEL_INFO_TX;
+       tun_info->options = NULL;
+       tun_info->options_len = 0;
+
+       *ts = new_state;
+
+       return 0;
+}
+
+static int ip6_tun_fill_encap_info(struct sk_buff *skb,
+                                  struct lwtunnel_state *lwtstate)
+{
+       struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate);
+
+       if (nla_put_u64(skb, LWTUNNEL_IP6_ID, tun_info->key.tun_id) ||
+           nla_put_in6_addr(skb, LWTUNNEL_IP6_DST, &tun_info->key.u.ipv6.dst) ||
+           nla_put_in6_addr(skb, LWTUNNEL_IP6_SRC, &tun_info->key.u.ipv6.src) ||
+           nla_put_u8(skb, LWTUNNEL_IP6_HOPLIMIT, tun_info->key.tos) ||
+           nla_put_u8(skb, LWTUNNEL_IP6_TC, tun_info->key.ttl) ||
+           nla_put_u16(skb, LWTUNNEL_IP6_SPORT, tun_info->key.tp_src) ||
+           nla_put_u16(skb, LWTUNNEL_IP6_DPORT, tun_info->key.tp_dst) ||
+           nla_put_u16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int ip6_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
+{
+       return nla_total_size(8)        /* LWTUNNEL_IP6_ID */
+               + nla_total_size(16)    /* LWTUNNEL_IP6_DST */
+               + nla_total_size(16)    /* LWTUNNEL_IP6_SRC */
+               + nla_total_size(1)     /* LWTUNNEL_IP6_HOPLIMIT */
+               + nla_total_size(1)     /* LWTUNNEL_IP6_TC */
+               + nla_total_size(2)     /* LWTUNNEL_IP6_SPORT */
+               + nla_total_size(2)     /* LWTUNNEL_IP6_DPORT */
+               + nla_total_size(2);    /* LWTUNNEL_IP6_FLAGS */
+}
+
+static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = {
+       .build_state = ip6_tun_build_state,
+       .fill_encap = ip6_tun_fill_encap_info,
+       .get_encap_size = ip6_tun_encap_nlsize,
+       .cmp_encap = ip_tun_cmp_encap,
+};
+
 void __init ip_tunnel_core_init(void)
 {
        lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP);
+       lwtunnel_encap_add_ops(&ip6_tun_lwt_ops, LWTUNNEL_ENCAP_IP6);
 }
 
 struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE;
index 2403e85..f3087aa 100644 (file)
@@ -1359,7 +1359,6 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
                list_del(&rt->rt_uncached);
                spin_unlock_bh(&ul->lock);
        }
-       lwtstate_put(rt->rt_lwtstate);
 }
 
 void rt_flush_dev(struct net_device *dev)
@@ -1408,7 +1407,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 #ifdef CONFIG_IP_ROUTE_CLASSID
                rt->dst.tclassid = nh->nh_tclassid;
 #endif
-               rt->rt_lwtstate = lwtstate_get(nh->nh_lwtstate);
+               rt->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
                if (unlikely(fnhe))
                        cached = rt_bind_exception(rt, fnhe, daddr);
                else if (!(rt->dst.flags & DST_NOCACHE))
@@ -1494,7 +1493,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
-       rth->rt_lwtstate = NULL;
        if (our) {
                rth->dst.input= ip_local_deliver;
                rth->rt_flags |= RTCF_LOCAL;
@@ -1624,19 +1622,18 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
-       rth->rt_lwtstate = NULL;
        RT_CACHE_STAT_INC(in_slow_tot);
 
        rth->dst.input = ip_forward;
        rth->dst.output = ip_output;
 
        rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
-       if (lwtunnel_output_redirect(rth->rt_lwtstate)) {
-               rth->rt_lwtstate->orig_output = rth->dst.output;
+       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_output = rth->dst.output;
                rth->dst.output = lwtunnel_output;
        }
-       if (lwtunnel_input_redirect(rth->rt_lwtstate)) {
-               rth->rt_lwtstate->orig_input = rth->dst.input;
+       if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_input = rth->dst.input;
                rth->dst.input = lwtunnel_input;
        }
        skb_dst_set(skb, &rth->dst);
@@ -1695,7 +1692,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
           by fib_lookup.
         */
 
-       tun_info = skb_tunnel_info(skb, AF_INET);
+       tun_info = skb_tunnel_info(skb);
        if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX)
                fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id;
        else
@@ -1815,7 +1812,6 @@ local_input:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
-       rth->rt_lwtstate = NULL;
 
        RT_CACHE_STAT_INC(in_slow_tot);
        if (res.type == RTN_UNREACHABLE) {
@@ -2006,7 +2002,6 @@ add:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
-       rth->rt_lwtstate = NULL;
        RT_CACHE_STAT_INC(out_slow_tot);
 
        if (flags & RTCF_LOCAL)
@@ -2029,7 +2024,7 @@ add:
        }
 
        rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0);
-       if (lwtunnel_output_redirect(rth->rt_lwtstate))
+       if (lwtunnel_output_redirect(rth->dst.lwtstate))
                rth->dst.output = lwtunnel_output;
 
        return rth;
@@ -2293,7 +2288,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_uses_gateway = ort->rt_uses_gateway;
 
                INIT_LIST_HEAD(&rt->rt_uncached);
-               rt->rt_lwtstate = NULL;
                dst_free(new);
        }
 
index 5924239..0f08d3b 100644 (file)
@@ -3656,7 +3656,7 @@ static void addrconf_dad_work(struct work_struct *w)
 
        /* send a neighbour solicitation for our addr */
        addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
-       ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any);
+       ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any, NULL);
 out:
        in6_ifa_put(ifp);
        rtnl_unlock();
index 2540ab4..f011c3d 100644 (file)
@@ -89,16 +89,13 @@ static void update_ipv6_locator(struct sk_buff *skb, struct ila_params *p)
 static int ila_output(struct sock *sk, struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
-       struct rt6_info *rt6 = NULL;
 
        if (skb->protocol != htons(ETH_P_IPV6))
                goto drop;
 
-       rt6 = (struct rt6_info *)dst;
+       update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate));
 
-       update_ipv6_locator(skb, ila_params_lwtunnel(rt6->rt6i_lwtstate));
-
-       return rt6->rt6i_lwtstate->orig_output(sk, skb);
+       return dst->lwtstate->orig_output(sk, skb);
 
 drop:
        kfree_skb(skb);
@@ -108,16 +105,13 @@ drop:
 static int ila_input(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
-       struct rt6_info *rt6 = NULL;
 
        if (skb->protocol != htons(ETH_P_IPV6))
                goto drop;
 
-       rt6 = (struct rt6_info *)dst;
-
-       update_ipv6_locator(skb, ila_params_lwtunnel(rt6->rt6i_lwtstate));
+       update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate));
 
-       return rt6->rt6i_lwtstate->orig_input(skb);
+       return dst->lwtstate->orig_input(skb);
 
 drop:
        kfree_skb(skb);
index 5693b5e..865e777 100644 (file)
@@ -178,7 +178,6 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
 static void rt6_release(struct rt6_info *rt)
 {
        if (atomic_dec_and_test(&rt->rt6i_ref)) {
-               lwtstate_put(rt->rt6i_lwtstate);
                rt6_free_pcpu(rt);
                dst_free(&rt->dst);
        }
index b305461..13d3c2b 100644 (file)
@@ -553,7 +553,8 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 
 void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                   const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr)
+                  const struct in6_addr *daddr, const struct in6_addr *saddr,
+                  struct sk_buff *oskb)
 {
        struct sk_buff *skb;
        struct in6_addr addr_buf;
@@ -589,6 +590,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
                                       dev->dev_addr);
 
+       if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE) && oskb)
+               skb_dst_copy(skb, oskb);
+
        ndisc_send_skb(skb, daddr, saddr);
 }
 
@@ -675,12 +679,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
                                  "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
                                  __func__, target);
                }
-               ndisc_send_ns(dev, neigh, target, target, saddr);
+               ndisc_send_ns(dev, neigh, target, target, saddr, skb);
        } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
                neigh_app_ns(neigh);
        } else {
                addrconf_addr_solict_mult(target, &mcaddr);
-               ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
+               ndisc_send_ns(dev, NULL, target, &mcaddr, saddr, skb);
        }
 }
 
index c373304..6c0fe4c 100644 (file)
 #include <net/tcp.h>
 #include <linux/rtnetlink.h>
 #include <net/dst.h>
+#include <net/dst_metadata.h>
 #include <net/xfrm.h>
 #include <net/netevent.h>
 #include <net/netlink.h>
 #include <net/nexthop.h>
 #include <net/lwtunnel.h>
+#include <net/ip_tunnels.h>
 
 #include <asm/uaccess.h>
 
@@ -538,7 +540,7 @@ static void rt6_probe_deferred(struct work_struct *w)
                container_of(w, struct __rt6_probe_work, work);
 
        addrconf_addr_solict_mult(&work->target, &mcaddr);
-       ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
+       ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL, NULL);
        dev_put(work->dev);
        kfree(work);
 }
@@ -1131,6 +1133,7 @@ void ip6_route_input(struct sk_buff *skb)
        const struct ipv6hdr *iph = ipv6_hdr(skb);
        struct net *net = dev_net(skb->dev);
        int flags = RT6_LOOKUP_F_HAS_SADDR;
+       struct ip_tunnel_info *tun_info;
        struct flowi6 fl6 = {
                .flowi6_iif = skb->dev->ifindex,
                .daddr = iph->daddr,
@@ -1140,6 +1143,10 @@ void ip6_route_input(struct sk_buff *skb)
                .flowi6_proto = iph->nexthdr,
        };
 
+       tun_info = skb_tunnel_info(skb);
+       if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX)
+               fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
+       skb_dst_drop(skb);
        skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
 }
 
@@ -1784,14 +1791,14 @@ int ip6_route_add(struct fib6_config *cfg)
                                           cfg->fc_encap, &lwtstate);
                if (err)
                        goto out;
-               rt->rt6i_lwtstate = lwtstate_get(lwtstate);
-               if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) {
-                       rt->rt6i_lwtstate->orig_output = rt->dst.output;
-                       rt->dst.output = lwtunnel_output6;
+               rt->dst.lwtstate = lwtstate_get(lwtstate);
+               if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
+                       rt->dst.lwtstate->orig_output = rt->dst.output;
+                       rt->dst.output = lwtunnel_output;
                }
-               if (lwtunnel_input_redirect(rt->rt6i_lwtstate)) {
-                       rt->rt6i_lwtstate->orig_input = rt->dst.input;
-                       rt->dst.input = lwtunnel_input6;
+               if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
+                       rt->dst.lwtstate->orig_input = rt->dst.input;
+                       rt->dst.input = lwtunnel_input;
                }
        }
 
@@ -2174,7 +2181,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
 #endif
        rt->rt6i_prefsrc = ort->rt6i_prefsrc;
        rt->rt6i_table = ort->rt6i_table;
-       rt->rt6i_lwtstate = lwtstate_get(ort->rt6i_lwtstate);
+       rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
 }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
@@ -2838,7 +2845,7 @@ static inline size_t rt6_nlmsg_size(struct rt6_info *rt)
               + nla_total_size(sizeof(struct rta_cacheinfo))
               + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
               + nla_total_size(1) /* RTA_PREF */
-              + lwtunnel_get_encap_size(rt->rt6i_lwtstate);
+              + lwtunnel_get_encap_size(rt->dst.lwtstate);
 }
 
 static int rt6_fill_node(struct net *net,
@@ -2991,7 +2998,7 @@ static int rt6_fill_node(struct net *net,
        if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
                goto nla_put_failure;
 
-       lwtunnel_fill_encap(skb, rt->rt6i_lwtstate);
+       lwtunnel_fill_encap(skb, rt->dst.lwtstate);
 
        nlmsg_end(skb, nlh);
        return 0;
index 276f8c9..3da5ca3 100644 (file)
@@ -48,7 +48,6 @@ int mpls_output(struct sock *sk, struct sk_buff *skb)
        struct dst_entry *dst = skb_dst(skb);
        struct rtable *rt = NULL;
        struct rt6_info *rt6 = NULL;
-       struct lwtunnel_state *lwtstate = NULL;
        int err = 0;
        bool bos;
        int i;
@@ -58,11 +57,9 @@ int mpls_output(struct sock *sk, struct sk_buff *skb)
        if (skb->protocol == htons(ETH_P_IP)) {
                ttl = ip_hdr(skb)->ttl;
                rt = (struct rtable *)dst;
-               lwtstate = rt->rt_lwtstate;
        } else if (skb->protocol == htons(ETH_P_IPV6)) {
                ttl = ipv6_hdr(skb)->hop_limit;
                rt6 = (struct rt6_info *)dst;
-               lwtstate = rt6->rt6i_lwtstate;
        } else {
                goto drop;
        }
@@ -72,12 +69,12 @@ int mpls_output(struct sock *sk, struct sk_buff *skb)
        /* Find the output device */
        out_dev = dst->dev;
        if (!mpls_output_possible(out_dev) ||
-           !lwtstate || skb_warn_if_lro(skb))
+           !dst->lwtstate || skb_warn_if_lro(skb))
                goto drop;
 
        skb_forward_csum(skb);
 
-       tun_encap_info = mpls_lwtunnel_encap(lwtstate);
+       tun_encap_info = mpls_lwtunnel_encap(dst->lwtstate);
 
        /* Verify the destination can hold the packet */
        new_header_size = mpls_encap_size(tun_encap_info);
index a6eb77a..4e7a3f7 100644 (file)
@@ -534,19 +534,19 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
                        tun_flags |= TUNNEL_KEY;
                        break;
                case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
-                       SW_FLOW_KEY_PUT(match, tun_key.ipv4_src,
+                       SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src,
                                        nla_get_in_addr(a), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
-                       SW_FLOW_KEY_PUT(match, tun_key.ipv4_dst,
+                       SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst,
                                        nla_get_in_addr(a), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_TOS:
-                       SW_FLOW_KEY_PUT(match, tun_key.ipv4_tos,
+                       SW_FLOW_KEY_PUT(match, tun_key.tos,
                                        nla_get_u8(a), is_mask);
                        break;
                case OVS_TUNNEL_KEY_ATTR_TTL:
-                       SW_FLOW_KEY_PUT(match, tun_key.ipv4_ttl,
+                       SW_FLOW_KEY_PUT(match, tun_key.ttl,
                                        nla_get_u8(a), is_mask);
                        ttl = true;
                        break;
@@ -609,7 +609,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
        }
 
        if (!is_mask) {
-               if (!match->key->tun_key.ipv4_dst) {
+               if (!match->key->tun_key.u.ipv4.dst) {
                        OVS_NLERR(log, "IPv4 tunnel dst address is zero");
                        return -EINVAL;
                }
@@ -647,18 +647,18 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
        if (output->tun_flags & TUNNEL_KEY &&
            nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
                return -EMSGSIZE;
-       if (output->ipv4_src &&
+       if (output->u.ipv4.src &&
            nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
-                           output->ipv4_src))
+                           output->u.ipv4.src))
                return -EMSGSIZE;
-       if (output->ipv4_dst &&
+       if (output->u.ipv4.dst &&
            nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
-                           output->ipv4_dst))
+                           output->u.ipv4.dst))
                return -EMSGSIZE;
-       if (output->ipv4_tos &&
-           nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos))
+       if (output->tos &&
+           nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos))
                return -EMSGSIZE;
-       if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ipv4_ttl))
+       if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ttl))
                return -EMSGSIZE;
        if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) &&
            nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
@@ -1116,7 +1116,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                        /* The userspace does not send tunnel attributes that
                         * are 0, but we should not wildcard them nonetheless.
                         */
-                       if (match->key->tun_key.ipv4_dst)
+                       if (match->key->tun_key.u.ipv4.dst)
                                SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
                                                         0xff, true);
 
@@ -1287,7 +1287,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
        if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
                goto nla_put_failure;
 
-       if ((swkey->tun_key.ipv4_dst || is_mask)) {
+       if ((swkey->tun_key.u.ipv4.dst || is_mask)) {
                const void *opts = NULL;
 
                if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT)
index 3a9d1dd..d22d8e9 100644 (file)
@@ -426,7 +426,7 @@ static u32 flow_hash(const struct sw_flow_key *key,
 
 static int flow_key_start(const struct sw_flow_key *key)
 {
-       if (key->tun_key.ipv4_dst)
+       if (key->tun_key.u.ipv4.dst)
                return 0;
        else
                return rounddown(offsetof(struct sw_flow_key, phy),
index 1da3a14..d01bd63 100644 (file)
@@ -203,8 +203,8 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
        }
 
        err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr,
-                             tun_key->ipv4_dst, tun_key->ipv4_tos,
-                             tun_key->ipv4_ttl, df, sport, dport,
+                             tun_key->u.ipv4.dst, tun_key->tos,
+                             tun_key->ttl, df, sport, dport,
                              tun_key->tun_flags, vni, opts_len, opts,
                              !!(tun_key->tun_flags & TUNNEL_CSUM), false);
        if (err < 0)
index 4b70aaa..a750115 100644 (file)
@@ -57,7 +57,7 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
        skb_push(skb, ETH_HLEN);
        ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
 
-       ovs_vport_receive(vport, skb, skb_tunnel_info(skb, AF_INET));
+       ovs_vport_receive(vport, skb, skb_tunnel_info(skb));
        return;
 
 error:
index d14f594..d73e5a1 100644 (file)
@@ -603,9 +603,9 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info,
         * saddr, tp_src and tp_dst
         */
        __ip_tunnel_info_init(egress_tun_info,
-                             fl.saddr, tun_key->ipv4_dst,
-                             tun_key->ipv4_tos,
-                             tun_key->ipv4_ttl,
+                             fl.saddr, tun_key->u.ipv4.dst,
+                             tun_key->tos,
+                             tun_key->ttl,
                              tp_src, tp_dst,
                              tun_key->tun_id,
                              tun_key->tun_flags,
index 1a689c2..b88b3ee 100644 (file)
@@ -254,9 +254,9 @@ static inline struct rtable *ovs_tunnel_route_lookup(struct net *net,
        struct rtable *rt;
 
        memset(fl, 0, sizeof(*fl));
-       fl->daddr = key->ipv4_dst;
-       fl->saddr = key->ipv4_src;
-       fl->flowi4_tos = RT_TOS(key->ipv4_tos);
+       fl->daddr = key->u.ipv4.dst;
+       fl->saddr = key->u.ipv4.src;
+       fl->flowi4_tos = RT_TOS(key->tos);
        fl->flowi4_mark = mark;
        fl->flowi4_proto = protocol;