libnftnl  1.2.3
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 struct nftnl_expr_rt {
23  enum nft_rt_keys key;
24  enum nft_registers dreg;
25 };
26 
27 static int
28 nftnl_expr_rt_set(struct nftnl_expr *e, uint16_t type,
29  const void *data, uint32_t data_len)
30 {
31  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
32 
33  switch (type) {
34  case NFTNL_EXPR_RT_KEY:
35  memcpy(&rt->key, data, sizeof(rt->key));
36  break;
37  case NFTNL_EXPR_RT_DREG:
38  memcpy(&rt->dreg, data, sizeof(rt->dreg));
39  break;
40  default:
41  return -1;
42  }
43  return 0;
44 }
45 
46 static const void *
47 nftnl_expr_rt_get(const struct nftnl_expr *e, uint16_t type,
48  uint32_t *data_len)
49 {
50  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
51 
52  switch (type) {
53  case NFTNL_EXPR_RT_KEY:
54  *data_len = sizeof(rt->key);
55  return &rt->key;
56  case NFTNL_EXPR_RT_DREG:
57  *data_len = sizeof(rt->dreg);
58  return &rt->dreg;
59  }
60  return NULL;
61 }
62 
63 static int nftnl_expr_rt_cb(const struct nlattr *attr, void *data)
64 {
65  const struct nlattr **tb = data;
66  int type = mnl_attr_get_type(attr);
67 
68  if (mnl_attr_type_valid(attr, NFTA_RT_MAX) < 0)
69  return MNL_CB_OK;
70 
71  switch (type) {
72  case NFTA_RT_KEY:
73  case NFTA_RT_DREG:
74  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
75  abi_breakage();
76  break;
77  }
78 
79  tb[type] = attr;
80  return MNL_CB_OK;
81 }
82 
83 static void
84 nftnl_expr_rt_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
85 {
86  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
87 
88  if (e->flags & (1 << NFTNL_EXPR_RT_KEY))
89  mnl_attr_put_u32(nlh, NFTA_RT_KEY, htonl(rt->key));
90  if (e->flags & (1 << NFTNL_EXPR_RT_DREG))
91  mnl_attr_put_u32(nlh, NFTA_RT_DREG, htonl(rt->dreg));
92 }
93 
94 static int
95 nftnl_expr_rt_parse(struct nftnl_expr *e, struct nlattr *attr)
96 {
97  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
98  struct nlattr *tb[NFTA_RT_MAX+1] = {};
99 
100  if (mnl_attr_parse_nested(attr, nftnl_expr_rt_cb, tb) < 0)
101  return -1;
102 
103  if (tb[NFTA_RT_KEY]) {
104  rt->key = ntohl(mnl_attr_get_u32(tb[NFTA_RT_KEY]));
105  e->flags |= (1 << NFTNL_EXPR_RT_KEY);
106  }
107  if (tb[NFTA_RT_DREG]) {
108  rt->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_RT_DREG]));
109  e->flags |= (1 << NFTNL_EXPR_RT_DREG);
110  }
111 
112  return 0;
113 }
114 
115 static const char *rt_key2str_array[NFT_RT_MAX + 1] = {
116  [NFT_RT_CLASSID] = "classid",
117  [NFT_RT_NEXTHOP4] = "nexthop4",
118  [NFT_RT_NEXTHOP6] = "nexthop6",
119  [NFT_RT_TCPMSS] = "tcpmss",
120  [NFT_RT_XFRM] = "ipsec",
121 };
122 
123 static const char *rt_key2str(uint8_t key)
124 {
125  if (key <= NFT_RT_MAX)
126  return rt_key2str_array[key];
127 
128  return "unknown";
129 }
130 
131 static inline int str2rt_key(const char *str)
132 {
133  int i;
134 
135  for (i = 0; i < NFT_RT_MAX; i++) {
136  if (strcmp(str, rt_key2str_array[i]) == 0)
137  return i;
138  }
139 
140  errno = EINVAL;
141  return -1;
142 }
143 
144 static int
145 nftnl_expr_rt_snprintf(char *buf, size_t len,
146  uint32_t flags, const struct nftnl_expr *e)
147 {
148  struct nftnl_expr_rt *rt = nftnl_expr_data(e);
149 
150  if (e->flags & (1 << NFTNL_EXPR_RT_DREG)) {
151  return snprintf(buf, len, "load %s => reg %u ",
152  rt_key2str(rt->key), rt->dreg);
153  }
154  return 0;
155 }
156 
157 struct expr_ops expr_ops_rt = {
158  .name = "rt",
159  .alloc_len = sizeof(struct nftnl_expr_rt),
160  .max_attr = NFTA_RT_MAX,
161  .set = nftnl_expr_rt_set,
162  .get = nftnl_expr_rt_get,
163  .parse = nftnl_expr_rt_parse,
164  .build = nftnl_expr_rt_build,
165  .output = nftnl_expr_rt_snprintf,
166 };