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
28static struct nl_cache_ops rtnl_route_ops;
29
30static 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
42static 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
59static 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
211errout:
212 rtnl_route_put(route);
213 return err;
214
215errout_errno:
216 err = nl_get_errno();
217 goto errout;
218}
219
220static 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 */
241struct 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
264static 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
361nla_put_failure:
362 nlmsg_free(msg);
363 return NULL;
364}
365
366struct 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
371int 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
389struct 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
394int 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
414static 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
421static 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
437static void __init route_init(void)
438{
439 nl_cache_mngt_register(&rtnl_route_ops);
440}
441
442static void __exit route_exit(void)
443{
444 nl_cache_mngt_unregister(&rtnl_route_ops);
445}
446
447/** @} */
struct nl_addr * nl_addr_alloc(size_t maxsize)
Allocate new abstract address object.
Definition: addr.c:164
int nla_nest_end(struct nl_msg *n, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:675
#define NLA_PUT_ADDR(n, attrtype, addr)
Add a address attribute to a netlink message.
Definition: attr.h:245
struct nl_addr * nla_get_addr(struct nlattr *nla, int family)
Return payload of address attribute.
Definition: attr.c:765
void * nla_data(const struct nlattr *nla)
head of payload
Definition: attr.c:151
#define NLA_PUT_U32(n, attrtype, value)
Add a u32 netlink attribute to a netlink message.
Definition: attr.h:201
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
parse nested attributes
Definition: attr.c:307
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
uint32_t nla_get_u32(struct nlattr *nla)
Return payload of u32 attribute.
Definition: attr.c:693
int nla_len(const struct nlattr *nla)
length of payload
Definition: attr.c:160
char * nla_get_string(struct nlattr *nla)
return payload of string attribute
Definition: attr.c:733
struct nlattr * nla_nest_start(struct nl_msg *n, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:655
@ NLA_STRING
character string
Definition: attr.h:41
@ NLA_NESTED
nested attributes
Definition: attr.h:44
@ NLA_U32
32bit integer
Definition: attr.h:39
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:261
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:226
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate an empty cache.
Definition: cache.c:170
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
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:448
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
Definition: msg.c:656
#define NLM_F_CREATE
Create config object if it doesn't already exist.
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
void * nlmsg_data(const struct nlmsghdr *nlh)
head of message payload
Definition: msg.c:218
#define NLM_F_DUMP
Dump all entries.
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
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_wait_for_ack(struct nl_handle *handle)
Wait for ACK.
Definition: nl.c:801
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
int nl_rtgen_request(struct nl_handle *handle, int type, int family, int flags)
Send routing netlink request message.
Definition: rtnl.c:40
Address family to netlink group association.
Definition: cache-api.h:144
Cache Operations.
Definition: cache-api.h:164
attribute validation policy
Definition: attr.h:73
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:75
Netlink message header.
uint16_t nlmsg_type
Message type (content type)
Netlink socket address.
Definition: netlink-kernel.h:9