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