Commit 3bc1c4f2 authored by Ben Greear's avatar Ben Greear Committed by Stephen Hemminger

iproute2: Fix filtering related to flushing IP addresses.

The old 'ip addr flush' logic had several flaws:

* It reversed logic for primary v/s secondary flags
  (though, it sort of worked right anyway)

* The code tried to remove secondaries and then primaries,
  but in practice, it always removed one primary per loop,
  which not at all efficient.

* The filter logic in the core would run only the first
  filter in most cases.

* If you used '-s -s', the ifa_flags member would be
  modified, which could make future filters fail
  to function fine.

This patch attempts to fix all of these issues.
Tested-by: default avatarBrian Haley <brian.haley@hp.com>
Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
parent a130b49b
...@@ -453,6 +453,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, ...@@ -453,6 +453,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
struct ifaddrmsg *ifa = NLMSG_DATA(n); struct ifaddrmsg *ifa = NLMSG_DATA(n);
int len = n->nlmsg_len; int len = n->nlmsg_len;
int deprecated = 0; int deprecated = 0;
/* Use local copy of ifa_flags to not interfere with filtering code */
unsigned int ifa_flags;
struct rtattr * rta_tb[IFA_MAX+1]; struct rtattr * rta_tb[IFA_MAX+1];
char abuf[256]; char abuf[256];
SPRINT_BUF(b1); SPRINT_BUF(b1);
...@@ -572,40 +574,41 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, ...@@ -572,40 +574,41 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
abuf, sizeof(abuf))); abuf, sizeof(abuf)));
} }
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
ifa_flags = ifa->ifa_flags;
if (ifa->ifa_flags&IFA_F_SECONDARY) { if (ifa->ifa_flags&IFA_F_SECONDARY) {
ifa->ifa_flags &= ~IFA_F_SECONDARY; ifa_flags &= ~IFA_F_SECONDARY;
if (ifa->ifa_family == AF_INET6) if (ifa->ifa_family == AF_INET6)
fprintf(fp, "temporary "); fprintf(fp, "temporary ");
else else
fprintf(fp, "secondary "); fprintf(fp, "secondary ");
} }
if (ifa->ifa_flags&IFA_F_TENTATIVE) { if (ifa->ifa_flags&IFA_F_TENTATIVE) {
ifa->ifa_flags &= ~IFA_F_TENTATIVE; ifa_flags &= ~IFA_F_TENTATIVE;
fprintf(fp, "tentative "); fprintf(fp, "tentative ");
} }
if (ifa->ifa_flags&IFA_F_DEPRECATED) { if (ifa->ifa_flags&IFA_F_DEPRECATED) {
ifa->ifa_flags &= ~IFA_F_DEPRECATED; ifa_flags &= ~IFA_F_DEPRECATED;
deprecated = 1; deprecated = 1;
fprintf(fp, "deprecated "); fprintf(fp, "deprecated ");
} }
if (ifa->ifa_flags&IFA_F_HOMEADDRESS) { if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
ifa->ifa_flags &= ~IFA_F_HOMEADDRESS; ifa_flags &= ~IFA_F_HOMEADDRESS;
fprintf(fp, "home "); fprintf(fp, "home ");
} }
if (ifa->ifa_flags&IFA_F_NODAD) { if (ifa->ifa_flags&IFA_F_NODAD) {
ifa->ifa_flags &= ~IFA_F_NODAD; ifa_flags &= ~IFA_F_NODAD;
fprintf(fp, "nodad "); fprintf(fp, "nodad ");
} }
if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
fprintf(fp, "dynamic "); fprintf(fp, "dynamic ");
} else } else
ifa->ifa_flags &= ~IFA_F_PERMANENT; ifa_flags &= ~IFA_F_PERMANENT;
if (ifa->ifa_flags&IFA_F_DADFAILED) { if (ifa->ifa_flags&IFA_F_DADFAILED) {
ifa->ifa_flags &= ~IFA_F_DADFAILED; ifa_flags &= ~IFA_F_DADFAILED;
fprintf(fp, "dadfailed "); fprintf(fp, "dadfailed ");
} }
if (ifa->ifa_flags) if (ifa_flags)
fprintf(fp, "flags %02x ", ifa->ifa_flags); fprintf(fp, "flags %02x ", ifa_flags);
if (rta_tb[IFA_LABEL]) if (rta_tb[IFA_LABEL])
fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL])); fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
if (rta_tb[IFA_CACHEINFO]) { if (rta_tb[IFA_CACHEINFO]) {
...@@ -638,7 +641,7 @@ int print_addrinfo_primary(const struct sockaddr_nl *who, struct nlmsghdr *n, ...@@ -638,7 +641,7 @@ int print_addrinfo_primary(const struct sockaddr_nl *who, struct nlmsghdr *n,
{ {
struct ifaddrmsg *ifa = NLMSG_DATA(n); struct ifaddrmsg *ifa = NLMSG_DATA(n);
if (!ifa->ifa_flags & IFA_F_SECONDARY) if (ifa->ifa_flags & IFA_F_SECONDARY)
return 0; return 0;
return print_addrinfo(who, n, arg); return print_addrinfo(who, n, arg);
...@@ -649,7 +652,7 @@ int print_addrinfo_secondary(const struct sockaddr_nl *who, struct nlmsghdr *n, ...@@ -649,7 +652,7 @@ int print_addrinfo_secondary(const struct sockaddr_nl *who, struct nlmsghdr *n,
{ {
struct ifaddrmsg *ifa = NLMSG_DATA(n); struct ifaddrmsg *ifa = NLMSG_DATA(n);
if (ifa->ifa_flags & IFA_F_SECONDARY) if (!(ifa->ifa_flags & IFA_F_SECONDARY))
return 0; return 0;
return print_addrinfo(who, n, arg); return print_addrinfo(who, n, arg);
...@@ -849,6 +852,7 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush) ...@@ -849,6 +852,7 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush)
exit(1); exit(1);
} }
if (filter.flushed == 0) { if (filter.flushed == 0) {
flush_done:
if (show_stats) { if (show_stats) {
if (round == 0) if (round == 0)
printf("Nothing to flush.\n"); printf("Nothing to flush.\n");
...@@ -866,6 +870,14 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush) ...@@ -866,6 +870,14 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush)
printf("\n*** Round %d, deleting %d addresses ***\n", round, filter.flushed); printf("\n*** Round %d, deleting %d addresses ***\n", round, filter.flushed);
fflush(stdout); fflush(stdout);
} }
/* If we are flushing, and specifying primary, then we
* want to flush only a single round. Otherwise, we'll
* start flushing secondaries that were promoted to
* primaries.
*/
if (!(filter.flags & IFA_F_SECONDARY) && (filter.flagmask & IFA_F_SECONDARY))
goto flush_done;
} }
fprintf(stderr, "*** Flush remains incomplete after %d rounds. ***\n", MAX_ROUNDS); fflush(stderr); fprintf(stderr, "*** Flush remains incomplete after %d rounds. ***\n", MAX_ROUNDS); fflush(stderr);
return 1; return 1;
......
...@@ -189,6 +189,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, ...@@ -189,6 +189,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
while (1) { while (1) {
int status; int status;
const struct rtnl_dump_filter_arg *a; const struct rtnl_dump_filter_arg *a;
int found_done = 0;
int msglen = 0;
iov.iov_len = sizeof(buf); iov.iov_len = sizeof(buf);
status = recvmsg(rth->fd, &msg, 0); status = recvmsg(rth->fd, &msg, 0);
...@@ -208,8 +210,9 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, ...@@ -208,8 +210,9 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
for (a = arg; a->filter; a++) { for (a = arg; a->filter; a++) {
struct nlmsghdr *h = (struct nlmsghdr*)buf; struct nlmsghdr *h = (struct nlmsghdr*)buf;
msglen = status;
while (NLMSG_OK(h, status)) { while (NLMSG_OK(h, msglen)) {
int err; int err;
if (nladdr.nl_pid != 0 || if (nladdr.nl_pid != 0 ||
...@@ -224,8 +227,10 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, ...@@ -224,8 +227,10 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
goto skip_it; goto skip_it;
} }
if (h->nlmsg_type == NLMSG_DONE) if (h->nlmsg_type == NLMSG_DONE) {
return 0; found_done = 1;
break; /* process next filter */
}
if (h->nlmsg_type == NLMSG_ERROR) { if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
...@@ -242,15 +247,19 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, ...@@ -242,15 +247,19 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
return err; return err;
skip_it: skip_it:
h = NLMSG_NEXT(h, status); h = NLMSG_NEXT(h, msglen);
} }
} while (0); }
if (found_done)
return 0;
if (msg.msg_flags & MSG_TRUNC) { if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n"); fprintf(stderr, "Message truncated\n");
continue; continue;
} }
if (status) { if (msglen) {
fprintf(stderr, "!!!Remnant of size %d\n", status); fprintf(stderr, "!!!Remnant of size %d\n", msglen);
exit(1); exit(1);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment