#include <netinet/ip.h>
#include <arpa/inet.h>
#include <linux/in_route.h>
+#include <linux/ip_mp_alg.h>
#include "rt_names.h"
#include "utils.h"
fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n");
+ fprintf(stderr, " [ mpath MP_ALGO ]\n");
fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n");
fprintf(stderr, "FLAGS := [ equalize ]\n");
+ fprintf(stderr, "MP_ALGO := { rr | drr | random | wrandom }\n");
fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
exit(-1);
char *flushb;
int flushp;
int flushe;
- struct rtnl_handle *rth;
int protocol, protocolmask;
int scope, scopemask;
int type, typemask;
inet_prefix msrc;
} filter;
+static char *mp_alg_names[IP_MP_ALG_MAX+1] = {
+ [IP_MP_ALG_NONE] = "none",
+ [IP_MP_ALG_RR] = "rr",
+ [IP_MP_ALG_DRR] = "drr",
+ [IP_MP_ALG_RANDOM] = "random",
+ [IP_MP_ALG_WRANDOM] = "wrandom"
+};
+
static int flush_update(void)
{
- if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
+ if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) {
perror("Failed to send flush request\n");
return -1;
}
memset(&via, 0, sizeof(via));
via.family = r->rtm_family;
if (tb[RTA_GATEWAY])
- memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len);
+ memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
}
if (filter.rprefsrc.bitlen>0) {
memset(&prefsrc, 0, sizeof(prefsrc));
prefsrc.family = r->rtm_family;
if (tb[RTA_PREFSRC])
- memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len);
+ memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
}
if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
memcpy(fn, n, n->nlmsg_len);
fn->nlmsg_type = RTM_DELROUTE;
fn->nlmsg_flags = NLM_F_REQUEST;
- fn->nlmsg_seq = ++filter.rth->seq;
+ fn->nlmsg_seq = ++rth.seq;
filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
filter.flushed++;
if (show_stats < 2)
SPRINT_BUF(b1);
fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
}
+
+ if (tb[RTA_MP_ALGO]) {
+ __u32 mp_alg = *(__u32*) RTA_DATA(tb[RTA_MP_ALGO]);
+ if (mp_alg > IP_MP_ALG_NONE) {
+ fprintf(fp, "mpath %s ",
+ mp_alg < IP_MP_ALG_MAX ? mp_alg_names[mp_alg] : "unknown");
+ }
+ }
+
if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
fprintf(fp, "via %s ",
format_host(r->rtm_family,
}
memset(rtnh, 0, sizeof(*rtnh));
rtnh->rtnh_len = sizeof(*rtnh);
- rtnh->rtnh_ifindex = 0;
- rtnh->rtnh_flags = 0;
- rtnh->rtnh_hops = 0;
rta->rta_len += rtnh->rtnh_len;
parse_one_nh(rta, rtnh, &argc, &argv);
rtnh = RTNH_NEXT(rtnh);
int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
{
- struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct rtmsg r;
invarg("\"metric\" value is invalid\n", *argv);
addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
} else if (strcmp(*argv, "scope") == 0) {
- int scope = 0;
+ __u32 scope = 0;
NEXT_ARG();
if (rtnl_rtscope_a2n(&scope, *argv))
invarg("invalid \"scope\" value\n", *argv);
nhs_ok = 1;
break;
} else if (matches(*argv, "protocol") == 0) {
- int prot;
+ __u32 prot;
NEXT_ARG();
if (rtnl_rtprot_a2n(&prot, *argv))
invarg("\"protocol\" value is invalid\n", *argv);
req.r.rtm_protocol = prot;
proto_ok =1;
} else if (matches(*argv, "table") == 0) {
- int tid;
+ __u32 tid;
NEXT_ARG();
if (rtnl_rttable_a2n(&tid, *argv))
invarg("\"table\" value is invalid\n", *argv);
strcmp(*argv, "oif") == 0) {
NEXT_ARG();
d = *argv;
+ } else if (strcmp(*argv, "mpath") == 0 ||
+ strcmp(*argv, "mp") == 0) {
+ int i;
+ __u32 mp_alg = IP_MP_ALG_NONE;
+
+ NEXT_ARG();
+ for (i = 1; i < ARRAY_SIZE(mp_alg_names); i++)
+ if (strcmp(*argv, mp_alg_names[i]) == 0)
+ mp_alg = i;
+ if (mp_alg == IP_MP_ALG_NONE)
+ invarg("\"mpath\" value is invalid\n", *argv);
+ addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg));
} else {
int type;
inet_prefix dst;
argc--; argv++;
}
- if (rtnl_open(&rth, 0) < 0)
- exit(1);
-
if (d || nhs_ok) {
int idx;
static int iproute_list_or_flush(int argc, char **argv, int flush)
{
int do_ipv6 = preferred_family;
- struct rtnl_handle rth;
char *id = NULL;
char *od = NULL;
while (argc > 0) {
if (matches(*argv, "table") == 0) {
- int tid;
+ __u32 tid;
NEXT_ARG();
if (rtnl_rttable_a2n(&tid, *argv)) {
if (strcmp(*argv, "all") == 0) {
filter.tos = tos;
filter.tosmask = -1;
} else if (matches(*argv, "protocol") == 0) {
- int prot = 0;
+ __u32 prot = 0;
NEXT_ARG();
filter.protocolmask = -1;
if (rtnl_rtprot_a2n(&prot, *argv)) {
}
filter.protocol = prot;
} else if (matches(*argv, "scope") == 0) {
- int scope = 0;
+ __u32 scope = 0;
NEXT_ARG();
filter.scopemask = -1;
if (rtnl_rtscope_a2n(&scope, *argv)) {
if (do_ipv6 == AF_UNSPEC && filter.tb)
do_ipv6 = AF_INET;
- if (rtnl_open(&rth, 0) < 0)
- exit(1);
-
ll_init_map(&rth);
if (id || od) {
filter.flushb = flushb;
filter.flushp = 0;
filter.flushe = sizeof(flushb);
- filter.rth = &rth;
for (;;) {
if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
int iproute_get(int argc, char **argv)
{
- struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct rtmsg r;
exit(1);
}
- if (rtnl_open(&rth, 0) < 0)
- exit(1);
-
ll_init_map(&rth);
if (idev || odev) {