libnl 3.12.0
nh_encap_ip6.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2
3#include "nl-default.h"
4
5#include <linux/lwtunnel.h>
6#include <linux-private/linux/if_tunnel.h>
7
8#include <netlink/route/nexthop.h>
9
10#include "nexthop-encap.h"
11#include "nl-aux-core/nl-core.h"
12#include "nl-aux-route/nl-route.h"
13#include "nl-route.h"
14
16 struct nl_addr *dst;
17 struct nl_addr *src;
18 uint64_t id;
19 uint8_t tc;
20 uint8_t hoplimit;
21 uint16_t flags;
22};
23
24static void ip6_encap_dump(void *priv, struct nl_dump_params *dp)
25{
26 struct ip6_tunnel_encap *encap_info = priv;
27 char buf[256];
28
29 if (encap_info->id)
30 nl_dump(dp, "id %llu ", (unsigned long long)encap_info->id);
31
32 nl_dump(dp, "%s ", nl_addr2str(encap_info->dst, buf, sizeof(buf)));
33
34 if (encap_info->src)
35 nl_dump(dp, "src %s ",
36 nl_addr2str(encap_info->src, buf, sizeof(buf)));
37
38 if (encap_info->tc)
39 nl_dump(dp, "tc %u ", encap_info->tc);
40
41 if (encap_info->hoplimit)
42 nl_dump(dp, "hoplimit %u ", encap_info->hoplimit);
43
44 if (encap_info->flags) {
45 if (encap_info->flags & TUNNEL_KEY)
46 nl_dump(dp, "key ");
47 if (encap_info->flags & TUNNEL_CSUM)
48 nl_dump(dp, "csum ");
49 if (encap_info->flags & TUNNEL_SEQ)
50 nl_dump(dp, "seq ");
51 }
52}
53
54static int ip6_encap_build_msg(struct nl_msg *msg, void *priv)
55{
56 struct ip6_tunnel_encap *encap_info = priv;
57
58 if (encap_info->id)
59 NLA_PUT_U64(msg, LWTUNNEL_IP6_ID, htonll(encap_info->id));
60 NLA_PUT_ADDR(msg, LWTUNNEL_IP6_DST, encap_info->dst);
61 if (encap_info->src)
62 NLA_PUT_ADDR(msg, LWTUNNEL_IP6_SRC, encap_info->src);
63 if (encap_info->tc)
64 NLA_PUT_U8(msg, LWTUNNEL_IP6_TC, encap_info->tc);
65 if (encap_info->hoplimit)
66 NLA_PUT_U8(msg, LWTUNNEL_IP6_HOPLIMIT, encap_info->hoplimit);
67 if (encap_info->flags)
68 NLA_PUT_U16(msg, LWTUNNEL_IP6_FLAGS, encap_info->flags);
69
70 return 0;
71
72nla_put_failure:
73 return -NLE_MSGSIZE;
74}
75
76static void ip6_encap_destructor(void *priv)
77{
78 struct ip6_tunnel_encap *encap_info = priv;
79
80 nl_addr_put(encap_info->dst);
81 nl_addr_put(encap_info->src);
82}
83
84static void *ip6_encap_clone(void *priv)
85{
86 struct ip6_tunnel_encap *src = priv;
87 struct ip6_tunnel_encap *clone;
88
89 if (!src)
90 return NULL;
91
92 clone = calloc(1, sizeof(*clone));
93 if (!clone)
94 return NULL;
95
96 clone->dst = nl_addr_get(src->dst);
97 if (src->src)
98 clone->src = nl_addr_get(src->src);
99 clone->id = src->id;
100 clone->tc = src->tc;
101 clone->hoplimit = src->hoplimit;
102 clone->flags = src->flags;
103
104 return clone;
105}
106
107static struct nla_policy ip6_encap_policy[LWTUNNEL_IP6_MAX + 1] = {
108 [LWTUNNEL_IP6_ID] = { .type = NLA_U64 },
109 [LWTUNNEL_IP6_DST] = { .type = NLA_BINARY, .minlen = 16, .maxlen = 16 },
110 [LWTUNNEL_IP6_SRC] = { .type = NLA_BINARY, .minlen = 16, .maxlen = 16 },
111 [LWTUNNEL_IP6_HOPLIMIT] = { .type = NLA_U8 },
112 [LWTUNNEL_IP6_TC] = { .type = NLA_U8 },
113 [LWTUNNEL_IP6_FLAGS] = { .type = NLA_U16 },
114};
115
116static int ip6_encap_parse_msg(struct nlattr *nla,
117 struct rtnl_nh_encap **encap_out)
118{
119 _nl_auto_rtnl_nh_encap struct rtnl_nh_encap *nh_encap = NULL;
120 _nl_auto_nl_addr struct nl_addr *dst = NULL;
121 _nl_auto_nl_addr struct nl_addr *src = NULL;
122 struct nlattr *tb[LWTUNNEL_IP6_MAX + 1];
123 uint16_t flags = 0;
124 uint64_t id = 0;
125 uint8_t hoplimit = 0;
126 uint8_t tc = 0;
127 int err;
128
129 err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, nla, ip6_encap_policy);
130 if (err < 0)
131 return err;
132
133 if (!tb[LWTUNNEL_IP6_DST])
134 return -NLE_INVAL;
135
136 dst = nl_addr_alloc_attr(tb[LWTUNNEL_IP6_DST], AF_INET6);
137 if (!dst)
138 return -NLE_NOMEM;
139
140 if (tb[LWTUNNEL_IP6_SRC]) {
141 src = nl_addr_alloc_attr(tb[LWTUNNEL_IP6_SRC], AF_INET6);
142 if (!src)
143 return -NLE_NOMEM;
144 }
145
146 if (tb[LWTUNNEL_IP6_HOPLIMIT])
147 hoplimit = nla_get_u8(tb[LWTUNNEL_IP6_HOPLIMIT]);
148
149 if (tb[LWTUNNEL_IP6_TC])
150 tc = nla_get_u8(tb[LWTUNNEL_IP6_TC]);
151
152 if (tb[LWTUNNEL_IP6_ID])
153 id = ntohll(nla_get_u64(tb[LWTUNNEL_IP6_ID]));
154
155 if (tb[LWTUNNEL_IP6_FLAGS])
156 flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]);
157
158 nh_encap = rtnl_nh_encap_alloc();
159 if (!nh_encap)
160 return -NLE_NOMEM;
161
162 err = rtnl_nh_encap_ip6(nh_encap, dst);
163 if (err < 0)
164 return err;
165
166 if (src) {
167 err = rtnl_nh_set_encap_ip6_src(nh_encap, src);
168 if (err < 0)
169 return err;
170 }
171
172 if (id) {
173 err = rtnl_nh_set_encap_ip6_id(nh_encap, id);
174 if (err < 0)
175 return err;
176 }
177
178 if (hoplimit) {
179 err = rtnl_nh_set_encap_ip6_hoplimit(nh_encap, hoplimit);
180 if (err < 0)
181 return err;
182 }
183
184 if (tc) {
185 err = rtnl_nh_set_encap_ip6_tc(nh_encap, tc);
186 if (err < 0)
187 return err;
188 }
189
190 if (flags) {
191 err = rtnl_nh_set_encap_ip6_flags(nh_encap, flags);
192 if (err < 0)
193 return err;
194 }
195
196 *encap_out = _nl_steal_pointer(&nh_encap);
197
198 return 0;
199}
200
201static int ip6_encap_compare(void *_a, void *_b)
202{
203 struct ip6_tunnel_encap *a = _a;
204 struct ip6_tunnel_encap *b = _b;
205 int diff = 0;
206
207 diff |= (a->tc != b->tc);
208 diff |= (a->hoplimit != b->hoplimit);
209 diff |= (a->flags != b->flags);
210 diff |= (a->id != b->id);
211 diff |= nl_addr_cmp(a->src, b->src);
212 diff |= nl_addr_cmp(a->dst, b->dst);
213
214 return diff;
215}
216
217const struct nh_encap_ops ip6_encap_ops = {
218 .encap_type = LWTUNNEL_ENCAP_IP6,
219 .build_msg = ip6_encap_build_msg,
220 .parse_msg = ip6_encap_parse_msg,
221 .compare = ip6_encap_compare,
222 .clone = ip6_encap_clone,
223 .dump = ip6_encap_dump,
224 .destructor = ip6_encap_destructor,
225};
226
227int rtnl_nh_encap_ip6(struct rtnl_nh_encap *nh_encap, struct nl_addr *dst)
228{
229 struct ip6_tunnel_encap *ip6_encap;
230
231 if (!dst || !nh_encap)
232 return -NLE_INVAL;
233 if (nl_addr_get_family(dst) != AF_INET6)
234 return -NLE_INVAL;
235
236 ip6_encap = calloc(1, sizeof(*ip6_encap));
237 if (!ip6_encap)
238 return -NLE_NOMEM;
239
240 ip6_encap->dst = nl_addr_get(dst);
241
242 nh_encap->priv = ip6_encap;
243 nh_encap->ops = &ip6_encap_ops;
244
245 return 0;
246}
247
248static struct ip6_tunnel_encap *nh_encap_get_ip6(struct rtnl_nh_encap *nh_encap)
249{
250 return (struct ip6_tunnel_encap *)nh_encap_check_and_get_priv(
251 nh_encap, LWTUNNEL_ENCAP_IP6);
252}
253
254struct nl_addr *rtnl_nh_get_encap_ip6_dst(struct rtnl_nh_encap *nh_encap)
255{
256 struct ip6_tunnel_encap *ip6_encap;
257
258 ip6_encap = nh_encap_get_ip6(nh_encap);
259 if (!ip6_encap)
260 return NULL;
261
262 return ip6_encap->dst;
263}
264
265int rtnl_nh_set_encap_ip6_src(struct rtnl_nh_encap *nh_encap,
266 struct nl_addr *src)
267{
268 struct ip6_tunnel_encap *ip6_encap;
269 struct nl_addr *old_src;
270
271 ip6_encap = nh_encap_get_ip6(nh_encap);
272 if (!ip6_encap)
273 return -NLE_INVAL;
274 if (src && nl_addr_get_family(src) != AF_INET6)
275 return -NLE_INVAL;
276
277 old_src = ip6_encap->src;
278 if (src)
279 ip6_encap->src = nl_addr_get(src);
280 else
281 ip6_encap->src = NULL;
282
283 nl_addr_put(old_src);
284
285 return 0;
286}
287
288struct nl_addr *rtnl_nh_get_encap_ip6_src(struct rtnl_nh_encap *nh_encap)
289{
290 struct ip6_tunnel_encap *ip6_encap;
291
292 ip6_encap = nh_encap_get_ip6(nh_encap);
293 if (!ip6_encap)
294 return NULL;
295
296 return ip6_encap->src;
297}
298
299int rtnl_nh_set_encap_ip6_tc(struct rtnl_nh_encap *nh_encap, uint8_t tc)
300{
301 struct ip6_tunnel_encap *ip6_encap;
302
303 ip6_encap = nh_encap_get_ip6(nh_encap);
304 if (!ip6_encap)
305 return -NLE_INVAL;
306
307 ip6_encap->tc = tc;
308 return 0;
309}
310
311int rtnl_nh_get_encap_ip6_tc(struct rtnl_nh_encap *nh_encap)
312{
313 struct ip6_tunnel_encap *ip6_encap;
314
315 ip6_encap = nh_encap_get_ip6(nh_encap);
316 if (!ip6_encap)
317 return -NLE_INVAL;
318
319 return ip6_encap->tc;
320}
321
322int rtnl_nh_set_encap_ip6_hoplimit(struct rtnl_nh_encap *nh_encap,
323 uint8_t hoplimit)
324{
325 struct ip6_tunnel_encap *ip6_encap;
326
327 ip6_encap = nh_encap_get_ip6(nh_encap);
328 if (!ip6_encap)
329 return -NLE_INVAL;
330
331 ip6_encap->hoplimit = hoplimit;
332 return 0;
333}
334
335int rtnl_nh_get_encap_ip6_hoplimit(struct rtnl_nh_encap *nh_encap)
336{
337 struct ip6_tunnel_encap *ip6_encap;
338
339 ip6_encap = nh_encap_get_ip6(nh_encap);
340 if (!ip6_encap)
341 return -NLE_INVAL;
342
343 return ip6_encap->hoplimit;
344}
345
346int rtnl_nh_set_encap_ip6_flags(struct rtnl_nh_encap *nh_encap, uint16_t flags)
347{
348 struct ip6_tunnel_encap *ip6_encap;
349
350 ip6_encap = nh_encap_get_ip6(nh_encap);
351 if (!ip6_encap)
352 return -NLE_INVAL;
353
354 ip6_encap->flags = flags;
355 return 0;
356}
357
358int rtnl_nh_get_encap_ip6_flags(struct rtnl_nh_encap *nh_encap)
359{
360 struct ip6_tunnel_encap *ip6_encap;
361
362 ip6_encap = nh_encap_get_ip6(nh_encap);
363 if (!ip6_encap)
364 return -NLE_INVAL;
365
366 return ip6_encap->flags;
367}
368
369int rtnl_nh_set_encap_ip6_id(struct rtnl_nh_encap *nh_encap, uint64_t id)
370{
371 struct ip6_tunnel_encap *ip6_encap;
372
373 ip6_encap = nh_encap_get_ip6(nh_encap);
374 if (!ip6_encap)
375 return -NLE_INVAL;
376
377 ip6_encap->id = id;
378
379 return 0;
380}
381
382uint64_t rtnl_nh_get_encap_ip6_id(struct rtnl_nh_encap *nh_encap)
383{
384 struct ip6_tunnel_encap *ip6_encap;
385
386 ip6_encap = nh_encap_get_ip6(nh_encap);
387 if (!ip6_encap)
388 return 0;
389
390 return ip6_encap->id;
391}
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition addr.c:525
struct nl_addr * nl_addr_alloc_attr(const struct nlattr *nla, int family)
Allocate abstract address based on Netlink attribute.
Definition addr.c:261
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition addr.c:587
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition addr.c:895
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition addr.c:1001
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition addr.c:541
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition attr.c:664
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition attr.h:219
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition attr.h:201
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
Definition attr.c:769
#define NLA_PUT_ADDR(msg, attrtype, addr)
Add address attribute to netlink message.
Definition attr.h:290
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition attr.c:614
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1101
#define NLA_PUT_U64(msg, attrtype, value)
Add 64 bit integer attribute to netlink message.
Definition attr.h:255
@ NLA_U64
64 bit integer
Definition attr.h:38
@ NLA_U8
8 bit integer
Definition attr.h:35
@ NLA_U16
16 bit integer
Definition attr.h:36
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
Dumping parameters.
Definition types.h:32
Attribute validation policy.
Definition attr.h:66