ip: use rtnl_send_check() on flush commands, closes 6962
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 22 May 2019 11:54:46 +0000 (13:54 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 22 May 2019 11:54:46 +0000 (13:54 +0200)
function                                             old     new   delta
rtnl_send_check                                        -     160    +160
xrtnl_wilddump_request                                64      66      +2
ipneigh_list_or_flush                                714     706      -8
rtnl_send                                             69       -     -69
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/1 up/down: 162/-77)            Total: 85 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/libiproute/ipaddress.c
networking/libiproute/ipneigh.c
networking/libiproute/iproute.c
networking/libiproute/libnetlink.c
networking/libiproute/libnetlink.h

index fc6a4fb773349abadbf360000a33f3bc63fb87b8..7b7e0154b17572dbf846ed83d101b89816fdca38 100644 (file)
@@ -23,6 +23,7 @@
 
 struct filter_t {
        char *label;
+       /* Flush cmd buf. If !NULL, print_addrinfo() constructs flush commands in it */
        char *flushb;
        struct rtnl_handle *rth;
        int scope, scopemask;
@@ -34,6 +35,8 @@ struct filter_t {
        smallint showqueue;
        smallint oneline;
        smallint up;
+       /* Misnomer. Does not mean "flushed something" */
+       /* More like "flush commands were constructed by print_addrinfo()" */
        smallint flushed;
        inet_prefix pfx;
 } FIX_ALIASING;
@@ -201,7 +204,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
 
 static int flush_update(void)
 {
-       if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
+       if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
                bb_perror_msg("can't send flush request");
                return -1;
        }
@@ -510,7 +513,6 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
                xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
        }
 
-
        if (G_filter.family && G_filter.family != AF_PACKET) {
                struct nlmsg_list **lp;
                lp = &linfo;
index f572414e9ace3ac1c0ee858773a14966d838c572..984dd4bdd5b27923f23739b57e02a4ec96f70067 100644 (file)
@@ -32,7 +32,10 @@ struct filter_t {
        int state;
        int unused_only;
        inet_prefix pfx;
+       /* Misnomer. Does not mean "flushed N something" */
+       /* More like "no_of_flush_commands_constructed_by_print_neigh()" */
        int flushed;
+       /* Flush cmd buf. If !NULL, print_neigh() constructs flush commands in it */
        char *flushb;
        int flushp;
        int flushe;
@@ -45,7 +48,7 @@ typedef struct filter_t filter_t;
 
 static int flush_update(void)
 {
-       if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
+       if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
                bb_perror_msg("can't send flush request");
                return -1;
        }
@@ -299,9 +302,7 @@ static int FAST_FUNC ipneigh_list_or_flush(char **argv, int flush)
                G_filter.rth = &rth;
 
                while (round < MAX_ROUNDS) {
-                       if (xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH) < 0) {
-                               bb_perror_msg_and_die("can't send dump request");
-                       }
+                       xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH);
                        G_filter.flushed = 0;
                        if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) {
                                bb_perror_msg_and_die("flush terminated");
index 2a8610ea66376f3d864c6b0f40121d6918ea42d3..b11078ed59ddf766229d3658702c778e30c60060 100644 (file)
 
 struct filter_t {
        int tb;
+       /* Misnomer. Does not mean "flushed something" */
+       /* More like "flush commands were constructed by print_route()" */
        smallint flushed;
+       /* Flush cmd buf. If !NULL, print_route() constructs flush commands in it */
        char *flushb;
        int flushp;
        int flushe;
@@ -53,7 +56,7 @@ typedef struct filter_t filter_t;
 
 static int flush_update(void)
 {
-       if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
+       if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
                bb_perror_msg("can't send flush request");
                return -1;
        }
index 40955fcae63eb92cb3ec5161701495c2186dac01..b0d4166ac47906c218640f09bfa22ccc77cff02a 100644 (file)
@@ -34,7 +34,7 @@ void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
        rth->seq = time(NULL);
 }
 
-int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
+void FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
 {
        struct {
                struct nlmsghdr nlh;
@@ -48,18 +48,45 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty
        req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
        req.g.rtgen_family = family;
 
-       return rtnl_send(rth, (void*)&req, sizeof(req));
+       rtnl_send(rth, (void*)&req, sizeof(req));
 }
 
-//TODO: pass rth->fd instead of full rth?
-int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
+/* A version which checks for e.g. EPERM errors.
+ * Try: setuidgid 1:1 ip addr flush dev eth0
+ */
+int FAST_FUNC rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
 {
-       struct sockaddr_nl nladdr;
+       struct nlmsghdr *h;
+       int status;
+       char resp[1024];
 
-       memset(&nladdr, 0, sizeof(nladdr));
-       nladdr.nl_family = AF_NETLINK;
+       status = write(rth->fd, buf, len);
+       if (status < 0)
+               return status;
+
+       /* Check for immediate errors */
+       status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
+       if (status < 0) {
+               if (errno == EAGAIN) /* if no error, this happens */
+                       return 0;
+               return -1;
+       }
 
-       return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
+       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)))
+                               bb_error_msg("ERROR truncated");
+                       else
+                               errno = -err->error;
+                       return -1;
+               }
+       }
+
+       return 0;
 }
 
 int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
index 51bee2d670ece11ecf431b217070a905b7b9bfc6..1b082e0199329d4fa07d2fb71e0a83ab5d1bf15c 100644 (file)
@@ -20,7 +20,7 @@ struct rtnl_handle {
 
 extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC;
 #define rtnl_close(rth) (close((rth)->fd))
-extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
+extern void xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC;
 extern int xrtnl_dump_filter(struct rtnl_handle *rth,
                int (*filter)(const struct sockaddr_nl*, struct nlmsghdr *n, void*) FAST_FUNC,
@@ -34,8 +34,23 @@ extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
                int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
                void *jarg) FAST_FUNC;
 
-extern int rtnl_send(struct rtnl_handle *rth, char *buf, int) FAST_FUNC;
+int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) FAST_FUNC;
+//TODO: pass rth->fd instead of full rth?
+static ALWAYS_INLINE void rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
+{
+       // Used to be:
+       //struct sockaddr_nl nladdr;
+       //memset(&nladdr, 0, sizeof(nladdr));
+       //nladdr.nl_family = AF_NETLINK;
+       //return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
 
+       // iproute2-4.2.0 simplified the above to:
+       //return send(rth->fd, buf, len, 0);
+
+       // We are using even shorter:
+       xwrite(rth->fd, buf, len);
+       // and convert to void, inline.
+}
 
 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC;
 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC;