libnl  3.6.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 
35 struct 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 
48 struct 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 
92 void 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 
108 int 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 
138 static 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 
178 static 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 
228 void 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 
246 void 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 
269 void 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 
275 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
276 {
277  return nh->rtnh_weight;
278 }
279 
280 void 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 
286 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
287 {
288  return nh->rtnh_ifindex;
289 }
290 
291 /* FIXME: Convert to return an int */
292 void 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 
308 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
309 {
310  return nh->rtnh_gateway;
311 }
312 
313 void 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 
320 void 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 
327 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
328 {
329  return nh->rtnh_flags;
330 }
331 
332 void 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 
338 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
339 {
340  return nh->rtnh_realms;
341 }
342 
343 int 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 
361 struct nl_addr *rtnl_route_nh_get_newdst(struct rtnl_nexthop *nh)
362 {
363  return nh->rtnh_newdst;
364 }
365 
366 int 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 
384 struct 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 
396 static 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 
402 char *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 
407 int rtnl_route_nh_str2flags(const char *name)
408 {
409  return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
410 }
411 
412 /** @} */
413 
414 /** @} */
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:993
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition: addr.c:579
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:487
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:517
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:533
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