libnftnl  1.0.5
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 
24  uint16_t queuenum;
25  uint16_t queues_total;
26  uint16_t flags;
27 };
28 
29 static int nftnl_expr_queue_set(struct nftnl_expr *e, uint16_t type,
30  const void *data, uint32_t data_len)
31 {
32  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
33 
34  switch(type) {
35  case NFTNL_EXPR_QUEUE_NUM:
36  queue->queuenum = *((uint16_t *)data);
37  break;
38  case NFTNL_EXPR_QUEUE_TOTAL:
39  queue->queues_total = *((uint16_t *)data);
40  break;
41  case NFTNL_EXPR_QUEUE_FLAGS:
42  queue->flags = *((uint16_t *)data);
43  break;
44  default:
45  return -1;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_queue_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
55 
56  switch(type) {
57  case NFTNL_EXPR_QUEUE_NUM:
58  *data_len = sizeof(queue->queuenum);
59  return &queue->queuenum;
60  case NFTNL_EXPR_QUEUE_TOTAL:
61  *data_len = sizeof(queue->queues_total);
62  return &queue->queues_total;
63  case NFTNL_EXPR_QUEUE_FLAGS:
64  *data_len = sizeof(queue->flags);
65  return &queue->flags;
66  }
67  return NULL;
68 }
69 
70 static int nftnl_expr_queue_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_QUEUE_MAX) < 0)
76  return MNL_CB_OK;
77 
78  switch(type) {
79  case NFTA_QUEUE_NUM:
80  case NFTA_QUEUE_TOTAL:
81  case NFTA_QUEUE_FLAGS:
82  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 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_queue_build(struct nlmsghdr *nlh, struct nftnl_expr *e)
93 {
94  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
95 
96  if (e->flags & (1 << NFTNL_EXPR_QUEUE_NUM))
97  mnl_attr_put_u16(nlh, NFTA_QUEUE_NUM, htons(queue->queuenum));
98  if (e->flags & (1 << NFTNL_EXPR_QUEUE_TOTAL))
99  mnl_attr_put_u16(nlh, NFTA_QUEUE_TOTAL, htons(queue->queues_total));
100  if (e->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS))
101  mnl_attr_put_u16(nlh, NFTA_QUEUE_FLAGS, htons(queue->flags));
102 }
103 
104 static int
105 nftnl_expr_queue_parse(struct nftnl_expr *e, struct nlattr *attr)
106 {
107  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
108  struct nlattr *tb[NFTA_QUEUE_MAX+1] = {};
109 
110  if (mnl_attr_parse_nested(attr, nftnl_expr_queue_cb, tb) < 0)
111  return -1;
112 
113  if (tb[NFTA_QUEUE_NUM]) {
114  queue->queuenum = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_NUM]));
115  e->flags |= (1 << NFTNL_EXPR_QUEUE_NUM);
116  }
117  if (tb[NFTA_QUEUE_TOTAL]) {
118  queue->queues_total = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_TOTAL]));
119  e->flags |= (1 << NFTNL_EXPR_QUEUE_TOTAL);
120  }
121  if (tb[NFTA_QUEUE_FLAGS]) {
122  queue->flags = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_FLAGS]));
123  e->flags |= (1 << NFTNL_EXPR_QUEUE_FLAGS);
124  }
125 
126  return 0;
127 }
128 
129 static int
130 nftnl_expr_queue_json_parse(struct nftnl_expr *e, json_t *root,
131  struct nftnl_parse_err *err)
132 {
133 #ifdef JSON_PARSING
134  uint16_t type;
135  uint16_t code;
136 
137  if (nftnl_jansson_parse_val(root, "num", NFTNL_TYPE_U16, &type, err) == 0)
138  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_NUM, type);
139  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_NUM, type);
140 
141  if (nftnl_jansson_parse_val(root, "total", NFTNL_TYPE_U16, &code, err) == 0)
142  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_TOTAL, code);
143 
144  if (nftnl_jansson_parse_val(root, "flags", NFTNL_TYPE_U16, &code, err) == 0)
145  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_FLAGS, code);
146 
147  return 0;
148 #else
149  errno = EOPNOTSUPP;
150  return -1;
151 #endif
152 }
153 
154 static int
155 nftnl_expr_queue_xml_parse(struct nftnl_expr *e, mxml_node_t *tree,
156  struct nftnl_parse_err *err)
157 {
158 #ifdef XML_PARSING
159  uint16_t queue_num, queue_total, flags;
160 
161  if (nftnl_mxml_num_parse(tree, "num", MXML_DESCEND_FIRST, BASE_DEC,
162  &queue_num, NFTNL_TYPE_U16, NFTNL_XML_MAND,
163  err) == 0)
164  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_NUM, queue_num);
165 
166  if (nftnl_mxml_num_parse(tree, "total", MXML_DESCEND_FIRST, BASE_DEC,
167  &queue_total, NFTNL_TYPE_U16,
168  NFTNL_XML_MAND, err) == 0)
169  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_TOTAL, queue_total);
170 
171  if (nftnl_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
172  &flags, NFTNL_TYPE_U16,
173  NFTNL_XML_MAND, err) == 0)
174  nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_FLAGS, flags);
175 
176  return 0;
177 #else
178  errno = EOPNOTSUPP;
179  return -1;
180 #endif
181 }
182 
183 static int nftnl_expr_queue_snprintf_default(char *buf, size_t len,
184  struct nftnl_expr *e)
185 {
186  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
187  int ret, size = len, offset = 0;
188  uint16_t total_queues;
189 
190  total_queues = queue->queuenum + queue->queues_total -1;
191 
192  ret = snprintf(buf + offset, len, "num %u", queue->queuenum);
193  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
194 
195  if (queue->queues_total && total_queues != queue->queuenum) {
196  ret = snprintf(buf + offset, len, "-%u", total_queues);
197  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
198  }
199 
200  if (e->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS)) {
201  if (queue->flags & (NFT_QUEUE_FLAG_BYPASS)) {
202  ret = snprintf(buf + offset, len, " bypass");
203  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
204  }
205  if (queue->flags & (NFT_QUEUE_FLAG_CPU_FANOUT)) {
206  ret = snprintf(buf + offset, len, " fanout");
207  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
208  }
209  }
210  return offset;
211 }
212 
213 static int nftnl_expr_queue_export(char *buf, size_t size,
214  struct nftnl_expr *e, int type)
215 {
216  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
217  NFTNL_BUF_INIT(b, buf, size);
218 
219  if (e->flags & (1 << NFTNL_EXPR_QUEUE_NUM))
220  nftnl_buf_u32(&b, type, queue->queuenum, NUM);
221  if (e->flags & (1 << NFTNL_EXPR_QUEUE_TOTAL))
222  nftnl_buf_u32(&b, type, queue->queues_total, TOTAL);
223  if (e->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS))
224  nftnl_buf_u32(&b, type, queue->flags, FLAGS);
225 
226  return nftnl_buf_done(&b);
227 }
228 
229 static int
230 nftnl_expr_queue_snprintf(char *buf, size_t len, uint32_t type,
231  uint32_t flags, struct nftnl_expr *e)
232 {
233 
234  switch (type) {
235  case NFTNL_OUTPUT_DEFAULT:
236  return nftnl_expr_queue_snprintf_default(buf, len, e);
237  case NFTNL_OUTPUT_XML:
238  case NFTNL_OUTPUT_JSON:
239  return nftnl_expr_queue_export(buf, len, e, type);
240  default:
241  break;
242  }
243  return -1;
244 }
245 
246 struct expr_ops expr_ops_queue = {
247  .name = "queue",
248  .alloc_len = sizeof(struct nftnl_expr_queue),
249  .max_attr = NFTA_QUEUE_MAX,
250  .set = nftnl_expr_queue_set,
251  .get = nftnl_expr_queue_get,
252  .parse = nftnl_expr_queue_parse,
253  .build = nftnl_expr_queue_build,
254  .snprintf = nftnl_expr_queue_snprintf,
255  .xml_parse = nftnl_expr_queue_xml_parse,
256  .json_parse = nftnl_expr_queue_json_parse,
257 };