libnftnl  1.2.5
hash.c
1 /*
2  * (C) 2016 by Laura Garcia <nevola@gmail.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 
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  enum nft_hash_types type;
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  unsigned int len;
28  unsigned int modulus;
29  unsigned int seed;
30  unsigned int offset;
31 };
32 
33 static int
34 nftnl_expr_hash_set(struct nftnl_expr *e, uint16_t type,
35  const void *data, uint32_t data_len)
36 {
37  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
38  switch (type) {
39  case NFTNL_EXPR_HASH_SREG:
40  memcpy(&hash->sreg, data, sizeof(hash->sreg));
41  break;
42  case NFTNL_EXPR_HASH_DREG:
43  memcpy(&hash->dreg, data, sizeof(hash->dreg));
44  break;
45  case NFTNL_EXPR_HASH_LEN:
46  memcpy(&hash->len, data, sizeof(hash->len));
47  break;
48  case NFTNL_EXPR_HASH_MODULUS:
49  memcpy(&hash->modulus, data, sizeof(hash->modulus));
50  break;
51  case NFTNL_EXPR_HASH_SEED:
52  memcpy(&hash->seed, data, sizeof(hash->seed));
53  break;
54  case NFTNL_EXPR_HASH_OFFSET:
55  memcpy(&hash->offset, data, sizeof(hash->offset));
56  break;
57  case NFTNL_EXPR_HASH_TYPE:
58  memcpy(&hash->type, data, sizeof(hash->type));
59  break;
60  default:
61  return -1;
62  }
63  return 0;
64 }
65 
66 static const void *
67 nftnl_expr_hash_get(const struct nftnl_expr *e, uint16_t type,
68  uint32_t *data_len)
69 {
70  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
71 
72  switch (type) {
73  case NFTNL_EXPR_HASH_SREG:
74  *data_len = sizeof(hash->sreg);
75  return &hash->sreg;
76  case NFTNL_EXPR_HASH_DREG:
77  *data_len = sizeof(hash->dreg);
78  return &hash->dreg;
79  case NFTNL_EXPR_HASH_LEN:
80  *data_len = sizeof(hash->len);
81  return &hash->len;
82  case NFTNL_EXPR_HASH_MODULUS:
83  *data_len = sizeof(hash->modulus);
84  return &hash->modulus;
85  case NFTNL_EXPR_HASH_SEED:
86  *data_len = sizeof(hash->seed);
87  return &hash->seed;
88  case NFTNL_EXPR_HASH_OFFSET:
89  *data_len = sizeof(hash->offset);
90  return &hash->offset;
91  case NFTNL_EXPR_HASH_TYPE:
92  *data_len = sizeof(hash->type);
93  return &hash->type;
94  }
95  return NULL;
96 }
97 
98 static int nftnl_expr_hash_cb(const struct nlattr *attr, void *data)
99 {
100  const struct nlattr **tb = data;
101  int type = mnl_attr_get_type(attr);
102 
103  if (mnl_attr_type_valid(attr, NFTA_HASH_MAX) < 0)
104  return MNL_CB_OK;
105 
106  switch (type) {
107  case NFTA_HASH_SREG:
108  case NFTA_HASH_DREG:
109  case NFTA_HASH_LEN:
110  case NFTA_HASH_MODULUS:
111  case NFTA_HASH_SEED:
112  case NFTA_HASH_OFFSET:
113  case NFTA_HASH_TYPE:
114  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
115  abi_breakage();
116  break;
117  }
118 
119  tb[type] = attr;
120  return MNL_CB_OK;
121 }
122 
123 static void
124 nftnl_expr_hash_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
125 {
126  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
127 
128  if (e->flags & (1 << NFTNL_EXPR_HASH_SREG))
129  mnl_attr_put_u32(nlh, NFTA_HASH_SREG, htonl(hash->sreg));
130  if (e->flags & (1 << NFTNL_EXPR_HASH_DREG))
131  mnl_attr_put_u32(nlh, NFTA_HASH_DREG, htonl(hash->dreg));
132  if (e->flags & (1 << NFTNL_EXPR_HASH_LEN))
133  mnl_attr_put_u32(nlh, NFTA_HASH_LEN, htonl(hash->len));
134  if (e->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
135  mnl_attr_put_u32(nlh, NFTA_HASH_MODULUS, htonl(hash->modulus));
136  if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
137  mnl_attr_put_u32(nlh, NFTA_HASH_SEED, htonl(hash->seed));
138  if (e->flags & (1 << NFTNL_EXPR_HASH_OFFSET))
139  mnl_attr_put_u32(nlh, NFTA_HASH_OFFSET, htonl(hash->offset));
140  if (e->flags & (1 << NFTNL_EXPR_HASH_TYPE))
141  mnl_attr_put_u32(nlh, NFTA_HASH_TYPE, htonl(hash->type));
142 }
143 
144 static int
145 nftnl_expr_hash_parse(struct nftnl_expr *e, struct nlattr *attr)
146 {
147  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
148  struct nlattr *tb[NFTA_HASH_MAX+1] = {};
149  int ret = 0;
150 
151  if (mnl_attr_parse_nested(attr, nftnl_expr_hash_cb, tb) < 0)
152  return -1;
153 
154  if (tb[NFTA_HASH_SREG]) {
155  hash->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SREG]));
156  e->flags |= (1 << NFTNL_EXPR_HASH_SREG);
157  }
158  if (tb[NFTA_HASH_DREG]) {
159  hash->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_DREG]));
160  e->flags |= (1 << NFTNL_EXPR_HASH_DREG);
161  }
162  if (tb[NFTA_HASH_LEN]) {
163  hash->len = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_LEN]));
164  e->flags |= (1 << NFTNL_EXPR_HASH_LEN);
165  }
166  if (tb[NFTA_HASH_MODULUS]) {
167  hash->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_MODULUS]));
168  e->flags |= (1 << NFTNL_EXPR_HASH_MODULUS);
169  }
170  if (tb[NFTA_HASH_SEED]) {
171  hash->seed = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SEED]));
172  e->flags |= (1 << NFTNL_EXPR_HASH_SEED);
173  }
174  if (tb[NFTA_HASH_OFFSET]) {
175  hash->offset = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_OFFSET]));
176  e->flags |= (1 << NFTNL_EXPR_HASH_OFFSET);
177  }
178  if (tb[NFTA_HASH_TYPE]) {
179  hash->type = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_TYPE]));
180  e->flags |= (1 << NFTNL_EXPR_HASH_TYPE);
181  }
182 
183  return ret;
184 }
185 
186 static int
187 nftnl_expr_hash_snprintf(char *buf, size_t remain,
188  uint32_t flags, const struct nftnl_expr *e)
189 {
190  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
191  int offset = 0, ret;
192 
193  switch (hash->type) {
194  case NFT_HASH_SYM:
195  ret =
196  snprintf(buf, remain, "reg %u = symhash() %% mod %u ",
197  hash->dreg,
198  hash->modulus);
199  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
200  break;
201  case NFT_HASH_JENKINS:
202  default:
203  ret =
204  snprintf(buf, remain,
205  "reg %u = jhash(reg %u, %u, 0x%x) %% mod %u ",
206  hash->dreg, hash->sreg, hash->len, hash->seed,
207  hash->modulus);
208  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
209  break;
210  }
211 
212  if (hash->offset) {
213  ret = snprintf(buf + offset, remain, "offset %u ",
214  hash->offset);
215  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
216  }
217 
218  return offset;
219 }
220 
221 struct expr_ops expr_ops_hash = {
222  .name = "hash",
223  .alloc_len = sizeof(struct nftnl_expr_hash),
224  .max_attr = NFTA_HASH_MAX,
225  .set = nftnl_expr_hash_set,
226  .get = nftnl_expr_hash_get,
227  .parse = nftnl_expr_hash_parse,
228  .build = nftnl_expr_hash_build,
229  .output = nftnl_expr_hash_snprintf,
230 };