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