]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net...
authorSimon Horman <horms@verge.net.au>
Thu, 13 Jan 2011 01:29:21 +0000 (10:29 +0900)
committerSimon Horman <horms@verge.net.au>
Thu, 13 Jan 2011 01:29:21 +0000 (10:29 +0900)
13 files changed:
1  2 
include/linux/netfilter.h
include/linux/skbuff.h
include/net/netfilter/nf_conntrack.h
net/core/skbuff.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/netfilter/core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c

index 928a35ec21c7962370aa241e3e3efc9b2a56c158,1893837b39660821351c4e744a166f0983244f7d..0ab7ca787b22058816889c856ed91266712f1878
@@@ -33,6 -33,8 +33,8 @@@
  
  #define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
  
+ #define NF_DROP_ERR(x) (((-x) << NF_VERDICT_BITS) | NF_DROP)
  /* only for userspace compatibility */
  #ifndef __KERNEL__
  /* Generic cache responses from hook functions.
@@@ -215,7 -217,7 +217,7 @@@ NF_HOOK_COND(uint8_t pf, unsigned int h
        int ret;
  
        if (!cond ||
-           (ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1))
+           ((ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN)) == 1))
                ret = okfn(skb);
        return ret;
  }
@@@ -265,7 -267,7 +267,7 @@@ struct nf_afinfo 
        int             route_key_size;
  };
  
 -extern const struct nf_afinfo *nf_afinfo[NFPROTO_NUMPROTO];
 +extern const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO];
  static inline const struct nf_afinfo *nf_get_afinfo(unsigned short family)
  {
        return rcu_dereference(nf_afinfo[family]);
@@@ -355,9 -357,9 +357,9 @@@ nf_nat_decode_session(struct sk_buff *s
  #endif /*CONFIG_NETFILTER*/
  
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 -extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
 +extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *) __rcu;
  extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
 -extern void (*nf_ct_destroy)(struct nf_conntrack *);
 +extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu;
  #else
  static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
  #endif
diff --combined include/linux/skbuff.h
index 4f2db79a2abba273ad8aebbb07d865a13f5112fd,20ec0a64cb9ff0f8708a66ddaeb2ffd1d3ed72c9..bf221d65d9ad5d0c2878795021b2733012c4ef2f
@@@ -255,11 -255,6 +255,11 @@@ typedef unsigned int sk_buff_data_t
  typedef unsigned char *sk_buff_data_t;
  #endif
  
 +#if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \
 +    defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
 +#define NET_SKBUFF_NF_DEFRAG_NEEDED 1
 +#endif
 +
  /** 
   *    struct sk_buff - socket buffer
   *    @next: Next buffer in list
@@@ -367,8 -362,6 +367,8 @@@ struct sk_buff 
        void                    (*destructor)(struct sk_buff *skb);
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct nf_conntrack     *nfct;
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        struct sk_buff          *nfct_reasm;
  #endif
  #ifdef CONFIG_BRIDGE_NETFILTER
  #else
        __u8                    deliver_no_wcard:1;
  #endif
+       __u8                    ooo_okay:1;
        kmemcheck_bitfield_end(flags2);
  
-       /* 0/14 bit hole */
+       /* 0/13 bit hole */
  
  #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
@@@ -1361,6 -1355,11 +1362,11 @@@ static inline void skb_set_mac_header(s
  }
  #endif /* NET_SKBUFF_DATA_USES_OFFSET */
  
