summaryrefslogtreecommitdiff
path: root/tools/net/ynl/lib
diff options
context:
space:
mode:
Diffstat (limited to 'tools/net/ynl/lib')
-rw-r--r--tools/net/ynl/lib/nlspec.py6
-rw-r--r--tools/net/ynl/lib/ynl.c12
-rw-r--r--tools/net/ynl/lib/ynl.h22
-rw-r--r--tools/net/ynl/lib/ynl.py29
4 files changed, 63 insertions, 6 deletions
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index 37bcb4d8b37b..92889298b197 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -149,6 +149,7 @@ class SpecAttr(SpecElement):
Represents a single attribute type within an attr space.
Attributes:
+ type string, attribute type
value numerical ID when serialized
attr_set Attribute Set containing this attr
is_multi bool, attr may repeat multiple times
@@ -157,10 +158,13 @@ class SpecAttr(SpecElement):
len integer, optional byte length of binary types
display_hint string, hint to help choose format specifier
when displaying the value
+
+ is_auto_scalar bool, attr is a variable-size scalar
"""
def __init__(self, family, attr_set, yaml, value):
super().__init__(family, yaml)
+ self.type = yaml['type']
self.value = value
self.attr_set = attr_set
self.is_multi = yaml.get('multi-attr', False)
@@ -170,6 +174,8 @@ class SpecAttr(SpecElement):
self.len = yaml.get('len')
self.display_hint = yaml.get('display-hint')
+ self.is_auto_scalar = self.type == "sint" or self.type == "uint"
+
class SpecAttrSet(SpecElement):
""" Netlink Attribute Set class.
diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c
index 514e0d69e731..830d25097009 100644
--- a/tools/net/ynl/lib/ynl.c
+++ b/tools/net/ynl/lib/ynl.c
@@ -352,6 +352,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (u64 %s)", policy->name);
return -1;
+ case YNL_PT_UINT:
+ if (len == sizeof(__u32) || len == sizeof(__u64))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (uint %s)", policy->name);
+ return -1;
case YNL_PT_FLAG:
/* Let flags grow into real attrs, why not.. */
break;
@@ -373,6 +379,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (string %s)", policy->name);
return -1;
+ case YNL_PT_BITFIELD32:
+ if (len == sizeof(struct nla_bitfield32))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (bitfield32 %s)", policy->name);
+ return -1;
default:
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (unknown %s)", policy->name);
diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h
index 9eafa3552c16..e974378e3b8c 100644
--- a/tools/net/ynl/lib/ynl.h
+++ b/tools/net/ynl/lib/ynl.h
@@ -133,7 +133,9 @@ enum ynl_policy_type {
YNL_PT_U16,
YNL_PT_U32,
YNL_PT_U64,
+ YNL_PT_UINT,
YNL_PT_NUL_STR,
+ YNL_PT_BITFIELD32,
};
struct ynl_policy_attr {
@@ -156,7 +158,7 @@ struct ynl_parse_arg {
struct ynl_dump_list_type {
struct ynl_dump_list_type *next;
- unsigned char data[] __attribute__ ((aligned (8)));
+ unsigned char data[] __attribute__((aligned(8)));
};
extern struct ynl_dump_list_type *YNL_LIST_END;
@@ -186,7 +188,7 @@ struct ynl_ntf_base_type {
__u8 cmd;
struct ynl_ntf_base_type *next;
void (*free)(struct ynl_ntf_base_type *ntf);
- unsigned char data[] __attribute__ ((aligned (8)));
+ unsigned char data[] __attribute__((aligned(8)));
};
extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
@@ -234,4 +236,20 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
+#ifndef MNL_HAS_AUTO_SCALARS
+static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
+{
+ if (mnl_attr_get_len(attr) == 4)
+ return mnl_attr_get_u32(attr);
+ return mnl_attr_get_u64(attr);
+}
+
+static inline void
+mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
+{
+ if ((uint32_t)data == (uint64_t)data)
+ return mnl_attr_put_u32(nlh, type, data);
+ return mnl_attr_put_u64(nlh, type, data);
+}
+#endif
#endif
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 13c4b019a881..b1da4aea9336 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -130,6 +130,13 @@ class NlAttr:
format = self.get_format(attr_type, byte_order)
return format.unpack(self.raw)[0]
+ def as_auto_scalar(self, attr_type, byte_order=None):
+ if len(self.raw) != 4 and len(self.raw) != 8:
+ raise Exception(f"Auto-scalar len payload be 4 or 8 bytes, got {len(self.raw)}")
+ real_type = attr_type[0] + str(len(self.raw) * 8)
+ format = self.get_format(real_type, byte_order)
+ return format.unpack(self.raw)[0]
+
def as_strz(self):
return self.raw.decode('ascii')[:-1]
@@ -463,9 +470,16 @@ class YnlFamily(SpecFamily):
attr_payload = bytes.fromhex(value)
else:
raise Exception(f'Unknown type for binary attribute, value: {value}')
+ elif attr.is_auto_scalar:
+ scalar = int(value)
+ real_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64')
+ format = NlAttr.get_format(real_type, attr.byte_order)
+ attr_payload = format.pack(int(value))
elif attr['type'] in NlAttr.type_formats:
format = NlAttr.get_format(attr['type'], attr.byte_order)
attr_payload = format.pack(int(value))
+ elif attr['type'] in "bitfield32":
+ attr_payload = struct.pack("II", int(value["value"]), int(value["selector"]))
else:
raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}')
@@ -474,7 +488,7 @@ class YnlFamily(SpecFamily):
def _decode_enum(self, raw, attr_spec):
enum = self.consts[attr_spec['enum']]
- if 'enum-as-flags' in attr_spec and attr_spec['enum-as-flags']:
+ if enum.type == 'flags' or attr_spec.get('enum-as-flags', False):
i = 0
value = set()
while raw:
@@ -529,16 +543,23 @@ class YnlFamily(SpecFamily):
decoded = self._decode_binary(attr, attr_spec)
elif attr_spec["type"] == 'flag':
decoded = True
+ elif attr_spec.is_auto_scalar:
+ decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order)
elif attr_spec["type"] in NlAttr.type_formats:
decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order)
+ if 'enum' in attr_spec:
+ decoded = self._decode_enum(decoded, attr_spec)
elif attr_spec["type"] == 'array-nest':
decoded = self._decode_array_nest(attr, attr_spec)
+ elif attr_spec["type"] == 'bitfield32':
+ value, selector = struct.unpack("II", attr.raw)
+ if 'enum' in attr_spec:
+ value = self._decode_enum(value, attr_spec)
+ selector = self._decode_enum(selector, attr_spec)
+ decoded = {"value": value, "selector": selector}
else:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
- if 'enum' in attr_spec:
- decoded = self._decode_enum(decoded, attr_spec)
-
if not attr_spec.is_multi:
rsp[attr_spec['name']] = decoded
elif attr_spec.name in rsp: