libnftnl  1.2.9
fib.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2016 Red Hat GmbH
4  * Author: Florian Westphal <fw@strlen.de>
5  */
6 
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <inttypes.h>
10 #include <string.h>
11 #include <arpa/inet.h>
12 #include <errno.h>
13 #include <linux/netfilter/nf_tables.h>
14 
15 #include "internal.h"
16 #include <libmnl/libmnl.h>
17 #include <libnftnl/expr.h>
18 #include <libnftnl/rule.h>
19 
21  uint32_t flags;
22  uint32_t result;
23  enum nft_registers dreg;
24 };
25 
26 static int
27 nftnl_expr_fib_set(struct nftnl_expr *e, uint16_t result,
28  const void *data, uint32_t data_len)
29 {
30  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
31 
32  switch (result) {
33  case NFTNL_EXPR_FIB_RESULT:
34  memcpy(&fib->result, data, data_len);
35  break;
36  case NFTNL_EXPR_FIB_DREG:
37  memcpy(&fib->dreg, data, data_len);
38  break;
39  case NFTNL_EXPR_FIB_FLAGS:
40  memcpy(&fib->flags, data, data_len);
41  break;
42  }
43  return 0;
44 }
45 
46 static const void *
47 nftnl_expr_fib_get(const struct nftnl_expr *e, uint16_t result,
48  uint32_t *data_len)
49 {
50  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
51 
52  switch (result) {
53  case NFTNL_EXPR_FIB_RESULT:
54  *data_len = sizeof(fib->result);
55  return &fib->result;
56  case NFTNL_EXPR_FIB_DREG:
57  *data_len = sizeof(fib->dreg);
58  return &fib->dreg;
59  case NFTNL_EXPR_FIB_FLAGS:
60  *data_len = sizeof(fib->flags);
61  return &fib->flags;
62  }
63  return NULL;
64 }
65 
66 static int nftnl_expr_fib_cb(const struct nlattr *attr, void *data)
67 {
68  const struct nlattr **tb = data;
69  int type = mnl_attr_get_type(attr);
70 
71  if (mnl_attr_type_valid(attr, NFTA_FIB_MAX) < 0)
72  return MNL_CB_OK;
73 
74  switch (type) {
75  case NFTA_FIB_RESULT:
76  case NFTA_FIB_DREG:
77  case NFTA_FIB_FLAGS:
78  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
79  abi_breakage();
80  break;
81  }
82 
83  tb[type] = attr;
84  return MNL_CB_OK;
85 }
86 
87 static void
88 nftnl_expr_fib_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
89 {
90  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
91 
92  if (e->flags & (1 << NFTNL_EXPR_FIB_FLAGS))
93  mnl_attr_put_u32(nlh, NFTA_FIB_FLAGS, htonl(fib->flags));
94  if (e->flags & (1 << NFTNL_EXPR_FIB_RESULT))
95  mnl_attr_put_u32(nlh, NFTA_FIB_RESULT, htonl(fib->result));
96  if (e->flags & (1 << NFTNL_EXPR_FIB_DREG))
97  mnl_attr_put_u32(nlh, NFTA_FIB_DREG, htonl(fib->dreg));
98 }
99 
100 static int
101 nftnl_expr_fib_parse(struct nftnl_expr *e, struct nlattr *attr)
102 {
103  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
104  struct nlattr *tb[NFTA_FIB_MAX+1] = {};
105  int ret = 0;
106 
107  if (mnl_attr_parse_nested(attr, nftnl_expr_fib_cb, tb) < 0)
108  return -1;
109 
110  if (tb[NFTA_FIB_RESULT]) {
111  fib->result = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_RESULT]));
112  e->flags |= (1 << NFTNL_EXPR_FIB_RESULT);
113  }
114  if (tb[NFTA_FIB_DREG]) {
115  fib->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_DREG]));
116  e->flags |= (1 << NFTNL_EXPR_FIB_DREG);
117  }
118  if (tb[NFTA_FIB_FLAGS]) {
119  fib->flags = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_FLAGS]));
120  e->flags |= (1 << NFTNL_EXPR_FIB_FLAGS);
121  }
122  return ret;
123 }
124 
125 static const char *fib_type[NFT_FIB_RESULT_MAX + 1] = {
126  [NFT_FIB_RESULT_OIF] = "oif",
127  [NFT_FIB_RESULT_OIFNAME] = "oifname",
128  [NFT_FIB_RESULT_ADDRTYPE] = "type",
129 };
130 
131 static const char *fib_type_str(enum nft_fib_result r)
132 {
133  if (r <= NFT_FIB_RESULT_MAX)
134  return fib_type[r];
135 
136  return "unknown";
137 }
138 
139 static int
140 nftnl_expr_fib_snprintf(char *buf, size_t remain,
141  uint32_t printflags, const struct nftnl_expr *e)
142 {
143  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
144  uint32_t flags = fib->flags & ~NFTA_FIB_F_PRESENT;
145  uint32_t present_flag = fib->flags & NFTA_FIB_F_PRESENT;
146  int offset = 0, ret, i;
147  static const struct {
148  int bit;
149  const char *name;
150  } tab[] = {
151  { NFTA_FIB_F_SADDR, "saddr" },
152  { NFTA_FIB_F_DADDR, "daddr" },
153  { NFTA_FIB_F_MARK, "mark" },
154  { NFTA_FIB_F_IIF, "iif" },
155  { NFTA_FIB_F_OIF, "oif" },
156  };
157 
158  for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
159  if (flags & tab[i].bit) {
160  ret = snprintf(buf + offset, remain, "%s ",
161  tab[i].name);
162  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
163 
164  flags &= ~tab[i].bit;
165  if (flags) {
166  ret = snprintf(buf + offset, remain, ". ");
167  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
168  }
169  }
170  }
171 
172  if (flags) {
173  ret = snprintf(buf + offset, remain, "unknown 0x%" PRIx32,
174  flags);
175  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
176  }
177 
178  ret = snprintf(buf + offset, remain, "%s%s => reg %d ",
179  fib_type_str(fib->result),
180  present_flag ? " present" : "",
181  fib->dreg);
182  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
183 
184  return offset;
185 }
186 
187 static struct attr_policy fib_attr_policy[__NFTNL_EXPR_FIB_MAX] = {
188  [NFTNL_EXPR_FIB_DREG] = { .maxlen = sizeof(uint32_t) },
189  [NFTNL_EXPR_FIB_RESULT] = { .maxlen = sizeof(uint32_t) },
190  [NFTNL_EXPR_FIB_FLAGS] = { .maxlen = sizeof(uint32_t) },
191 };
192 
193 struct expr_ops expr_ops_fib = {
194  .name = "fib",
195  .alloc_len = sizeof(struct nftnl_expr_fib),
196  .nftnl_max_attr = __NFTNL_EXPR_FIB_MAX - 1,
197  .attr_policy = fib_attr_policy,
198  .set = nftnl_expr_fib_set,
199  .get = nftnl_expr_fib_get,
200  .parse = nftnl_expr_fib_parse,
201  .build = nftnl_expr_fib_build,
202  .output = nftnl_expr_fib_snprintf,
203 };