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