Skip to content

Commit c038a76

Browse files
Amerigo Wangdavem330
authored andcommitted
ipv6: add a new namespace for nf_conntrack_reasm
As pointed by Michal, it is necessary to add a new namespace for nf_conntrack_reasm code, this prepares for the second patch. Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Michal Kubeček <mkubecek@suse.cz> Cc: David Miller <davem@davemloft.net> Cc: Patrick McHardy <kaber@trash.net> Cc: Pablo Neira Ayuso <pablo@netfilter.org> Cc: netfilter-devel@vger.kernel.org Signed-off-by: Cong Wang <amwang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 8c4c49d commit c038a76

File tree

3 files changed

+106
-42
lines changed

3 files changed

+106
-42
lines changed

include/net/net_namespace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ struct net {
9292
struct netns_xt xt;
9393
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
9494
struct netns_ct ct;
95+
#endif
96+
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
97+
struct netns_nf_frag nf_frag;
9598
#endif
9699
struct sock *nfnl;
97100
struct sock *nfnl_stash;

include/net/netns/ipv6.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,12 @@ struct netns_ipv6 {
7171
#endif
7272
#endif
7373
};
74+
75+
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
76+
struct netns_nf_frag {
77+
struct netns_sysctl_ipv6 sysctl;
78+
struct netns_frags frags;
79+
};
80+
#endif
81+
7482
#endif

net/ipv6/netfilter/nf_conntrack_reasm.c

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -71,35 +71,82 @@ struct nf_ct_frag6_queue
7171
};
7272

7373
static struct inet_frags nf_frags;
74-
static struct netns_frags nf_init_frags;
7574

7675
#ifdef CONFIG_SYSCTL
7776
static struct ctl_table nf_ct_frag6_sysctl_table[] = {
7877
{
7978
.procname = "nf_conntrack_frag6_timeout",
80-
.data = &nf_init_frags.timeout,
79+
.data = &init_net.nf_frag.frags.timeout,
8180
.maxlen = sizeof(unsigned int),
8281
.mode = 0644,
8382
.proc_handler = proc_dointvec_jiffies,
8483
},
8584
{
8685
.procname = "nf_conntrack_frag6_low_thresh",
87-
.data = &nf_init_frags.low_thresh,
86+
.data = &init_net.nf_frag.frags.low_thresh,
8887
.maxlen = sizeof(unsigned int),
8988
.mode = 0644,
9089
.proc_handler = proc_dointvec,
9190
},
9291
{
9392
.procname = "nf_conntrack_frag6_high_thresh",
94-
.data = &nf_init_frags.high_thresh,
93+
.data = &init_net.nf_frag.frags.high_thresh,
9594
.maxlen = sizeof(unsigned int),
9695
.mode = 0644,
9796
.proc_handler = proc_dointvec,
9897
},
9998
{ }
10099
};
101100

102-
static struct ctl_table_header *nf_ct_frag6_sysctl_header;
101+
static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
102+
{
103+
struct ctl_table *table;
104+
struct ctl_table_header *hdr;
105+
106+
table = nf_ct_frag6_sysctl_table;
107+
if (!net_eq(net, &init_net)) {
108+
table = kmemdup(table, sizeof(nf_ct_frag6_sysctl_table),
109+
GFP_KERNEL);
110+
if (table == NULL)
111+
goto err_alloc;
112+
113+
table[0].data = &net->ipv6.frags.high_thresh;
114+
table[1].data = &net->ipv6.frags.low_thresh;
115+
table[2].data = &net->ipv6.frags.timeout;
116+
}
117+
118+
hdr = register_net_sysctl(net, "net/netfilter", table);
119+
if (hdr == NULL)
120+
goto err_reg;
121+
122+
net->ipv6.sysctl.frags_hdr = hdr;
123+
return 0;
124+
125+
err_reg:
126+
if (!net_eq(net, &init_net))
127+
kfree(table);
128+
err_alloc:
129+
return -ENOMEM;
130+
}
131+
132+
static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
133+
{
134+
struct ctl_table *table;
135+
136+
table = net->nf_frag.sysctl.frags_hdr->ctl_table_arg;
137+
unregister_net_sysctl_table(net->nf_frag.sysctl.frags_hdr);
138+
if (!net_eq(net, &init_net))
139+
kfree(table);
140+
}
141+
142+
#else
143+
static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
144+
{
145+
return 0;
146+
}
147+
static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
148+
{
149+
}
103150
#endif
104151

105152
static unsigned int nf_hashfn(struct inet_frag_queue *q)
@@ -131,13 +178,6 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
131178
inet_frag_kill(&fq->q, &nf_frags);
132179
}
133180

134-
static void nf_ct_frag6_evictor(void)
135-
{
136-
local_bh_disable();
137-
inet_frag_evictor(&nf_init_frags, &nf_frags);
138-
local_bh_enable();
139-
}
140-
141181
static void nf_ct_frag6_expire(unsigned long data)
142182
{
143183
struct nf_ct_frag6_queue *fq;
@@ -158,9 +198,9 @@ static void nf_ct_frag6_expire(unsigned long data)
158198
}
159199

