netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iproute2 flush: handle larger tables and deleted entries
@ 2009-07-13 16:39 Gautam Kachroo
  2009-07-14  9:38 ` Patrick McHardy
  0 siblings, 1 reply; 8+ messages in thread
From: Gautam Kachroo @ 2009-07-13 16:39 UTC (permalink / raw)
  To: netdev

use a new netlink socket when sending flush messages to avoid reading
any pending data on the existing netlink socket.

read all of the response from the netlink request -- this response can
be split over multiple recv calls, pretty much one per netlink request
message. ENOENT errors, which correspond to attempts to delete an
already deleted entry, are ignored. Other errors are not ignored.

Signed-off-by: Gautam Kachroo <gk@aristanetworks.com>
---

resending in plain text format

rtnl_send_check calls recv after sending the delete messages. It does
this to catch errors, e.g. user doesn't have permissions to send
netlink messages. It treats *any* response as an error, even if the
message is not an NLMSG_ERROR. However, this doesn't work if the dump
is in the middle of being processed. recv will return the next chunk
of the dump. This was causing the flush operation to bail early, e.g.
when there is a large arp cache.

Ignoring ENOENT lets flush succeed even if entries have been deleted
from underneath the flush.


--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -111,7 +111,10 @@ int rtnl_send(struct rtnl_handle *rth, const char
*buf, int len)
        return send(rth->fd, buf, len, 0);
 }

-int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
+/* send the message in buf using the socket in rth and check for errors
+   (ignoring ENOENT errors)
+*/
+int rtnl_send_check_impl(struct rtnl_handle *rth, const char *buf, int len)
 {
        struct nlmsghdr *h;
        int status;
@@ -122,28 +125,51 @@ int rtnl_send_check(struct rtnl_handle *rth,
const char *buf, int len)
                return status;

        /* Check for errors */
-       status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
-       if (status < 0) {
-               if (errno == EAGAIN)
-                       return 0;
-               return -1;
-       }
+       for (;;) {
+               status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
+               if (status < 0) {
+                       if (errno == EAGAIN)
+                               return 0;
+                       return -1;
+               }

-       for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
-            h = NLMSG_NEXT(h, status)) {
-               if (h->nlmsg_type == NLMSG_ERROR) {
-                       struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
-                       if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct
nlmsgerr)))
-                               fprintf(stderr, "ERROR truncated\n");
-                       else
-                               errno = -err->error;
+               for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
+                    h = NLMSG_NEXT(h, status)) {
+                       if (h->nlmsg_type == NLMSG_ERROR) {
+                               struct nlmsgerr *err = (struct
nlmsgerr*)NLMSG_DATA(h);
+                               if (h->nlmsg_len <
NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+                                       fprintf(stderr, "ERROR truncated\n");
+                                       return -1;
+                               }
+                               else {
+                                       if (err->error != -ENOENT) {
+                                               errno = -err->error;
+                                               return -1;
+                                       }
+                               }
+                       }
                }
-               return -1;
        }

        return 0;
 }

+/* creates a netlink socket and passes it to rtnl_send_check_impl to send the
+   message in buf
+*/
+int rtnl_send_check(struct rtnl_handle *unused, const char *buf, int len)
+{
+       struct rtnl_handle rth = { .fd = -1 };
+       int ret;
+       if (rtnl_open(&rth, 0) < 0) {
+               fprintf(stderr, "Cannot open rtnetlink\n");
+               return -1;
+       }
+       ret = rtnl_send_check_impl(&rth, buf, len);
+       rtnl_close(&rth);
+       return ret;
+}
+
 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
 {
        struct nlmsghdr nlh;

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-08-21  0:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-13 16:39 [PATCH] iproute2 flush: handle larger tables and deleted entries Gautam Kachroo
2009-07-14  9:38 ` Patrick McHardy
2009-07-14 16:45   ` Gautam Kachroo
2009-07-15 15:19     ` Patrick McHardy
2009-07-15 17:50       ` Gautam Kachroo
2009-07-15 19:19         ` Stephen Hemminger
2009-07-15 22:04           ` Gautam Kachroo
2009-08-21  0:08             ` Gautam Kachroo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).