/* 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 */ /** * @ingroup cli * @defgroup cli_route Routing * * @{ */ #include #include 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); } /** @} */