1 /*
2  * src/lib/route.c     CLI Route Helpers
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) 2008-2009 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup cli
14  * @defgroup cli_route Routing
15  *
16  * @{
17  */
18 
19 #include <netlink/cli/utils.h>
20 #include <netlink/cli/route.h>
21 
nl_cli_route_alloc(void)22 struct rtnl_route *nl_cli_route_alloc(void)
23 {
24 	struct rtnl_route *route;
25 
26 	route = rtnl_route_alloc();
27 	if (!route)
28 		nl_cli_fatal(ENOMEM, "Unable to allocate route object");
29 
30 	return route;
31 }
32 
nl_cli_route_alloc_cache(struct nl_sock * sk,int flags)33 struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *sk, int flags)
34 {
35 	struct nl_cache *cache;
36 	int err;
37 
38 	if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0)
39 		nl_cli_fatal(err, "Unable to allocate route cache: %s\n",
40 			     nl_geterror(err));
41 
42 	nl_cache_mngt_provide(cache);
43 
44 	return cache;
45 }
46 
nl_cli_route_parse_family(struct rtnl_route * route,char * arg)47 void nl_cli_route_parse_family(struct rtnl_route *route, char *arg)
48 {
49 	int family;
50 
51 	if ((family = nl_str2af(arg)) != AF_UNSPEC)
52 		rtnl_route_set_family(route, family);
53 }
54 
nl_cli_route_parse_dst(struct rtnl_route * route,char * arg)55 void nl_cli_route_parse_dst(struct rtnl_route *route, char *arg)
56 {
57 	struct nl_addr *addr;
58 	int err;
59 
60 	addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
61 	if ((err = rtnl_route_set_dst(route, addr)) < 0)
62 		nl_cli_fatal(err, "Unable to set destination address: %s",
63 		      nl_geterror(err));
64 
65 	nl_addr_put(addr);
66 }
67 
nl_cli_route_parse_src(struct rtnl_route * route,char * arg)68 void nl_cli_route_parse_src(struct rtnl_route *route, char *arg)
69 {
70 	struct nl_addr *addr;
71 	int err;
72 
73 	addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
74 	if ((err = rtnl_route_set_src(route, addr)) < 0)
75 		nl_cli_fatal(err, "Unable to set source address: %s",
76 		      nl_geterror(err));
77 
78 	nl_addr_put(addr);
79 }
80 
nl_cli_route_parse_pref_src(struct rtnl_route * route,char * arg)81 void nl_cli_route_parse_pref_src(struct rtnl_route *route, char *arg)
82 {
83 	struct nl_addr *addr;
84 	int err;
85 
86 	addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
87 	if ((err = rtnl_route_set_pref_src(route, addr)) < 0)
88 		nl_cli_fatal(err, "Unable to set preferred source address: %s",
89 		      nl_geterror(err));
90 
91 	nl_addr_put(addr);
92 }
93 
nl_cli_route_parse_metric(struct rtnl_route * route,char * subopts)94 void nl_cli_route_parse_metric(struct rtnl_route *route, char *subopts)
95 {
96 	/* strict equal order to RTAX_* */
97 	static char *const tokens[] = {
98 		"unspec",
99 		"lock",
100 		"mtu",
101 		"window",
102 		"rtt",
103 		"rttvar",
104 		"sstresh",
105 		"cwnd",
106 		"advmss",
107 		"reordering",
108 		"hoplimit",
109 		"initcwnd",
110 		"features",
111 		NULL,
112 	};
113 	unsigned long lval;
114 	char *arg, *endptr;
115 
116 	while (*subopts != '\0') {
117 		int ret = getsubopt(&subopts, tokens, &arg);
118 		if (ret == -1)
119 			nl_cli_fatal(EINVAL, "Unknown metric token \"%s\"", arg);
120 
121 		if (ret == 0)
122 			nl_cli_fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]);
123 
124 		if (arg == NULL)
125 			nl_cli_fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]);
126 
127 		lval = strtoul(arg, &endptr, 0);
128 		if (endptr == arg)
129 			nl_cli_fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]);
130 
131 		if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0)
132 			nl_cli_fatal(ret, "Unable to set metric: %s",
133 			      nl_geterror(ret));
134 	}
135 }
136 
nl_cli_route_parse_nexthop(struct rtnl_route * route,char * subopts,struct nl_cache * link_cache)137 void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
138 		   struct nl_cache *link_cache)
139 {
140 	enum {
141 		NH_DEV,
142 		NH_VIA,
143 		NH_WEIGHT,
144 	};
145 	static char *const tokens[] = {
146 		"dev",
147 		"via",
148 		"weight",
149 		NULL,
150 	};
151 	struct rtnl_nexthop *nh;
152 	unsigned long lval;
153 	struct nl_addr *addr;
154 	int ival;
155 	char *arg, *endptr;
156 
157 	if (!(nh = rtnl_route_nh_alloc()))
158 		nl_cli_fatal(ENOMEM, "Out of memory");
159 
160 	while (*subopts != '\0') {
161 		int ret = getsubopt(&subopts, tokens, &arg);
162 		if (ret == -1)
163 			nl_cli_fatal(EINVAL, "Unknown nexthop token \"%s\"", arg);
164 
165 		if (arg == NULL)
166 			nl_cli_fatal(EINVAL, "Missing argument to option \"%s\"\n",
167 				tokens[ret]);
168 
169 		switch (ret) {
170 		case NH_DEV:
171 			if (!(ival = rtnl_link_name2i(link_cache, arg)))
172 				nl_cli_fatal(ENOENT,"Link \"%s\" does not exist", arg);
173 
174 			rtnl_route_nh_set_ifindex(nh, ival);
175 			break;
176 
177 		case NH_VIA:
178 			addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
179 			rtnl_route_nh_set_gateway(nh, addr);
180 			nl_addr_put(addr);
181 			break;
182 
183 		case NH_WEIGHT:
184 			lval = strtoul(arg, &endptr, 0);
185 			if (endptr == arg)
186 				nl_cli_fatal(EINVAL,
187 					     "Invalid weight \"%s\", not numeric",
188 					     arg);
189 			rtnl_route_nh_set_weight(nh, lval);
190 			break;
191 		}
192 	}
193 
194 	rtnl_route_add_nexthop(route, nh);
195 }
196 
nl_cli_route_parse_table(struct rtnl_route * route,char * arg)197 void nl_cli_route_parse_table(struct rtnl_route *route, char *arg)
198 {
199 	unsigned long lval;
200 	char *endptr;
201 
202 	lval = strtoul(arg, &endptr, 0);
203 	if (endptr == arg) {
204 		if ((lval = rtnl_route_str2table(arg)) < 0)
205 			nl_cli_fatal(EINVAL, "Unknown table name \"%s\"", arg);
206 	}
207 
208 	rtnl_route_set_table(route, lval);
209 }
210 
nl_cli_route_parse_prio(struct rtnl_route * route,char * arg)211 void nl_cli_route_parse_prio(struct rtnl_route *route, char *arg)
212 {
213 	unsigned long lval;
214 	char *endptr;
215 
216 	lval = strtoul(arg, &endptr, 0);
217 	if (endptr == arg)
218 		nl_cli_fatal(EINVAL, "Invalid priority value, not numeric");
219 	rtnl_route_set_priority(route, lval);
220 }
221 
nl_cli_route_parse_scope(struct rtnl_route * route,char * arg)222 void nl_cli_route_parse_scope(struct rtnl_route *route, char *arg)
223 {
224 	int ival;
225 
226 	if ((ival = rtnl_str2scope(arg)) < 0)
227 		nl_cli_fatal(EINVAL, "Unknown routing scope \"%s\"", arg);
228 
229 	rtnl_route_set_scope(route, ival);
230 }
231 
nl_cli_route_parse_protocol(struct rtnl_route * route,char * arg)232 void nl_cli_route_parse_protocol(struct rtnl_route *route, char *arg)
233 {
234 	unsigned long lval;
235 	char *endptr;
236 
237 	lval = strtoul(arg, &endptr, 0);
238 	if (endptr == arg) {
239 		if ((lval = rtnl_route_str2proto(arg)) < 0)
240 			nl_cli_fatal(EINVAL,
241 				     "Unknown routing protocol name \"%s\"",
242 				     arg);
243 	}
244 
245 	rtnl_route_set_protocol(route, lval);
246 }
247 
nl_cli_route_parse_type(struct rtnl_route * route,char * arg)248 void nl_cli_route_parse_type(struct rtnl_route *route, char *arg)
249 {
250 	int ival;
251 
252 	if ((ival = nl_str2rtntype(arg)) < 0)
253 		nl_cli_fatal(EINVAL, "Unknown routing type \"%s\"", arg);
254 
255 	if ((ival = rtnl_route_set_type(route, ival)) < 0)
256 		nl_cli_fatal(ival, "Unable to set routing type: %s",
257 		      nl_geterror(ival));
258 }
259 
nl_cli_route_parse_iif(struct rtnl_route * route,char * arg,struct nl_cache * link_cache)260 void nl_cli_route_parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache)
261 {
262 	int ival;
263 
264 	if (!(ival = rtnl_link_name2i(link_cache, arg)))
265 		nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
266 
267 	rtnl_route_set_iif(route, ival);
268 }
269 
270 /** @} */
271