Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: conntrack: add nf_ct_iter_data object for nf_ct_iterate_cleanup*()

This patch adds a structure to collect all the context data that is
passed to the cleanup iterator.

struct nf_ct_iter_data {
struct net *net;
void *data;
u32 portid;
int report;
};

There is a netns field that allows to clean up conntrack entries
specifically owned by the specified netns.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+56 -44
+9 -3
include/net/netfilter/nf_conntrack.h
··· 236 236 return nf_ct_delete(ct, 0, 0); 237 237 } 238 238 239 + struct nf_ct_iter_data { 240 + struct net *net; 241 + void *data; 242 + u32 portid; 243 + int report; 244 + }; 245 + 239 246 /* Iterate over all conntracks: if iter returns true, it's deleted. */ 240 - void nf_ct_iterate_cleanup_net(struct net *net, 241 - int (*iter)(struct nf_conn *i, void *data), 242 - void *data, u32 portid, int report); 247 + void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data), 248 + const struct nf_ct_iter_data *iter_data); 243 249 244 250 /* also set unconfirmed conntracks as dying. Only use in module exit path. */ 245 251 void nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data),
+22 -34
net/netfilter/nf_conntrack_core.c
··· 2335 2335 /* Bring out ya dead! */ 2336 2336 static struct nf_conn * 2337 2337 get_next_corpse(int (*iter)(struct nf_conn *i, void *data), 2338 - void *data, unsigned int *bucket) 2338 + const struct nf_ct_iter_data *iter_data, unsigned int *bucket) 2339 2339 { 2340 2340 struct nf_conntrack_tuple_hash *h; 2341 2341 struct nf_conn *ct; ··· 2366 2366 * tuple while iterating. 2367 2367 */ 2368 2368 ct = nf_ct_tuplehash_to_ctrack(h); 2369 - if (iter(ct, data)) 2369 + 2370 + if (iter_data->net && 2371 + !net_eq(iter_data->net, nf_ct_net(ct))) 2372 + continue; 2373 + 2374 + if (iter(ct, iter_data->data)) 2370 2375 goto found; 2371 2376 } 2372 2377 spin_unlock(lockp); ··· 2388 2383 } 2389 2384 2390 2385 static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), 2391 - void *data, u32 portid, int report) 2386 + const struct nf_ct_iter_data *iter_data) 2392 2387 { 2393 2388 unsigned int bucket = 0; 2394 2389 struct nf_conn *ct; ··· 2396 2391 might_sleep(); 2397 2392 2398 2393 mutex_lock(&nf_conntrack_mutex); 2399 - while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) { 2394 + while ((ct = get_next_corpse(iter, iter_data, &bucket)) != NULL) { 2400 2395 /* Time to push up daises... */ 2401 2396 2402 - nf_ct_delete(ct, portid, report); 2397 + nf_ct_delete(ct, iter_data->portid, iter_data->report); 2403 2398 nf_ct_put(ct); 2404 2399 cond_resched(); 2405 2400 } 2406 2401 mutex_unlock(&nf_conntrack_mutex); 2407 2402 } 2408 2403 2409 - struct iter_data { 2410 - int (*iter)(struct nf_conn *i, void *data); 2411 - void *data; 2412 - struct net *net; 2413 - }; 2414 - 2415 - static int iter_net_only(struct nf_conn *i, void *data) 2404 + void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data), 2405 + const struct nf_ct_iter_data *iter_data) 2416 2406 { 2417 - struct iter_data *d = data; 2418 - 2419 - if (!net_eq(d->net, nf_ct_net(i))) 2420 - return 0; 2421 - 2422 - return d->iter(i, d->data); 2423 - } 2424 - 2425 - void nf_ct_iterate_cleanup_net(struct net *net, 2426 - int (*iter)(struct nf_conn *i, void *data), 2427 - void *data, u32 portid, int report) 2428 - { 2407 + struct net *net = iter_data->net; 2429 2408 struct nf_conntrack_net *cnet = nf_ct_pernet(net); 2430 - struct iter_data d; 2431 2409 2432 2410 might_sleep(); 2433 2411 2434 2412 if (atomic_read(&cnet->count) == 0) 2435 2413 return; 2436 2414 2437 - d.iter = iter; 2438 - d.data = data; 2439 - d.net = net; 2440 - 2441 - nf_ct_iterate_cleanup(iter_net_only, &d, portid, report); 2415 + nf_ct_iterate_cleanup(iter, iter_data); 2442 2416 } 2443 2417 EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net); 2444 2418 ··· 2435 2451 void 2436 2452 nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data) 2437 2453 { 2454 + struct nf_ct_iter_data iter_data = {}; 2438 2455 struct net *net; 2439 2456 2440 2457 down_read(&net_rwsem); ··· 2463 2478 synchronize_net(); 2464 2479 2465 2480 nf_ct_ext_bump_genid(); 2466 - nf_ct_iterate_cleanup(iter, data, 0, 0); 2481 + iter_data.data = data; 2482 + nf_ct_iterate_cleanup(iter, &iter_data); 2467 2483 2468 2484 /* Another cpu might be in a rcu read section with 2469 2485 * rcu protected pointer cleared in iter callback ··· 2478 2492 2479 2493 static int kill_all(struct nf_conn *i, void *data) 2480 2494 { 2481 - return net_eq(nf_ct_net(i), data); 2495 + return 1; 2482 2496 } 2483 2497 2484 2498 void nf_conntrack_cleanup_start(void) ··· 2513 2527 2514 2528 void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) 2515 2529 { 2516 - int busy; 2530 + struct nf_ct_iter_data iter_data = {}; 2517 2531 struct net *net; 2532 + int busy; 2518 2533 2519 2534 /* 2520 2535 * This makes sure all current packets have passed through ··· 2528 2541 list_for_each_entry(net, net_exit_list, exit_list) { 2529 2542 struct nf_conntrack_net *cnet = nf_ct_pernet(net); 2530 2543 2531 - nf_ct_iterate_cleanup(kill_all, net, 0, 0); 2544 + iter_data.net = net; 2545 + nf_ct_iterate_cleanup_net(kill_all, &iter_data); 2532 2546 if (atomic_read(&cnet->count) != 0) 2533 2547 busy = 1; 2534 2548 }
+8 -2
net/netfilter/nf_conntrack_netlink.c
··· 1559 1559 u32 portid, int report, u8 family) 1560 1560 { 1561 1561 struct ctnetlink_filter *filter = NULL; 1562 + struct nf_ct_iter_data iter = { 1563 + .net = net, 1564 + .portid = portid, 1565 + .report = report, 1566 + }; 1562 1567 1563 1568 if (ctnetlink_needs_filter(family, cda)) { 1564 1569 if (cda[CTA_FILTER]) ··· 1572 1567 filter = ctnetlink_alloc_filter(cda, family); 1573 1568 if (IS_ERR(filter)) 1574 1569 return PTR_ERR(filter); 1570 + 1571 + iter.data = filter; 1575 1572 } 1576 1573 1577 - nf_ct_iterate_cleanup_net(net, ctnetlink_flush_iterate, filter, 1578 - portid, report); 1574 + nf_ct_iterate_cleanup_net(ctnetlink_flush_iterate, &iter); 1579 1575 kfree(filter); 1580 1576 1581 1577 return 0;
+7 -3
net/netfilter/nf_conntrack_proto.c
··· 538 538 out_unlock: 539 539 mutex_unlock(&nf_ct_proto_mutex); 540 540 541 - if (fixup_needed) 542 - nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup, 543 - (void *)(unsigned long)nfproto, 0, 0); 541 + if (fixup_needed) { 542 + struct nf_ct_iter_data iter_data = { 543 + .net = net, 544 + .data = (void *)(unsigned long)nfproto, 545 + }; 546 + nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data); 547 + } 544 548 545 549 return err; 546 550 }
+6 -1
net/netfilter/nf_conntrack_timeout.c
··· 38 38 39 39 void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout) 40 40 { 41 - nf_ct_iterate_cleanup_net(net, untimeout, timeout, 0, 0); 41 + struct nf_ct_iter_data iter_data = { 42 + .net = net, 43 + .data = timeout, 44 + }; 45 + 46 + nf_ct_iterate_cleanup_net(untimeout, &iter_data); 42 47 } 43 48 EXPORT_SYMBOL_GPL(nf_ct_untimeout); 44 49
+4 -1
net/netfilter/nf_nat_masquerade.c
··· 77 77 78 78 static void iterate_cleanup_work(struct work_struct *work) 79 79 { 80 + struct nf_ct_iter_data iter_data = {}; 80 81 struct masq_dev_work *w; 81 82 82 83 w = container_of(work, struct masq_dev_work, work); 83 84 84 - nf_ct_iterate_cleanup_net(w->net, w->iter, (void *)w, 0, 0); 85 + iter_data.net = w->net; 86 + iter_data.data = (void *)w; 87 + nf_ct_iterate_cleanup_net(w->iter, &iter_data); 85 88 86 89 put_net_track(w->net, &w->ns_tracker); 87 90 kfree(w);