+ static inline int skb_checksum_start_offset(const struct sk_buff *skb)
+ {
+       return skb->csum_start - skb_headroom(skb);
+ }
  static inline int skb_transport_offset(const struct sk_buff *skb)
  {
        return skb_transport_header(skb) - skb->data;
@@@ -2058,8 -2057,6 +2064,8 @@@ static inline void nf_conntrack_get(str
        if (nfct)
                atomic_inc(&nfct->use);
  }
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
  static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
  {
        if (skb)
@@@ -2088,8 -2085,6 +2094,8 @@@ static inline void nf_reset(struct sk_b
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(skb->nfct_reasm);
        skb->nfct_reasm = NULL;
  #endif
@@@ -2106,8 -2101,6 +2112,8 @@@ static inline void __nf_copy(struct sk_
        dst->nfct = src->nfct;
        nf_conntrack_get(src->nfct);
        dst->nfctinfo = src->nfctinfo;
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        dst->nfct_reasm = src->nfct_reasm;
        nf_conntrack_get_reasm(src->nfct_reasm);
  #endif
@@@ -2121,8 -2114,6 +2127,8 @@@ static inline void nf_copy(struct sk_bu
  {
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(dst->nfct);
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(dst->nfct_reasm);
  #endif
  #ifdef CONFIG_BRIDGE_NETFILTER
@@@ -2179,8 -2170,9 +2185,9 @@@ static inline bool skb_rx_queue_recorde
        return skb->queue_mapping != 0;
  }
  
- extern u16 skb_tx_hash(const struct net_device *dev,
-                      const struct sk_buff *skb);
+ extern u16 __skb_tx_hash(const struct net_device *dev,
+                        const struct sk_buff *skb,
+                        unsigned int num_tx_queues);
  
  #ifdef CONFIG_XFRM
  static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
index 8a58901c96d3b91ed20b98f9a257127aa79dd2a4,d85cff10e1693535f326b7467330b985734d2309..2bc344c98215e436ca62adb1973e62a009a8415c
@@@ -50,24 -50,11 +50,24 @@@ union nf_conntrack_expect_proto 
  /* per conntrack: application helper private data */
  union nf_conntrack_help {
        /* insert conntrack helper private data (master) here */
 +#if defined(CONFIG_NF_CONNTRACK_FTP) || defined(CONFIG_NF_CONNTRACK_FTP_MODULE)
        struct nf_ct_ftp_master ct_ftp_info;
 +#endif
 +#if defined(CONFIG_NF_CONNTRACK_PPTP) || \
 +    defined(CONFIG_NF_CONNTRACK_PPTP_MODULE)
        struct nf_ct_pptp_master ct_pptp_info;
 +#endif
 +#if defined(CONFIG_NF_CONNTRACK_H323) || \
 +    defined(CONFIG_NF_CONNTRACK_H323_MODULE)
        struct nf_ct_h323_master ct_h323_info;
 +#endif
 +#if defined(CONFIG_NF_CONNTRACK_SANE) || \
 +    defined(CONFIG_NF_CONNTRACK_SANE_MODULE)
        struct nf_ct_sane_master ct_sane_info;
 +#endif
 +#if defined(CONFIG_NF_CONNTRACK_SIP) || defined(CONFIG_NF_CONNTRACK_SIP_MODULE)
        struct nf_ct_sip_master ct_sip_info;
 +#endif
  };
  
  #include <linux/types.h>
@@@ -129,14 -116,14 +129,14 @@@ struct nf_conn 
        u_int32_t secmark;
  #endif
  
 -      /* Storage reserved for other modules: */
 -      union nf_conntrack_proto proto;
 -
        /* Extensions */
        struct nf_ct_ext *ext;
  #ifdef CONFIG_NET_NS
        struct net *ct_net;
  #endif
 +
 +      /* Storage reserved for other modules, must be the last member */
 +      union nf_conntrack_proto proto;
  };
  
  static inline struct nf_conn *
@@@ -311,6 -298,8 +311,8 @@@ static inline int nf_ct_is_untracked(co
  extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
  extern unsigned int nf_conntrack_htable_size;
  extern unsigned int nf_conntrack_max;
+ extern unsigned int nf_conntrack_hash_rnd;
+ void init_nf_conntrack_hash_rnd(void);
  
  #define NF_CT_STAT_INC(net, count)    \
        __this_cpu_inc((net)->ct.stat->count)
diff --combined net/core/skbuff.c
index 74ebf4b5258a3f552c38836dd67469b86d0e64f2,19d6c21220fd47bb7141d8376a55c1785627a5e8..d31bb36ae0dc21cfdab61b90dd2f2fbfd665ce81
@@@ -380,8 -380,6 +380,8 @@@ static void skb_release_head_state(stru
        }
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(skb->nfct);
 +#endif
 +#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(skb->nfct_reasm);
  #endif
  #ifdef CONFIG_BRIDGE_NETFILTER
@@@ -780,6 -778,28 +780,28 @@@ int pskb_expand_head(struct sk_buff *sk
  
        size = SKB_DATA_ALIGN(size);
  
+       /* Check if we can avoid taking references on fragments if we own
+        * the last reference on skb->head. (see skb_release_data())
+        */
+       if (!skb->cloned)
+               fastpath = true;
+       else {
+               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
+               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+       }
+       if (fastpath &&
+           size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
+               memmove(skb->head + size, skb_shinfo(skb),
+                       offsetof(struct skb_shared_info,
+                                frags[skb_shinfo(skb)->nr_frags]));
+               memmove(skb->head + nhead, skb->head,
+                       skb_tail_pointer(skb) - skb->head);
+               off = nhead;
+               goto adjust_others;
+       }
        data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
        if (!data)
                goto nodata;
               skb_shinfo(skb),
               offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
  
-       /* Check if we can avoid taking references on fragments if we own
-        * the last reference on skb->head. (see skb_release_data())
-        */
-       if (!skb->cloned)
-               fastpath = true;
-       else {
-               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
-               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
-       }
        if (fastpath) {
                kfree(skb->head);
        } else {
        off = (data + nhead) - skb->head;
  
        skb->head     = data;
+ adjust_others:
        skb->data    += off;
  #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->end      = size;
@@@ -1814,7 -1824,7 +1826,7 @@@ void skb_copy_and_csum_dev(const struc
        long csstart;
  
        if (skb->ip_summed == CHECKSUM_PARTIAL)
-               csstart = skb->csum_start - skb_headroom(skb);
+               csstart = skb_checksum_start_offset(skb);
        else
                csstart = skb_headlen(skb);
  
index ab9c05c9734e8e6fa490cf4b08d6ca9772d9ae43,63f60fc5d26a49ea844c106e8570260b29445a88..5585980fce2e351b35d2e6f0f741531f6a87d199
@@@ -20,7 -20,6 +20,7 @@@
  #include <net/netfilter/nf_conntrack_l4proto.h>
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <net/netfilter/nf_conntrack_acct.h>
 +#include <linux/rculist_nulls.h>
  
  struct ct_iter_state {
        struct seq_net_private p;
@@@ -36,8 -35,7 +36,8 @@@ static struct hlist_nulls_node *ct_get_
        for (st->bucket = 0;
             st->bucket < net->ct.htable_size;
             st->bucket++) {
 -              n = rcu_dereference(net->ct.hash[st->bucket].first);
 +              n = rcu_dereference(
 +                      hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
                if (!is_a_nulls(n))
                        return n;
        }
@@@ -50,14 -48,13 +50,14 @@@ static struct hlist_nulls_node *ct_get_
        struct net *net = seq_file_net(seq);
        struct ct_iter_state *st = seq->private;
  
 -      head = rcu_dereference(head->next);
 +      head = rcu_dereference(hlist_nulls_next_rcu(head));
        while (is_a_nulls(head)) {
                if (likely(get_nulls_value(head) == st->bucket)) {
                        if (++st->bucket >= net->ct.htable_size)
                                return NULL;
                }
 -              head = rcu_dereference(net->ct.hash[st->bucket].first);
 +              head = rcu_dereference(
 +                      hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
        }
        return head;
  }
@@@ -100,7 -97,7 +100,7 @@@ static int ct_show_secctx(struct seq_fi
  
        ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
        if (ret)
-               return ret;
+               return 0;
  
        ret = seq_printf(s, "secctx=%s ", secctx);
  
@@@ -220,8 -217,7 +220,8 @@@ static struct hlist_node *ct_expect_get
        struct hlist_node *n;
  
        for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
 -              n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 +              n = rcu_dereference(
 +                      hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
                if (n)
                        return n;
        }
@@@ -234,12 -230,11 +234,12 @@@ static struct hlist_node *ct_expect_get
        struct net *net = seq_file_net(seq);
        struct ct_expect_iter_state *st = seq->private;
  
 -      head = rcu_dereference(head->next);
 +      head = rcu_dereference(hlist_next_rcu(head));
        while (head == NULL) {
                if (++st->bucket >= nf_ct_expect_hsize)
                        return NULL;
 -              head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 +              head = rcu_dereference(
 +                      hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
        }
        return head;
  }
index eb9f1c03de3f2aae363ec544bc153755c334aa4f,79d43aa8fa8da80b405689bf7c751d7a9cc89ad4..66e003e1fcd595c009c78063df4fecd10aa46496
@@@ -73,7 -73,7 +73,7 @@@ static struct inet_frags nf_frags
  static struct netns_frags nf_init_frags;
  
  #ifdef CONFIG_SYSCTL
 -struct ctl_table nf_ct_frag6_sysctl_table[] = {
 +static struct ctl_table nf_ct_frag6_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_frag6_timeout",
                .data           = &nf_init_frags.timeout,
@@@ -286,7 -286,7 +286,7 @@@ found
  
        /* Check for overlap with preceding fragment. */
        if (prev &&
-           (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0)
+           (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset)
                goto discard_fq;
  
        /* Look for overlap with succeeding segment. */
diff --combined net/netfilter/core.c
index 5faec4fd8193325715de3f602e08e88cf37089b4,32fcbe290c047802942b5d9838489a2193b622b2..e69d537362c72bb7d1436f85ce57cdf589719fb1
@@@ -173,9 -173,11 +173,11 @@@ next_hook
                             outdev, &elem, okfn, hook_thresh);
        if (verdict == NF_ACCEPT || verdict == NF_STOP) {
                ret = 1;
-       } else if (verdict == NF_DROP) {
+       } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
                kfree_skb(skb);
-               ret = -EPERM;
+               ret = -(verdict >> NF_VERDICT_BITS);
+               if (ret == 0)
+                       ret = -EPERM;
        } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
                if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
                              verdict >> NF_VERDICT_BITS))
@@@ -212,7 -214,7 +214,7 @@@ EXPORT_SYMBOL(skb_make_writable)
  /* This does not belong here, but locally generated errors need it if connection
     tracking in use: without this, connection may not be in hash table, and hence
     manufactured ICMP or RST packets will not be associated with it. */
 -void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
 +void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *) __rcu __read_mostly;
  EXPORT_SYMBOL(ip_ct_attach);
  
  void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
  }
  EXPORT_SYMBOL(nf_ct_attach);
  
 -void (*nf_ct_destroy)(struct nf_conntrack *);
 +void (*nf_ct_destroy)(struct nf_conntrack *) __rcu __read_mostly;
  EXPORT_SYMBOL(nf_ct_destroy);
  
  void nf_conntrack_destroy(struct nf_conntrack *nfct)
index d12a13c497ba2374f402e14e22c5671ccf5d1f51,22f7ad5101abb32d24af2d254dcd3528501d6553..ca49e928f30220f242c81f3263a6148b13a6e669
@@@ -92,7 -92,7 +92,7 @@@ int sysctl_ip_vs_nat_icmp_send = 0
  int sysctl_ip_vs_conntrack;
  #endif
  int sysctl_ip_vs_snat_reroute = 1;
 -
 +int sysctl_ip_vs_sync_ver = 1;                /* Default version of sync proto */
  
  #ifdef CONFIG_IP_VS_DEBUG
  static int sysctl_ip_vs_debug_level = 0;
@@@ -110,10 -110,8 +110,8 @@@ static int __ip_vs_addr_is_local_v6(con
        struct rt6_info *rt;
        struct flowi fl = {
                .oif = 0,
-               .nl_u = {
-                       .ip6_u = {
-                               .daddr = *addr,
-                               .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+               .fl6_dst = *addr,
+               .fl6_src = { .s6_addr32 = {0, 0, 0, 0} },
        };
  
        rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
@@@ -657,12 -655,12 +655,12 @@@ ip_vs_lookup_dest(struct ip_vs_service 
  struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
                                   __be16 dport,
                                   const union nf_inet_addr *vaddr,
 -                                 __be16 vport, __u16 protocol)
 +                                 __be16 vport, __u16 protocol, __u32 fwmark)
  {
        struct ip_vs_dest *dest;
        struct ip_vs_service *svc;
  
 -      svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
 +      svc = ip_vs_service_get(af, fwmark, protocol, vaddr, vport);
        if (!svc)
                return NULL;
        dest = ip_vs_lookup_dest(svc, daddr, dport);
@@@ -1139,7 -1137,7 +1137,7 @@@ ip_vs_add_service(struct ip_vs_service_
        }
  
        if (u->pe_name && *u->pe_name) {
 -              pe = ip_vs_pe_get(u->pe_name);
 +              pe = ip_vs_pe_getbyname(u->pe_name);
                if (pe == NULL) {
                        pr_info("persistence engine module ip_vs_pe_%s "
                                "not found\n", u->pe_name);
@@@ -1250,7 -1248,7 +1248,7 @@@ ip_vs_edit_service(struct ip_vs_servic
        old_sched = sched;
  
        if (u->pe_name && *u->pe_name) {
 -              pe = ip_vs_pe_get(u->pe_name);
 +              pe = ip_vs_pe_getbyname(u->pe_name);
                if (pe == NULL) {
                        pr_info("persistence engine module ip_vs_pe_%s "
                                "not found\n", u->pe_name);
@@@ -1536,25 -1534,6 +1534,25 @@@ proc_do_sync_threshold(ctl_table *table
        return rc;
  }
  
 +static int
 +proc_do_sync_mode(ctl_table *table, int write,
 +                   void __user *buffer, size_t *lenp, loff_t *ppos)
 +{
 +      int *valp = table->data;
 +      int val = *valp;
 +      int rc;
 +
 +      rc = proc_dointvec(table, write, buffer, lenp, ppos);
 +      if (write && (*valp != val)) {
 +              if ((*valp < 0) || (*valp > 1)) {
 +                      /* Restore the correct value */
 +                      *valp = val;
 +              } else {
 +                      ip_vs_sync_switch_mode(val);
 +              }
 +      }
 +      return rc;
 +}
  
  /*
   *    IPVS sysctl table (under the /proc/sys/net/ipv4/vs/)
@@@ -1621,13 -1600,6 +1619,13 @@@ static struct ctl_table vs_vars[] = 
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
 +      {
 +              .procname       = "sync_version",
 +              .data           = &sysctl_ip_vs_sync_ver,
 +              .maxlen         = sizeof(int),
 +              .mode           = 0644,
 +              .proc_handler   = &proc_do_sync_mode,
 +      },
  #if 0
        {
                .procname       = "timeout_established",
@@@ -3458,7 -3430,7 +3456,7 @@@ void ip_vs_control_cleanup(void
  {
        EnterFunction(2);
        ip_vs_trash_cleanup();
-       cancel_rearming_delayed_work(&defense_work);
+       cancel_delayed_work_sync(&defense_work);
        cancel_work_sync(&defense_work.work);
        ip_vs_kill_estimator(&ip_vs_stats);
        unregister_sysctl_table(sysctl_header);
index fb2a445ddc596718972645e0a65ca6dcc45fdb52,5325a3fbe4ac8e8ab5a2e8175f9a5b93e1cc663c..1f2a4e35fb115bef5da5eba86df4500733c4213c
@@@ -96,12 -96,8 +96,8 @@@ __ip_vs_get_out_rt(struct sk_buff *skb
                if (!(rt = (struct rtable *)
                      __ip_vs_dst_check(dest, rtos))) {
                        struct flowi fl = {
-                               .oif = 0,
-                               .nl_u = {
-                                       .ip4_u = {
-                                               .daddr = dest->addr.ip,
-                                               .saddr = 0,
-                                               .tos = rtos, } },
+                               .fl4_dst = dest->addr.ip,
+                               .fl4_tos = rtos,
                        };
  
                        if (ip_route_output_key(net, &rt, &fl)) {
                spin_unlock(&dest->dst_lock);
        } else {
                struct flowi fl = {
-                       .oif = 0,
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = daddr,
-                                       .saddr = 0,
-                                       .tos = rtos, } },
+                       .fl4_dst = daddr,
+                       .fl4_tos = rtos,
                };
  
                if (ip_route_output_key(net, &rt, &fl)) {
@@@ -178,16 -170,12 +170,11 @@@ __ip_vs_reroute_locally(struct sk_buff 
                refdst_drop(orefdst);
        } else {
                struct flowi fl = {
-                       .oif = 0,
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = iph->daddr,
-                                       .saddr = iph->saddr,
-                                       .tos = RT_TOS(iph->tos),
-                               }
-                       },
+                       .fl4_dst = iph->daddr,
+                       .fl4_src = iph->saddr,
+                       .fl4_tos = RT_TOS(iph->tos),
                        .mark = skb->mark,
                };
 -              struct rtable *rt;
  
                if (ip_route_output_key(net, &rt, &fl))
                        return 0;
@@@ -215,12 -203,7 +202,7 @@@ __ip_vs_route_output_v6(struct net *net
  {
        struct dst_entry *dst;
        struct flowi fl = {
-               .oif = 0,
-               .nl_u = {
-                       .ip6_u = {
-                               .daddr = *daddr,
-                       },
-               },
+               .fl6_dst = *daddr,
        };
  
        dst = ip6_route_output(net, NULL, &fl);
@@@ -407,8 -390,7 +389,8 @@@ ip_vs_bypass_xmit(struct sk_buff *skb, 
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 +      if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
 +          !skb_is_gso(skb)) {
                ip_rt_put(rt);
                icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@@ -461,7 -443,7 +443,7 @@@ ip_vs_bypass_xmit_v6(struct sk_buff *sk
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if (skb->len > mtu) {
 +      if (skb->len > mtu && !skb_is_gso(skb)) {
                if (!skb->dev) {
                        struct net *net = dev_net(skb_dst(skb)->dev);
  
@@@ -561,8 -543,7 +543,8 @@@ ip_vs_nat_xmit(struct sk_buff *skb, str
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 +      if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
 +          !skb_is_gso(skb)) {
                icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
                IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
                                 "ip_vs_nat_xmit(): frag needed for");
@@@ -677,7 -658,7 +659,7 @@@ ip_vs_nat_xmit_v6(struct sk_buff *skb, 
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if (skb->len > mtu) {
 +      if (skb->len > mtu && !skb_is_gso(skb)) {
                if (!skb->dev) {
                        struct net *net = dev_net(skb_dst(skb)->dev);
  
@@@ -792,8 -773,8 +774,8 @@@ ip_vs_tunnel_xmit(struct sk_buff *skb, 
  
        df |= (old_iph->frag_off & htons(IP_DF));
  
 -      if ((old_iph->frag_off & htons(IP_DF))
 -          && mtu < ntohs(old_iph->tot_len)) {
 +      if ((old_iph->frag_off & htons(IP_DF) &&
 +          mtu < ntohs(old_iph->tot_len) && !skb_is_gso(skb))) {
                icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
                goto tx_error_put;
@@@ -905,8 -886,7 +887,8 @@@ ip_vs_tunnel_xmit_v6(struct sk_buff *sk
        if (skb_dst(skb))
                skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
  
 -      if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
 +      if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
 +          !skb_is_gso(skb)) {
                if (!skb->dev) {
                        struct net *net = dev_net(skb_dst(skb)->dev);
  
@@@ -1011,8 -991,7 +993,8 @@@ ip_vs_dr_xmit(struct sk_buff *skb, stru
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
 +      if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu &&
 +          !skb_is_gso(skb)) {
                icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
                ip_rt_put(rt);
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@@ -1179,8 -1158,7 +1161,8 @@@ ip_vs_icmp_xmit(struct sk_buff *skb, st
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
 +      if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF)) &&
 +          !skb_is_gso(skb)) {
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
                goto tx_error_put;
@@@ -1294,7 -1272,7 +1276,7 @@@ ip_vs_icmp_xmit_v6(struct sk_buff *skb
  
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
 -      if (skb->len > mtu) {
 +      if (skb->len > mtu && !skb_is_gso(skb)) {
                if (!skb->dev) {
                        struct net *net = dev_net(skb_dst(skb)->dev);
  
index 0ba7d4801daf9a3e50126251853ef1d7abcdde7b,e61511929c66c99b02286388a41e909d8e8fc6fc..e95ac42ef673ca5d0c0a9a3320f93e533869c090
@@@ -65,7 -65,7 +65,7 @@@ EXPORT_SYMBOL_GPL(nf_conntrack_max)
  DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
  EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
  
static unsigned int nf_conntrack_hash_rnd __read_mostly;
+ unsigned int nf_conntrack_hash_rnd __read_mostly;
  
  static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, u16 zone)
  {
@@@ -596,6 -596,21 +596,21 @@@ static noinline int early_drop(struct n
        return dropped;
  }
  
+ void init_nf_conntrack_hash_rnd(void)
+ {
+       unsigned int rand;
+       /*
+        * Why not initialize nf_conntrack_rnd in a "init()" function ?
+        * Because there isn't enough entropy when system initializing,
+        * and we initialize it as late as possible.
+        */
+       do {
+               get_random_bytes(&rand, sizeof(rand));
+       } while (!rand);
+       cmpxchg(&nf_conntrack_hash_rnd, 0, rand);
+ }
  static struct nf_conn *
  __nf_conntrack_alloc(struct net *net, u16 zone,
                     const struct nf_conntrack_tuple *orig,
        struct nf_conn *ct;
  
        if (unlikely(!nf_conntrack_hash_rnd)) {
-               unsigned int rand;
-               /*
-                * Why not initialize nf_conntrack_rnd in a "init()" function ?
-                * Because there isn't enough entropy when system initializing,
-                * and we initialize it as late as possible.
-                */
-               do {
-                       get_random_bytes(&rand, sizeof(rand));
-               } while (!rand);
-               cmpxchg(&nf_conntrack_hash_rnd, 0, rand);
+               init_nf_conntrack_hash_rnd();
                /* recompute the hash as nf_conntrack_hash_rnd is initialized */
                hash = hash_conntrack_raw(orig, zone);
        }
         * and ct->tuplehash[IP_CT_DIR_REPLY].hnnode.next unchanged.
         */
        memset(&ct->tuplehash[IP_CT_DIR_MAX], 0,
 -             sizeof(*ct) - offsetof(struct nf_conn, tuplehash[IP_CT_DIR_MAX]));
 +             offsetof(struct nf_conn, proto) -
 +             offsetof(struct nf_conn, tuplehash[IP_CT_DIR_MAX]));
        spin_lock_init(&ct->lock);
        ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
        ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL;
index 774f32ba2ac97db629997caa6bef063434a1c9ba,a20fb0bd1efe850543a9dea62fdf4bf53330a335..4a9ed23180df090e41c5f181c68e6e32f4fa51e4
@@@ -32,9 -32,7 +32,7 @@@
  unsigned int nf_ct_expect_hsize __read_mostly;
  EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
  
- static unsigned int nf_ct_expect_hash_rnd __read_mostly;
  unsigned int nf_ct_expect_max __read_mostly;
- static int nf_ct_expect_hash_rnd_initted __read_mostly;
  
  static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
  
@@@ -77,15 -75,13 +75,13 @@@ static unsigned int nf_ct_expect_dst_ha
  {
        unsigned int hash;
  
-       if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
-               get_random_bytes(&nf_ct_expect_hash_rnd,
-                                sizeof(nf_ct_expect_hash_rnd));
-               nf_ct_expect_hash_rnd_initted = 1;
+       if (unlikely(!nf_conntrack_hash_rnd)) {
+               init_nf_conntrack_hash_rnd();
        }
  
        hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
                      (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
-                      (__force __u16)tuple->dst.u.all) ^ nf_ct_expect_hash_rnd);
+                      (__force __u16)tuple->dst.u.all) ^ nf_conntrack_hash_rnd);
        return ((u64)hash * nf_ct_expect_hsize) >> 32;
  }
  
@@@ -323,8 -319,7 +319,8 @@@ static void nf_ct_expect_insert(struct 
        const struct nf_conntrack_expect_policy *p;
        unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
  
 -      atomic_inc(&exp->use);
 +      /* two references : one for hash insert, one for the timer */
 +      atomic_add(2, &exp->use);
  
        if (master_help) {
                hlist_add_head(&exp->lnode, &master_help->expectations);
        setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
                    (unsigned long)exp);
        if (master_help) {
 -              p = &master_help->helper->expect_policy[exp->class];
 +              p = &rcu_dereference_protected(
 +                              master_help->helper,
 +                              lockdep_is_held(&nf_conntrack_lock)
 +                              )->expect_policy[exp->class];
                exp->timeout.expires = jiffies + p->timeout * HZ;
        }
        add_timer(&exp->timeout);
  
 -      atomic_inc(&exp->use);
        NF_CT_STAT_INC(net, expect_create);
  }
  
@@@ -376,10 -369,7 +372,10 @@@ static inline int refresh_timer(struct 
        if (!del_timer(&i->timeout))
                return 0;
  
 -      p = &master_help->helper->expect_policy[i->class];
 +      p = &rcu_dereference_protected(
 +              master_help->helper,
 +              lockdep_is_held(&nf_conntrack_lock)
 +              )->expect_policy[i->class];
        i->timeout.expires = jiffies + p->timeout * HZ;
        add_timer(&i->timeout);
        return 1;
@@@ -417,10 -407,7 +413,10 @@@ static inline int __nf_ct_expect_check(
        }
        /* Will be over limit? */
        if (master_help) {
 -              p = &master_help->helper->expect_policy[expect->class];
 +              p = &rcu_dereference_protected(
 +                      master_help->helper,
 +                      lockdep_is_held(&nf_conntrack_lock)
 +                      )->expect_policy[expect->class];
                if (p->max_expected &&
                    master_help->expecting[expect->class] >= p->max_expected) {
                        evict_oldest_expect(master, expect);
@@@ -491,7 -478,7 +487,7 @@@ static struct hlist_node *ct_expect_get
        struct hlist_node *n;
  
        for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
 -              n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 +              n = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
                if (n)
                        return n;
        }
@@@ -504,11 -491,11 +500,11 @@@ static struct hlist_node *ct_expect_get
        struct net *net = seq_file_net(seq);
        struct ct_expect_iter_state *st = seq->private;
  
 -      head = rcu_dereference(head->next);
 +      head = rcu_dereference(hlist_next_rcu(head));
        while (head == NULL) {
                if (++st->bucket >= nf_ct_expect_hsize)
                        return NULL;
 -              head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
 +              head = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
        }
        return head;
  }
index 7f59be82449ffcbab5c33228f642197f222353bd,0cdba50c0d69be7ad5ddfed136e1be9a20a6f338..9eabaa6f28a81e7bc8a3934112bd621d6e1074e8
@@@ -254,7 -254,7 +254,7 @@@ ctnetlink_dump_secctx(struct sk_buff *s
  
        ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
        if (ret)
-               return ret;
+               return 0;
  
        ret = -1;
        nest_secctx = nla_nest_start(skb, CTA_SECCTX | NLA_F_NESTED);
@@@ -453,16 -453,22 +453,22 @@@ ctnetlink_counters_size(const struct nf
               ;
  }
  
- #ifdef CONFIG_NF_CONNTRACK_SECMARK
static int ctnetlink_nlmsg_secctx_size(const struct nf_conn *ct)
+ static inline int
ctnetlink_secctx_size(const struct nf_conn *ct)
  {
-       int len;
+ #ifdef CONFIG_NF_CONNTRACK_SECMARK
+       int len, ret;
  
-       security_secid_to_secctx(ct->secmark, NULL, &len);
+       ret = security_secid_to_secctx(ct->secmark, NULL, &len);
+       if (ret)
+               return 0;
  
-       return sizeof(char) * len;
- }
+       return nla_total_size(0) /* CTA_SECCTX */
+              + nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
+ #else
+       return 0;
  #endif
+ }
  
  static inline size_t
  ctnetlink_nlmsg_size(const struct nf_conn *ct)
               + nla_total_size(0) /* CTA_PROTOINFO */
               + nla_total_size(0) /* CTA_HELP */
               + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
- #ifdef CONFIG_NF_CONNTRACK_SECMARK
-              + nla_total_size(0) /* CTA_SECCTX */
-              + nla_total_size(ctnetlink_nlmsg_secctx_size(ct)) /* CTA_SECCTX_NAME */
- #endif
+              + ctnetlink_secctx_size(ct)
  #ifdef CONFIG_NF_NAT_NEEDED
               + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
               + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
@@@ -1375,7 -1378,6 +1378,7 @@@ ctnetlink_create_conntrack(struct net *
        }
  #endif
  
 +      memset(&ct->proto, 0, sizeof(ct->proto));
        if (cda[CTA_PROTOINFO]) {
                err = ctnetlink_change_protoinfo(ct, cda);
                if (err < 0)
index 328f1d2a51f8ea15aca900d67f228e33ee580d5b,b4d7f0f24b27e9534a97851e7830714c8135a7bf..8257bf64359370ac45a49162e9c003388273245d
@@@ -29,7 -29,6 +29,7 @@@
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <net/netfilter/nf_conntrack_acct.h>
  #include <net/netfilter/nf_conntrack_zones.h>
 +#include <linux/rculist_nulls.h>
  
  MODULE_LICENSE("GPL");
  
@@@ -57,7 -56,7 +57,7 @@@ static struct hlist_nulls_node *ct_get_
        for (st->bucket = 0;
             st->bucket < net->ct.htable_size;
             st->bucket++) {
 -              n = rcu_dereference(net->ct.hash[st->bucket].first);
 +              n = rcu_dereference(hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
                if (!is_a_nulls(n))
                        return n;
        }
@@@ -70,15 -69,13 +70,15 @@@ static struct hlist_nulls_node *ct_get_
        struct net *net = seq_file_net(seq);
        struct ct_iter_state *st = seq->private;
  
 -      head = rcu_dereference(head->next);
 +      head = rcu_dereference(hlist_nulls_next_rcu(head));
        while (is_a_nulls(head)) {
                if (likely(get_nulls_value(head) == st->bucket)) {
                        if (++st->bucket >= net->ct.htable_size)
                                return NULL;
                }
 -              head = rcu_dereference(net->ct.hash[st->bucket].first);
 +              head = rcu_dereference(
 +                              hlist_nulls_first_rcu(
 +                                      &net->ct.hash[st->bucket]));
        }
        return head;
  }
@@@ -121,7 -118,7 +121,7 @@@ static int ct_show_secctx(struct seq_fi
  
        ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
        if (ret)
-               return ret;
+               return 0;
  
        ret = seq_printf(s, "secctx=%s ", secctx);