|
|
318a74 |
From 5845a145808162560293cf4f7c55bbb5afc8dce7 Mon Sep 17 00:00:00 2001
|
|
|
318a74 |
From: Phil Sutter <psutter@redhat.com>
|
|
|
318a74 |
Date: Thu, 21 Feb 2019 14:38:57 +0100
|
|
|
318a74 |
Subject: [PATCH] ip-route: Fix segfault with many nexthops
|
|
|
318a74 |
|
|
|
318a74 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1624656
|
|
|
318a74 |
Upstream Status: iproute2.git commit bd59e5b1517b0
|
|
|
318a74 |
Conflicts: Context changes due to missing other commits.
|
|
|
318a74 |
|
|
|
318a74 |
commit bd59e5b1517b09b6f26d59f38fe6077d953c2396
|
|
|
318a74 |
Author: Phil Sutter <phil@nwl.cc>
|
|
|
318a74 |
Date: Thu Sep 6 15:31:51 2018 +0200
|
|
|
318a74 |
|
|
|
318a74 |
ip-route: Fix segfault with many nexthops
|
|
|
318a74 |
|
|
|
318a74 |
It was possible to crash ip-route by adding an IPv6 route with 37
|
|
|
318a74 |
nexthop statements. A simple reproducer is:
|
|
|
318a74 |
|
|
|
318a74 |
| for i in `seq 37`; do
|
|
|
318a74 |
| nhs="nexthop via 1111::$i "$nhs
|
|
|
318a74 |
| done
|
|
|
318a74 |
| ip -6 route add 3333::/64 $nhs
|
|
|
318a74 |
|
|
|
318a74 |
The related code was broken in multiple ways:
|
|
|
318a74 |
|
|
|
318a74 |
* parse_one_nh() assumed that rta points to 4kB of storage but caller
|
|
|
318a74 |
provided just 1kB. Fixed by passing 'len' parameter with the correct
|
|
|
318a74 |
value.
|
|
|
318a74 |
|
|
|
318a74 |
* Error checking of rta_addattr*() calls in parse_one_nh() and called
|
|
|
318a74 |
functions was completely absent, so with above fix in place output
|
|
|
318a74 |
flood would occur due to parser looping forever.
|
|
|
318a74 |
|
|
|
318a74 |
While being at it, increase message buffer sizes to 4k. This allows for
|
|
|
318a74 |
at most 144 nexthops.
|
|
|
318a74 |
|
|
|
318a74 |
Signed-off-by: Phil Sutter <phil@nwl.cc>
|
|
|
318a74 |
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
|
|
|
318a74 |
---
|
|
|
318a74 |
ip/iproute.c | 43 +++++++++++++++++++++--------------
|
|
|
318a74 |
ip/iproute_lwtunnel.c | 63 ++++++++++++++++++++++++++++++++-------------------
|
|
|
318a74 |
2 files changed, 66 insertions(+), 40 deletions(-)
|
|
|
318a74 |
|
|
|
318a74 |
diff --git a/ip/iproute.c b/ip/iproute.c
|
|
|
318a74 |
index 759032d..d4db035 100644
|
|
|
318a74 |
--- a/ip/iproute.c
|
|
|
318a74 |
+++ b/ip/iproute.c
|
|
|
318a74 |
@@ -721,7 +721,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
- struct rtattr *rta, struct rtnexthop *rtnh,
|
|
|
318a74 |
+ struct rtattr *rta, size_t len, struct rtnexthop *rtnh,
|
|
|
318a74 |
int *argcp, char ***argvp)
|
|
|
318a74 |
{
|
|
|
318a74 |
int argc = *argcp;
|
|
|
318a74 |
@@ -742,11 +742,16 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
if (r->rtm_family == AF_UNSPEC)
|
|
|
318a74 |
r->rtm_family = addr.family;
|
|
|
318a74 |
if (addr.family == r->rtm_family) {
|
|
|
318a74 |
- rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
|
|
|
318a74 |
- rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
|
|
|
318a74 |
+ if (rta_addattr_l(rta, len, RTA_GATEWAY,
|
|
|
318a74 |
+ &addr.data, addr.bytelen))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
+ rtnh->rtnh_len += sizeof(struct rtattr)
|
|
|
318a74 |
+ + addr.bytelen;
|
|
|
318a74 |
} else {
|
|
|
318a74 |
- rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
|
|
|
318a74 |
- rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2);
|
|
|
318a74 |
+ if (rta_addattr_l(rta, len, RTA_VIA,
|
|
|
318a74 |
+ &addr.family, addr.bytelen + 2))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
+ rtnh->rtnh_len += RTA_SPACE(addr.bytelen + 2);
|
|
|
318a74 |
}
|
|
|
318a74 |
} else if (strcmp(*argv, "dev") == 0) {
|
|
|
318a74 |
NEXT_ARG();
|
|
|
318a74 |
@@ -769,13 +774,15 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
NEXT_ARG();
|
|
|
318a74 |
if (get_rt_realms_or_raw(&realm, *argv))
|
|
|
318a74 |
invarg("\"realm\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr32(rta, 4096, RTA_FLOW, realm);
|
|
|
318a74 |
+ if (rta_addattr32(rta, len, RTA_FLOW, realm))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
rtnh->rtnh_len += sizeof(struct rtattr) + 4;
|
|
|
318a74 |
} else if (strcmp(*argv, "encap") == 0) {
|
|
|
318a74 |
- int len = rta->rta_len;
|
|
|
318a74 |
+ int old_len = rta->rta_len;
|
|
|
318a74 |
|
|
|
318a74 |
- lwt_parse_encap(rta, 4096, &argc, &argv);
|
|
|
318a74 |
- rtnh->rtnh_len += rta->rta_len - len;
|
|
|
318a74 |
+ if (lwt_parse_encap(rta, len, &argc, &argv))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
+ rtnh->rtnh_len += rta->rta_len - old_len;
|
|
|
318a74 |
} else if (strcmp(*argv, "as") == 0) {
|
|
|
318a74 |
inet_prefix addr;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -783,8 +790,9 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
if (strcmp(*argv, "to") == 0)
|
|
|
318a74 |
NEXT_ARG();
|
|
|
318a74 |
get_addr(&addr, *argv, r->rtm_family);
|
|
|
318a74 |
- rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data,
|
|
|
318a74 |
- addr.bytelen);
|
|
|
318a74 |
+ if (rta_addattr_l(rta, len, RTA_NEWDST,
|
|
|
318a74 |
+ &addr.data, addr.bytelen))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
|
|
|
318a74 |
} else
|
|
|
318a74 |
break;
|
|
|
318a74 |
@@ -797,7 +805,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
int argc, char **argv)
|
|
|
318a74 |
{
|
|
|
318a74 |
- char buf[1024];
|
|
|
318a74 |
+ char buf[4096];
|
|
|
318a74 |
struct rtattr *rta = (void *)buf;
|
|
|
318a74 |
struct rtnexthop *rtnh;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -817,7 +825,7 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
memset(rtnh, 0, sizeof(*rtnh));
|
|
|
318a74 |
rtnh->rtnh_len = sizeof(*rtnh);
|
|
|
318a74 |
rta->rta_len += rtnh->rtnh_len;
|
|
|
318a74 |
- if (parse_one_nh(n, r, rta, rtnh, &argc, &argv)) {
|
|
|
318a74 |
+ if (parse_one_nh(n, r, rta, 4096, rtnh, &argc, &argv)) {
|
|
|
318a74 |
fprintf(stderr, "Error: cannot parse nexthop\n");
|
|
|
318a74 |
exit(-1);
|
|
|
318a74 |
}
|
|
|
318a74 |
@@ -825,7 +833,8 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
if (rta->rta_len > RTA_LENGTH(0))
|
|
|
318a74 |
- addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
|
|
318a74 |
+ return addattr_l(n, 4096, RTA_MULTIPATH,
|
|
|
318a74 |
+ RTA_DATA(rta), RTA_PAYLOAD(rta));
|
|
|
318a74 |
return 0;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
@@ -834,7 +843,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|
|
318a74 |
struct {
|
|
|
318a74 |
struct nlmsghdr n;
|
|
|
318a74 |
struct rtmsg r;
|
|
|
318a74 |
- char buf[1024];
|
|
|
318a74 |
+ char buf[4096];
|
|
|
318a74 |
} req = {
|
|
|
318a74 |
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
|
|
|
318a74 |
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
|
|
318a74 |
@@ -1238,8 +1247,8 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|
|
318a74 |
addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
- if (nhs_ok)
|
|
|
318a74 |
- parse_nexthops(&req.n, &req.r, argc, argv);
|
|
|
318a74 |
+ if (nhs_ok && parse_nexthops(&req.n, &req.r, argc, argv))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
|
|
|
318a74 |
if (req.r.rtm_family == AF_UNSPEC)
|
|
|
318a74 |
req.r.rtm_family = AF_INET;
|
|
|
318a74 |
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
|
|
|
318a74 |
index 0fa1cab..1a68912 100644
|
|
|
318a74 |
--- a/ip/iproute_lwtunnel.c
|
|
|
318a74 |
+++ b/ip/iproute_lwtunnel.c
|
|
|
318a74 |
@@ -255,8 +255,9 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
|
|
|
318a74 |
exit(1);
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
- rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
|
|
|
318a74 |
- addr.bytelen);
|
|
|
318a74 |
+ if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
|
|
|
318a74 |
+ &addr.data, addr.bytelen))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
|
|
|
318a74 |
*argcp = argc;
|
|
|
318a74 |
*argvp = argv;
|
|
|
318a74 |
@@ -270,6 +271,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
|
|
|
318a74 |
char **argv = *argvp;
|
|
|
318a74 |
int argc = *argcp;
|
|
|
318a74 |
+ int ret = 0;
|
|
|
318a74 |
|
|
|
318a74 |
while (argc > 0) {
|
|
|
318a74 |
if (strcmp(*argv, "id") == 0) {
|
|
|
318a74 |
@@ -280,7 +282,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
duparg2("id", *argv);
|
|
|
318a74 |
if (get_be64(&id, *argv, 0))
|
|
|
318a74 |
invarg("\"id\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
|
|
|
318a74 |
+ ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
|
|
|
318a74 |
} else if (strcmp(*argv, "dst") == 0) {
|
|
|
318a74 |
inet_prefix addr;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -288,8 +290,8 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
if (dst_ok++)
|
|
|
318a74 |
duparg2("dst", *argv);
|
|
|
318a74 |
get_addr(&addr, *argv, AF_INET);
|
|
|
318a74 |
- rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
|
|
|
318a74 |
- &addr.data, addr.bytelen);
|
|
|
318a74 |
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
|
|
|
318a74 |
+ &addr.data, addr.bytelen);
|
|
|
318a74 |
} else if (strcmp(*argv, "tos") == 0) {
|
|
|
318a74 |
__u32 tos;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -298,7 +300,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
duparg2("tos", *argv);
|
|
|
318a74 |
if (rtnl_dsfield_a2n(&tos, *argv))
|
|
|
318a74 |
invarg("\"tos\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
|
|
|
318a74 |
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
|
|
|
318a74 |
} else if (strcmp(*argv, "ttl") == 0) {
|
|
|
318a74 |
__u8 ttl;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -307,10 +309,12 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
duparg2("ttl", *argv);
|
|
|
318a74 |
if (get_u8(&ttl, *argv, 0))
|
|
|
318a74 |
invarg("\"ttl\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
|
|
|
318a74 |
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
|
|
|
318a74 |
} else {
|
|
|
318a74 |
break;
|
|
|
318a74 |
}
|
|
|
318a74 |
+ if (ret)
|
|
|
318a74 |
+ break;
|
|
|
318a74 |
argc--; argv++;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
@@ -321,7 +325,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
|
|
|
318a74 |
*argcp = argc + 1;
|
|
|
318a74 |
*argvp = argv - 1;
|
|
|
318a74 |
|
|
|
318a74 |
- return 0;
|
|
|
318a74 |
+ return ret;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
static int parse_encap_ila(struct rtattr *rta, size_t len,
|
|
|
318a74 |
@@ -330,6 +334,7 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
|
|
|
318a74 |
__u64 locator;
|
|
|
318a74 |
int argc = *argcp;
|
|
|
318a74 |
char **argv = *argvp;
|
|
|
318a74 |
+ int ret = 0;
|
|
|
318a74 |
|
|
|
318a74 |
if (get_addr64(&locator, *argv) < 0) {
|
|
|
318a74 |
fprintf(stderr, "Bad locator: %s\n", *argv);
|
|
|
318a74 |
@@ -338,7 +343,8 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
|
|
|
318a74 |
|
|
|
318a74 |
argc--; argv++;
|
|
|
318a74 |
|
|
|
318a74 |
- rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
|
|
|
318a74 |
+ if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
|
|
|
318a74 |
+ return -1;
|
|
|
318a74 |
|
|
|
318a74 |
while (argc > 0) {
|
|
|
318a74 |
if (strcmp(*argv, "csum-mode") == 0) {
|
|
|
318a74 |
@@ -351,12 +357,15 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
|
|
|
318a74 |
invarg("\"csum-mode\" value is invalid\n",
|
|
|
318a74 |
*argv);
|
|
|
318a74 |
|
|
|
318a74 |
- rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE, csum_mode);
|
|
|
318a74 |
+ ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
|
|
|
318a74 |
+ (__u8)csum_mode);
|
|
|
318a74 |
|
|
|
318a74 |
argc--; argv++;
|
|
|
318a74 |
} else {
|
|
|
318a74 |
break;
|
|
|
318a74 |
}
|
|
|
318a74 |
+ if (ret)
|
|
|
318a74 |
+ break;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
/* argv is currently the first unparsed argument,
|
|
|
318a74 |
@@ -366,7 +375,7 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
|
|
|
318a74 |
*argcp = argc + 1;
|
|
|
318a74 |
*argvp = argv - 1;
|
|
|
318a74 |
|
|
|
318a74 |
- return 0;
|
|
|
318a74 |
+ return ret;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
@@ -375,6 +384,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
|
|
|
318a74 |
char **argv = *argvp;
|
|
|
318a74 |
int argc = *argcp;
|
|
|
318a74 |
+ int ret = 0;
|
|
|
318a74 |
|
|
|
318a74 |
while (argc > 0) {
|
|
|
318a74 |
if (strcmp(*argv, "id") == 0) {
|
|
|
318a74 |
@@ -385,7 +395,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
duparg2("id", *argv);
|
|
|
318a74 |
if (get_be64(&id, *argv, 0))
|
|
|
318a74 |
invarg("\"id\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
|
|
|
318a74 |
+ ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
|
|
|
318a74 |
} else if (strcmp(*argv, "dst") == 0) {
|
|
|
318a74 |
inet_prefix addr;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -393,8 +403,8 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
if (dst_ok++)
|
|
|
318a74 |
duparg2("dst", *argv);
|
|
|
318a74 |
get_addr(&addr, *argv, AF_INET6);
|
|
|
318a74 |
- rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
|
|
|
318a74 |
- &addr.data, addr.bytelen);
|
|
|
318a74 |
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
|
|
|
318a74 |
+ &addr.data, addr.bytelen);
|
|
|
318a74 |
} else if (strcmp(*argv, "tc") == 0) {
|
|
|
318a74 |
__u32 tc;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -403,7 +413,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
duparg2("tc", *argv);
|
|
|
318a74 |
if (rtnl_dsfield_a2n(&tc, *argv))
|
|
|
318a74 |
invarg("\"tc\" value is invalid\n", *argv);
|
|
|
318a74 |
- rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
|
|
|
318a74 |
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
|
|
|
318a74 |
} else if (strcmp(*argv, "hoplimit") == 0) {
|
|
|
318a74 |
__u8 hoplimit;
|
|
|
318a74 |
|
|
|
318a74 |
@@ -413,10 +423,13 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
if (get_u8(&hoplimit, *argv, 0))
|
|
|
318a74 |
invarg("\"hoplimit\" value is invalid\n",
|
|
|
318a74 |
*argv);
|
|
|
318a74 |
- rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
|
|
|
318a74 |
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
|
|
|
318a74 |
+ hoplimit);
|
|
|
318a74 |
} else {
|
|
|
318a74 |
break;
|
|
|
318a74 |
}
|
|
|
318a74 |
+ if (ret)
|
|
|
318a74 |
+ break;
|
|
|
318a74 |
argc--; argv++;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
@@ -427,7 +440,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|
|
318a74 |
*argcp = argc + 1;
|
|
|
318a74 |
*argvp = argv - 1;
|
|
|
318a74 |
|
|
|
318a74 |
- return 0;
|
|
|
318a74 |
+ return ret;
|
|
|
318a74 |
}
|
|
|
318a74 |
|
|
|
318a74 |
struct lwt_x {
|
|
|
318a74 |
@@ -542,6 +555,7 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
|
|
|
318a74 |
int argc = *argcp;
|
|
|
318a74 |
char **argv = *argvp;
|
|
|
318a74 |
__u16 type;
|
|
|
318a74 |
+ int ret = 0;
|
|
|
318a74 |
|
|
|
318a74 |
NEXT_ARG();
|
|
|
318a74 |
type = read_encap_type(*argv);
|
|
|
318a74 |
@@ -558,16 +572,16 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
|
|
|
318a74 |
nest = rta_nest(rta, 1024, RTA_ENCAP);
|
|
|
318a74 |
switch (type) {
|
|
|
318a74 |
case LWTUNNEL_ENCAP_MPLS:
|
|
|
318a74 |
- parse_encap_mpls(rta, len, &argc, &argv);
|
|
|
318a74 |
+ ret = parse_encap_mpls(rta, len, &argc, &argv);
|
|
|
318a74 |
break;
|
|
|
318a74 |
case LWTUNNEL_ENCAP_IP:
|
|
|
318a74 |
- parse_encap_ip(rta, len, &argc, &argv);
|
|
|
318a74 |
+ ret = parse_encap_ip(rta, len, &argc, &argv);
|
|
|
318a74 |
break;
|
|
|
318a74 |
case LWTUNNEL_ENCAP_ILA:
|
|
|
318a74 |
- parse_encap_ila(rta, len, &argc, &argv);
|
|
|
318a74 |
+ ret = parse_encap_ila(rta, len, &argc, &argv);
|
|
|
318a74 |
break;
|
|
|
318a74 |
case LWTUNNEL_ENCAP_IP6:
|
|
|
318a74 |
- parse_encap_ip6(rta, len, &argc, &argv);
|
|
|
318a74 |
+ ret = parse_encap_ip6(rta, len, &argc, &argv);
|
|
|
318a74 |
break;
|
|
|
318a74 |
case LWTUNNEL_ENCAP_BPF:
|
|
|
318a74 |
if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
|
|
|
318a74 |
@@ -577,12 +591,15 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
|
|
|
318a74 |
fprintf(stderr, "Error: unsupported encap type\n");
|
|
|
318a74 |
break;
|
|
|
318a74 |
}
|
|
|
318a74 |
+ if (ret)
|
|
|
318a74 |
+ return ret;
|
|
|
318a74 |
+
|
|
|
318a74 |
rta_nest_end(rta, nest);
|
|
|
318a74 |
|
|
|
318a74 |
- rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
|
|
|
318a74 |
+ ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
|
|
|
318a74 |
|
|
|
318a74 |
*argcp = argc;
|
|
|
318a74 |
*argvp = argv;
|
|
|
318a74 |
|
|
|
318a74 |
- return 0;
|
|
|
318a74 |
+ return ret;
|
|
|
318a74 |
}
|
|
|
318a74 |
--
|
|
|
318a74 |
1.8.3.1
|
|
|
318a74 |
|