libnl 3.9.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-route.h"
21#include "nl-priv-dynamic-core/nl-core.h"
22
23/** @cond SKIP */
24#define NH_ATTR_FLAGS 0x000001
25#define NH_ATTR_WEIGHT 0x000002
26#define NH_ATTR_IFINDEX 0x000004
27#define NH_ATTR_GATEWAY 0x000008
28#define NH_ATTR_REALMS 0x000010
29#define NH_ATTR_NEWDST 0x000020
30#define NH_ATTR_VIA 0x000040
31#define NH_ATTR_ENCAP 0x000080
32/** @endcond */
33
34/**
35 * @name Allocation/Freeing
36 * @{
37 */
38
39struct rtnl_nexthop *rtnl_route_nh_alloc(void)
40{
41 struct rtnl_nexthop *nh;
42
43 nh = calloc(1, sizeof(*nh));
44 if (!nh)
45 return NULL;
46
47 nl_init_list_head(&nh->rtnh_list);
48
49 return nh;
50}
51
52struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
53{
54 struct rtnl_nexthop *nh;
55
56 nh = rtnl_route_nh_alloc();
57 if (!nh)
58 return NULL;
59
60 nh->rtnh_flags = src->rtnh_flags;
61 nh->rtnh_flag_mask = src->rtnh_flag_mask;
62 nh->rtnh_weight = src->rtnh_weight;
63 nh->rtnh_ifindex = src->rtnh_ifindex;
64 nh->ce_mask = src->ce_mask;
65
66 if (src->rtnh_gateway) {
67 nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
68 if (!nh->rtnh_gateway) {
69 free(nh);
70 return NULL;
71 }
72 }
73
74 if (src->rtnh_newdst) {
75 nh->rtnh_newdst = nl_addr_clone(src->rtnh_newdst);
76 if (!nh->rtnh_newdst) {
77 nl_addr_put(nh->rtnh_gateway);
78 free(nh);
79 return NULL;
80 }
81 }
82
83 if (src->rtnh_via) {
84 nh->rtnh_via = nl_addr_clone(src->rtnh_via);
85 if (!nh->rtnh_via) {
86 nl_addr_put(nh->rtnh_gateway);
87 nl_addr_put(nh->rtnh_newdst);
88 free(nh);
89 return NULL;
90 }
91 }
92
93 return 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 if (nh->rtnh_encap) {
102 if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
103 nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
104 free(nh->rtnh_encap->priv);
105 free(nh->rtnh_encap);
106 }
107 free(nh);
108}
109
110/** @} */
111
112int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
113 uint32_t attrs, int loose)
114{
115 uint32_t diff = 0;
116
117#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
118 diff |= _DIFF(NH_ATTR_IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex);
119 diff |= _DIFF(NH_ATTR_WEIGHT, a->rtnh_weight != b->rtnh_weight);
120 diff |= _DIFF(NH_ATTR_REALMS, a->rtnh_realms != b->rtnh_realms);
121 diff |= _DIFF(NH_ATTR_GATEWAY,
122 nl_addr_cmp(a->rtnh_gateway, b->rtnh_gateway));
123 diff |= _DIFF(NH_ATTR_NEWDST,
124 nl_addr_cmp(a->rtnh_newdst, b->rtnh_newdst));
125 diff |= _DIFF(NH_ATTR_VIA, nl_addr_cmp(a->rtnh_via, b->rtnh_via));
126 diff |= _DIFF(NH_ATTR_ENCAP,
127 nh_encap_compare(a->rtnh_encap, b->rtnh_encap));
128
129 if (loose)
130 diff |= _DIFF(NH_ATTR_FLAGS, (a->rtnh_flags ^ b->rtnh_flags) &
131 b->rtnh_flag_mask);
132 else
133 diff |= _DIFF(NH_ATTR_FLAGS, a->rtnh_flags != b->rtnh_flags);
134#undef _DIFF
135
136 return diff;
137}
138
139static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
140{
141 struct nl_cache *link_cache;
142 char buf[128];
143
144 link_cache = nl_cache_mngt_require_safe("route/link");
145
146 if (nh->ce_mask & NH_ATTR_ENCAP)
147 nh_encap_dump(nh->rtnh_encap, dp);
148
149 if (nh->ce_mask & NH_ATTR_NEWDST)
150 nl_dump(dp, "as to %s ",
151 nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
152
153 nl_dump(dp, "via");
154
155 if (nh->ce_mask & NH_ATTR_VIA)
156 nl_dump(dp, " %s",
157 nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
158
159 if (nh->ce_mask & NH_ATTR_GATEWAY)
160 nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
161 buf, sizeof(buf)));
162
163 if(nh->ce_mask & NH_ATTR_IFINDEX) {
164 if (link_cache) {
165 nl_dump(dp, " dev %s",
166 rtnl_link_i2name(link_cache,
167 nh->rtnh_ifindex,
168 buf, sizeof(buf)));
169 } else
170 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
171 }
172
173 nl_dump(dp, " ");
174
175 if (link_cache)
176 nl_cache_put(link_cache);
177}
178
179static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
180{
181 struct nl_cache *link_cache;
182 char buf[128];
183
184 link_cache = nl_cache_mngt_require_safe("route/link");
185
186 nl_dump(dp, "nexthop");
187
188 if (nh->ce_mask & NH_ATTR_ENCAP)
189 nh_encap_dump(nh->rtnh_encap, dp);
190
191 if (nh->ce_mask & NH_ATTR_NEWDST)
192 nl_dump(dp, " as to %s",
193 nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
194
195 if (nh->ce_mask & NH_ATTR_VIA)
196 nl_dump(dp, " via %s",
197 nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
198
199 if (nh->ce_mask & NH_ATTR_GATEWAY)
200 nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
201 buf, sizeof(buf)));
202
203 if(nh->ce_mask & NH_ATTR_IFINDEX) {
204 if (link_cache) {
205 nl_dump(dp, " dev %s",
206 rtnl_link_i2name(link_cache,
207 nh->rtnh_ifindex,
208 buf, sizeof(buf)));
209 } else
210 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
211 }
212
213 if (nh->ce_mask & NH_ATTR_WEIGHT)
214 nl_dump(dp, " weight %u", nh->rtnh_weight);
215
216 if (nh->ce_mask & NH_ATTR_REALMS)
217 nl_dump(dp, " realm %04x:%04x",
218 RTNL_REALM_FROM(nh->rtnh_realms),
219 RTNL_REALM_TO(nh->rtnh_realms));
220
221 if (nh->ce_mask & NH_ATTR_FLAGS)
222 nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
223 buf, sizeof(buf)));
224
225 if (link_cache)
226 nl_cache_put(link_cache);
227}
228
229void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
230{
231 switch (dp->dp_type) {
232 case NL_DUMP_LINE:
233 nh_dump_line(nh, dp);
234 break;
235
236 case NL_DUMP_DETAILS:
237 case NL_DUMP_STATS:
238 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
239 nh_dump_details(nh, dp);
240 break;
241
242 default:
243 break;
244 }
245}
246
247void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap)
248{
249 if (nh->rtnh_encap) {
250 if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
251 nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
252 free(nh->rtnh_encap->priv);
253 free(nh->rtnh_encap);
254 }
255
256 if (rtnh_encap) {
257 nh->rtnh_encap = rtnh_encap;
258 nh->ce_mask |= NH_ATTR_ENCAP;
259 } else {
260 nh->rtnh_encap = NULL;
261 nh->ce_mask &= ~NH_ATTR_ENCAP;
262 }
263}
264
265/**
266 * @name Attributes
267 * @{
268 */
269
270void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
271{
272 nh->rtnh_weight = weight;
273 nh->ce_mask |= NH_ATTR_WEIGHT;
274}
275
276uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
277{
278 return nh->rtnh_weight;
279}
280
281void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
282{
283 nh->rtnh_ifindex = ifindex;
284 nh->ce_mask |= NH_ATTR_IFINDEX;
285}
286
287int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
288{
289 return nh->rtnh_ifindex;
290}
291
292/* FIXME: Convert to return an int */
293void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
294{
295 struct nl_addr *old = nh->rtnh_gateway;
296
297 if (addr) {
298 nh->rtnh_gateway = nl_addr_get(addr);
299 nh->ce_mask |= NH_ATTR_GATEWAY;
300 } else {
301 nh->ce_mask &= ~NH_ATTR_GATEWAY;
302 nh->rtnh_gateway = NULL;
303 }
304
305 if (old)
306 nl_addr_put(old);
307}
308
309struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
310{
311 return nh->rtnh_gateway;
312}
313
314void rtnl_route_nh_set_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
321void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
322{
323 nh->rtnh_flag_mask |= flags;
324 nh->rtnh_flags &= ~flags;
325 nh->ce_mask |= NH_ATTR_FLAGS;
326}
327
328unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
329{
330 return nh->rtnh_flags;
331}
332
333void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
334{
335 nh->rtnh_realms = realms;
336 nh->ce_mask |= NH_ATTR_REALMS;
337}
338
339uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
340{
341 return nh->rtnh_realms;
342}
343
344int rtnl_route_nh_set_newdst(struct rtnl_nexthop *nh, struct nl_addr *addr)
345{
346 struct nl_addr *old = nh->rtnh_newdst;
347
348 if (addr) {
349 nh->rtnh_newdst = nl_addr_get(addr);
350 nh->ce_mask |= NH_ATTR_NEWDST;
351 } else {
352 nh->ce_mask &= ~NH_ATTR_NEWDST;
353 nh->rtnh_newdst = NULL;
354 }
355
356 if (old)
357 nl_addr_put(old);
358
359 return 0;
360}
361
362struct nl_addr *rtnl_route_nh_get_newdst(struct rtnl_nexthop *nh)
363{
364 return nh->rtnh_newdst;
365}
366
367int rtnl_route_nh_set_via(struct rtnl_nexthop *nh, struct nl_addr *addr)
368{
369 struct nl_addr *old = nh->rtnh_via;
370
371 if (addr) {
372 nh->rtnh_via = nl_addr_get(addr);
373 nh->ce_mask |= NH_ATTR_VIA;
374 } else {
375 nh->ce_mask &= ~NH_ATTR_VIA;
376 nh->rtnh_via= NULL;
377 }
378
379 if (old)
380 nl_addr_put(old);
381
382 return 0;
383}
384
385struct nl_addr *rtnl_route_nh_get_via(struct rtnl_nexthop *nh)
386{
387 return nh->rtnh_via;
388}
389
390/** @} */
391
392/**
393 * @name Nexthop Flags Translations
394 * @{
395 */
396
397static const struct trans_tbl nh_flags[] = {
398 __ADD(RTNH_F_DEAD, dead),
399 __ADD(RTNH_F_PERVASIVE, pervasive),
400 __ADD(RTNH_F_ONLINK, onlink),
401};
402
403char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
404{
405 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
406}
407
408int rtnl_route_nh_str2flags(const char *name)
409{
410 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
411}
412
413/** @} */
414
415/** @} */
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
#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:1017
@ 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