libnftnl  1.0.2
queue.c
1 /*
2  * (C) 2013 by Eric Leblond <eric@regit.org>
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 
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <arpa/inet.h>
15 #include <errno.h>
16 #include <linux/netfilter/nf_tables.h>
17 
18 #include "internal.h"
19 #include <libmnl/libmnl.h>
20 #include <libnftnl/expr.h>
21 #include <libnftnl/rule.h>
22 #include "expr_ops.h"
23 
25  uint16_t queuenum;
26  uint16_t queues_total;
27  uint16_t flags;
28 };
29 
30 static int nft_rule_expr_queue_set(struct nft_rule_expr *e, uint16_t type,
31  const void *data, uint32_t data_len)
32 {
33  struct nft_expr_queue *queue = nft_expr_data(e);
34 
35  switch(type) {
36  case NFT_EXPR_QUEUE_NUM:
37  queue->queuenum = *((uint16_t *)data);
38  break;
39  case NFT_EXPR_QUEUE_TOTAL:
40  queue->queues_total = *((uint16_t *)data);
41  break;
42  case NFT_EXPR_QUEUE_FLAGS:
43  queue->flags = *((uint16_t *)data);
44  break;
45  default:
46  return -1;
47  }
48  return 0;
49 }
50 
51 static const void *
52 nft_rule_expr_queue_get(const struct nft_rule_expr *e, uint16_t type,
53  uint32_t *data_len)
54 {
55  struct nft_expr_queue *queue = nft_expr_data(e);
56 
57  switch(type) {
58  case NFT_EXPR_QUEUE_NUM:
59  *data_len = sizeof(queue->queuenum);
60  return &queue->queuenum;
61  case NFT_EXPR_QUEUE_TOTAL:
62  *data_len = sizeof(queue->queues_total);
63  return &queue->queues_total;
64  case NFT_EXPR_QUEUE_FLAGS:
65  *data_len = sizeof(queue->flags);
66  return &queue->flags;
67  }
68  return NULL;
69 }
70 
71 static int nft_rule_expr_queue_cb(const struct nlattr *attr, void *data)
72 {
73  const struct nlattr **tb = data;
74  int type = mnl_attr_get_type(attr);
75 
76  if (mnl_attr_type_valid(attr, NFTA_QUEUE_MAX) < 0)
77  return MNL_CB_OK;
78 
79  switch(type) {
80  case NFTA_QUEUE_NUM:
81  case NFTA_QUEUE_TOTAL:
82  case NFTA_QUEUE_FLAGS:
83  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
84  perror("mnl_attr_validate");
85  return MNL_CB_ERROR;
86  }
87  break;
88  }
89 
90  tb[type] = attr;
91  return MNL_CB_OK;
92 }
93 
94 static void
95 nft_rule_expr_queue_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
96 {
97  struct nft_expr_queue *queue = nft_expr_data(e);
98 
99  if (e->flags & (1 << NFT_EXPR_QUEUE_NUM))
100  mnl_attr_put_u16(nlh, NFTA_QUEUE_NUM, htons(queue->queuenum));
101  if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL))
102  mnl_attr_put_u16(nlh, NFTA_QUEUE_TOTAL, htons(queue->queues_total));
103  if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS))
104  mnl_attr_put_u16(nlh, NFTA_QUEUE_FLAGS, htons(queue->flags));
105 }
106 
107 static int
108 nft_rule_expr_queue_parse(struct nft_rule_expr *e, struct nlattr *attr)
109 {
110  struct nft_expr_queue *queue = nft_expr_data(e);
111  struct nlattr *tb[NFTA_QUEUE_MAX+1] = {};
112 
113  if (mnl_attr_parse_nested(attr, nft_rule_expr_queue_cb, tb) < 0)
114  return -1;
115 
116  if (tb[NFTA_QUEUE_NUM]) {
117  queue->queuenum = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_NUM]));
118  e->flags |= (1 << NFT_EXPR_QUEUE_NUM);
119  }
120  if (tb[NFTA_QUEUE_TOTAL]) {
121  queue->queues_total = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_TOTAL]));
122  e->flags |= (1 << NFT_EXPR_QUEUE_TOTAL);
123  }
124  if (tb[NFTA_QUEUE_FLAGS]) {
125  queue->flags = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_FLAGS]));
126  e->flags |= (1 << NFT_EXPR_QUEUE_FLAGS);
127  }
128 
129  return 0;
130 }
131 
132 static int
133 nft_rule_expr_queue_json_parse(struct nft_rule_expr *e, json_t *root,
134  struct nft_parse_err *err)
135 {
136 #ifdef JSON_PARSING
137  uint16_t type;
138  uint16_t code;
139 
140  if (nft_jansson_parse_val(root, "num", NFT_TYPE_U16, &type, err) == 0)
141  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_NUM, type);
142  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_NUM, type);
143 
144  if (nft_jansson_parse_val(root, "total", NFT_TYPE_U16, &code, err) == 0)
145  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_TOTAL, code);
146 
147  if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U16, &code, err) == 0)
148  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_FLAGS, code);
149 
150  return 0;
151 #else
152  errno = EOPNOTSUPP;
153  return -1;
154 #endif
155 }
156 
157 static int
158 nft_rule_expr_queue_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
159  struct nft_parse_err *err)
160 {
161 #ifdef XML_PARSING
162  uint16_t queue_num, queue_total, flags;
163 
164  if (nft_mxml_num_parse(tree, "num", MXML_DESCEND_FIRST, BASE_DEC,
165  &queue_num, NFT_TYPE_U16, NFT_XML_MAND,
166  err) == 0)
167  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_NUM, queue_num);
168 
169  if (nft_mxml_num_parse(tree, "total", MXML_DESCEND_FIRST, BASE_DEC,
170  &queue_total, NFT_TYPE_U16,
171  NFT_XML_MAND, err) == 0)
172  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_TOTAL, queue_total);
173 
174  if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
175  &flags, NFT_TYPE_U16,
176  NFT_XML_MAND, err) == 0)
177  nft_rule_expr_set_u16(e, NFT_EXPR_QUEUE_FLAGS, flags);
178 
179  return 0;
180 #else
181  errno = EOPNOTSUPP;
182  return -1;
183 #endif
184 }
185 
186 static int nft_rule_expr_queue_snprintf_default(char *buf, size_t len,
187  struct nft_rule_expr *e)
188 {
189  struct nft_expr_queue *queue = nft_expr_data(e);
190  int ret, size = len, offset = 0;
191  uint16_t total_queues;
192 
193  total_queues = queue->queuenum + queue->queues_total -1;
194 
195  ret = snprintf(buf + offset, len, "num %u", queue->queuenum);
196  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
197 
198  if (queue->queues_total && total_queues != queue->queuenum) {
199  ret = snprintf(buf + offset, len, "-%u", total_queues);
200  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
201  }
202 
203  if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS)) {
204  if (queue->flags & (NFT_QUEUE_FLAG_BYPASS)) {
205  ret = snprintf(buf + offset, len, " bypass");
206  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
207  }
208  if (queue->flags & (NFT_QUEUE_FLAG_CPU_FANOUT)) {
209  ret = snprintf(buf + offset, len, " fanout");
210  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
211  }
212  }
213  return offset;
214 }
215 
216 static int nft_rule_expr_queue_snprintf_xml(char *buf, size_t len,
217  struct nft_rule_expr *e)
218 {
219  int ret, size = len, offset = 0;
220  struct nft_expr_queue *queue = nft_expr_data(e);
221 
222  if (e->flags & (1 << NFT_EXPR_QUEUE_NUM)) {
223  ret = snprintf(buf + offset, len, "<num>%u</num>",
224  queue->queuenum);
225  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
226  }
227 
228  if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL)) {
229  ret = snprintf(buf + offset, len, "<total>%u</total>",
230  queue->queues_total);
231  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
232  }
233  if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS)) {
234  ret = snprintf(buf + offset, len, "<flags>%u</flags>",
235  queue->flags);
236  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
237  }
238  return offset;
239 }
240 
241 static int nft_rule_expr_queue_snprintf_json(char *buf, size_t len,
242  struct nft_rule_expr *e)
243 {
244  int ret, size = len, offset = 0;
245  struct nft_expr_queue *queue = nft_expr_data(e);
246 
247  if (e->flags & (1 << NFT_EXPR_QUEUE_NUM)) {
248  ret = snprintf(buf + offset, len, "\"num\":%u,",
249  queue->queuenum);
250  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
251  }
252 
253  if (e->flags & (1 << NFT_EXPR_QUEUE_TOTAL)) {
254  ret = snprintf(buf + offset, len, "\"total\":%u,",
255  queue->queues_total);
256  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
257  }
258  if (e->flags & (1 << NFT_EXPR_QUEUE_FLAGS)) {
259  ret = snprintf(buf + offset, len, "\"flags\":%u,",
260  queue->flags);
261  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
262  }
263 
264  /* Remove the last comma characther */
265  if (offset > 0)
266  offset--;
267 
268  return offset;
269 }
270 
271 static int
272 nft_rule_expr_queue_snprintf(char *buf, size_t len, uint32_t type,
273  uint32_t flags, struct nft_rule_expr *e)
274 {
275 
276  switch(type) {
277  case NFT_OUTPUT_DEFAULT:
278  return nft_rule_expr_queue_snprintf_default(buf, len, e);
279  case NFT_OUTPUT_XML:
280  return nft_rule_expr_queue_snprintf_xml(buf, len, e);
281  case NFT_OUTPUT_JSON:
282  return nft_rule_expr_queue_snprintf_json(buf, len, e);
283  default:
284  break;
285  }
286  return -1;
287 }
288 
289 struct expr_ops expr_ops_queue = {
290  .name = "queue",
291  .alloc_len = sizeof(struct nft_expr_queue),
292  .max_attr = NFTA_QUEUE_MAX,
293  .set = nft_rule_expr_queue_set,
294  .get = nft_rule_expr_queue_get,
295  .parse = nft_rule_expr_queue_parse,
296  .build = nft_rule_expr_queue_build,
297  .snprintf = nft_rule_expr_queue_snprintf,
298  .xml_parse = nft_rule_expr_queue_xml_parse,
299  .json_parse = nft_rule_expr_queue_json_parse,
300 };
301 
302 static void __init expr_queue_init(void)
303 {
304  nft_expr_ops_register(&expr_ops_queue);
305 }