160200
/* Creation primitives. */
161-
162-
static __inline__ struct nf_ct_frag6_queue *
163-
fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
201+
static inline struct nf_ct_frag6_queue *fq_find(struct net *net, __be32 id,
202+
u32 user, struct in6_addr *src,
203+
struct in6_addr *dst)
164204
{
165205
struct inet_frag_queue *q;
166206
struct ip6_create_arg arg;
@@ -174,7 +214,7 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
174214
read_lock_bh(&nf_frags.lock);
175215
hash = inet6_hash_frag(id, src, dst, nf_frags.rnd);
176216

177-
q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
217+
q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash);
178218
local_bh_enable();
179219
if (q == NULL)
180220
goto oom;
@@ -312,7 +352,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
312352
fq->q.meat += skb->len;
313353
if (payload_len > fq->q.max_size)
314354
fq->q.max_size = payload_len;
315-
atomic_add(skb->truesize, &nf_init_frags.mem);
355+
atomic_add(skb->truesize, &fq->q.net->mem);
316356

317357
/* The first fragment.
318358
* nhoffset is obtained from the first fragment, of course.
@@ -322,7 +362,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
322362
fq->q.last_in |= INET_FRAG_FIRST_IN;
323363
}
324364
write_lock(&nf_frags.lock);
325-
list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list);
365+
list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
326366
write_unlock(&nf_frags.lock);
327367
return 0;
328368

@@ -391,7 +431,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
391431
clone->ip_summed = head->ip_summed;
392432

393433
NFCT_FRAG6_CB(clone)->orig = NULL;
394-
atomic_add(clone->truesize, &nf_init_frags.mem);
434+
atomic_add(clone->truesize, &fq->q.net->mem);
395435
}
396436

397437
/* We have to remove fragment header from datagram and to relocate
@@ -415,7 +455,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
415455
head->csum = csum_add(head->csum, fp->csum);
416456
head->truesize += fp->truesize;
417457
}
418-
atomic_sub(head->truesize, &nf_init_frags.mem);
458+
atomic_sub(head->truesize, &fq->q.net->mem);
419459

420460
head->local_df = 1;
421461
head->next = NULL;
@@ -527,6 +567,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
527567
{
528568
struct sk_buff *clone;
529569
struct net_device *dev = skb->dev;
570+
struct net *net = skb_dst(skb) ? dev_net(skb_dst(skb)->dev)
571+
: dev_net(skb->dev);
530572
struct frag_hdr *fhdr;
531573
struct nf_ct_frag6_queue *fq;
532574
struct ipv6hdr *hdr;
@@ -560,10 +602,13 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
560602
hdr = ipv6_hdr(clone);
561603
fhdr = (struct frag_hdr *)skb_transport_header(clone);
562604

563-
if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh)
564-
nf_ct_frag6_evictor();
605+
if (atomic_read(&net->nf_frag.frags.mem) > net->nf_frag.frags.high_thresh) {
606+
local_bh_disable();
607+
inet_frag_evictor(&net->nf_frag.frags, &nf_frags);
608+
local_bh_enable();
609+
}
565610

566-
fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr);
611+
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
567612
if (fq == NULL) {
568613
pr_debug("Can't find and can't create new queue\n");
569614
goto ret_orig;
@@ -621,8 +666,31 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
621666
nf_conntrack_put_reasm(skb);
622667
}
623668

669+
static int nf_ct_net_init(struct net *net)
670+
{
671+
net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
672+
net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
673+
net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT;
674+
inet_frags_init_net(&net->nf_frag.frags);
675+
676+
return nf_ct_frag6_sysctl_register(net);
677+
}
678+
679+
static void nf_ct_net_exit(struct net *net)
680+
{
681+
nf_ct_frags6_sysctl_unregister(net);
682+
inet_frags_exit_net(&net->nf_frag.frags, &nf_frags);
683+
}
684+
685+
static struct pernet_operations nf_ct_net_ops = {
686+
.init = nf_ct_net_init,
687+
.exit = nf_ct_net_exit,
688+
};
689+
624690
int nf_ct_frag6_init(void)
625691
{
692+
int ret = 0;
693+
626694
nf_frags.hashfn = nf_hashfn;
627695
nf_frags.constructor = ip6_frag_init;
628696
nf_frags.destructor = NULL;
@@ -631,32 +699,17 @@ int nf_ct_frag6_init(void)
631699
nf_frags.match = ip6_frag_match;
632700
nf_frags.frag_expire = nf_ct_frag6_expire;
633701
nf_frags.secret_interval = 10 * 60 * HZ;
634-
nf_init_frags.timeout = IPV6_FRAG_TIMEOUT;
635-
nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
636-
nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH;
637-
inet_frags_init_net(&nf_init_frags);
638702
inet_frags_init(&nf_frags);
639703

640-
#ifdef CONFIG_SYSCTL
641-
nf_ct_frag6_sysctl_header = register_net_sysctl(&init_net, "net/netfilter",
642-
nf_ct_frag6_sysctl_table);
643-
if (!nf_ct_frag6_sysctl_header) {
704+
ret = register_pernet_subsys(&nf_ct_net_ops);
705+
if (ret)
644706
inet_frags_fini(&nf_frags);
645-
return -ENOMEM;
646-
}
647-
#endif
648707

649-
return 0;
708+
return ret;
650709
}
651710

652711
void nf_ct_frag6_cleanup(void)
653712
{
654-
#ifdef CONFIG_SYSCTL
655-
unregister_net_sysctl_table(nf_ct_frag6_sysctl_header);
656-
nf_ct_frag6_sysctl_header = NULL;
657-
#endif
713+
unregister_pernet_subsys(&nf_ct_net_ops);
658714
inet_frags_fini(&nf_frags);
659-
660-
nf_init_frags.low_thresh = 0;
661-
nf_ct_frag6_evictor();
662715
}

0 commit comments

Comments
 (0)