summaryrefslogtreecommitdiff
path: root/dcb
diff options
context:
space:
mode:
authorPetr Machata <me@pmachata.org>2021-01-02 01:03:38 +0100
committerDavid Ahern <dsahern@kernel.org>2021-01-18 04:09:29 +0000
commite59876ff556bc796eee7f6e68984a44e8f2d837b (patch)
tree9ea7e7237f48f3da79e818616e75f57a0ee8f2de /dcb
parent69290c32dca82368ab74f23aaca7866d506c7cde (diff)
downloadiproute2-e59876ff556bc796eee7f6e68984a44e8f2d837b.tar.gz
dcb: Generalize dcb_get_attribute()
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>
Diffstat (limited to 'dcb')
-rw-r--r--dcb/dcb.c79
-rw-r--r--dcb/dcb.h4
2 files changed, 68 insertions, 15 deletions
diff --git a/dcb/dcb.c b/dcb/dcb.c
index 9bbbbfa7..89f9b0ec 100644
--- 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;
}
diff --git a/dcb/dcb.h b/dcb/dcb.h
index da14937c..8c7327a4 100644
--- 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);