libnftnl  1.2.9
ruleset.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  * (C) 2013 by Arturo Borrero Gonzalez <arturo@debian.org>
5  * (C) 2013 by Alvaro Neira Ayuso <alvaroneay@gmail.com>
6  *
7  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
8  */
9 
10 #include <errno.h>
11 
12 #include "internal.h"
13 #include <stdlib.h>
14 
15 #include <libmnl/libmnl.h>
16 #include <libnftnl/ruleset.h>
17 #include <libnftnl/table.h>
18 #include <libnftnl/chain.h>
19 #include <libnftnl/set.h>
20 #include <libnftnl/rule.h>
21 
22 struct nftnl_ruleset {
23  struct nftnl_table_list *table_list;
24  struct nftnl_chain_list *chain_list;
25  struct nftnl_set_list *set_list;
26  struct nftnl_rule_list *rule_list;
27 
28  uint16_t flags;
29 };
30 
32  enum nftnl_cmd_type cmd;
33  enum nftnl_ruleset_type type;
34  union {
35  struct nftnl_table *table;
36  struct nftnl_chain *chain;
37  struct nftnl_rule *rule;
38  struct nftnl_set *set;
39  struct nftnl_set_elem *set_elem;
40  };
41  void *data;
42 
43  /* These fields below are not exposed to the user */
44  uint32_t format;
45  uint32_t set_id;
46  struct nftnl_set_list *set_list;
47 
48  int (*cb)(const struct nftnl_parse_ctx *ctx);
49  uint16_t flags;
50 };
51 
52 EXPORT_SYMBOL(nftnl_ruleset_alloc);
53 struct nftnl_ruleset *nftnl_ruleset_alloc(void)
54 {
55  return calloc(1, sizeof(struct nftnl_ruleset));
56 }
57 
58 EXPORT_SYMBOL(nftnl_ruleset_free);
59 void nftnl_ruleset_free(const struct nftnl_ruleset *r)
60 {
61  if (r->flags & (1 << NFTNL_RULESET_TABLELIST))
62  nftnl_table_list_free(r->table_list);
63  if (r->flags & (1 << NFTNL_RULESET_CHAINLIST))
64  nftnl_chain_list_free(r->chain_list);
65  if (r->flags & (1 << NFTNL_RULESET_SETLIST))
66  nftnl_set_list_free(r->set_list);
67  if (r->flags & (1 << NFTNL_RULESET_RULELIST))
68  nftnl_rule_list_free(r->rule_list);
69  xfree(r);
70 }
71 
72 EXPORT_SYMBOL(nftnl_ruleset_is_set);
73 bool nftnl_ruleset_is_set(const struct nftnl_ruleset *r, uint16_t attr)
74 {
75  return r->flags & (1 << attr);
76 }
77 
78 EXPORT_SYMBOL(nftnl_ruleset_unset);
79 void nftnl_ruleset_unset(struct nftnl_ruleset *r, uint16_t attr)
80 {
81  if (!(r->flags & (1 << attr)))
82  return;
83 
84  switch (attr) {
85  case NFTNL_RULESET_TABLELIST:
86  nftnl_table_list_free(r->table_list);
87  break;
88  case NFTNL_RULESET_CHAINLIST:
89  nftnl_chain_list_free(r->chain_list);
90  break;
91  case NFTNL_RULESET_SETLIST:
92  nftnl_set_list_free(r->set_list);
93  break;
94  case NFTNL_RULESET_RULELIST:
95  nftnl_rule_list_free(r->rule_list);
96  break;
97  }
98  r->flags &= ~(1 << attr);
99 }
100 
101 EXPORT_SYMBOL(nftnl_ruleset_set);
102 void nftnl_ruleset_set(struct nftnl_ruleset *r, uint16_t attr, void *data)
103 {
104  switch (attr) {
105  case NFTNL_RULESET_TABLELIST:
106  nftnl_ruleset_unset(r, NFTNL_RULESET_TABLELIST);
107  r->table_list = data;
108  break;
109  case NFTNL_RULESET_CHAINLIST:
110  nftnl_ruleset_unset(r, NFTNL_RULESET_CHAINLIST);
111  r->chain_list = data;
112  break;
113  case NFTNL_RULESET_SETLIST:
114  nftnl_ruleset_unset(r, NFTNL_RULESET_SETLIST);
115  r->set_list = data;
116  break;
117  case NFTNL_RULESET_RULELIST:
118  nftnl_ruleset_unset(r, NFTNL_RULESET_RULELIST);
119  r->rule_list = data;
120  break;
121  default:
122  return;
123  }
124  r->flags |= (1 << attr);
125 }
126 
127 EXPORT_SYMBOL(nftnl_ruleset_get);
128 void *nftnl_ruleset_get(const struct nftnl_ruleset *r, uint16_t attr)
129 {
130  if (!(r->flags & (1 << attr)))
131  return NULL;
132 
133  switch (attr) {
134  case NFTNL_RULESET_TABLELIST:
135  return r->table_list;
136  case NFTNL_RULESET_CHAINLIST:
137  return r->chain_list;
138  case NFTNL_RULESET_SETLIST:
139  return r->set_list;
140  case NFTNL_RULESET_RULELIST:
141  return r->rule_list;
142  default:
143  return NULL;
144  }
145 }
146 
147 EXPORT_SYMBOL(nftnl_ruleset_ctx_free);
148 void nftnl_ruleset_ctx_free(const struct nftnl_parse_ctx *ctx)
149 {
150  switch (ctx->type) {
151  case NFTNL_RULESET_TABLE:
152  nftnl_table_free(ctx->table);
153  break;
154  case NFTNL_RULESET_CHAIN:
155  nftnl_chain_free(ctx->chain);
156  break;
157  case NFTNL_RULESET_RULE:
158  nftnl_rule_free(ctx->rule);
159  break;
160  case NFTNL_RULESET_SET:
161  case NFTNL_RULESET_SET_ELEMS:
162  nftnl_set_free(ctx->set);
163  break;
164  case NFTNL_RULESET_RULESET:
165  case NFTNL_RULESET_UNSPEC:
166  break;
167  }
168 }
169 
170 EXPORT_SYMBOL(nftnl_ruleset_ctx_is_set);
171 bool nftnl_ruleset_ctx_is_set(const struct nftnl_parse_ctx *ctx, uint16_t attr)
172 {
173  return ctx->flags & (1 << attr);
174 }
175 
176 EXPORT_SYMBOL(nftnl_ruleset_ctx_get);
177 void *nftnl_ruleset_ctx_get(const struct nftnl_parse_ctx *ctx, uint16_t attr)
178 {
179  if (!(ctx->flags & (1 << attr)))
180  return NULL;
181 
182  switch (attr) {
183  case NFTNL_RULESET_CTX_CMD:
184  return (void *)&ctx->cmd;
185  case NFTNL_RULESET_CTX_TYPE:
186  return (void *)&ctx->type;
187  case NFTNL_RULESET_CTX_TABLE:
188  return ctx->table;
189  case NFTNL_RULESET_CTX_CHAIN:
190  return ctx->chain;
191  case NFTNL_RULESET_CTX_RULE:
192  return ctx->rule;
193  case NFTNL_RULESET_CTX_SET:
194  return ctx->set;
195  case NFTNL_RULESET_CTX_DATA:
196  return ctx->data;
197  default:
198  return NULL;
199  }
200 }
201 
202 EXPORT_SYMBOL(nftnl_ruleset_ctx_get_u32);
203 uint32_t nftnl_ruleset_ctx_get_u32(const struct nftnl_parse_ctx *ctx, uint16_t attr)
204 {
205  const void *ret = nftnl_ruleset_ctx_get(ctx, attr);
206  return ret == NULL ? 0 : *((uint32_t *)ret);
207 }
208 
209 
210 EXPORT_SYMBOL(nftnl_ruleset_parse_file_cb);
211 int nftnl_ruleset_parse_file_cb(enum nftnl_parse_type type, FILE *fp,
212  struct nftnl_parse_err *err, void *data,
213  int (*cb)(const struct nftnl_parse_ctx *ctx))
214 {
215  errno = EOPNOTSUPP;
216  return -1;
217 }
218 
219 EXPORT_SYMBOL(nftnl_ruleset_parse_buffer_cb);
220 int nftnl_ruleset_parse_buffer_cb(enum nftnl_parse_type type, const char *buffer,
221  struct nftnl_parse_err *err, void *data,
222  int (*cb)(const struct nftnl_parse_ctx *ctx))
223 {
224  errno = EOPNOTSUPP;
225  return -1;
226 }
227 
228 static int nftnl_ruleset_cb(const struct nftnl_parse_ctx *ctx)
229 {
230  struct nftnl_ruleset *r = ctx->data;
231 
232  if (ctx->cmd != NFTNL_CMD_ADD)
233  return -1;
234 
235  switch (ctx->type) {
236  case NFTNL_RULESET_TABLE:
237  if (r->table_list == NULL) {
238  r->table_list = nftnl_table_list_alloc();
239  if (r->table_list == NULL)
240  return -1;
241 
242  nftnl_ruleset_set(r, NFTNL_RULESET_TABLELIST,
243  r->table_list);
244  }
245  nftnl_table_list_add_tail(ctx->table, r->table_list);
246  break;
247  case NFTNL_RULESET_CHAIN:
248  if (r->chain_list == NULL) {
249  r->chain_list = nftnl_chain_list_alloc();
250  if (r->chain_list == NULL)
251  return -1;
252 
253  nftnl_ruleset_set(r, NFTNL_RULESET_CHAINLIST,
254  r->chain_list);
255  }
256  nftnl_chain_list_add_tail(ctx->chain, r->chain_list);
257  break;
258  case NFTNL_RULESET_SET:
259  if (r->set_list == NULL) {
260  r->set_list = nftnl_set_list_alloc();
261  if (r->set_list == NULL)
262  return -1;
263 
264  nftnl_ruleset_set(r, NFTNL_RULESET_SETLIST,
265  r->set_list);
266  }
267  nftnl_set_list_add_tail(ctx->set, r->set_list);
268  break;
269  case NFTNL_RULESET_RULE:
270  if (r->rule_list == NULL) {
271  r->rule_list = nftnl_rule_list_alloc();
272  if (r->rule_list == NULL)
273  return -1;
274 
275  nftnl_ruleset_set(r, NFTNL_RULESET_RULELIST,
276  r->rule_list);
277  }
278  nftnl_rule_list_add_tail(ctx->rule, r->rule_list);
279  break;
280  case NFTNL_RULESET_RULESET:
281  break;
282  default:
283  return -1;
284  }
285 
286  return 0;
287 }
288 
289 EXPORT_SYMBOL(nftnl_ruleset_parse);
290 int nftnl_ruleset_parse(struct nftnl_ruleset *r, enum nftnl_parse_type type,
291  const char *data, struct nftnl_parse_err *err)
292 {
293  errno = EOPNOTSUPP;
294  return -1;
295 }
296 
297 EXPORT_SYMBOL(nftnl_ruleset_parse_file);
298 int nftnl_ruleset_parse_file(struct nftnl_ruleset *rs, enum nftnl_parse_type type,
299  FILE *fp, struct nftnl_parse_err *err)
300 {
301  return nftnl_ruleset_parse_file_cb(type, fp, err, rs, nftnl_ruleset_cb);
302 }
303 
304 static int
305 nftnl_ruleset_snprintf_table(char *buf, size_t remain,
306  const struct nftnl_ruleset *rs, uint32_t type,
307  uint32_t flags)
308 {
309  struct nftnl_table *t;
310  struct nftnl_table_list_iter *ti;
311  const char *sep = "";
312  int ret, offset = 0;
313 
314  ti = nftnl_table_list_iter_create(rs->table_list);
315  if (ti == NULL)
316  return 0;
317 
318  t = nftnl_table_list_iter_next(ti);
319  while (t != NULL) {
320  ret = snprintf(buf + offset, remain, "%s", sep);
321  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
322 
323  ret = nftnl_table_snprintf(buf + offset, remain, t, type, flags);
324  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
325 
326  t = nftnl_table_list_iter_next(ti);
327  sep = "\n";
328  }
329  nftnl_table_list_iter_destroy(ti);
330 
331  return offset;
332 }
333 
334 static int
335 nftnl_ruleset_snprintf_chain(char *buf, size_t remain,
336  const struct nftnl_ruleset *rs, uint32_t type,
337  uint32_t flags)
338 {
339  struct nftnl_chain *c;
340  struct nftnl_chain_list_iter *ci;
341  const char *sep = "";
342  int ret, offset = 0;
343 
344  ci = nftnl_chain_list_iter_create(rs->chain_list);
345  if (ci == NULL)
346  return 0;
347 
348  c = nftnl_chain_list_iter_next(ci);
349  while (c != NULL) {
350  ret = snprintf(buf + offset, remain, "%s", sep);
351  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
352 
353  ret = nftnl_chain_snprintf(buf + offset, remain, c, type, flags);
354  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
355 
356  c = nftnl_chain_list_iter_next(ci);
357  sep = "\n";
358  }
359  nftnl_chain_list_iter_destroy(ci);
360 
361  return offset;
362 }
363 
364 static int
365 nftnl_ruleset_snprintf_set(char *buf, size_t remain,
366  const struct nftnl_ruleset *rs, uint32_t type,
367  uint32_t flags)
368 {
369  struct nftnl_set *s;
370  struct nftnl_set_list_iter *si;
371  const char *sep = "";
372  int ret, offset = 0;
373 
374  si = nftnl_set_list_iter_create(rs->set_list);
375  if (si == NULL)
376  return 0;
377 
378  s = nftnl_set_list_iter_next(si);
379  while (s != NULL) {
380  ret = snprintf(buf + offset, remain, "%s", sep);
381  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
382 
383  ret = nftnl_set_snprintf(buf + offset, remain, s, type, flags);
384  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
385 
386  s = nftnl_set_list_iter_next(si);
387  sep = "\n";
388  }
389  nftnl_set_list_iter_destroy(si);
390 
391  return offset;
392 }
393 
394 static int
395 nftnl_ruleset_snprintf_rule(char *buf, size_t remain,
396  const struct nftnl_ruleset *rs, uint32_t type,
397  uint32_t flags)
398 {
399  struct nftnl_rule *r;
400  struct nftnl_rule_list_iter *ri;
401  const char *sep = "";
402  int ret, offset = 0;
403 
404  ri = nftnl_rule_list_iter_create(rs->rule_list);
405  if (ri == NULL)
406  return 0;
407 
408  r = nftnl_rule_list_iter_next(ri);
409  while (r != NULL) {
410  ret = snprintf(buf + offset, remain, "%s", sep);
411  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
412 
413  ret = nftnl_rule_snprintf(buf + offset, remain, r, type, flags);
414  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
415 
416  r = nftnl_rule_list_iter_next(ri);
417  sep = "\n";
418  }
419  nftnl_rule_list_iter_destroy(ri);
420 
421  return offset;
422 }
423 
424 static int
425 nftnl_ruleset_do_snprintf(char *buf, size_t remain,
426  const struct nftnl_ruleset *rs,
427  uint32_t cmd, uint32_t type, uint32_t flags)
428 {
429  uint32_t inner_flags = flags;
430  const char *sep = "";
431  int ret, offset = 0;
432 
433  /* dont pass events flags to child calls of _snprintf() */
434  inner_flags &= ~NFTNL_OF_EVENT_ANY;
435 
436  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST) &&
437  (!nftnl_table_list_is_empty(rs->table_list))) {
438  ret = nftnl_ruleset_snprintf_table(buf + offset, remain, rs,
439  type, inner_flags);
440  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
441 
442  if (ret > 0)
443  sep = "\n";
444  }
445 
446  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST) &&
447  (!nftnl_chain_list_is_empty(rs->chain_list))) {
448  ret = snprintf(buf + offset, remain, "%s", sep);
449  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
450 
451  ret = nftnl_ruleset_snprintf_chain(buf + offset, remain, rs,
452  type, inner_flags);
453  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
454 
455  if (ret > 0)
456  sep = "\n";
457  }
458 
459  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST) &&
460  (!nftnl_set_list_is_empty(rs->set_list))) {
461  ret = snprintf(buf + offset, remain, "%s", sep);
462  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
463 
464  ret = nftnl_ruleset_snprintf_set(buf + offset, remain, rs,
465  type, inner_flags);
466  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
467 
468  if (ret > 0)
469  sep = "\n";
470  }
471 
472  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST) &&
473  (!nftnl_rule_list_is_empty(rs->rule_list))) {
474  ret = snprintf(buf + offset, remain, "%s", sep);
475  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
476 
477  ret = nftnl_ruleset_snprintf_rule(buf + offset, remain, rs,
478  type, inner_flags);
479  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
480  }
481 
482  return offset;
483 }
484 
485 EXPORT_SYMBOL(nftnl_ruleset_snprintf);
486 int nftnl_ruleset_snprintf(char *buf, size_t size, const struct nftnl_ruleset *r,
487  uint32_t type, uint32_t flags)
488 {
489  if (size)
490  buf[0] = '\0';
491 
492  if (type != NFTNL_OUTPUT_DEFAULT) {
493  errno = EOPNOTSUPP;
494  return -1;
495  }
496  return nftnl_ruleset_do_snprintf(buf, size, r, nftnl_flag2cmd(flags),
497  type, flags);
498 }
499 
500 static int nftnl_ruleset_fprintf_tables(FILE *fp, const struct nftnl_ruleset *rs,
501  uint32_t type, uint32_t flags)
502 {
503  int len = 0, ret = 0;
504  struct nftnl_table *t;
505  struct nftnl_table_list_iter *ti;
506  const char *sep = "";
507 
508  ti = nftnl_table_list_iter_create(rs->table_list);
509  if (ti == NULL)
510  return -1;
511 
512  t = nftnl_table_list_iter_next(ti);
513  while (t != NULL) {
514  ret = fprintf(fp, "%s", sep);
515  if (ret < 0)
516  goto err;
517 
518  len += ret;
519 
520  ret = nftnl_table_fprintf(fp, t, type, flags);
521  if (ret < 0)
522  goto err;
523 
524  len += ret;
525 
526  t = nftnl_table_list_iter_next(ti);
527  sep = "\n";
528 
529  }
530  nftnl_table_list_iter_destroy(ti);
531 
532  return len;
533 err:
534  nftnl_table_list_iter_destroy(ti);
535  return -1;
536 }
537 
538 static int nftnl_ruleset_fprintf_chains(FILE *fp, const struct nftnl_ruleset *rs,
539  uint32_t type, uint32_t flags)
540 {
541  int len = 0, ret = 0;
542  struct nftnl_chain *o;
543  struct nftnl_chain_list_iter *i;
544  const char *sep = "";
545 
546  i = nftnl_chain_list_iter_create(rs->chain_list);
547  if (i == NULL)
548  return -1;
549 
550  o = nftnl_chain_list_iter_next(i);
551  while (o != NULL) {
552  ret = fprintf(fp, "%s", sep);
553  if (ret < 0)
554  goto err;
555 
556  len += ret;
557 
558  ret = nftnl_chain_fprintf(fp, o, type, flags);
559  if (ret < 0)
560  goto err;
561 
562  len += ret;
563 
564  o = nftnl_chain_list_iter_next(i);
565  sep = "\n";
566  }
567  nftnl_chain_list_iter_destroy(i);
568 
569  return len;
570 err:
571  nftnl_chain_list_iter_destroy(i);
572  return -1;
573 }
574 
575 static int nftnl_ruleset_fprintf_sets(FILE *fp, const struct nftnl_ruleset *rs,
576  uint32_t type, uint32_t flags)
577 {
578  int len = 0, ret = 0;
579  struct nftnl_set *o;
580  struct nftnl_set_list_iter *i;
581  const char *sep = "";
582 
583  i = nftnl_set_list_iter_create(rs->set_list);
584  if (i == NULL)
585  return -1;
586 
587  o = nftnl_set_list_iter_next(i);
588  while (o != NULL) {
589  ret = fprintf(fp, "%s", sep);
590  if (ret < 0)
591  goto err;
592 
593  len += ret;
594 
595  ret = nftnl_set_fprintf(fp, o, type, flags);
596  if (ret < 0)
597  goto err;
598 
599  len += ret;
600 
601  o = nftnl_set_list_iter_next(i);
602  sep = "\n";
603  }
604  nftnl_set_list_iter_destroy(i);
605 
606  return len;
607 err:
608  nftnl_set_list_iter_destroy(i);
609  return -1;
610 }
611 
612 static int nftnl_ruleset_fprintf_rules(FILE *fp, const struct nftnl_ruleset *rs,
613  uint32_t type, uint32_t flags)
614 {
615  int len = 0, ret = 0;
616  struct nftnl_rule *o;
617  struct nftnl_rule_list_iter *i;
618  const char *sep = "";
619 
620  i = nftnl_rule_list_iter_create(rs->rule_list);
621  if (i == NULL)
622  return -1;
623 
624  o = nftnl_rule_list_iter_next(i);
625  while (o != NULL) {
626  ret = fprintf(fp, "%s", sep);
627  if (ret < 0)
628  goto err;
629 
630  len += ret;
631 
632  ret = nftnl_rule_fprintf(fp, o, type, flags);
633  if (ret < 0)
634  goto err;
635 
636  len += ret;
637 
638  o = nftnl_rule_list_iter_next(i);
639  sep = "\n";
640  }
641  nftnl_rule_list_iter_destroy(i);
642 
643  return len;
644 err:
645  nftnl_rule_list_iter_destroy(i);
646  return -1;
647 }
648 
649 #define NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len) \
650  if (ret < 0) \
651  return -1; \
652  len += ret;
653 
654 static int nftnl_ruleset_cmd_fprintf(FILE *fp, const struct nftnl_ruleset *rs,
655  uint32_t cmd, uint32_t type, uint32_t flags)
656 {
657  int len = 0, ret = 0;
658  uint32_t inner_flags = flags;
659  const char *sep = "";
660 
661  /* dont pass events flags to child calls of _snprintf() */
662  inner_flags &= ~NFTNL_OF_EVENT_ANY;
663 
664  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST)) &&
665  (!nftnl_table_list_is_empty(rs->table_list))) {
666  ret = nftnl_ruleset_fprintf_tables(fp, rs, type, inner_flags);
667  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
668 
669  if (ret > 0)
670  sep = "\n";
671  }
672 
673  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST)) &&
674  (!nftnl_chain_list_is_empty(rs->chain_list))) {
675  ret = fprintf(fp, "%s", sep);
676  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
677 
678  ret = nftnl_ruleset_fprintf_chains(fp, rs, type, inner_flags);
679  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
680 
681  if (ret > 0)
682  sep = "\n";
683  }
684 
685  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST)) &&
686  (!nftnl_set_list_is_empty(rs->set_list))) {
687  ret = fprintf(fp, "%s", sep);
688  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
689 
690  ret = nftnl_ruleset_fprintf_sets(fp, rs, type, inner_flags);
691  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
692 
693  if (ret > 0)
694  sep = "\n";
695  }
696 
697  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST)) &&
698  (!nftnl_rule_list_is_empty(rs->rule_list))) {
699  ret = fprintf(fp, "%s", sep);
700  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
701 
702  ret = nftnl_ruleset_fprintf_rules(fp, rs, type, inner_flags);
703  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
704  }
705 
706  return len;
707 }
708 
709 EXPORT_SYMBOL(nftnl_ruleset_fprintf);
710 int nftnl_ruleset_fprintf(FILE *fp, const struct nftnl_ruleset *rs, uint32_t type,
711  uint32_t flags)
712 {
713  return nftnl_ruleset_cmd_fprintf(fp, rs, nftnl_flag2cmd(flags), type,
714  flags);
715 }