libnl  1.1.4
route.c
1 /*
2  * lib/route/route.c Routes
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-2006 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup rtnl
14  * @defgroup route Routing
15  * @brief
16  * @{
17  */
18 
19 #include <netlink-local.h>
20 #include <netlink/netlink.h>
21 #include <netlink/cache.h>
22 #include <netlink/utils.h>
23 #include <netlink/data.h>
24 #include <netlink/route/rtnl.h>
25 #include <netlink/route/route.h>
26 #include <netlink/route/link.h>
27 
28 static struct nl_cache_ops rtnl_route_ops;
29 
30 static struct nla_policy route_policy[RTA_MAX+1] = {
31  [RTA_IIF] = { .type = NLA_STRING,
32  .maxlen = IFNAMSIZ, },
33  [RTA_OIF] = { .type = NLA_U32 },
34  [RTA_PRIORITY] = { .type = NLA_U32 },
35  [RTA_FLOW] = { .type = NLA_U32 },
36  [RTA_MP_ALGO] = { .type = NLA_U32 },
37  [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
38  [RTA_METRICS] = { .type = NLA_NESTED },
39  [RTA_MULTIPATH] = { .type = NLA_NESTED },
40 };
41 
42 static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
43  struct rtnl_route *route)
44 {
45  struct rtnl_rtcacheinfo nci = {
46  .rtci_clntref = ci->rta_clntref,
47  .rtci_last_use = ci->rta_lastuse,
48  .rtci_expires = ci->rta_expires,
49  .rtci_error = ci->rta_error,
50  .rtci_used = ci->rta_used,
51  .rtci_id = ci->rta_id,
52  .rtci_ts = ci->rta_ts,
53  .rtci_tsage = ci->rta_tsage,
54  };
55 
56  rtnl_route_set_cacheinfo(route, &nci);
57 }
58 
59 static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
60  struct nlmsghdr *nlh, struct nl_parser_param *pp)
61 {
62  struct rtmsg *rtm;
63  struct rtnl_route *route;
64  struct nlattr *tb[RTA_MAX + 1];
65  struct nl_addr *src = NULL, *dst = NULL, *addr;
66  int err;
67 
68  route = rtnl_route_alloc();
69  if (!route) {
70  err = nl_errno(ENOMEM);
71  goto errout;
72  }
73 
74  route->ce_msgtype = nlh->nlmsg_type;
75 
76  err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
77  route_policy);
78  if (err < 0)
79  goto errout;
80 
81  rtm = nlmsg_data(nlh);
82  rtnl_route_set_family(route, rtm->rtm_family);
83  rtnl_route_set_tos(route, rtm->rtm_tos);
84  rtnl_route_set_table(route, rtm->rtm_table);
85  rtnl_route_set_type(route, rtm->rtm_type);
86  rtnl_route_set_scope(route, rtm->rtm_scope);
87  rtnl_route_set_protocol(route, rtm->rtm_protocol);
88  rtnl_route_set_flags(route, rtm->rtm_flags);
89 
90  if (tb[RTA_DST]) {
91  dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family);
92  if (dst == NULL)
93  goto errout_errno;
94  } else {
95  dst = nl_addr_alloc(0);
96  nl_addr_set_family(dst, rtm->rtm_family);
97  }
98 
99  nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
100  err = rtnl_route_set_dst(route, dst);
101  if (err < 0)
102  goto errout;
103 
104  nl_addr_put(dst);
105 
106  if (tb[RTA_SRC]) {
107  src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family);
108  if (src == NULL)
109  goto errout_errno;
110  } else if (rtm->rtm_src_len)
111  src = nl_addr_alloc(0);
112 
113  if (src) {
114  nl_addr_set_prefixlen(src, rtm->rtm_src_len);
115  rtnl_route_set_src(route, src);
116  nl_addr_put(src);
117  }
118 
119  if (tb[RTA_IIF])
120  rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF]));
121 
122  if (tb[RTA_OIF])
123  rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF]));
124 
125  if (tb[RTA_GATEWAY]) {
126  addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family);
127  if (addr == NULL)
128  goto errout_errno;
129  rtnl_route_set_gateway(route, addr);
130  nl_addr_put(addr);
131  }
132 
133  if (tb[RTA_PRIORITY])
134  rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY]));
135 
136  if (tb[RTA_PREFSRC]) {
137  addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family);
138  if (addr == NULL)
139  goto errout_errno;
140  rtnl_route_set_pref_src(route, addr);
141  nl_addr_put(addr);
142  }
143 
144  if (tb[RTA_METRICS]) {
145  struct nlattr *mtb[RTAX_MAX + 1];
146  int i;
147 
148  err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
149  if (err < 0)
150  goto errout;
151 
152  for (i = 1; i <= RTAX_MAX; i++) {
153  if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
154  uint32_t m = nla_get_u32(mtb[i]);
155  if (rtnl_route_set_metric(route, i, m) < 0)
156  goto errout_errno;
157  }
158  }
159  }
160 
161  if (tb[RTA_MULTIPATH]) {
162  struct rtnl_nexthop *nh;
163  struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
164  size_t tlen = nla_len(tb[RTA_MULTIPATH]);
165 
166  while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
167  nh = rtnl_route_nh_alloc();
168  if (!nh)
169  goto errout;
170 
171  rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
172  rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
173  rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
174 
175  if (rtnh->rtnh_len > sizeof(*rtnh)) {
176  struct nlattr *ntb[RTA_MAX + 1];
177  nla_parse(ntb, RTA_MAX, (struct nlattr *)
178  RTNH_DATA(rtnh),
179  rtnh->rtnh_len - sizeof(*rtnh),
180  route_policy);
181 
182  if (ntb[RTA_GATEWAY]) {
183  nh->rtnh_gateway = nla_get_addr(
184  ntb[RTA_GATEWAY],
185  route->rt_family);
186  nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
187  }
188  }
189 
190  rtnl_route_add_nexthop(route, nh);
191  tlen -= RTNH_ALIGN(rtnh->rtnh_len);
192  rtnh = RTNH_NEXT(rtnh);
193  }
194  }
195 
196  if (tb[RTA_FLOW])
197  rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW]));
198 
199  if (tb[RTA_CACHEINFO])
200  copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);
201 
202  if (tb[RTA_MP_ALGO])
203  rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO]));
204 
205  err = pp->pp_cb((struct nl_object *) route, pp);
206  if (err < 0)
207  goto errout;
208 
209  err = P_ACCEPT;
210 
211 errout:
212  rtnl_route_put(route);
213  return err;
214 
215 errout_errno:
216  err = nl_get_errno();
217  goto errout;
218 }
219 
220 static int route_request_update(struct nl_cache *c, struct nl_handle *h)
221 {
222  return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
223 }
224 
225 /**
226  * @name Cache Management
227  * @{
228  */
229 
230 /**
231  * Build a route cache holding all routes currently configured in the kernel
232  * @arg handle netlink handle
233  *
234  * Allocates a new cache, initializes it properly and updates it to
235  * contain all routes currently configured in the kernel.
236  *
237  * @note The caller is responsible for destroying and freeing the
238  * cache after using it.
239  * @return The cache or NULL if an error has occured.
240  */
241 struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
242 {
243  struct nl_cache *cache;
244 
245  cache = nl_cache_alloc(&rtnl_route_ops);
246  if (!cache)
247  return NULL;
248 
249  if (handle && nl_cache_refill(handle, cache) < 0) {
250  free(cache);
251  return NULL;
252  }
253 
254  return cache;
255 }
256 
257 /** @} */
258 
259 /**
260  * @name Route Addition
261  * @{
262  */
263 
264 static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
265  int flags)
266 {
267  struct nl_msg *msg;
268  struct nl_addr *addr;
269  int scope, i, oif, nmetrics = 0;
270  struct nlattr *metrics;
271  struct rtmsg rtmsg = {
272  .rtm_family = rtnl_route_get_family(tmpl),
273  .rtm_dst_len = rtnl_route_get_dst_len(tmpl),
274  .rtm_src_len = rtnl_route_get_src_len(tmpl),
275  .rtm_tos = rtnl_route_get_tos(tmpl),
276  .rtm_table = rtnl_route_get_table(tmpl),
277  .rtm_type = rtnl_route_get_type(tmpl),
278  .rtm_protocol = rtnl_route_get_protocol(tmpl),
279  .rtm_flags = rtnl_route_get_flags(tmpl),
280  };
281 
282  if (rtmsg.rtm_family == AF_UNSPEC) {
283  nl_error(EINVAL, "Cannot build route message, address " \
284  "family is unknown.");
285  return NULL;
286  }
287 
288  scope = rtnl_route_get_scope(tmpl);
289  if (scope == RT_SCOPE_NOWHERE) {
290  if (rtmsg.rtm_type == RTN_LOCAL)
291  scope = RT_SCOPE_HOST;
292  else {
293  /* XXX Change to UNIVERSE if gw || nexthops */
294  scope = RT_SCOPE_LINK;
295  }
296  }
297 
298  rtmsg.rtm_scope = scope;
299 
300  msg = nlmsg_alloc_simple(cmd, flags);
301  if (msg == NULL)
302  return NULL;
303 
304  if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
305  goto nla_put_failure;
306 
307  addr = rtnl_route_get_dst(tmpl);
308  if (addr)
309  NLA_PUT_ADDR(msg, RTA_DST, addr);
310 
311  addr = rtnl_route_get_src(tmpl);
312  if (addr)
313  NLA_PUT_ADDR(msg, RTA_SRC, addr);
314 
315  addr = rtnl_route_get_gateway(tmpl);
316  if (addr)
317  NLA_PUT_ADDR(msg, RTA_GATEWAY, addr);
318 
319  addr = rtnl_route_get_pref_src(tmpl);
320  if (addr)
321  NLA_PUT_ADDR(msg, RTA_PREFSRC, addr);
322 
323  NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl));
324 
325  oif = rtnl_route_get_oif(tmpl);
326  if (oif != RTNL_LINK_NOT_FOUND)
327  NLA_PUT_U32(msg, RTA_OIF, oif);
328 
329  for (i = 1; i <= RTAX_MAX; i++)
330  if (rtnl_route_get_metric(tmpl, i) != UINT_MAX)
331  nmetrics++;
332 
333  if (nmetrics > 0) {
334  unsigned int val;
335 
336  metrics = nla_nest_start(msg, RTA_METRICS);
337  if (metrics == NULL)
338  goto nla_put_failure;
339 
340  for (i = 1; i <= RTAX_MAX; i++) {
341  val = rtnl_route_get_metric(tmpl, i);
342  if (val != UINT_MAX)
343  NLA_PUT_U32(msg, i, val);
344  }
345 
346  nla_nest_end(msg, metrics);
347  }
348 
349 #if 0
350  RTA_IIF,
351  RTA_MULTIPATH,
352  RTA_PROTOINFO,
353  RTA_FLOW,
354  RTA_CACHEINFO,
355  RTA_SESSION,
356  RTA_MP_ALGO,
357 #endif
358 
359  return msg;
360 
361 nla_put_failure:
362  nlmsg_free(msg);
363  return NULL;
364 }
365 
366 struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
367 {
368  return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
369 }
370 
371 int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
372  int flags)
373 {
374  struct nl_msg *msg;
375  int err;
376 
377  msg = rtnl_route_build_add_request(route, flags);
378  if (!msg)
379  return nl_get_errno();
380 
381  err = nl_send_auto_complete(handle, msg);
382  nlmsg_free(msg);
383  if (err < 0)
384  return err;
385 
386  return nl_wait_for_ack(handle);
387 }
388 
389 struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
390 {
391  return build_route_msg(tmpl, RTM_DELROUTE, flags);
392 }
393 
394 int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
395  int flags)
396 {
397  struct nl_msg *msg;
398  int err;
399 
400  msg = rtnl_route_build_del_request(route, flags);
401  if (!msg)
402  return nl_get_errno();
403 
404  err = nl_send_auto_complete(handle, msg);
405  nlmsg_free(msg);
406  if (err < 0)
407  return err;
408 
409  return nl_wait_for_ack(handle);
410 }
411 
412 /** @} */
413 
414 static struct nl_af_group route_groups[] = {
415  { AF_INET, RTNLGRP_IPV4_ROUTE },
416  { AF_INET6, RTNLGRP_IPV6_ROUTE },
417  { AF_DECnet, RTNLGRP_DECnet_ROUTE },
418  { END_OF_GROUP_LIST },
419 };
420 
421 static struct nl_cache_ops rtnl_route_ops = {
422  .co_name = "route/route",
423  .co_hdrsize = sizeof(struct rtmsg),
424  .co_msgtypes = {
425  { RTM_NEWROUTE, NL_ACT_NEW, "new" },
426  { RTM_DELROUTE, NL_ACT_DEL, "del" },
427  { RTM_GETROUTE, NL_ACT_GET, "get" },
428  END_OF_MSGTYPES_LIST,
429  },
430  .co_protocol = NETLINK_ROUTE,
431  .co_groups = route_groups,
432  .co_request_update = route_request_update,
433  .co_msg_parser = route_msg_parser,
434  .co_obj_ops = &route_obj_ops,
435 };
436 
437 static void __init route_init(void)
438 {
439  nl_cache_mngt_register(&rtnl_route_ops);
440 }
441 
442 static void __exit route_exit(void)
443 {
444  nl_cache_mngt_unregister(&rtnl_route_ops);
445 }
446 
447 /** @} */
32bit integer
Definition: attr.h:39
struct nl_addr * nl_addr_alloc(size_t maxsize)
Allocate new abstract address object.
Definition: addr.c:164
struct nl_cache * rtnl_route_alloc_cache(struct nl_handle *handle)
Build a route cache holding all routes currently configured in the kernel.
Definition: route.c:241
void * nlmsg_data(const struct nlmsghdr *nlh)
head of message payload
Definition: msg.c:218
uint16_t nlmsg_type
Message type (content type)
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:261
attribute validation policy
Definition: attr.h:73
int nl_wait_for_ack(struct nl_handle *handle)
Wait for ACK.
Definition: nl.c:801
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
Definition: msg.c:656
Netlink message header.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:319
int nla_nest_end(struct nl_msg *n, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:675
nested attributes
Definition: attr.h:44
character string
Definition: attr.h:41
int nl_send_auto_complete(struct nl_handle *handle, struct nl_msg *msg)
Send netlink message and check & extend header values as needed.
Definition: nl.c:373
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:226
int nl_cache_refill(struct nl_handle *handle, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition: cache.c:680
#define NLM_F_CREATE
Create config object if it doesn't already exist.
#define NLM_F_DUMP
Dump all entries.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
parse nested attributes
Definition: attr.c:307
Cache Operations.
Definition: cache-api.h:163
void * nla_data(const struct nlattr *nla)
head of payload
Definition: attr.c:151
int nl_rtgen_request(struct nl_handle *handle, int type, int family, int flags)
Send routing netlink request message.
Definition: rtnl.c:40
int nla_len(const struct nlattr *nla)
length of payload
Definition: attr.c:160
struct nl_addr * nla_get_addr(struct nlattr *nla, int family)
Return payload of address attribute.
Definition: attr.c:765
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, struct nla_policy *policy)
Parse a stream of attributes into a tb buffer.
Definition: attr.c:262
#define NLA_PUT_ADDR(n, attrtype, addr)
Add a address attribute to a netlink message.
Definition: attr.h:245
Netlink socket address.
Definition: netlink-kernel.h:8
char * nla_get_string(struct nlattr *nla)
return payload of string attribute
Definition: attr.c:733
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:549
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:75
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:448
struct nlattr * nla_nest_start(struct nl_msg *n, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:655
uint32_t nla_get_u32(struct nlattr *nla)
Return payload of u32 attribute.
Definition: attr.c:693
Address family to netlink group association.
Definition: cache-api.h:143
#define NLA_PUT_U32(n, attrtype, value)
Add a u32 netlink attribute to a netlink message.
Definition: attr.h:201
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate an empty cache.
Definition: cache.c:170