Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[firefly-linux-kernel-4.4.55.git] / include / net / inet_frag.h
index 76c3fe5ecc2e6ed9fcf1b81be7dbd3d3dc258d73..bfcbc0017950372ddd39dd540ff3f6da99f2bee6 100644 (file)
@@ -41,12 +41,25 @@ struct inet_frag_queue {
        struct netns_frags      *net;
 };
 
-#define INETFRAGS_HASHSZ               64
+#define INETFRAGS_HASHSZ       1024
+
+/* averaged:
+ * max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ /
+ *            rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or
+ *            struct frag_queue))
+ */
+#define INETFRAGS_MAXDEPTH             128
+
+struct inet_frag_bucket {
+       struct hlist_head       chain;
+       spinlock_t              chain_lock;
+};
 
 struct inet_frags {
-       struct hlist_head       hash[INETFRAGS_HASHSZ];
+       struct inet_frag_bucket hash[INETFRAGS_HASHSZ];
        /* This rwlock is a global lock (seperate per IPv4, IPv6 and
         * netfilter). Important to keep this on a seperate cacheline.
+        * Its primarily a rebuild protection rwlock.
         */
        rwlock_t                lock ____cacheline_aligned_in_smp;
        int                     secret_interval;
@@ -76,6 +89,8 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force);
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
                struct inet_frags *f, void *key, unsigned int hash)
        __releases(&f->lock);
+void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q,
+                                  const char *prefix);
 
 static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
 {
@@ -126,14 +141,16 @@ static inline int sum_frag_mem_limit(struct netns_frags *nf)
 static inline void inet_frag_lru_move(struct inet_frag_queue *q)
 {
        spin_lock(&q->net->lru_lock);
-       list_move_tail(&q->lru_list, &q->net->lru_list);
+       if (!list_empty(&q->lru_list))
+               list_move_tail(&q->lru_list, &q->net->lru_list);
        spin_unlock(&q->net->lru_lock);
 }
 
 static inline void inet_frag_lru_del(struct inet_frag_queue *q)
 {
        spin_lock(&q->net->lru_lock);
-       list_del(&q->lru_list);
+       list_del_init(&q->lru_list);
+       q->net->nqueues--;
        spin_unlock(&q->net->lru_lock);
 }
 
@@ -142,6 +159,19 @@ static inline void inet_frag_lru_add(struct netns_frags *nf,
 {
        spin_lock(&nf->lru_lock);
        list_add_tail(&q->lru_list, &nf->lru_list);
+       q->net->nqueues++;
        spin_unlock(&nf->lru_lock);
 }
+
+/* RFC 3168 support :
+ * We want to check ECN values of all fragments, do detect invalid combinations.
+ * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value.
+ */
+#define        IPFRAG_ECN_NOT_ECT      0x01 /* one frag had ECN_NOT_ECT */
+#define        IPFRAG_ECN_ECT_1        0x02 /* one frag had ECN_ECT_1 */
+#define        IPFRAG_ECN_ECT_0        0x04 /* one frag had ECN_ECT_0 */
+#define        IPFRAG_ECN_CE           0x08 /* one frag had ECN_CE */
+
+extern const u8 ip_frag_ecn_table[16];
+
 #endif