530-ip-use-rtnl_send_check-on-flush-commands.patch 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. From 028c5aa18b5273c029f0278232d922ee1a164de6 Mon Sep 17 00:00:00 2001
  2. From: Denys Vlasenko <vda.linux@googlemail.com>
  3. Date: Wed, 22 May 2019 13:54:46 +0200
  4. Subject: ip: use rtnl_send_check() on flush commands, closes 6962
  5. function old new delta
  6. rtnl_send_check - 160 +160
  7. xrtnl_wilddump_request 64 66 +2
  8. ipneigh_list_or_flush 714 706 -8
  9. rtnl_send 69 - -69
  10. ------------------------------------------------------------------------------
  11. (add/remove: 1/1 grow/shrink: 1/1 up/down: 162/-77) Total: 85 bytes
  12. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
  13. ---
  14. networking/libiproute/ipaddress.c | 6 ++++--
  15. networking/libiproute/ipneigh.c | 9 ++++----
  16. networking/libiproute/iproute.c | 5 ++++-
  17. networking/libiproute/libnetlink.c | 43 +++++++++++++++++++++++++++++++-------
  18. networking/libiproute/libnetlink.h | 19 +++++++++++++++--
  19. 5 files changed, 65 insertions(+), 17 deletions(-)
  20. --- a/networking/libiproute/ipaddress.c
  21. +++ b/networking/libiproute/ipaddress.c
  22. @@ -23,6 +23,7 @@
  23. struct filter_t {
  24. char *label;
  25. + /* Flush cmd buf. If !NULL, print_addrinfo() constructs flush commands in it */
  26. char *flushb;
  27. struct rtnl_handle *rth;
  28. int scope, scopemask;
  29. @@ -34,6 +35,8 @@ struct filter_t {
  30. smallint showqueue;
  31. smallint oneline;
  32. smallint up;
  33. + /* Misnomer. Does not mean "flushed something" */
  34. + /* More like "flush commands were constructed by print_addrinfo()" */
  35. smallint flushed;
  36. inet_prefix pfx;
  37. } FIX_ALIASING;
  38. @@ -201,7 +204,7 @@ static NOINLINE int print_linkinfo(const
  39. static int flush_update(void)
  40. {
  41. - if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  42. + if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  43. bb_perror_msg("can't send flush request");
  44. return -1;
  45. }
  46. @@ -507,7 +510,6 @@ int FAST_FUNC ipaddr_list_or_flush(char
  47. xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
  48. }
  49. -
  50. if (G_filter.family && G_filter.family != AF_PACKET) {
  51. struct nlmsg_list **lp;
  52. lp = &linfo;
  53. --- a/networking/libiproute/ipneigh.c
  54. +++ b/networking/libiproute/ipneigh.c
  55. @@ -32,7 +32,10 @@ struct filter_t {
  56. int state;
  57. int unused_only;
  58. inet_prefix pfx;
  59. + /* Misnomer. Does not mean "flushed N something" */
  60. + /* More like "no_of_flush_commands_constructed_by_print_neigh()" */
  61. int flushed;
  62. + /* Flush cmd buf. If !NULL, print_neigh() constructs flush commands in it */
  63. char *flushb;
  64. int flushp;
  65. int flushe;
  66. @@ -45,7 +48,7 @@ typedef struct filter_t filter_t;
  67. static int flush_update(void)
  68. {
  69. - if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  70. + if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  71. bb_perror_msg("can't send flush request");
  72. return -1;
  73. }
  74. @@ -299,9 +302,7 @@ static int FAST_FUNC ipneigh_list_or_flu
  75. G_filter.rth = &rth;
  76. while (round < MAX_ROUNDS) {
  77. - if (xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH) < 0) {
  78. - bb_perror_msg_and_die("can't send dump request");
  79. - }
  80. + xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH);
  81. G_filter.flushed = 0;
  82. if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) {
  83. bb_perror_msg_and_die("flush terminated");
  84. --- a/networking/libiproute/iproute.c
  85. +++ b/networking/libiproute/iproute.c
  86. @@ -26,7 +26,10 @@
  87. struct filter_t {
  88. int tb;
  89. + /* Misnomer. Does not mean "flushed something" */
  90. + /* More like "flush commands were constructed by print_route()" */
  91. smallint flushed;
  92. + /* Flush cmd buf. If !NULL, print_route() constructs flush commands in it */
  93. char *flushb;
  94. int flushp;
  95. int flushe;
  96. @@ -53,7 +56,7 @@ typedef struct filter_t filter_t;
  97. static int flush_update(void)
  98. {
  99. - if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  100. + if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
  101. bb_perror_msg("can't send flush request");
  102. return -1;
  103. }
  104. --- a/networking/libiproute/libnetlink.c
  105. +++ b/networking/libiproute/libnetlink.c
  106. @@ -34,7 +34,7 @@ void FAST_FUNC xrtnl_open(struct rtnl_ha
  107. rth->seq = time(NULL);
  108. }
  109. -int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
  110. +void FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
  111. {
  112. struct {
  113. struct nlmsghdr nlh;
  114. @@ -48,18 +48,45 @@ int FAST_FUNC xrtnl_wilddump_request(str
  115. req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  116. req.g.rtgen_family = family;
  117. - return rtnl_send(rth, (void*)&req, sizeof(req));
  118. + rtnl_send(rth, (void*)&req, sizeof(req));
  119. }
  120. -//TODO: pass rth->fd instead of full rth?
  121. -int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
  122. +/* A version which checks for e.g. EPERM errors.
  123. + * Try: setuidgid 1:1 ip addr flush dev eth0
  124. + */
  125. +int FAST_FUNC rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
  126. {
  127. - struct sockaddr_nl nladdr;
  128. + struct nlmsghdr *h;
  129. + int status;
  130. + char resp[1024];
  131. +
  132. + status = write(rth->fd, buf, len);
  133. + if (status < 0)
  134. + return status;
  135. +
  136. + /* Check for immediate errors */
  137. + status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
  138. + if (status < 0) {
  139. + if (errno == EAGAIN) /* if no error, this happens */
  140. + return 0;
  141. + return -1;
  142. + }
  143. +
  144. + for (h = (struct nlmsghdr *)resp;
  145. + NLMSG_OK(h, status);
  146. + h = NLMSG_NEXT(h, status)
  147. + ) {
  148. + if (h->nlmsg_type == NLMSG_ERROR) {
  149. + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  150. + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
  151. + bb_error_msg("ERROR truncated");
  152. + else
  153. + errno = -err->error;
  154. + return -1;
  155. + }
  156. + }
  157. - memset(&nladdr, 0, sizeof(nladdr));
  158. - nladdr.nl_family = AF_NETLINK;
  159. -
  160. - return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
  161. + return 0;
  162. }
  163. int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
  164. --- a/networking/libiproute/libnetlink.h
  165. +++ b/networking/libiproute/libnetlink.h
  166. @@ -20,7 +20,7 @@ struct rtnl_handle {
  167. extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC;
  168. #define rtnl_close(rth) (close((rth)->fd))
  169. -extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
  170. +extern void xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
  171. extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC;
  172. extern int xrtnl_dump_filter(struct rtnl_handle *rth,
  173. int (*filter)(const struct sockaddr_nl*, struct nlmsghdr *n, void*) FAST_FUNC,
  174. @@ -34,8 +34,23 @@ extern int rtnl_talk(struct rtnl_handle
  175. int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
  176. void *jarg) FAST_FUNC;
  177. -extern int rtnl_send(struct rtnl_handle *rth, char *buf, int) FAST_FUNC;
  178. +int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) FAST_FUNC;
  179. +//TODO: pass rth->fd instead of full rth?
  180. +static ALWAYS_INLINE void rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
  181. +{
  182. + // Used to be:
  183. + //struct sockaddr_nl nladdr;
  184. + //memset(&nladdr, 0, sizeof(nladdr));
  185. + //nladdr.nl_family = AF_NETLINK;
  186. + //return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
  187. + // iproute2-4.2.0 simplified the above to:
  188. + //return send(rth->fd, buf, len, 0);
  189. +
  190. + // We are using even shorter:
  191. + xwrite(rth->fd, buf, len);
  192. + // and convert to void, inline.
  193. +}
  194. extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC;
  195. extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC;