/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/route.c CLI Route Helpers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cli
* @defgroup cli_route Routing
*
* @{
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/route.h>
struct rtnl_route *nl_cli_route_alloc(void)
{
struct rtnl_route *route;
route = rtnl_route_alloc();
if (!route)
nl_cli_fatal(ENOMEM, "Unable to allocate route object");
return route;
}
struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *sk, int flags)
{
struct nl_cache *cache;
int err;
if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0)
nl_cli_fatal(err, "Unable to allocate route cache: %s\n",
nl_geterror(err));
nl_cache_mngt_provide(cache);
return cache;
}
void nl_cli_route_parse_family(struct rtnl_route *route, char *arg)
{
int family;
if ((family = nl_str2af(arg)) != AF_UNSPEC)
rtnl_route_set_family(route, family);
}
void nl_cli_route_parse_dst(struct rtnl_route *route, char *arg)
{
struct nl_addr *addr;
int err;
addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
if ((err = rtnl_route_set_dst(route, addr)) < 0)
nl_cli_fatal(err, "Unable to set destination address: %s",
nl_geterror(err));
nl_addr_put(addr);
}
void nl_cli_route_parse_src(struct rtnl_route *route, char *arg)
{
struct nl_addr *addr;
int err;
addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
if ((err = rtnl_route_set_src(route, addr)) < 0)
nl_cli_fatal(err, "Unable to set source address: %s",
nl_geterror(err));
nl_addr_put(addr);
}
void nl_cli_route_parse_pref_src(struct rtnl_route *route, char *arg)
{
struct nl_addr *addr;
int err;
addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
if ((err = rtnl_route_set_pref_src(route, addr)) < 0)
nl_cli_fatal(err, "Unable to set preferred source address: %s",
nl_geterror(err));
nl_addr_put(addr);
}
void nl_cli_route_parse_metric(struct rtnl_route *route, char *subopts)
{
/* strict equal order to RTAX_* */
static char *const tokens[] = {
"unspec",
"lock",
"mtu",
"window",
"rtt",
"rttvar",
"sstresh",
"cwnd",
"advmss",
"reordering",
"hoplimit",
"initcwnd",
"features",
NULL,
};
unsigned long lval;
char *arg, *endptr;
while (*subopts != '\0') {
int ret = getsubopt(&subopts, tokens, &arg);
if (ret == -1)
nl_cli_fatal(EINVAL, "Unknown metric token \"%s\"", arg);
if (ret == 0)
nl_cli_fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]);
if (arg == NULL)
nl_cli_fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]);
lval = strtoul(arg, &endptr, 0);
if (endptr == arg)
nl_cli_fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]);
if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0)
nl_cli_fatal(ret, "Unable to set metric: %s",
nl_geterror(ret));
}
}
void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
struct nl_cache *link_cache)
{
enum {
NH_DEV,
NH_VIA,
NH_WEIGHT,
NH_AS,
};
static char *const tokens[] = {
"dev",
"via",
"weight",
"as",
NULL,
};
struct rtnl_nexthop *nh;
unsigned long lval;
struct nl_addr *addr;
int ival;
char *arg, *endptr;
if (!(nh = rtnl_route_nh_alloc()))
nl_cli_fatal(ENOMEM, "Out of memory");
while (*subopts != '\0') {
int ret = getsubopt(&subopts, tokens, &arg);
if (ret == -1)
nl_cli_fatal(EINVAL, "Unknown nexthop token \"%s\"", arg);
if (arg == NULL)
nl_cli_fatal(EINVAL, "Missing argument to option \"%s\"\n",
tokens[ret]);
switch (ret) {
case NH_DEV:
if (!(ival = rtnl_link_name2i(link_cache, arg)))
nl_cli_fatal(ENOENT,"Link \"%s\" does not exist", arg);
rtnl_route_nh_set_ifindex(nh, ival);
break;
case NH_VIA:
if (rtnl_route_get_family(route) == AF_MPLS) {
addr = nl_cli_addr_parse(arg, 0);
rtnl_route_nh_set_via(nh, addr);
} else {
addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
rtnl_route_nh_set_gateway(nh, addr);
}
nl_addr_put(addr);
break;
case NH_AS:
addr = nl_cli_addr_parse(arg,
rtnl_route_get_family(route));
rtnl_route_nh_set_newdst(nh, addr);
nl_addr_put(addr);
break;
case NH_WEIGHT:
lval = strtoul(arg, &endptr, 0);
if (endptr == arg)
nl_cli_fatal(EINVAL,
"Invalid weight \"%s\", not numeric",
arg);
rtnl_route_nh_set_weight(nh, lval);
break;
}
}
rtnl_route_add_nexthop(route, nh);
}
void nl_cli_route_parse_table(struct rtnl_route *route, char *arg)
{
unsigned long lval;
char *endptr;
int table;
lval = strtoul(arg, &endptr, 0);
if (endptr == arg) {
if ((table = rtnl_route_str2table(arg)) < 0)
nl_cli_fatal(EINVAL, "Unknown table name \"%s\"", arg);
}
else {
table = lval;
}
rtnl_route_set_table(route, table);
}
void nl_cli_route_parse_prio(struct rtnl_route *route, char *arg)
{
unsigned long lval;
char *endptr;
lval = strtoul(arg, &endptr, 0);
if (endptr == arg)
nl_cli_fatal(EINVAL, "Invalid priority value, not numeric");
rtnl_route_set_priority(route, lval);
}
void nl_cli_route_parse_scope(struct rtnl_route *route, char *arg)
{
int ival;
if ((ival = rtnl_str2scope(arg)) < 0)
nl_cli_fatal(EINVAL, "Unknown routing scope \"%s\"", arg);
rtnl_route_set_scope(route, ival);
}
void nl_cli_route_parse_protocol(struct rtnl_route *route, char *arg)
{
unsigned long lval;
char *endptr;
int proto;
lval = strtoul(arg, &endptr, 0);
if (endptr == arg) {
if ((proto = rtnl_route_str2proto(arg)) < 0)
nl_cli_fatal(EINVAL,
"Unknown routing protocol name \"%s\"",
arg);
}
else {
proto = lval;
}
rtnl_route_set_protocol(route, proto);
}
void nl_cli_route_parse_type(struct rtnl_route *route, char *arg)
{
int ival;
if ((ival = nl_str2rtntype(arg)) < 0)
nl_cli_fatal(EINVAL, "Unknown routing type \"%s\"", arg);
if ((ival = rtnl_route_set_type(route, ival)) < 0)
nl_cli_fatal(ival, "Unable to set routing type: %s",
nl_geterror(ival));
}
void nl_cli_route_parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache)
{
int ival;
if (!(ival = rtnl_link_name2i(link_cache, arg)))
nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
rtnl_route_set_iif(route, ival);
}
/** @} */