These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / include / net / ipv6.h
index eec8ad3..9a5c9f0 100644 (file)
@@ -19,7 +19,7 @@
 #include <net/if_inet6.h>
 #include <net/ndisc.h>
 #include <net/flow.h>
-#include <net/flow_keys.h>
+#include <net/flow_dissector.h>
 #include <net/snmp.h>
 
 #define SIN6_LEN_RFC2133       24
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
  */
 
 struct ipv6_txoptions {
+       atomic_t                refcnt;
        /* Length of this structure */
        int                     tot_len;
 
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
        struct ipv6_opt_hdr     *dst0opt;
        struct ipv6_rt_hdr      *srcrt; /* Routing Header */
        struct ipv6_opt_hdr     *dst1opt;
-
+       struct rcu_head         rcu;
        /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
 };
 
@@ -239,8 +240,10 @@ struct ip6_flowlabel {
        struct net              *fl_net;
 };
 
-#define IPV6_FLOWINFO_MASK     cpu_to_be32(0x0FFFFFFF)
-#define IPV6_FLOWLABEL_MASK    cpu_to_be32(0x000FFFFF)
+#define IPV6_FLOWINFO_MASK             cpu_to_be32(0x0FFFFFFF)
+#define IPV6_FLOWLABEL_MASK            cpu_to_be32(0x000FFFFF)
+#define IPV6_FLOWLABEL_STATELESS_FLAG  cpu_to_be32(0x00080000)
+
 #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
 #define IPV6_TCLASS_SHIFT      20
 
@@ -250,6 +253,24 @@ struct ipv6_fl_socklist {
        struct rcu_head                 rcu;
 };
 
+static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
+{
+       struct ipv6_txoptions *opt;
+
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt && !atomic_inc_not_zero(&opt->refcnt))
+               opt = NULL;
+       rcu_read_unlock();
+       return opt;
+}
+
+static inline void txopt_put(struct ipv6_txoptions *opt)
+{
+       if (opt && atomic_dec_and_test(&opt->refcnt))
+               kfree_rcu(opt, rcu);
+}
+
 struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
                                         struct ip6_flowlabel *fl,
@@ -488,6 +509,7 @@ struct ip6_create_arg {
        u32 user;
        const struct in6_addr *src;
        const struct in6_addr *dst;
+       int iif;
        u8 ecn;
 };
 
@@ -669,8 +691,9 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
 }
 
-void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr,
-                      struct rt6_info *rt);
+__be32 ipv6_select_ident(struct net *net,
+                        const struct in6_addr *daddr,
+                        const struct in6_addr *saddr);
 void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb);
 
 int ip6_dst_hoplimit(struct dst_entry *dst);
@@ -689,47 +712,84 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
        return hlimit;
 }
 
-#if IS_ENABLED(CONFIG_IPV6)
-static inline void ip6_set_txhash(struct sock *sk)
+/* copy IPv6 saddr & daddr to flow_keys, possibly using 64bit load/store
+ * Equivalent to :     flow->v6addrs.src = iph->saddr;
+ *                     flow->v6addrs.dst = iph->daddr;
+ */
+static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
+                                           const struct ipv6hdr *iph)
 {
-       struct inet_sock *inet = inet_sk(sk);
-       struct ipv6_pinfo *np = inet6_sk(sk);
-       struct flow_keys keys;
+       BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) !=
+                    offsetof(typeof(flow->addrs), v6addrs.src) +
+                    sizeof(flow->addrs.v6addrs.src));
+       memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs));
+       flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+}
 
-       keys.src = (__force __be32)ipv6_addr_hash(&np->saddr);
-       keys.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr);
-       keys.port16[0] = inet->inet_sport;
-       keys.port16[1] = inet->inet_dport;
+#if IS_ENABLED(CONFIG_IPV6)
 
