libnftnl  1.0.8
rt.c
1 /*
2  * Copyright (c) 2016 Anders K. Pedersen <akp@cohaesio.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <arpa/inet.h>
14 #include <errno.h>
15 #include <linux/netfilter/nf_tables.h>
16 
17 #include "internal.h"
18 #include <libmnl/libmnl.h>
19 #include <libnftnl/expr.h>
20 #include <libnftnl/rule.h>
21 
22 #ifndef NFT_RT_MAX
23 #define NFT_RT_MAX (NFT_RT_TCPMSS + 1)
24 #endif
25 
26 struct nftnl_expr_rt {
27  enum nft_rt_keys key;
28  enum nft_registers dreg;
29 };
30 
31 static int
32 nftnl_expr_rt_set(struct nftnl_expr *e, uint16_t type,
33  const void *data, uint32_t data_len)
34 {
35  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
36 
37  switch (type) {
38  case NFTNL_EXPR_RT_KEY:
39  rt->key = *((uint32_t *)data);
40  break;
41  case NFTNL_EXPR_RT_DREG:
42  rt->dreg = *((uint32_t *)data);
43  break;
44  default:
45  return -1;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_rt_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
55 
56  switch (type) {
57  case NFTNL_EXPR_RT_KEY:
58  *data_len = sizeof(rt->key);
59  return &rt->key;
60  case NFTNL_EXPR_RT_DREG:
61  *data_len = sizeof(rt->dreg);
62  return &rt->dreg;
63  }
64  return NULL;
65 }
66 
67 static int nftnl_expr_rt_cb(const struct nlattr *attr, void *data)
68 {
69  const struct nlattr **tb = data;
70  int type = mnl_attr_get_type(attr);
71 
72  if (mnl_attr_type_valid(attr, NFTA_RT_MAX) < 0)
73  return MNL_CB_OK;
74 
75  switch (type) {
76  case NFTA_RT_KEY:
77  case NFTA_RT_DREG:
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_rt_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
89 {
90  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
91 
92  if (e->flags & (1 << NFTNL_EXPR_RT_KEY))
93  mnl_attr_put_u32(nlh, NFTA_RT_KEY, htonl(rt->key));
94  if (e->flags & (1 << NFTNL_EXPR_RT_DREG))
95  mnl_attr_put_u32(nlh, NFTA_RT_DREG, htonl(rt->dreg));
96 }
97 
98 static int
99 nftnl_expr_rt_parse(struct nftnl_expr *e, struct nlattr *attr)
100 {
101  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
102  struct nlattr *tb[NFTA_RT_MAX+1] = {};
103 
104  if (mnl_attr_parse_nested(attr, nftnl_expr_rt_cb, tb) < 0)
105  return -1;
106 
107  if (tb[NFTA_RT_KEY]) {
108  rt->key = ntohl(mnl_attr_get_u32(tb[NFTA_RT_KEY]));
109  e->flags |= (1 << NFTNL_EXPR_RT_KEY);
110  }
111  if (tb[NFTA_RT_DREG]) {
112  rt->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_RT_DREG]));
113  e->flags |= (1 << NFTNL_EXPR_RT_DREG);
114  }
115 
116  return 0;
117 }
118 
119 static const char *rt_key2str_array[NFT_RT_MAX] = {
120  [NFT_RT_CLASSID] = "classid",
121  [NFT_RT_NEXTHOP4] = "nexthop4",
122  [NFT_RT_NEXTHOP6] = "nexthop6",
123  [NFT_RT_TCPMSS] = "tcpmss",
124 };
125 
126 static const char *rt_key2str(uint8_t key)
127 {
128  if (key < NFT_RT_MAX)
129  return rt_key2str_array[key];
130 
131  return "unknown";
132 }
133 
134 static inline int str2rt_key(const char *str)
135 {
136  int i;
137 
138  for (i = 0; i < NFT_RT_MAX; i++) {
139  if (strcmp(str, rt_key2str_array[i]) == 0)
140  return i;
141  }
142 
143  errno = EINVAL;
144  return -1;
145 }
146 
147 static int nftnl_expr_rt_json_parse(struct nftnl_expr *e, json_t *root,
148  struct nftnl_parse_err *err)
149 {
150 #ifdef JSON_PARSING
151  const char *val_str;
152  uint32_t reg;
153  int val32;
154 
155  val_str = nftnl_jansson_parse_str(root, "key", err);
156  if (val_str != NULL) {
157  val32 = str2rt_key(val_str);
158  if (val32 >= 0)
159  nftnl_expr_set_u32(e, NFTNL_EXPR_RT_KEY, val32);
160  }
161 
162  if (nftnl_jansson_node_exist(root, "dreg")) {
163  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32, &reg,
164  err) == 0)
165  nftnl_expr_set_u32(e, NFTNL_EXPR_RT_DREG, reg);
166  }
167 
168  return 0;
169 #else
170  errno = EOPNOTSUPP;
171  return -1;
172 #endif
173 }
174 
175 static int
176 nftnl_expr_rt_snprintf_default(char *buf, size_t len,
177  const struct nftnl_expr *e)
178 {
179  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
180 
181  if (e->flags & (1 << NFTNL_EXPR_RT_DREG)) {
182  return snprintf(buf, len, "load %s => reg %u ",
183  rt_key2str(rt->key), rt->dreg);
184  }
185  return 0;
186 }
187 
188 static int nftnl_expr_rt_export(char *buf, size_t size,
189  const struct nftnl_expr *e, int type)
190 {
191  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
192  NFTNL_BUF_INIT(b, buf, size);
193 
194  if (e->flags & (1 << NFTNL_EXPR_RT_DREG))
195  nftnl_buf_u32(&b, type, rt->dreg, DREG);
196  if (e->flags & (1 << NFTNL_EXPR_RT_KEY))
197  nftnl_buf_str(&b, type, rt_key2str(rt->key), KEY);
198 
199  return nftnl_buf_done(&b);
200 }
201 
202 static int
203 nftnl_expr_rt_snprintf(char *buf, size_t len, uint32_t type,
204  uint32_t flags, const struct nftnl_expr *e)
205 {
206  switch (type) {
207  case NFTNL_OUTPUT_DEFAULT:
208  return nftnl_expr_rt_snprintf_default(buf, len, e);
209  case NFTNL_OUTPUT_XML:
210  case NFTNL_OUTPUT_JSON:
211  return nftnl_expr_rt_export(buf, len, e, type);
212  default:
213  break;
214  }
215  return -1;
216 }
217 
218 static bool nftnl_expr_rt_cmp(const struct nftnl_expr *e1,
219  const struct nftnl_expr *e2)
220 {
221  struct nftnl_expr_rt *r1 = nftnl_expr_data(e1);
222  struct nftnl_expr_rt *r2 = nftnl_expr_data(e2);
223  bool eq = true;
224 
225  if (e1->flags & (1 << NFTNL_EXPR_RT_KEY))
226  eq &= (r1->key == r2->key);
227  if (e1->flags & (1 << NFTNL_EXPR_RT_DREG))
228  eq &= (r1->dreg == r2->dreg);
229 
230  return eq;
231 }
232 
233 struct expr_ops expr_ops_rt = {
234  .name = "rt",
235  .alloc_len = sizeof(struct nftnl_expr_rt),
236  .max_attr = NFTA_RT_MAX,
237  .cmp = nftnl_expr_rt_cmp,
238  .set = nftnl_expr_rt_set,
239  .get = nftnl_expr_rt_get,
240  .parse = nftnl_expr_rt_parse,
241  .build = nftnl_expr_rt_build,
242  .snprintf = nftnl_expr_rt_snprintf,
243  .json_parse = nftnl_expr_rt_json_parse,
244 };