libnftnl  1.2.9
queue.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2013 by Eric Leblond <eric@regit.org>
4  */
5 
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <arpa/inet.h>
10 #include <errno.h>
11 #include <linux/netfilter/nf_tables.h>
12 
13 #include "internal.h"
14 #include <libmnl/libmnl.h>
15 #include <libnftnl/expr.h>
16 #include <libnftnl/rule.h>
17 
19  enum nft_registers sreg_qnum;
20  uint16_t queuenum;
21  uint16_t queues_total;
22  uint16_t flags;
23 };
24 
25 static int nftnl_expr_queue_set(struct nftnl_expr *e, uint16_t type,
26  const void *data, uint32_t data_len)
27 {
28  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
29 
30  switch(type) {
31  case NFTNL_EXPR_QUEUE_NUM:
32  memcpy(&queue->queuenum, data, data_len);
33  break;
34  case NFTNL_EXPR_QUEUE_TOTAL:
35  memcpy(&queue->queues_total, data, data_len);
36  break;
37  case NFTNL_EXPR_QUEUE_FLAGS:
38  memcpy(&queue->flags, data, data_len);
39  break;
40  case NFTNL_EXPR_QUEUE_SREG_QNUM:
41  memcpy(&queue->sreg_qnum, data, data_len);
42  break;
43  }
44  return 0;
45 }
46 
47 static const void *
48 nftnl_expr_queue_get(const struct nftnl_expr *e, uint16_t type,
49  uint32_t *data_len)
50 {
51  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
52 
53  switch(type) {
54  case NFTNL_EXPR_QUEUE_NUM:
55  *data_len = sizeof(queue->queuenum);
56  return &queue->queuenum;
57  case NFTNL_EXPR_QUEUE_TOTAL:
58  *data_len = sizeof(queue->queues_total);
59  return &queue->queues_total;
60  case NFTNL_EXPR_QUEUE_FLAGS:
61  *data_len = sizeof(queue->flags);
62  return &queue->flags;
63  case NFTNL_EXPR_QUEUE_SREG_QNUM:
64  *data_len = sizeof(queue->sreg_qnum);
65  return &queue->sreg_qnum;
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  case NFTA_QUEUE_SREG_QNUM:
86  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
87  abi_breakage();
88  break;
89  }
90 
91  tb[type] = attr;
92  return MNL_CB_OK;
93 }
94 
95 static void
96 nftnl_expr_queue_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
97 {
98  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
99 
100  if (e->flags & (1 << NFTNL_EXPR_QUEUE_NUM))
101  mnl_attr_put_u16(nlh, NFTA_QUEUE_NUM, htons(queue->queuenum));
102  if (e->flags & (1 << NFTNL_EXPR_QUEUE_TOTAL))
103  mnl_attr_put_u16(nlh, NFTA_QUEUE_TOTAL, htons(queue->queues_total));
104  if (e->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS))
105  mnl_attr_put_u16(nlh, NFTA_QUEUE_FLAGS, htons(queue->flags));
106  if (e->flags & (1 << NFTNL_EXPR_QUEUE_SREG_QNUM))
107  mnl_attr_put_u32(nlh, NFTA_QUEUE_SREG_QNUM, htonl(queue->sreg_qnum));
108 }
109 
110 static int
111 nftnl_expr_queue_parse(struct nftnl_expr *e, struct nlattr *attr)
112 {
113  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
114  struct nlattr *tb[NFTA_QUEUE_MAX+1] = {};
115 
116  if (mnl_attr_parse_nested(attr, nftnl_expr_queue_cb, tb) < 0)
117  return -1;
118 
119  if (tb[NFTA_QUEUE_NUM]) {
120  queue->queuenum = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_NUM]));
121  e->flags |= (1 << NFTNL_EXPR_QUEUE_NUM);
122  }
123  if (tb[NFTA_QUEUE_TOTAL]) {
124  queue->queues_total = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_TOTAL]));
125  e->flags |= (1 << NFTNL_EXPR_QUEUE_TOTAL);
126  }
127  if (tb[NFTA_QUEUE_FLAGS]) {
128  queue->flags = ntohs(mnl_attr_get_u16(tb[NFTA_QUEUE_FLAGS]));
129  e->flags |= (1 << NFTNL_EXPR_QUEUE_FLAGS);
130  }
131  if (tb[NFTA_QUEUE_SREG_QNUM]) {
132  queue->sreg_qnum = ntohl(mnl_attr_get_u32(tb[NFTA_QUEUE_SREG_QNUM]));
133  e->flags |= (1 << NFTNL_EXPR_QUEUE_SREG_QNUM);
134  }
135 
136  return 0;
137 }
138 
139 static int
140 nftnl_expr_queue_snprintf(char *buf, size_t remain,
141  uint32_t flags, const struct nftnl_expr *e)
142 {
143  struct nftnl_expr_queue *queue = nftnl_expr_data(e);
144  uint16_t total_queues;
145  int ret, offset = 0;
146 
147  if (e->flags & (1 << NFTNL_EXPR_QUEUE_NUM)) {
148  total_queues = queue->queuenum + queue->queues_total - 1;
149 
150  ret = snprintf(buf + offset, remain, "num %u", queue->queuenum);
151  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
152 
153  if (queue->queues_total && total_queues != queue->queuenum) {
154  ret = snprintf(buf + offset, remain, "-%u", total_queues);
155  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
156  }
157 
158  ret = snprintf(buf + offset, remain, " ");
159  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
160  }
161 
162  if (e->flags & (1 << NFTNL_EXPR_QUEUE_SREG_QNUM)) {
163  ret = snprintf(buf + offset, remain, "sreg_qnum %u ",
164  queue->sreg_qnum);
165  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
166  }
167 
168  if (e->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS)) {
169  if (queue->flags & (NFT_QUEUE_FLAG_BYPASS)) {
170  ret = snprintf(buf + offset, remain, "bypass ");
171  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
172  }
173  if (queue->flags & (NFT_QUEUE_FLAG_CPU_FANOUT)) {
174  ret = snprintf(buf + offset, remain, "fanout ");
175  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
176  }
177  }
178  return offset;
179 }
180 
181 static struct attr_policy queue_attr_policy[__NFTNL_EXPR_QUEUE_MAX] = {
182  [NFTNL_EXPR_QUEUE_NUM] = { .maxlen = sizeof(uint16_t) },
183  [NFTNL_EXPR_QUEUE_TOTAL] = { .maxlen = sizeof(uint16_t) },
184  [NFTNL_EXPR_QUEUE_FLAGS] = { .maxlen = sizeof(uint16_t) },
185  [NFTNL_EXPR_QUEUE_SREG_QNUM] = { .maxlen = sizeof(uint32_t) },
186 };
187 
188 struct expr_ops expr_ops_queue = {
189  .name = "queue",
190  .alloc_len = sizeof(struct nftnl_expr_queue),
191  .nftnl_max_attr = __NFTNL_EXPR_QUEUE_MAX - 1,
192  .attr_policy = queue_attr_policy,
193  .set = nftnl_expr_queue_set,
194  .get = nftnl_expr_queue_get,
195  .parse = nftnl_expr_queue_parse,
196  .build = nftnl_expr_queue_build,
197  .output = nftnl_expr_queue_snprintf,
198 };