• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/route/route.c	Routes
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 rtnl
15  * @defgroup route Routing
16  * @brief
17  * @{
18  */
19 
20 #include <netlink-private/netlink.h>
21 #include <netlink/netlink.h>
22 #include <netlink/cache.h>
23 #include <netlink/utils.h>
24 #include <netlink/data.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink/route/route.h>
27 #include <netlink/route/link.h>
28 
29 static struct nl_cache_ops rtnl_route_ops;
30 
route_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)31 static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
32 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
33 {
34 	struct rtnl_route *route;
35 	int err;
36 
37 	if ((err = rtnl_route_parse(nlh, &route)) < 0)
38 		return err;
39 
40 	err = pp->pp_cb((struct nl_object *) route, pp);
41 
42 	rtnl_route_put(route);
43 	return err;
44 }
45 
route_request_update(struct nl_cache * c,struct nl_sock * h)46 static int route_request_update(struct nl_cache *c, struct nl_sock *h)
47 {
48 	struct rtmsg rhdr = {
49 		.rtm_family = c->c_iarg1,
50 	};
51 
52 	if (c->c_iarg2 & ROUTE_CACHE_CONTENT)
53 		rhdr.rtm_flags |= RTM_F_CLONED;
54 
55 	return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr));
56 }
57 
58 /**
59  * @name Cache Management
60  * @{
61  */
62 
63 /**
64  * Build a route cache holding all routes currently configured in the kernel
65  * @arg sk		Netlink socket.
66  * @arg family		Address family of routes to cover or AF_UNSPEC
67  * @arg flags		Flags
68  * @arg result		Result pointer
69  *
70  * Allocates a new cache, initializes it properly and updates it to
71  * contain all routes currently configured in the kernel.
72  *
73  * Valid flags:
74  *   * ROUTE_CACHE_CONTENT - Cache will contain contents of routing cache
75  *                           instead of actual routes.
76  *
77  * @note The caller is responsible for destroying and freeing the
78  *       cache after using it.
79  * @return 0 on success or a negative error code.
80  */
rtnl_route_alloc_cache(struct nl_sock * sk,int family,int flags,struct nl_cache ** result)81 int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags,
82 			   struct nl_cache **result)
83 {
84 	struct nl_cache *cache;
85 	int err;
86 
87 	if (!(cache = nl_cache_alloc(&rtnl_route_ops)))
88 		return -NLE_NOMEM;
89 
90 	cache->c_iarg1 = family;
91 	cache->c_iarg2 = flags;
92 
93 	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
94 		free(cache);
95 		return err;
96 	}
97 
98 	*result = cache;
99 	return 0;
100 }
101 
102 /** @} */
103 
104 /**
105  * @name Route Addition
106  * @{
107  */
108 
build_route_msg(struct rtnl_route * tmpl,int cmd,int flags,struct nl_msg ** result)109 static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags,
110 			   struct nl_msg **result)
111 {
112 	struct nl_msg *msg;
113 	int err;
114 
115 	if (!(msg = nlmsg_alloc_simple(cmd, flags)))
116 		return -NLE_NOMEM;
117 
118 	if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) {
119 		nlmsg_free(msg);
120 		return err;
121 	}
122 
123 	*result = msg;
124 	return 0;
125 }
126 
rtnl_route_build_add_request(struct rtnl_route * tmpl,int flags,struct nl_msg ** result)127 int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags,
128 				 struct nl_msg **result)
129 {
130 	return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags,
131 			       result);
132 }
133 
rtnl_route_add(struct nl_sock * sk,struct rtnl_route * route,int flags)134 int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags)
135 {
136 	struct nl_msg *msg;
137 	int err;
138 
139 	if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0)
140 		return err;
141 
142 	err = nl_send_auto_complete(sk, msg);
143 	nlmsg_free(msg);
144 	if (err < 0)
145 		return err;
146 
147 	return wait_for_ack(sk);
148 }
149 
rtnl_route_build_del_request(struct rtnl_route * tmpl,int flags,struct nl_msg ** result)150 int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags,
151 				 struct nl_msg **result)
152 {
153 	return build_route_msg(tmpl, RTM_DELROUTE, flags, result);
154 }
155 
rtnl_route_delete(struct nl_sock * sk,struct rtnl_route * route,int flags)156 int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags)
157 {
158 	struct nl_msg *msg;
159 	int err;
160 
161 	if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0)
162 		return err;
163 
164 	err = nl_send_auto_complete(sk, msg);
165 	nlmsg_free(msg);
166 	if (err < 0)
167 		return err;
168 
169 	return wait_for_ack(sk);
170 }
171 
172 /** @} */
173 
174 static struct nl_af_group route_groups[] = {
175 	{ AF_INET,	RTNLGRP_IPV4_ROUTE },
176 	{ AF_INET6,	RTNLGRP_IPV6_ROUTE },
177 	{ AF_MPLS,	RTNLGRP_MPLS_ROUTE },
178 	{ AF_DECnet,	RTNLGRP_DECnet_ROUTE },
179 	{ END_OF_GROUP_LIST },
180 };
181 
182 static struct nl_cache_ops rtnl_route_ops = {
183 	.co_name		= "route/route",
184 	.co_hdrsize		= sizeof(struct rtmsg),
185 	.co_msgtypes		= {
186 					{ RTM_NEWROUTE, NL_ACT_NEW, "new" },
187 					{ RTM_DELROUTE, NL_ACT_DEL, "del" },
188 					{ RTM_GETROUTE, NL_ACT_GET, "get" },
189 					END_OF_MSGTYPES_LIST,
190 				  },
191 	.co_protocol		= NETLINK_ROUTE,
192 	.co_groups		= route_groups,
193 	.co_request_update	= route_request_update,
194 	.co_msg_parser		= route_msg_parser,
195 	.co_obj_ops		= &route_obj_ops,
196 };
197 
route_init(void)198 static void __init route_init(void)
199 {
200 	nl_cache_mngt_register(&rtnl_route_ops);
201 }
202 
route_exit(void)203 static void __exit route_exit(void)
204 {
205 	nl_cache_mngt_unregister(&rtnl_route_ops);
206 }
207 
208 /** @} */
209