libnftnl  1.0.8
fib.c
1 /*
2  * (C) 2016 Red Hat GmbH
3  * Author: Florian Westphal <fw@strlen.de>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  */
10 
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <inttypes.h>
14 #include <string.h>
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <linux/netfilter/nf_tables.h>
18 
19 #include "internal.h"
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
23 
25  uint32_t flags;
26  uint32_t result;
27  enum nft_registers dreg;
28 };
29 
30 static int
31 nftnl_expr_fib_set(struct nftnl_expr *e, uint16_t result,
32  const void *data, uint32_t data_len)
33 {
34  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
35 
36  switch (result) {
37  case NFTNL_EXPR_FIB_RESULT:
38  fib->result = *((uint32_t *)data);
39  break;
40  case NFTNL_EXPR_FIB_DREG:
41  fib->dreg = *((uint32_t *)data);
42  break;
43  case NFTNL_EXPR_FIB_FLAGS:
44  fib->flags = *((uint32_t *)data);
45  break;
46  default:
47  return -1;
48  }
49  return 0;
50 }
51 
52 static const void *
53 nftnl_expr_fib_get(const struct nftnl_expr *e, uint16_t result,
54  uint32_t *data_len)
55 {
56  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
57 
58  switch (result) {
59  case NFTNL_EXPR_FIB_RESULT:
60  *data_len = sizeof(fib->result);
61  return &fib->result;
62  case NFTNL_EXPR_FIB_DREG:
63  *data_len = sizeof(fib->dreg);
64  return &fib->dreg;
65  case NFTNL_EXPR_FIB_FLAGS:
66  *data_len = sizeof(fib->flags);
67  return &fib->flags;
68  }
69  return NULL;
70 }
71 
72 static int nftnl_expr_fib_cb(const struct nlattr *attr, void *data)
73 {
74  const struct nlattr **tb = data;
75  int type = mnl_attr_get_type(attr);
76 
77  if (mnl_attr_type_valid(attr, NFTA_FIB_MAX) < 0)
78  return MNL_CB_OK;
79 
80  switch (type) {
81  case NFTA_FIB_RESULT:
82  case NFTA_FIB_DREG:
83  case NFTA_FIB_FLAGS:
84  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
85  abi_breakage();
86  break;
87  }
88 
89  tb[type] = attr;
90  return MNL_CB_OK;
91 }
92 
93 static void
94 nftnl_expr_fib_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
95 {
96  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
97 
98  if (e->flags & (1 << NFTNL_EXPR_FIB_FLAGS))
99  mnl_attr_put_u32(nlh, NFTA_FIB_FLAGS, htonl(fib->flags));
100  if (e->flags & (1 << NFTNL_EXPR_FIB_RESULT))
101  mnl_attr_put_u32(nlh, NFTA_FIB_RESULT, htonl(fib->result));
102  if (e->flags & (1 << NFTNL_EXPR_FIB_DREG))
103  mnl_attr_put_u32(nlh, NFTA_FIB_DREG, htonl(fib->dreg));
104 }
105 
106 static int
107 nftnl_expr_fib_parse(struct nftnl_expr *e, struct nlattr *attr)
108 {
109  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
110  struct nlattr *tb[NFTA_FIB_MAX+1] = {};
111  int ret = 0;
112 
113  if (mnl_attr_parse_nested(attr, nftnl_expr_fib_cb, tb) < 0)
114  return -1;
115 
116  if (tb[NFTA_FIB_RESULT]) {
117  fib->result = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_RESULT]));
118  e->flags |= (1 << NFTNL_EXPR_FIB_RESULT);
119  }
120  if (tb[NFTA_FIB_DREG]) {
121  fib->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_DREG]));
122  e->flags |= (1 << NFTNL_EXPR_FIB_DREG);
123  }
124  if (tb[NFTA_FIB_FLAGS]) {
125  fib->flags = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_FLAGS]));
126  e->flags |= (1 << NFTNL_EXPR_FIB_FLAGS);
127  }
128  return ret;
129 }
130 
131 static int nftnl_expr_fib_json_parse(struct nftnl_expr *e, json_t *root,
132  struct nftnl_parse_err *err)
133 {
134 #ifdef JSON_PARSING
135  uint32_t result, flags, dreg;
136 
137  if (nftnl_jansson_parse_reg(root, "result", NFTNL_TYPE_U32,
138  &result, err) == 0)
139  nftnl_expr_set_u32(e, NFTNL_EXPR_FIB_RESULT, result);
140 
141  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32,
142  &dreg, err) == 0)
143  nftnl_expr_set_u32(e, NFTNL_EXPR_FIB_DREG, dreg);
144 
145  if (nftnl_jansson_parse_val(root, "flags", NFTNL_TYPE_U32,
146  &flags, err) == 0)
147  nftnl_expr_set_u32(e, NFTNL_EXPR_FIB_FLAGS, flags);
148 
149  return 0;
150 #else
151  errno = EOPNOTSUPP;
152  return -1;
153 #endif
154 }
155 
156 static const char *fib_type[NFT_FIB_RESULT_MAX + 1] = {
157  [NFT_FIB_RESULT_OIF] = "oif",
158  [NFT_FIB_RESULT_OIFNAME] = "oifname",
159  [NFT_FIB_RESULT_ADDRTYPE] = "type",
160 };
161 
162 static const char *fib_type_str(enum nft_fib_result r)
163 {
164  if (r <= NFT_FIB_RESULT_MAX)
165  return fib_type[r];
166 
167  return "unknown";
168 }
169 
170 static int
171 nftnl_expr_fib_snprintf_default(char *buf, size_t size,
172  const struct nftnl_expr *e)
173 {
174  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
175  int remain = size, offset = 0, ret, i;
176  uint32_t flags = fib->flags & ~NFTA_FIB_F_PRESENT;
177  uint32_t present_flag = fib->flags & NFTA_FIB_F_PRESENT;
178  static const struct {
179  int bit;
180  const char *name;
181  } tab[] = {
182  { NFTA_FIB_F_SADDR, "saddr" },
183  { NFTA_FIB_F_DADDR, "daddr" },
184  { NFTA_FIB_F_MARK, "mark" },
185  { NFTA_FIB_F_IIF, "iif" },
186  { NFTA_FIB_F_OIF, "oif" },
187  };
188 
189  for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
190  if (flags & tab[i].bit) {
191  ret = snprintf(buf + offset, remain, "%s ",
192  tab[i].name);
193  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
194 
195  flags &= ~tab[i].bit;
196  if (flags) {
197  ret = snprintf(buf + offset, remain, ". ");
198  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
199  }
200  }
201  }
202 
203  if (flags) {
204  ret = snprintf(buf + offset, remain, "unknown 0x%" PRIx32,
205  flags);
206  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
207  }
208 
209  ret = snprintf(buf + offset, remain, "%s%s => reg %d ",
210  fib_type_str(fib->result),
211  present_flag ? " present" : "",
212  fib->dreg);
213  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
214 
215  return offset;
216 }
217 
218 static int nftnl_expr_fib_export(char *buf, size_t size,
219  const struct nftnl_expr *e, int type)
220 {
221  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
222 
223  NFTNL_BUF_INIT(b, buf, size);
224 
225  if (e->flags & (1 << NFTNL_EXPR_FIB_RESULT))
226  nftnl_buf_u32(&b, type, fib->result, OP);
227  if (e->flags & (1 << NFTNL_EXPR_FIB_DREG))
228  nftnl_buf_u32(&b, type, fib->dreg, DREG);
229  if (e->flags & (1 << NFTNL_EXPR_FIB_FLAGS))
230  nftnl_buf_u32(&b, type, fib->flags, FLAGS);
231 
232  return nftnl_buf_done(&b);
233 }
234 
235 static int
236 nftnl_expr_fib_snprintf(char *buf, size_t len, uint32_t type,
237  uint32_t flags, const struct nftnl_expr *e)
238 {
239  switch (type) {
240  case NFTNL_OUTPUT_DEFAULT:
241  return nftnl_expr_fib_snprintf_default(buf, len, e);
242  case NFTNL_OUTPUT_XML:
243  case NFTNL_OUTPUT_JSON:
244  return nftnl_expr_fib_export(buf, len, e, type);
245  default:
246  break;
247  }
248  return -1;
249 }
250 
251 static bool nftnl_expr_fib_cmp(const struct nftnl_expr *e1,
252  const struct nftnl_expr *e2)
253 {
254  struct nftnl_expr_fib *h1 = nftnl_expr_data(e1);
255  struct nftnl_expr_fib *h2 = nftnl_expr_data(e2);
256  bool eq = true;
257 
258  if (e1->flags & (1 << NFTNL_EXPR_FIB_RESULT))
259  eq &= (h1->result == h2->result);
260  if (e1->flags & (1 << NFTNL_EXPR_FIB_DREG))
261  eq &= (h1->dreg == h2->dreg);
262  if (e1->flags & (1 << NFTNL_EXPR_FIB_FLAGS))
263  eq &= (h1->flags == h2->flags);
264 
265  return eq;
266 }
267 
268 struct expr_ops expr_ops_fib = {
269  .name = "fib",
270  .alloc_len = sizeof(struct nftnl_expr_fib),
271  .max_attr = NFTA_FIB_MAX,
272  .cmp = nftnl_expr_fib_cmp,
273  .set = nftnl_expr_fib_set,
274  .get = nftnl_expr_fib_get,
275  .parse = nftnl_expr_fib_parse,
276  .build = nftnl_expr_fib_build,
277  .snprintf = nftnl_expr_fib_snprintf,
278  .json_parse = nftnl_expr_fib_json_parse,
279 };