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