net/mlx5: fix Netlink communication routine
authorViacheslav Ovsiienko <viacheslavo@mellanox.com>
Mon, 12 Nov 2018 20:01:40 +0000 (20:01 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 15 Nov 2018 22:54:53 +0000 (23:54 +0100)
While receiving the Netlink reply messages we should stop at DONE
or ACK message. The existing implementation stops at DONE message
or if no multiple message flag set ( NLM_F_MULTI). It prevents
the single query requests from working, these requests send the
single reply message without multi-message flag followed by
ACK message. This patch fixes receiving part of Netlink
communication routine.

Fixes: 6e74990b3463 ("net/mlx5: update E-Switch VXLAN netlink routines")

Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
Acked-by: Shahaf Shuler <shahafs@mellanox.com>
drivers/net/mlx5/mlx5_flow_tcf.c

index 5a38940..4d154b6 100644 (file)
@@ -3732,44 +3732,60 @@ flow_tcf_nl_ack(struct mlx5_flow_tcf_context *tcf,
 {
        unsigned int portid = mnl_socket_get_portid(tcf->nl);
        uint32_t seq = tcf->seq++;
-       int err, ret;
+       int ret, err = 0;
 
        assert(tcf->nl);
        assert(tcf->buf);
-       if (!seq)
+       if (!seq) {
                /* seq 0 is reserved for kernel event-driven notifications. */
                seq = tcf->seq++;
+       }
        nlh->nlmsg_seq = seq;
        nlh->nlmsg_flags |= NLM_F_ACK;
        ret = mnl_socket_sendto(tcf->nl, nlh, nlh->nlmsg_len);
-       err = (ret <= 0) ? errno : 0;
+       if (ret <= 0) {
+               /* Message send error occurres. */
+               rte_errno = errno;
+               return -rte_errno;
+       }
        nlh = (struct nlmsghdr *)(tcf->buf);
        /*
         * The following loop postpones non-fatal errors until multipart
         * messages are complete.
         */
-       if (ret > 0)
-               while (true) {
-                       ret = mnl_socket_recvfrom(tcf->nl, tcf->buf,
-                                                 tcf->buf_size);
+       while (true) {
+               ret = mnl_socket_recvfrom(tcf->nl, tcf->buf, tcf->buf_size);
+               if (ret < 0) {
+                       err = errno;
+                       /*
+                        * In case of overflow Will receive till
+                        * end of multipart message. We may lost part
+                        * of reply messages but mark and return an error.
+                        */
+                       if (err != ENOSPC ||
+                           !(nlh->nlmsg_flags & NLM_F_MULTI) ||
+                           nlh->nlmsg_type == NLMSG_DONE)
+                               break;
+               } else {
+                       ret = mnl_cb_run(nlh, ret, seq, portid, cb, arg);
+                       if (!ret) {
+                               /*
+                                * libmnl returns 0 if DONE or
+                                * success ACK message found.
+                                */
+                               break;
+                       }
                        if (ret < 0) {
+                               /*
+                                * ACK message with error found
+                                * or some error occurred.
+                                */
                                err = errno;
-                               if (err != ENOSPC)
-                                       break;
-                       }
-                       if (!err) {
-                               ret = mnl_cb_run(nlh, ret, seq, portid,
-                                                cb, arg);
-                               if (ret < 0) {
-                                       err = errno;
-                                       break;
-                               }
-                       }
-                       /* Will receive till end of multipart message */
-                       if (!(nlh->nlmsg_flags & NLM_F_MULTI) ||
-                             nlh->nlmsg_type == NLMSG_DONE)
                                break;
+                       }
+                       /* We should continue receiving. */
                }
+       }
        if (!err)
                return 0;
        rte_errno = err;