libnftnl  1.1.5
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, sizeof(fib->result));
39  break;
40  case NFTNL_EXPR_FIB_DREG:
41  memcpy(&fib->dreg, data, sizeof(fib->dreg));
42  break;
43  case NFTNL_EXPR_FIB_FLAGS:
44  memcpy(&fib->flags, data, sizeof(fib->flags));
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 const char *fib_type[NFT_FIB_RESULT_MAX + 1] = {
132  [NFT_FIB_RESULT_OIF] = "oif",
133  [NFT_FIB_RESULT_OIFNAME] = "oifname",
134  [NFT_FIB_RESULT_ADDRTYPE] = "type",
135 };
136 
137 static const char *fib_type_str(enum nft_fib_result r)
138 {
139  if (r <= NFT_FIB_RESULT_MAX)
140  return fib_type[r];
141 
142  return "unknown";
143 }
144 
145 static int
146 nftnl_expr_fib_snprintf_default(char *buf, size_t size,
147  const struct nftnl_expr *e)
148 {
149  struct nftnl_expr_fib *fib = nftnl_expr_data(e);
150  int remain = size, offset = 0, ret, i;
151  uint32_t flags = fib->flags & ~NFTA_FIB_F_PRESENT;
152  uint32_t present_flag = fib->flags & NFTA_FIB_F_PRESENT;
153  static const struct {
154  int bit;
155  const char *name;
156  } tab[] = {
157  { NFTA_FIB_F_SADDR, "saddr" },
158  { NFTA_FIB_F_DADDR, "daddr" },
159  { NFTA_FIB_F_MARK, "mark" },
160  { NFTA_FIB_F_IIF, "iif" },
161  { NFTA_FIB_F_OIF, "oif" },
162  };
163 
164  for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
165  if (flags & tab[i].bit) {
166  ret = snprintf(buf + offset, remain, "%s ",
167  tab[i].name);
168  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
169 
170  flags &= ~tab[i].bit;
171  if (flags) {
172  ret = snprintf(buf + offset, remain, ". ");
173  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
174  }
175  }
176  }
177 
178  if (flags) {
179  ret = snprintf(buf + offset, remain, "unknown 0x%" PRIx32,
180  flags);
181  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
182  }
183 
184  ret = snprintf(buf + offset, remain, "%s%s => reg %d ",
185  fib_type_str(fib->result),
186  present_flag ? " present" : "",
187  fib->dreg);
188  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
189 
190  return offset;
191 }
192 
193 static int
194 nftnl_expr_fib_snprintf(char *buf, size_t len, uint32_t type,
195  uint32_t flags, const struct nftnl_expr *e)
196 {
197  switch (type) {
198  case NFTNL_OUTPUT_DEFAULT:
199  return nftnl_expr_fib_snprintf_default(buf, len, e);
200  case NFTNL_OUTPUT_XML:
201  case NFTNL_OUTPUT_JSON:
202  default:
203  break;
204  }
205  return -1;
206 }
207 
208 struct expr_ops expr_ops_fib = {
209  .name = "fib",
210  .alloc_len = sizeof(struct nftnl_expr_fib),
211  .max_attr = NFTA_FIB_MAX,
212  .set = nftnl_expr_fib_set,
213  .get = nftnl_expr_fib_get,
214  .parse = nftnl_expr_fib_parse,
215  .build = nftnl_expr_fib_build,
216  .snprintf = nftnl_expr_fib_snprintf,
217 };