libnftnl  1.2.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  memcpy(&fib->result, data, data_len);
39  break;
40  case NFTNL_EXPR_FIB_DREG:
41  memcpy(&fib->dreg, data, data_len);
42  break;
43  case NFTNL_EXPR_FIB_FLAGS:
44  memcpy(&fib->flags, data, data_len);
45  break;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_fib_get(const struct nftnl_expr *e, uint16_t result,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
55 
56  switch (result) {
57  case NFTNL_EXPR_FIB_RESULT:
58  *data_len = sizeof(fib->result);
59  return &fib->result;
60  case NFTNL_EXPR_FIB_DREG:
61  *data_len = sizeof(fib->dreg);
62  return &fib->dreg;
63  case NFTNL_EXPR_FIB_FLAGS:
64  *data_len = sizeof(fib->flags);
65  return &fib->flags;
66  }
67  return NULL;
68 }
69 
70 static int nftnl_expr_fib_cb(const struct nlattr *attr, void *data)
71 {
72  const struct nlattr **tb = data;
73  int type = mnl_attr_get_type(attr);
74 
75  if (mnl_attr_type_valid(attr, NFTA_FIB_MAX) < 0)
76  return MNL_CB_OK;
77 
78  switch (type) {
79  case NFTA_FIB_RESULT:
80  case NFTA_FIB_DREG:
81  case NFTA_FIB_FLAGS:
82  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
83  abi_breakage();
84  break;
85  }
86 
87  tb[type] = attr;
88  return MNL_CB_OK;
89 }
90 
91 static void
92 nftnl_expr_fib_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
93 {
94  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
95 
96  if (e->flags & (1 << NFTNL_EXPR_FIB_FLAGS))
97  mnl_attr_put_u32(nlh, NFTA_FIB_FLAGS, htonl(fib->flags));
98  if (e->flags & (1 << NFTNL_EXPR_FIB_RESULT))
99  mnl_attr_put_u32(nlh, NFTA_FIB_RESULT, htonl(fib->result));
100  if (e->flags & (1 << NFTNL_EXPR_FIB_DREG))
101  mnl_attr_put_u32(nlh, NFTA_FIB_DREG, htonl(fib->dreg));
102 }
103 
104 static int
105 nftnl_expr_fib_parse(struct nftnl_expr *e, struct nlattr *attr)
106 {
107  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
108  struct nlattr *tb[NFTA_FIB_MAX+1] = {};
109  int ret = 0;
110 
111  if (mnl_attr_parse_nested(attr, nftnl_expr_fib_cb, tb) < 0)
112  return -1;
113 
114  if (tb[NFTA_FIB_RESULT]) {
115  fib->result = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_RESULT]));
116  e->flags |= (1 << NFTNL_EXPR_FIB_RESULT);
117  }
118  if (tb[NFTA_FIB_DREG]) {
119  fib->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_DREG]));
120  e->flags |= (1 << NFTNL_EXPR_FIB_DREG);
121  }
122  if (tb[NFTA_FIB_FLAGS]) {
123  fib->flags = ntohl(mnl_attr_get_u32(tb[NFTA_FIB_FLAGS]));
124  e->flags |= (1 << NFTNL_EXPR_FIB_FLAGS);
125  }
126  return ret;
127 }
128 
129 static const char *fib_type[NFT_FIB_RESULT_MAX + 1] = {
130  [NFT_FIB_RESULT_OIF] = "oif",
131  [NFT_FIB_RESULT_OIFNAME] = "oifname",
132  [NFT_FIB_RESULT_ADDRTYPE] = "type",
133 };
134 
135 static const char *fib_type_str(enum nft_fib_result r)
136 {
137  if (r <= NFT_FIB_RESULT_MAX)
138  return fib_type[r];
139 
140  return "unknown";
141 }
142 
143 static int
144 nftnl_expr_fib_snprintf(char *buf, size_t remain,
145  uint32_t printflags, const struct nftnl_expr *e)
146 {
147  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
148  uint32_t flags = fib->flags & ~NFTA_FIB_F_PRESENT;
149  uint32_t present_flag = fib->flags & NFTA_FIB_F_PRESENT;
150  int offset = 0, ret, i;
151  static const struct {
152  int bit;
153  const char *name;
154  } tab[] = {
155  { NFTA_FIB_F_SADDR, "saddr" },
156  { NFTA_FIB_F_DADDR, "daddr" },
157  { NFTA_FIB_F_MARK, "mark" },
158  { NFTA_FIB_F_IIF, "iif" },
159  { NFTA_FIB_F_OIF, "oif" },
160  };
161 
162  for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
163  if (flags & tab[i].bit) {
164  ret = snprintf(buf + offset, remain, "%s ",
165  tab[i].name);
166  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
167 
168  flags &= ~tab[i].bit;
169  if (flags) {
170  ret = snprintf(buf + offset, remain, ". ");
171  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
172  }
173  }
174  }
175 
176  if (flags) {
177  ret = snprintf(buf + offset, remain, "unknown 0x%" PRIx32,
178  flags);
179  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
180  }
181 
182  ret = snprintf(buf + offset, remain, "%s%s => reg %d ",
183  fib_type_str(fib->result),
184  present_flag ? " present" : "",
185  fib->dreg);
186  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
187 
188  return offset;
189 }
190 
191 static struct attr_policy fib_attr_policy[__NFTNL_EXPR_FIB_MAX] = {
192  [NFTNL_EXPR_FIB_DREG] = { .maxlen = sizeof(uint32_t) },
193  [NFTNL_EXPR_FIB_RESULT] = { .maxlen = sizeof(uint32_t) },
194  [NFTNL_EXPR_FIB_FLAGS] = { .maxlen = sizeof(uint32_t) },
195 };
196 
197 struct expr_ops expr_ops_fib = {
198  .name = "fib",
199  .alloc_len = sizeof(struct nftnl_expr_fib),
200  .nftnl_max_attr = __NFTNL_EXPR_FIB_MAX - 1,
201  .attr_policy = fib_attr_policy,
202  .set = nftnl_expr_fib_set,
203  .get = nftnl_expr_fib_get,
204  .parse = nftnl_expr_fib_parse,
205  .build = nftnl_expr_fib_build,
206  .output = nftnl_expr_fib_snprintf,
207 };