]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
dcb: Generalize dcb_get_attribute()
authorPetr Machata <me@pmachata.org>
Sat, 2 Jan 2021 00:03:38 +0000 (01:03 +0100)
committerDavid Ahern <dsahern@kernel.org>
Mon, 18 Jan 2021 04:09:29 +0000 (04:09 +0000)
The function dcb_get_attribute() assumes that the caller knows the exact
size of the looked-for payload. It also assumes that the response comes
wrapped in an DCB_ATTR_IEEE nest. The former assumption does not hold for
the IEEE APP table, which has variable size. The latter one does not hold
for DCBX, which is not IEEE-nested, and also for any CEE attributes, which
would come CEE-nested.

Factor out the payload extractor from the current dcb_get_attribute() code,
and put into a helper. Then rewrite dcb_get_attribute() compatibly in terms
of the new function. Introduce dcb_get_attribute_va() as a thin wrapper for
IEEE-nested access, and dcb_get_attribute_bare() for access to attributes
that are not nested.

Signed-off-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
dcb/dcb.c
dcb/dcb.h

index 9bbbbfa74619031bd33e1a6d16326cc580e8db13..89f9b0ec7ef9f02881b0710255aba2d2ad15a560 100644 (file)
--- a/dcb/dcb.c
+++ b/dcb/dcb.c
@@ -59,25 +59,19 @@ static void dcb_free(struct dcb *dcb)
 struct dcb_get_attribute {
        struct dcb *dcb;
        int attr;
-       void *data;
-       size_t data_len;
+       void *payload;
+       __u16 payload_len;
 };
 
 static int dcb_get_attribute_attr_ieee_cb(const struct nlattr *attr, void *data)
 {
        struct dcb_get_attribute *ga = data;
-       uint16_t len;
 
        if (mnl_attr_get_type(attr) != ga->attr)
                return MNL_CB_OK;
 
-       len = mnl_attr_get_payload_len(attr);
-       if (len != ga->data_len) {
-               fprintf(stderr, "Wrong len %d, expected %zd\n", len, ga->data_len);
-               return MNL_CB_ERROR;
-       }
-
-       memcpy(ga->data, mnl_attr_get_payload(attr), ga->data_len);
+       ga->payload = mnl_attr_get_payload(attr);
+       ga->payload_len = mnl_attr_get_payload_len(attr);
        return MNL_CB_STOP;
 }
 
@@ -94,6 +88,16 @@ static int dcb_get_attribute_cb(const struct nlmsghdr *nlh, void *data)
        return mnl_attr_parse(nlh, sizeof(struct dcbmsg), dcb_get_attribute_attr_cb, data);
 }
 
+static int dcb_get_attribute_bare_cb(const struct nlmsghdr *nlh, void *data)
+{
+       /* Bare attributes (e.g. DCB_ATTR_DCBX) are not wrapped inside an IEEE
+        * container, so this does not have to go through unpacking in
+        * dcb_get_attribute_attr_cb().
+        */
+       return mnl_attr_parse(nlh, sizeof(struct dcbmsg),
+                             dcb_get_attribute_attr_ieee_cb, data);
+}
+
 struct dcb_set_attribute_response {
        int response_attr;
 };
@@ -155,25 +159,70 @@ static struct nlmsghdr *dcb_prepare(struct dcb *dcb, const char *dev,
        return nlh;
 }
 
-int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr, void *data, size_t data_len)
+static int __dcb_get_attribute(struct dcb *dcb, int command,
+                              const char *dev, int attr,
+                              void **payload_p, __u16 *payload_len_p,
+                              int (*get_attribute_cb)(const struct nlmsghdr *nlh,
+                                                      void *data))
 {
        struct dcb_get_attribute ga;
        struct nlmsghdr *nlh;
        int ret;
 
-       nlh = dcb_prepare(dcb, dev, RTM_GETDCB, DCB_CMD_IEEE_GET);
+       nlh = dcb_prepare(dcb, dev, RTM_GETDCB, command);
 
        ga = (struct dcb_get_attribute) {
                .dcb = dcb,
                .attr = attr,
-               .data = data,
-               .data_len = data_len,
+               .payload = NULL,
        };
-       ret = dcb_talk(dcb, nlh, dcb_get_attribute_cb, &ga);
+       ret = dcb_talk(dcb, nlh, get_attribute_cb, &ga);
        if (ret) {
                perror("Attribute read");
                return ret;
        }
+       if (ga.payload == NULL) {
+               perror("Attribute not found");
+               return -ENOENT;
+       }
+
+       *payload_p = ga.payload;
+       *payload_len_p = ga.payload_len;
+       return 0;
+}
+
+int dcb_get_attribute_va(struct dcb *dcb, const char *dev, int attr,
+                        void **payload_p, __u16 *payload_len_p)
+{
+       return __dcb_get_attribute(dcb, DCB_CMD_IEEE_GET, dev, attr,
+                                  payload_p, payload_len_p,
+                                  dcb_get_attribute_cb);
+}
+
+int dcb_get_attribute_bare(struct dcb *dcb, int cmd, const char *dev, int attr,
+                          void **payload_p, __u16 *payload_len_p)
+{
+       return __dcb_get_attribute(dcb, cmd, dev, attr,
+                                  payload_p, payload_len_p,
+                                  dcb_get_attribute_bare_cb);
+}
+
+int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr, void *data, size_t data_len)
+{
+       __u16 payload_len;
+       void *payload;
+       int ret;
+
+       ret = dcb_get_attribute_va(dcb, dev, attr, &payload, &payload_len);
+       if (ret)
+               return ret;
+
+       if (payload_len != data_len) {
+               fprintf(stderr, "Wrong len %d, expected %zd\n", payload_len, data_len);
+               return -EINVAL;
+       }
+
+       memcpy(data, payload, data_len);
        return 0;
 }
 
index da14937c89258d22e3f8a954ce5d9534369dc8fc..8c7327a435888f036abb4c2a260254b73215058f 100644 (file)
--- a/dcb/dcb.h
+++ b/dcb/dcb.h
@@ -33,9 +33,13 @@ int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr,
                      void *data, size_t data_len);
 int dcb_set_attribute(struct dcb *dcb, const char *dev, int attr,
                      const void *data, size_t data_len);
+int dcb_get_attribute_va(struct dcb *dcb, const char *dev, int attr,
+                        void **payload_p, __u16 *payload_len_p);
 int dcb_set_attribute_va(struct dcb *dcb, int command, const char *dev,
                         int (*cb)(struct dcb *dcb, struct nlmsghdr *nlh, void *data),
                         void *data);
+int dcb_get_attribute_bare(struct dcb *dcb, int cmd, const char *dev, int attr,
+                          void **payload_p, __u16 *payload_len_p);
 int dcb_set_attribute_bare(struct dcb *dcb, int command, const char *dev,
                           int attr, const void *data, size_t data_len,
                           int response_attr);