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
22struct 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
33struct 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
47void 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
55void 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
68void 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
81void 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
94void 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
137void 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
197void 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
211void 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
222void 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
232void 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
248void 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
260void 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