libnl 3.12.0
nh_encap_ip.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 uint16_t flags;
20 uint8_t tos;
21 uint8_t ttl;
22};
23
24static void ip_encap_dump(void *priv, struct nl_dump_params *dp)
25{
26 struct ip_tunnel_encap *encap_info = priv;
27 char buf[256];
28
29 nl_dump(dp, "%s ", nl_addr2str(encap_info->dst, buf, sizeof(buf)));
30
31 if (encap_info->src)
32 nl_dump(dp, "src %s ",
33 nl_addr2str(encap_info->src, buf, sizeof(buf)));
34
35 if (encap_info->id)
36 nl_dump(dp, "id %llu ", (unsigned long long)encap_info->id);
37
38 if (encap_info->ttl)
39 nl_dump(dp, "ttl %u ", encap_info->ttl);
40
41 if (encap_info->tos)
42 nl_dump(dp, "tos %u ", encap_info->tos);
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 ip_encap_build_msg(struct nl_msg *msg, void *priv)
55{
56 struct ip_tunnel_encap *encap_info = priv;
57
58 NLA_PUT_ADDR(msg, LWTUNNEL_IP_DST, encap_info->dst);
59 if (encap_info->src)
60 NLA_PUT_ADDR(msg, LWTUNNEL_IP_SRC, encap_info->src);
61 if (encap_info->id)
62 NLA_PUT_U64(msg, LWTUNNEL_IP_ID, htonll(encap_info->id));
63 if (encap_info->ttl)
64 NLA_PUT_U8(msg, LWTUNNEL_IP_TTL, encap_info->ttl);
65 if (encap_info->tos)
66 NLA_PUT_U8(msg, LWTUNNEL_IP_TOS, encap_info->tos);
67 if (encap_info->flags)
68 NLA_PUT_U16(msg, LWTUNNEL_IP_FLAGS, encap_info->flags);
69
70 return 0;
71
72nla_put_failure:
73 return -NLE_MSGSIZE;
74}
75
76static void ip_encap_destructor(void *priv)
77{
78 struct ip_tunnel_encap *encap_info = priv;
79
80 nl_addr_put(encap_info->dst);
81 nl_addr_put(encap_info->src);
82}
83
84static void *ip_encap_clone(void *priv)
85{
86 struct ip_tunnel_encap *src = priv;
87 struct ip_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->flags = src->flags;
101 clone->tos = src->tos;
102 clone->ttl = src->ttl;
103
104 return clone;
105}
106
107static struct nla_policy ip_encap_policy[LWTUNNEL_IP_MAX + 1] = {
108 [LWTUNNEL_IP_DST] = { .type = NLA_BINARY, .minlen = 4, .maxlen = 4 },
109 [LWTUNNEL_IP_SRC] = { .type = NLA_BINARY, .minlen = 4, .maxlen = 4 },
110 [LWTUNNEL_IP_ID] = { .type = NLA_U64 },
111 [LWTUNNEL_IP_TTL] = { .type = NLA_U8 },
112 [LWTUNNEL_IP_TOS] = { .type = NLA_U8 },
113 [LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 },
114};
115
116static int ip_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_IP_MAX + 1];
123 uint16_t flags = 0;
124 uint64_t id = 0;
125 uint8_t ttl = 0;
126 uint8_t tos = 0;
127 int err;
128
129 err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, nla, ip_encap_policy);
130 if (err < 0)
131 return err;
132
133 if (!tb[LWTUNNEL_IP_DST])
134 return -NLE_INVAL;
135
136 dst = nl_addr_alloc_attr(tb[LWTUNNEL_IP_DST], AF_INET);
137 if (!dst)
138 return -NLE_NOMEM;
139
140 if (tb[LWTUNNEL_IP_SRC]) {
141 src = nl_addr_alloc_attr(tb[LWTUNNEL_IP_SRC], AF_INET);
142 if (!src)
143 return -NLE_NOMEM;
144 }
145
146 if (tb[LWTUNNEL_IP_ID])
147 id = ntohll(nla_get_u64(tb[LWTUNNEL_IP_ID]));
148 if (tb[LWTUNNEL_IP_TTL])
149 ttl = nla_get_u8(tb[LWTUNNEL_IP_TTL]);
150 if (tb[LWTUNNEL_IP_TOS])
151 tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
152 if (tb[LWTUNNEL_IP_FLAGS])
153 flags = nla_get_u16(tb[LWTUNNEL_IP_FLAGS]);
154
155 nh_encap = rtnl_nh_encap_alloc();
156 if (!nh_encap)
157 return -NLE_NOMEM;
158
159 err = rtnl_nh_encap_ip(nh_encap, dst);
160 if (err < 0)
161 return err;
162
163 if (src) {
164 err = rtnl_nh_set_encap_ip_src(nh_encap, src);
165 if (err < 0)
166 return err;
167 }
168
169 if (id) {
170 err = rtnl_nh_set_encap_ip_id(nh_encap, id);
171 if (err < 0)
172 return err;
173 }
174
175 if (ttl) {
176 err = rtnl_nh_set_encap_ip_ttl(nh_encap, ttl);
177 if (err < 0)
178 return err;
179 }
180
181 if (tos) {
182 err = rtnl_nh_set_encap_ip_tos(nh_encap, tos);
183 if (err < 0)
184 return err;
185 }
186
187 if (tb[LWTUNNEL_IP_FLAGS]) {
188 err = rtnl_nh_set_encap_ip_flags(nh_encap, flags);
189 if (err < 0)
190 return err;
191 }
192
193 *encap_out = _nl_steal_pointer(&nh_encap);
194
195 return 0;
196}
197
198static int ip_encap_compare(void *_a, void *_b)
199{
200 struct ip_tunnel_encap *a = _a;
201 struct ip_tunnel_encap *b = _b;
202 int diff = 0;
203
204 diff |= (a->id != b->id);
205 diff |= (a->flags != b->flags);
206 diff |= (a->tos != b->tos);
207 diff |= (a->ttl != b->ttl);
208 diff |= nl_addr_cmp(a->src, b->src);
209 diff |= nl_addr_cmp(a->dst, b->dst);
210
211 return diff;
212}
213
214const struct nh_encap_ops ip_encap_ops = {
215 .encap_type = LWTUNNEL_ENCAP_IP,
216 .build_msg = ip_encap_build_msg,
217 .parse_msg = ip_encap_parse_msg,
218 .compare = ip_encap_compare,
219 .clone = ip_encap_clone,
220 .dump = ip_encap_dump,
221 .destructor = ip_encap_destructor,
222};
223
224int rtnl_nh_encap_ip(struct rtnl_nh_encap *nh_encap, struct nl_addr *dst)
225{
226 struct ip_tunnel_encap *ip_encap;
227
228 if (!dst || !nh_encap)
229 return -NLE_INVAL;
230 if (nl_addr_get_family(dst) != AF_INET)
231 return -NLE_INVAL;
232
233 ip_encap = calloc(1, sizeof(*ip_encap));
234 if (!ip_encap)
235 return -NLE_NOMEM;
236
237 ip_encap->dst = nl_addr_get(dst);
238
239 nh_encap->priv = ip_encap;
240 nh_encap->ops = &ip_encap_ops;
241
242 return 0;
243}
244
245static struct ip_tunnel_encap *nh_encap_get_ip(struct rtnl_nh_encap *nh_encap)
246{
247 return (struct ip_tunnel_encap *)nh_encap_check_and_get_priv(
248 nh_encap, LWTUNNEL_ENCAP_IP);
249}
250
251struct nl_addr *rtnl_nh_get_encap_ip_dst(struct rtnl_nh_encap *nh_encap)
252{
253 struct ip_tunnel_encap *ip_encap;
254
255 ip_encap = nh_encap_get_ip(nh_encap);
256 if (!ip_encap)
257 return NULL;
258
259 return ip_encap->dst;
260}
261
262int rtnl_nh_set_encap_ip_src(struct rtnl_nh_encap *nh_encap,
263 struct nl_addr *src)
264{
265 struct ip_tunnel_encap *ip_encap;
266 struct nl_addr *old_src;
267
268 ip_encap = nh_encap_get_ip(nh_encap);
269 if (!ip_encap)
270 return -NLE_INVAL;
271 if (src && nl_addr_get_family(src) != AF_INET)
272 return -NLE_INVAL;
273
274 old_src = ip_encap->src;
275 if (src)
276 ip_encap->src = nl_addr_get(src);
277 else
278 ip_encap->src = NULL;
279
280 nl_addr_put(old_src);
281
282 return 0;
283}
284
285struct nl_addr *rtnl_nh_get_encap_ip_src(struct rtnl_nh_encap *nh_encap)
286{
287 struct ip_tunnel_encap *ip_encap;
288
289 ip_encap = nh_encap_get_ip(nh_encap);
290 if (!ip_encap)
291 return NULL;
292
293 return ip_encap->src;
294}
295
296int rtnl_nh_set_encap_ip_ttl(struct rtnl_nh_encap *nh_encap, uint8_t ttl)
297{
298 struct ip_tunnel_encap *ip_encap;
299
300 ip_encap = nh_encap_get_ip(nh_encap);
301 if (!ip_encap)
302 return -NLE_INVAL;
303
304 ip_encap->ttl = ttl;
305 return 0;
306}
307
308int rtnl_nh_get_encap_ip_ttl(struct rtnl_nh_encap *nh_encap)
309{
310 struct ip_tunnel_encap *ip_encap;
311
312 ip_encap = nh_encap_get_ip(nh_encap);
313 if (!ip_encap)
314 return -NLE_INVAL;
315
316 return ip_encap->ttl;
317}
318
319int rtnl_nh_set_encap_ip_tos(struct rtnl_nh_encap *nh_encap, uint8_t tos)
320{
321 struct ip_tunnel_encap *ip_encap;
322
323 ip_encap = nh_encap_get_ip(nh_encap);
324 if (!ip_encap)
325 return -NLE_INVAL;
326
327 ip_encap->tos = tos;
328 return 0;
329}
330
331int rtnl_nh_get_encap_ip_tos(struct rtnl_nh_encap *nh_encap)
332{
333 struct ip_tunnel_encap *ip_encap;
334
335 ip_encap = nh_encap_get_ip(nh_encap);
336 if (!ip_encap)
337 return -NLE_INVAL;
338
339 return ip_encap->tos;
340}
341
342int rtnl_nh_set_encap_ip_id(struct rtnl_nh_encap *nh_encap, uint64_t id)
343{
344 struct ip_tunnel_encap *ip_encap;
345
346 ip_encap = nh_encap_get_ip(nh_encap);
347 if (!ip_encap)
348 return -NLE_INVAL;
349
350 ip_encap->id = id;
351 return 0;
352}
353
354uint64_t rtnl_nh_get_encap_ip_id(struct rtnl_nh_encap *nh_encap)
355{
356 struct ip_tunnel_encap *ip_encap;
357
358 ip_encap = nh_encap_get_ip(nh_encap);
359 if (!ip_encap)
360 return 0;
361
362 return ip_encap->id;
363}
364
365int rtnl_nh_set_encap_ip_flags(struct rtnl_nh_encap *nh_encap, uint16_t flags)
366{
367 struct ip_tunnel_encap *ip_encap;
368
369 ip_encap = nh_encap_get_ip(nh_encap);
370 if (!ip_encap)
371 return -NLE_INVAL;
372
373 ip_encap->flags = flags;
374 return 0;
375}
376
377int rtnl_nh_get_encap_ip_flags(struct rtnl_nh_encap *nh_encap)
378{
379 struct ip_tunnel_encap *ip_encap;
380
381 ip_encap = nh_encap_get_ip(nh_encap);
382 if (!ip_encap)
383 return -NLE_INVAL;
384
385 return ip_encap->flags;
386}
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