-       sk->sk_txhash = flow_hash_from_keys(&keys);
-}
+/* Sysctl settings for net ipv6.auto_flowlabels */
+#define IP6_AUTO_FLOW_LABEL_OFF                0
+#define IP6_AUTO_FLOW_LABEL_OPTOUT     1
+#define IP6_AUTO_FLOW_LABEL_OPTIN      2
+#define IP6_AUTO_FLOW_LABEL_FORCED     3
+
+#define IP6_AUTO_FLOW_LABEL_MAX                IP6_AUTO_FLOW_LABEL_FORCED
+
+#define IP6_DEFAULT_AUTO_FLOW_LABELS   IP6_AUTO_FLOW_LABEL_OPTOUT
 
 static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
-                                       __be32 flowlabel, bool autolabel)
+                                       __be32 flowlabel, bool autolabel,
+                                       struct flowi6 *fl6)
 {
-       if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) {
-               u32 hash;
+       u32 hash;
 
-               hash = skb_get_hash(skb);
+       if (flowlabel ||
+           net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
+           (!autolabel &&
+            net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED))
+               return flowlabel;
 
-               /* Since this is being sent on the wire obfuscate hash a bit
-                * to minimize possbility that any useful information to an
-                * attacker is leaked. Only lower 20 bits are relevant.
-                */
-               hash ^= hash >> 12;
+       hash = skb_get_hash_flowi6(skb, fl6);
 
-               flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
-       }
+       /* Since this is being sent on the wire obfuscate hash a bit
+        * to minimize possbility that any useful information to an
+        * attacker is leaked. Only lower 20 bits are relevant.
+        */
+       rol32(hash, 16);
+
+       flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
+
+       if (net->ipv6.sysctl.flowlabel_state_ranges)
+               flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
 
        return flowlabel;
 }
+
+static inline int ip6_default_np_autolabel(struct net *net)
+{
+       switch (net->ipv6.sysctl.auto_flowlabels) {
+       case IP6_AUTO_FLOW_LABEL_OFF:
+       case IP6_AUTO_FLOW_LABEL_OPTIN:
+       default:
+               return 0;
+       case IP6_AUTO_FLOW_LABEL_OPTOUT:
+       case IP6_AUTO_FLOW_LABEL_FORCED:
+               return 1;
+       }
+}
 #else
 static inline void ip6_set_txhash(struct sock *sk) { }
 static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
-                                       __be32 flowlabel, bool autolabel)
+                                       __be32 flowlabel, bool autolabel,
+                                       struct flowi6 *fl6)
 {
        return flowlabel;
 }
+static inline int ip6_default_np_autolabel(struct net *net)
+{
+       return 0;
+}
 #endif
 
 
@@ -767,12 +827,12 @@ static inline u8 ip6_tclass(__be32 flowinfo)
 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
             struct packet_type *pt, struct net_device *orig_dev);
 
-int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb);
+int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
 
 /*
  *     upper-layer output functions
  */
-int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
+int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
             struct ipv6_txoptions *opt, int tclass);
 
 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
@@ -807,8 +867,9 @@ static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
                              &inet6_sk(sk)->cork);
 }
 
-int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6);
-struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
+int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
+                  struct flowi6 *fl6);
+struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
                                      const struct in6_addr *final_dst);
 struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
                                         const struct in6_addr *final_dst);
@@ -819,14 +880,13 @@ struct dst_entry *ip6_blackhole_route(struct net *net,
  *     skb processing functions
  */
 
-int ip6_output(struct sock *sk, struct sk_buff *skb);
+int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb);
 int ip6_forward(struct sk_buff *skb);
 int ip6_input(struct sk_buff *skb);
 int ip6_mc_input(struct sk_buff *skb);
 
-int __ip6_local_out(struct sk_buff *skb);
-int ip6_local_out_sk(struct sock *sk, struct sk_buff *skb);
-int ip6_local_out(struct sk_buff *skb);
+int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
 
 /*
  *     Extension header (options) processing