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