libnl 3.12.0
nexthop.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
4 */
5
6/**
7 * @ingroup route_obj
8 * @defgroup nexthop Nexthop
9 * @{
10 */
11
12#include "nl-default.h"
13
14#include <netlink/netlink.h>
15#include <netlink/utils.h>
16#include <netlink/route/rtnl.h>
17#include <netlink/route/route.h>
18
19#include "nexthop-encap.h"
20#include "nl-aux-route/nl-route.h"
21#include "nl-priv-dynamic-core/nl-core.h"
22#include "nl-route.h"
23
24/** @cond SKIP */
25#define NH_ATTR_FLAGS 0x000001
26#define NH_ATTR_WEIGHT 0x000002
27#define NH_ATTR_IFINDEX 0x000004
28#define NH_ATTR_GATEWAY 0x000008
29#define NH_ATTR_REALMS 0x000010
30#define NH_ATTR_NEWDST 0x000020
31#define NH_ATTR_VIA 0x000040
32#define NH_ATTR_ENCAP 0x000080
33/** @endcond */
34
35/**
36 * @name Allocation/Freeing
37 * @{
38 */
39
40struct rtnl_nexthop *rtnl_route_nh_alloc(void)
41{
42 struct rtnl_nexthop *nh;
43
44 nh = calloc(1, sizeof(*nh));
45 if (!nh)
46 return NULL;
47
48 nl_init_list_head(&nh->rtnh_list);
49
50 return nh;
51}
52
53struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
54{
55 _nl_auto_rtnl_nexthop struct rtnl_nexthop *nh = NULL;
56
57 nh = rtnl_route_nh_alloc();
58 if (!nh)
59 return NULL;
60
61 nh->rtnh_flags = src->rtnh_flags;
62 nh->rtnh_flag_mask = src->rtnh_flag_mask;
63 nh->rtnh_weight = src->rtnh_weight;
64 nh->rtnh_ifindex = src->rtnh_ifindex;
65 nh->rtnh_realms = src->rtnh_realms;
66 nh->ce_mask = src->ce_mask;
67
68 if (src->rtnh_gateway) {
69 nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
70 if (!nh->rtnh_gateway)
71 return NULL;
72 }
73
74 if (src->rtnh_newdst) {
75 nh->rtnh_newdst = nl_addr_clone(src->rtnh_newdst);
76 if (!nh->rtnh_newdst)
77 return NULL;
78 }
79
80 if (src->rtnh_via) {
81 nh->rtnh_via = nl_addr_clone(src->rtnh_via);
82 if (!nh->rtnh_via)
83 return NULL;
84 }
85
86 /* Clone encapsulation information if present */
87 if (src->rtnh_encap) {
88 nh->rtnh_encap = rtnl_nh_encap_clone(src->rtnh_encap);
89 if (!nh->rtnh_encap)
90 return NULL;
91 }
92
93 return _nl_steal_pointer(&nh);
94}
95
96void rtnl_route_nh_free(struct rtnl_nexthop *nh)
97{
98 nl_addr_put(nh->rtnh_gateway);
99 nl_addr_put(nh->rtnh_newdst);
100 nl_addr_put(nh->rtnh_via);
101 rtnl_nh_encap_free(nh->rtnh_encap);
102 free(nh);
103}
104
105/** @} */
106
107int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
108 uint32_t attrs, int loose)
109{
110 uint32_t diff = 0;
111
112#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
113 diff |= _DIFF(NH_ATTR_IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex);
114 diff |= _DIFF(NH_ATTR_WEIGHT, a->rtnh_weight != b->rtnh_weight);
115 diff |= _DIFF(NH_ATTR_REALMS, a->rtnh_realms != b->rtnh_realms);
116 diff |= _DIFF(NH_ATTR_GATEWAY,
117 nl_addr_cmp(a->rtnh_gateway, b->rtnh_gateway));
118 diff |= _DIFF(NH_ATTR_NEWDST,
119 nl_addr_cmp(a->rtnh_newdst, b->rtnh_newdst));
120 diff |= _DIFF(NH_ATTR_VIA, nl_addr_cmp(a->rtnh_via, b->rtnh_via));
121 diff |= _DIFF(NH_ATTR_ENCAP,
122 nh_encap_compare(a->rtnh_encap, b->rtnh_encap));
123
124 if (loose)
125 diff |= _DIFF(NH_ATTR_FLAGS, (a->rtnh_flags ^ b->rtnh_flags) &
126 b->rtnh_flag_mask);
127 else
128 diff |= _DIFF(NH_ATTR_FLAGS, a->rtnh_flags != b->rtnh_flags);
129#undef _DIFF
130
131 return diff;
132}
133
134/**
135 * Check if the fixed attributes of two nexthops are identical, and may
136 * only differ in flags or weight.
137 *
138 * @arg a a nexthop
139 * @arg b another nexthop
140 *
141 * @return true if both nexthop have equal attributes, otherwise false.
142 */
143int rtnl_route_nh_identical(struct rtnl_nexthop *a, struct rtnl_nexthop *b)
144{
145 return !rtnl_route_nh_compare(a, b,
146 NH_ATTR_IFINDEX | NH_ATTR_REALMS |
147 NH_ATTR_GATEWAY | NH_ATTR_NEWDST |
148 NH_ATTR_VIA | NH_ATTR_ENCAP,
149 0);
150}
151
152static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
153{
154 struct nl_cache *link_cache;
155 char buf[128];
156
157 link_cache = nl_cache_mngt_require_safe("route/link");
158
159 if (nh->ce_mask & NH_ATTR_ENCAP)
160 nh_encap_dump(nh->rtnh_encap, dp);
161
162 if (nh->ce_mask & NH_ATTR_NEWDST)
163 nl_dump(dp, "as to %s ",
164 nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
165
166 nl_dump(dp, "via");
167
168 if (nh->ce_mask & NH_ATTR_VIA)
169 nl_dump(dp, " %s", nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
170
171 if (nh->ce_mask & NH_ATTR_GATEWAY)
172 nl_dump(dp, " %s",
173 nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf)));
174
175 if (nh->ce_mask & NH_ATTR_IFINDEX) {
176 if (link_cache) {
177 nl_dump(dp, " dev %s",
178 rtnl_link_i2name(link_cache, nh->rtnh_ifindex,
179 buf, sizeof(buf)));
180 } else
181 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
182 }
183
184 nl_dump(dp, " ");
185
186 if (link_cache)
187 nl_cache_put(link_cache);
188}
189
190static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
191{
192 struct nl_cache *link_cache;
193 char buf[128];
194
195 link_cache = nl_cache_mngt_require_safe("route/link");
196
197 nl_dump(dp, "nexthop");
198
199 if (nh->ce_mask & NH_ATTR_ENCAP)
200 nh_encap_dump(nh->rtnh_encap, dp);
201
202 if (nh->ce_mask & NH_ATTR_NEWDST)
203 nl_dump(dp, " as to %s",
204 nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
205
206 if (nh->ce_mask & NH_ATTR_VIA)
207 nl_dump(dp, " via %s",
208 nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
209
210 if (nh->ce_mask & NH_ATTR_GATEWAY)
211 nl_dump(dp, " via %s",
212 nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf)));
213
214 if (nh->ce_mask & NH_ATTR_IFINDEX) {
215 if (link_cache) {
216 nl_dump(dp, " dev %s",
217 rtnl_link_i2name(link_cache, nh->rtnh_ifindex,
218 buf, sizeof(buf)));
219 } else
220 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
221 }
222
223 if (nh->ce_mask & NH_ATTR_WEIGHT)
224 nl_dump(dp, " weight %u", nh->rtnh_weight);
225
226 if (nh->ce_mask & NH_ATTR_REALMS)
227 nl_dump(dp, " realm %04x:%04x",
228 RTNL_REALM_FROM(nh->rtnh_realms),
229 RTNL_REALM_TO(nh->rtnh_realms));
230
231 if (nh->ce_mask & NH_ATTR_FLAGS)
232 nl_dump(dp, " <%s>",
233 rtnl_route_nh_flags2str(nh->rtnh_flags, buf,
234 sizeof(buf)));
235
236 if (link_cache)
237 nl_cache_put(link_cache);
238}
239
240void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
241{
242 switch (dp->dp_type) {
243 case NL_DUMP_LINE:
244 nh_dump_line(nh, dp);
245 break;
246
247 case NL_DUMP_DETAILS:
248 case NL_DUMP_STATS:
249 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
250 nh_dump_details(nh, dp);
251 break;
252
253 default:
254 break;
255 }
256}
257
258/**
259 * @name Attributes
260 * @{
261 */
262
263void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
264{
265 nh->rtnh_weight = weight;
266 nh->ce_mask |= NH_ATTR_WEIGHT;
267}
268
269uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
270{
271 return nh->rtnh_weight;
272}
273
274void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
275{
276 nh->rtnh_ifindex = ifindex;
277 nh->ce_mask |= NH_ATTR_IFINDEX;
278}
279
280int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
281{
282 return nh->rtnh_ifindex;
283}
284
285/* FIXME: Convert to return an int */
286void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
287{
288 struct nl_addr *old = nh->rtnh_gateway;
289
290 if (addr) {
291 nh->rtnh_gateway = nl_addr_get(addr);
292 nh->ce_mask |= NH_ATTR_GATEWAY;
293 } else {
294 nh->ce_mask &= ~NH_ATTR_GATEWAY;
295 nh->rtnh_gateway = NULL;
296 }
297
298 if (old)
299 nl_addr_put(old);
300}
301
302struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
303{
304 return nh->rtnh_gateway;
305}
306
307void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
308{
309 nh->rtnh_flag_mask |= flags;
310 nh->rtnh_flags |= flags;
311 nh->ce_mask |= NH_ATTR_FLAGS;
312}
313
314void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
315{
316 nh->rtnh_flag_mask |= flags;
317 nh->rtnh_flags &= ~flags;
318 nh->ce_mask |= NH_ATTR_FLAGS;
319}
320
321unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
322{
323 return nh->rtnh_flags;
324}
325
326void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
327{
328 nh->rtnh_realms = realms;
329 nh->ce_mask |= NH_ATTR_REALMS;
330}
331
332uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
333{
334 return nh->rtnh_realms;
335}
336
337int rtnl_route_nh_set_newdst(struct rtnl_nexthop *nh, struct nl_addr *addr)
338{
339 struct nl_addr *old = nh->rtnh_newdst;
340
341 if (addr) {
342 nh->rtnh_newdst = nl_addr_get(addr);
343 nh->ce_mask |= NH_ATTR_NEWDST;
344 } else {
345 nh->ce_mask &= ~NH_ATTR_NEWDST;
346 nh->rtnh_newdst = NULL;
347 }
348
349 if (old)
350 nl_addr_put(old);
351
352 return 0;
353}
354
355struct nl_addr *rtnl_route_nh_get_newdst(struct rtnl_nexthop *nh)
356{
357 return nh->rtnh_newdst;
358}
359
360int rtnl_route_nh_set_via(struct rtnl_nexthop *nh, struct nl_addr *addr)
361{
362 struct nl_addr *old = nh->rtnh_via;
363
364 if (addr) {
365 nh->rtnh_via = nl_addr_get(addr);
366 nh->ce_mask |= NH_ATTR_VIA;
367 } else {
368 nh->ce_mask &= ~NH_ATTR_VIA;
369 nh->rtnh_via = NULL;
370 }
371
372 if (old)
373 nl_addr_put(old);
374
375 return 0;
376}
377
378struct nl_addr *rtnl_route_nh_get_via(struct rtnl_nexthop *nh)
379{
380 return nh->rtnh_via;
381}
382
383/**
384 * Set nexthop encapsulation
385 * @arg nh Route nexthop object
386 * @arg nh_encap Encapsulation descriptor
387 *
388 * Assigns ownership of the encapsulation object to the route's nexthop.
389 * Any previously configured encapsulation is released. Passing a NULL
390 * encapsulation clears the encapsulation on the nexthop.
391 *
392 * On failure, the function consumes and frees \p nh_encap.
393 *
394 * @return 0 on success, or the appropriate error-code on failure.
395 */
396int rtnl_route_nh_set_encap(struct rtnl_nexthop *nh,
397 struct rtnl_nh_encap *nh_encap)
398{
399 if (!nh) {
400 rtnl_nh_encap_free(nh_encap);
401 return -NLE_INVAL;
402 }
403
404 if (nh_encap && !nh_encap->ops) {
405 rtnl_nh_encap_free(nh_encap);
406 return -NLE_INVAL;
407 }
408
409 rtnl_nh_encap_free(nh->rtnh_encap);
410
411 if (nh_encap) {
412 nh->rtnh_encap = nh_encap;
413 nh->ce_mask |= NH_ATTR_ENCAP;
414 } else {
415 nh->rtnh_encap = NULL;
416 nh->ce_mask &= ~NH_ATTR_ENCAP;
417 }
418
419 return 0;
420}
421
422/** @} */
423
424/**
425 * @name Nexthop Flags Translations
426 * @{
427 */
428
429static const struct trans_tbl nh_flags[] = {
430 __ADD(RTNH_F_DEAD, dead),
431 __ADD(RTNH_F_PERVASIVE, pervasive),
432 __ADD(RTNH_F_ONLINK, onlink),
433};
434
435char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
436{
437 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
438}
439
440int rtnl_route_nh_str2flags(const char *name)
441{
442 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
443}
444
445/** @} */
446
447/** @} */
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition addr.c:525
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition addr.c:587
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition addr.c:495
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
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition cache_mngt.c:430
int rtnl_route_nh_identical(struct rtnl_nexthop *a, struct rtnl_nexthop *b)
Check if the fixed attributes of two nexthops are identical, and may only differ in flags or weight.
Definition nexthop.c:143
int rtnl_route_nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *nh_encap)
Set nexthop encapsulation.
Definition nexthop.c:396
#define RTNL_REALM_TO(realm)
Extract TO realm from a realms field.
Definition rtnl.h:34
#define RTNL_REALM_FROM(realm)
Extract FROM realm from a realms field.
Definition rtnl.h:29
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition types.h:22
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
Dumping parameters.
Definition types.h:32
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
Definition types.h:36
int dp_ivar
PRIVATE Owned by the current caller.
Definition types.h:103