1 /*
2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10 */
11
12 #include <assert.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <xtables.h>
17
18 #include <linux/netfilter/nf_tables.h>
19
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/gen.h>
22 #include <libnftnl/set.h>
23 #include <libnftnl/table.h>
24
25 #include "nft.h"
26 #include "nft-cache.h"
27 #include "nft-chain.h"
28
cache_chain_list_insert(struct list_head * list,const char * name)29 static void cache_chain_list_insert(struct list_head *list, const char *name)
30 {
31 struct cache_chain *pos = NULL, *new;
32
33 list_for_each_entry(pos, list, head) {
34 int cmp = strcmp(pos->name, name);
35
36 if (!cmp)
37 return;
38 if (cmp > 0)
39 break;
40 }
41
42 new = xtables_malloc(sizeof(*new));
43 new->name = strdup(name);
44 list_add_tail(&new->head, pos ? &pos->head : list);
45 }
46
nft_cache_level_set(struct nft_handle * h,int level,const struct nft_cmd * cmd)47 void nft_cache_level_set(struct nft_handle *h, int level,
48 const struct nft_cmd *cmd)
49 {
50 struct nft_cache_req *req = &h->cache_req;
51
52 if (level > req->level)
53 req->level = level;
54
55 if (!cmd || !cmd->table || req->all_chains)
56 return;
57
58 if (!req->table)
59 req->table = strdup(cmd->table);
60 else
61 assert(!strcmp(req->table, cmd->table));
62
63 if (!cmd->chain) {
64 req->all_chains = true;
65 return;
66 }
67
68 cache_chain_list_insert(&req->chain_list, cmd->chain);
69 if (cmd->rename)
70 cache_chain_list_insert(&req->chain_list, cmd->rename);
71 if (cmd->jumpto)
72 cache_chain_list_insert(&req->chain_list, cmd->jumpto);
73 }
74
genid_cb(const struct nlmsghdr * nlh,void * data)75 static int genid_cb(const struct nlmsghdr *nlh, void *data)
76 {
77 uint32_t *genid = data;
78 struct nftnl_gen *gen;
79
80 gen = nftnl_gen_alloc();
81 if (!gen)
82 return MNL_CB_ERROR;
83
84 if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
85 goto out;
86
87 *genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
88
89 nftnl_gen_free(gen);
90 return MNL_CB_STOP;
91 out:
92 nftnl_gen_free(gen);
93 return MNL_CB_ERROR;
94 }
95
mnl_genid_get(struct nft_handle * h,uint32_t * genid)96 static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
97 {
98 char buf[MNL_SOCKET_BUFFER_SIZE];
99 struct nlmsghdr *nlh;
100 int ret;
101
102 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
103 ret = mnl_talk(h, nlh, genid_cb, genid);
104 if (ret == 0)
105 return;
106
107 xtables_error(RESOURCE_PROBLEM,
108 "Could not fetch rule set generation id: %s\n", nft_strerror(errno));
109 }
110
nftnl_table_list_cb(const struct nlmsghdr * nlh,void * data)111 static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
112 {
113 struct nftnl_table *nftnl = nftnl_table_alloc();
114 const struct builtin_table *t;
115 struct nft_handle *h = data;
116 const char *name;
117
118 if (!nftnl)
119 return MNL_CB_OK;
120
121 if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0)
122 goto out;
123
124 name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME);
125 if (!name)
126 goto out;
127
128 t = nft_table_builtin_find(h, name);
129 if (!t)
130 goto out;
131
132 h->cache->table[t->type].exists = true;
133 out:
134 nftnl_table_free(nftnl);
135 return MNL_CB_OK;
136 }
137
fetch_table_cache(struct nft_handle * h)138 static int fetch_table_cache(struct nft_handle *h)
139 {
140 struct nlmsghdr *nlh;
141 char buf[16536];
142 int i, ret;
143
144 nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
145 NLM_F_DUMP, h->seq);
146
147 ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
148 if (ret < 0 && errno == EINTR)
149 assert(nft_restart(h) >= 0);
150
151 for (i = 0; i < NFT_TABLE_MAX; i++) {
152 enum nft_table_type type = h->tables[i].type;
153
154 if (!h->tables[i].name)
155 continue;
156
157 h->cache->table[type].chains = nft_chain_list_alloc();
158
159 h->cache->table[type].sets = nftnl_set_list_alloc();
160 if (!h->cache->table[type].sets)
161 return 0;
162 }
163
164 return 1;
165 }
166
djb_hash(const char * key)167 static uint32_t djb_hash(const char *key)
168 {
169 uint32_t i, hash = 5381;
170
171 for (i = 0; i < strlen(key); i++)
172 hash = ((hash << 5) + hash) + key[i];
173
174 return hash;
175 }
176
chain_name_hlist(struct nft_handle * h,const struct builtin_table * t,const char * chain)177 static struct hlist_head *chain_name_hlist(struct nft_handle *h,
178 const struct builtin_table *t,
179 const char *chain)
180 {
181 int key = djb_hash(chain) % CHAIN_NAME_HSIZE;
182
183 return &h->cache->table[t->type].chains->names[key];
184 }
185
186 struct nft_chain *
nft_chain_find(struct nft_handle * h,const char * table,const char * chain)187 nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
188 {
189 const struct builtin_table *t;
190 struct hlist_node *node;
191 struct nft_chain *c;
192
193 t = nft_table_builtin_find(h, table);
194 if (!t)
195 return NULL;
196
197 hlist_for_each_entry(c, node, chain_name_hlist(h, t, chain), hnode) {
198 if (!strcmp(nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME),
199 chain))
200 return c;
201 }
202 return NULL;
203 }
204
nft_cache_add_chain(struct nft_handle * h,const struct builtin_table * t,struct nftnl_chain * c)205 int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
206 struct nftnl_chain *c)
207 {
208 const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
209 struct nft_chain *nc = nft_chain_alloc(c);
210
211 if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
212 uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
213
214 if (hooknum >= NF_INET_NUMHOOKS) {
215 nft_chain_free(nc);
216 return -EINVAL;
217 }
218
219 if (h->cache->table[t->type].base_chains[hooknum]) {
220 nft_chain_free(nc);
221 return -EEXIST;
222 }
223
224 h->cache->table[t->type].base_chains[hooknum] = nc;
225 } else {
226 struct nft_chain_list *clist = h->cache->table[t->type].chains;
227 struct list_head *pos = &clist->list;
228 struct nft_chain *cur;
229 const char *n;
230
231 list_for_each_entry(cur, &clist->list, head) {
232 n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
233 if (strcmp(cname, n) <= 0) {
234 pos = &cur->head;
235 break;
236 }
237 }
238 list_add_tail(&nc->head, pos);
239 }
240 hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
241 return 0;
242 }
243
244 struct nftnl_chain_list_cb_data {
245 struct nft_handle *h;
246 const struct builtin_table *t;
247 };
248
nftnl_chain_list_cb(const struct nlmsghdr * nlh,void * data)249 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
250 {
251 struct nftnl_chain_list_cb_data *d = data;
252 const struct builtin_table *t = d->t;
253 struct nft_handle *h = d->h;
254 struct nftnl_chain *c;
255 const char *tname;
256
257 c = nftnl_chain_alloc();
258 if (c == NULL)
259 goto err;
260
261 if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
262 goto out;
263
264 tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
265
266 if (!t) {
267 t = nft_table_builtin_find(h, tname);
268 if (!t)
269 goto out;
270 } else if (strcmp(t->name, tname)) {
271 goto out;
272 }
273
274 if (nft_cache_add_chain(h, t, c))
275 goto out;
276
277 return MNL_CB_OK;
278 out:
279 nftnl_chain_free(c);
280 err:
281 return MNL_CB_OK;
282 }
283
284 struct nftnl_set_list_cb_data {
285 struct nft_handle *h;
286 const struct builtin_table *t;
287 };
288
nftnl_set_list_cb(const struct nlmsghdr * nlh,void * data)289 static int nftnl_set_list_cb(const struct nlmsghdr *nlh, void *data)
290 {
291 struct nftnl_set_list_cb_data *d = data;
292 const struct builtin_table *t = d->t;
293 struct nftnl_set_list *list;
294 struct nft_handle *h = d->h;
295 const char *tname, *sname;
296 struct nftnl_set *s;
297
298 s = nftnl_set_alloc();
299 if (s == NULL)
300 return MNL_CB_OK;
301
302 if (nftnl_set_nlmsg_parse(nlh, s) < 0)
303 goto out_free;
304
305 tname = nftnl_set_get_str(s, NFTNL_SET_TABLE);
306
307 if (!t)
308 t = nft_table_builtin_find(h, tname);
309 else if (strcmp(t->name, tname))
310 goto out_free;
311
312 if (!t)
313 goto out_free;
314
315 list = h->cache->table[t->type].sets;
316 sname = nftnl_set_get_str(s, NFTNL_SET_NAME);
317
318 if (nftnl_set_list_lookup_byname(list, sname))
319 goto out_free;
320
321 nftnl_set_list_add_tail(s, list);
322
323 return MNL_CB_OK;
324 out_free:
325 nftnl_set_free(s);
326 return MNL_CB_OK;
327 }
328
set_elem_cb(const struct nlmsghdr * nlh,void * data)329 static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
330 {
331 return nftnl_set_elems_nlmsg_parse(nlh, data) ? -1 : MNL_CB_OK;
332 }
333
set_has_elements(struct nftnl_set * s)334 static bool set_has_elements(struct nftnl_set *s)
335 {
336 struct nftnl_set_elems_iter *iter;
337 bool ret = false;
338
339 iter = nftnl_set_elems_iter_create(s);
340 if (iter) {
341 ret = !!nftnl_set_elems_iter_cur(iter);
342 nftnl_set_elems_iter_destroy(iter);
343 }
344 return ret;
345 }
346
set_fetch_elem_cb(struct nftnl_set * s,void * data)347 static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
348 {
349 char buf[MNL_SOCKET_BUFFER_SIZE];
350 struct nft_handle *h = data;
351 struct nlmsghdr *nlh;
352
353 if (set_has_elements(s))
354 return 0;
355
356 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, h->family,
357 NLM_F_DUMP, h->seq);
358 nftnl_set_elems_nlmsg_build_payload(nlh, s);
359
360 return mnl_talk(h, nlh, set_elem_cb, s);
361 }
362
fetch_set_cache(struct nft_handle * h,const struct builtin_table * t,const char * set)363 static int fetch_set_cache(struct nft_handle *h,
364 const struct builtin_table *t, const char *set)
365 {
366 struct nftnl_set_list_cb_data d = {
367 .h = h,
368 .t = t,
369 };
370 uint16_t flags = NLM_F_DUMP;
371 struct nftnl_set *s = NULL;
372 struct nlmsghdr *nlh;
373 char buf[16536];
374 int i, ret;
375
376 if (t) {
377 s = nftnl_set_alloc();
378 if (!s)
379 return -1;
380
381 nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
382
383 if (set) {
384 nftnl_set_set_str(s, NFTNL_SET_NAME, set);
385 flags = NLM_F_ACK;
386 }
387 }
388
389 nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
390 h->family, flags, h->seq);
391
392 if (s) {
393 nftnl_set_nlmsg_build_payload(nlh, s);
394 nftnl_set_free(s);
395 }
396
397 ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
398 if (ret < 0 && errno == EINTR) {
399 assert(nft_restart(h) >= 0);
400 return ret;
401 }
402
403 if (t) {
404 nftnl_set_list_foreach(h->cache->table[t->type].sets,
405 set_fetch_elem_cb, h);
406 } else {
407 for (i = 0; i < NFT_TABLE_MAX; i++) {
408 enum nft_table_type type = h->tables[i].type;
409
410 if (!h->tables[i].name)
411 continue;
412
413 nftnl_set_list_foreach(h->cache->table[type].sets,
414 set_fetch_elem_cb, h);
415 }
416 }
417 return ret;
418 }
419
__fetch_chain_cache(struct nft_handle * h,const struct builtin_table * t,const struct nftnl_chain * c)420 static int __fetch_chain_cache(struct nft_handle *h,
421 const struct builtin_table *t,
422 const struct nftnl_chain *c)
423 {
424 struct nftnl_chain_list_cb_data d = {
425 .h = h,
426 .t = t,
427 };
428 char buf[16536];
429 struct nlmsghdr *nlh;
430 int ret;
431
432 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
433 c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
434 if (c)
435 nftnl_chain_nlmsg_build_payload(nlh, c);
436
437 ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
438 if (ret < 0 && errno == EINTR)
439 assert(nft_restart(h) >= 0);
440
441 return ret;
442 }
443
fetch_chain_cache(struct nft_handle * h,const struct builtin_table * t,struct list_head * chains)444 static int fetch_chain_cache(struct nft_handle *h,
445 const struct builtin_table *t,
446 struct list_head *chains)
447 {
448 struct cache_chain *cc;
449 struct nftnl_chain *c;
450 int rc, ret = 0;
451
452 if (!chains)
453 return __fetch_chain_cache(h, t, NULL);
454
455 assert(t);
456
457 c = nftnl_chain_alloc();
458 if (!c)
459 return -1;
460
461 nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
462
463 list_for_each_entry(cc, chains, head) {
464 nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
465 rc = __fetch_chain_cache(h, t, c);
466 if (rc)
467 ret = rc;
468 }
469
470 nftnl_chain_free(c);
471 return ret;
472 }
473
nftnl_rule_list_cb(const struct nlmsghdr * nlh,void * data)474 static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
475 {
476 struct nftnl_chain *c = data;
477 struct nftnl_rule *r;
478
479 r = nftnl_rule_alloc();
480 if (r == NULL)
481 return MNL_CB_OK;
482
483 if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
484 nftnl_rule_free(r);
485 return MNL_CB_OK;
486 }
487
488 nftnl_chain_rule_add_tail(r, c);
489 return MNL_CB_OK;
490 }
491
nft_rule_list_update(struct nft_chain * nc,void * data)492 static int nft_rule_list_update(struct nft_chain *nc, void *data)
493 {
494 struct nftnl_chain *c = nc->nftnl;
495 struct nft_handle *h = data;
496 char buf[16536];
497 struct nlmsghdr *nlh;
498 struct nftnl_rule *rule;
499 int ret;
500
501 if (nftnl_rule_lookup_byindex(c, 0))
502 return 0;
503
504 rule = nftnl_rule_alloc();
505 if (!rule)
506 return -1;
507
508 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
509 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
510 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
511 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
512
513 nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
514 NLM_F_DUMP, h->seq);
515 nftnl_rule_nlmsg_build_payload(nlh, rule);
516
517 ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
518 if (ret < 0 && errno == EINTR)
519 assert(nft_restart(h) >= 0);
520
521 nftnl_rule_free(rule);
522
523 if (h->family == NFPROTO_BRIDGE)
524 nft_bridge_chain_postprocess(h, c);
525
526 return 0;
527 }
528
fetch_rule_cache(struct nft_handle * h,const struct builtin_table * t)529 static int fetch_rule_cache(struct nft_handle *h,
530 const struct builtin_table *t)
531 {
532 int i;
533
534 if (t)
535 return nft_chain_foreach(h, t->name, nft_rule_list_update, h);
536
537 for (i = 0; i < NFT_TABLE_MAX; i++) {
538
539 if (!h->tables[i].name)
540 continue;
541
542 if (nft_chain_foreach(h, h->tables[i].name,
543 nft_rule_list_update, h))
544 return -1;
545 }
546 return 0;
547 }
548
549 static int flush_cache(struct nft_handle *h, struct nft_cache *c,
550 const char *tablename);
551
552 static void
__nft_build_cache(struct nft_handle * h)553 __nft_build_cache(struct nft_handle *h)
554 {
555 struct nft_cache_req *req = &h->cache_req;
556 const struct builtin_table *t = NULL;
557 struct list_head *chains = NULL;
558 uint32_t genid_check;
559
560 if (h->cache_init)
561 return;
562
563 if (req->table) {
564 t = nft_table_builtin_find(h, req->table);
565 if (!req->all_chains)
566 chains = &req->chain_list;
567 }
568
569 h->cache_init = true;
570 retry:
571 mnl_genid_get(h, &h->nft_genid);
572
573 if (req->level >= NFT_CL_TABLES)
574 fetch_table_cache(h);
575 if (req->level == NFT_CL_FAKE)
576 goto genid_check;
577 if (req->level >= NFT_CL_CHAINS)
578 fetch_chain_cache(h, t, chains);
579 if (req->level >= NFT_CL_SETS)
580 fetch_set_cache(h, t, NULL);
581 if (req->level >= NFT_CL_RULES)
582 fetch_rule_cache(h, t);
583 genid_check:
584 mnl_genid_get(h, &genid_check);
585 if (h->nft_genid != genid_check) {
586 flush_cache(h, h->cache, NULL);
587 goto retry;
588 }
589 }
590
__nft_flush_cache(struct nft_handle * h)591 static void __nft_flush_cache(struct nft_handle *h)
592 {
593 if (!h->cache_index) {
594 h->cache_index++;
595 h->cache = &h->__cache[h->cache_index];
596 } else {
597 flush_chain_cache(h, NULL);
598 }
599 }
600
____flush_rule_cache(struct nftnl_rule * r,void * data)601 static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
602 {
603 nftnl_rule_list_del(r);
604 nftnl_rule_free(r);
605
606 return 0;
607 }
608
__flush_rule_cache(struct nft_chain * c,void * data)609 static int __flush_rule_cache(struct nft_chain *c, void *data)
610 {
611 return nftnl_rule_foreach(c->nftnl, ____flush_rule_cache, NULL);
612 }
613
flush_rule_cache(struct nft_handle * h,const char * table,struct nft_chain * c)614 int flush_rule_cache(struct nft_handle *h, const char *table,
615 struct nft_chain *c)
616 {
617 if (c)
618 return __flush_rule_cache(c, NULL);
619
620 nft_chain_foreach(h, table, __flush_rule_cache, NULL);
621 return 0;
622 }
623
__flush_chain_cache(struct nft_chain * c,void * data)624 static int __flush_chain_cache(struct nft_chain *c, void *data)
625 {
626 nft_chain_list_del(c);
627 nft_chain_free(c);
628
629 return 0;
630 }
631
__flush_set_cache(struct nftnl_set * s,void * data)632 static int __flush_set_cache(struct nftnl_set *s, void *data)
633 {
634 nftnl_set_list_del(s);
635 nftnl_set_free(s);
636
637 return 0;
638 }
639
flush_base_chain_cache(struct nft_chain ** base_chains)640 static void flush_base_chain_cache(struct nft_chain **base_chains)
641 {
642 int i;
643
644 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
645 if (!base_chains[i])
646 continue;
647 hlist_del(&base_chains[i]->hnode);
648 nft_chain_free(base_chains[i]);
649 base_chains[i] = NULL;
650 }
651 }
652
flush_cache(struct nft_handle * h,struct nft_cache * c,const char * tablename)653 static int flush_cache(struct nft_handle *h, struct nft_cache *c,
654 const char *tablename)
655 {
656 const struct builtin_table *table;
657 int i;
658
659 if (tablename) {
660 table = nft_table_builtin_find(h, tablename);
661 if (!table)
662 return 0;
663
664 flush_base_chain_cache(c->table[table->type].base_chains);
665 nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
666
667 if (c->table[table->type].sets)
668 nftnl_set_list_foreach(c->table[table->type].sets,
669 __flush_set_cache, NULL);
670 return 0;
671 }
672
673 for (i = 0; i < NFT_TABLE_MAX; i++) {
674 if (h->tables[i].name == NULL)
675 continue;
676
677 flush_base_chain_cache(c->table[i].base_chains);
678 if (c->table[i].chains) {
679 nft_chain_list_free(c->table[i].chains);
680 c->table[i].chains = NULL;
681 }
682
683 if (c->table[i].sets) {
684 nftnl_set_list_free(c->table[i].sets);
685 c->table[i].sets = NULL;
686 }
687
688 c->table[i].exists = false;
689 }
690
691 return 1;
692 }
693
flush_chain_cache(struct nft_handle * h,const char * tablename)694 void flush_chain_cache(struct nft_handle *h, const char *tablename)
695 {
696 if (!h->cache_init)
697 return;
698
699 if (flush_cache(h, h->cache, tablename))
700 h->cache_init = false;
701 }
702
nft_rebuild_cache(struct nft_handle * h)703 void nft_rebuild_cache(struct nft_handle *h)
704 {
705 if (h->cache_init) {
706 __nft_flush_cache(h);
707 h->cache_init = false;
708 }
709
710 __nft_build_cache(h);
711 }
712
nft_cache_build(struct nft_handle * h)713 void nft_cache_build(struct nft_handle *h)
714 {
715 struct nft_cache_req *req = &h->cache_req;
716 const struct builtin_table *t = NULL;
717 int i;
718
719 if (req->table)
720 t = nft_table_builtin_find(h, req->table);
721
722 /* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
723 * doesn't override policies by accident */
724 if (t && !req->all_chains) {
725 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
726 const char *cname = t->chains[i].name;
727
728 if (!cname)
729 break;
730 cache_chain_list_insert(&req->chain_list, cname);
731 }
732 }
733
734 __nft_build_cache(h);
735 }
736
nft_release_cache(struct nft_handle * h)737 void nft_release_cache(struct nft_handle *h)
738 {
739 struct nft_cache_req *req = &h->cache_req;
740 struct cache_chain *cc, *cc_tmp;
741
742 while (h->cache_index)
743 flush_cache(h, &h->__cache[h->cache_index--], NULL);
744 flush_cache(h, &h->__cache[0], NULL);
745 h->cache = &h->__cache[0];
746 h->cache_init = false;
747
748 if (req->level != NFT_CL_FAKE)
749 req->level = NFT_CL_TABLES;
750 if (req->table) {
751 free(req->table);
752 req->table = NULL;
753 }
754 req->all_chains = false;
755 list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
756 list_del(&cc->head);
757 free(cc->name);
758 free(cc);
759 }
760 }
761
762 struct nftnl_set_list *
nft_set_list_get(struct nft_handle * h,const char * table,const char * set)763 nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
764 {
765 const struct builtin_table *t;
766
767 t = nft_table_builtin_find(h, table);
768 if (!t)
769 return NULL;
770
771 return h->cache->table[t->type].sets;
772 }
773