summaryrefslogtreecommitdiffstats
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.py55
-rw-r--r--tools/net/ynl/lib/ynl-priv.h144
-rw-r--r--tools/net/ynl/lib/ynl.c14
-rw-r--r--tools/net/ynl/lib/ynl.h149
-rw-r--r--tools/net/ynl/lib/ynl.py98
5 files changed, 283 insertions, 177 deletions
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index 92889298b197..44f13e383e8a 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -158,6 +158,9 @@ class SpecAttr(SpecElement):
len integer, optional byte length of binary types
display_hint string, hint to help choose format specifier
when displaying the value
+ sub_message string, name of sub message type
+ selector string, name of attribute used to select
+ sub-message type
is_auto_scalar bool, attr is a variable-size scalar
"""
@@ -173,6 +176,8 @@ class SpecAttr(SpecElement):
self.byte_order = yaml.get('byte-order')
self.len = yaml.get('len')
self.display_hint = yaml.get('display-hint')
+ self.sub_message = yaml.get('sub-message')
+ self.selector = yaml.get('selector')
self.is_auto_scalar = self.type == "sint" or self.type == "uint"
@@ -278,6 +283,47 @@ class SpecStruct(SpecElement):
return self.members.items()
+class SpecSubMessage(SpecElement):
+ """ Netlink sub-message definition
+
+ Represents a set of sub-message formats for polymorphic nlattrs
+ that contain type-specific sub messages.
+
+ Attributes:
+ name string, name of sub-message definition
+ formats dict of sub-message formats indexed by match value
+ """
+ def __init__(self, family, yaml):
+ super().__init__(family, yaml)
+
+ self.formats = collections.OrderedDict()
+ for elem in self.yaml['formats']:
+ format = self.new_format(family, elem)
+ self.formats[format.value] = format
+
+ def new_format(self, family, format):
+ return SpecSubMessageFormat(family, format)
+
+
+class SpecSubMessageFormat(SpecElement):
+ """ Netlink sub-message definition
+
+ Represents a set of sub-message formats for polymorphic nlattrs
+ that contain type-specific sub messages.
+
+ Attributes:
+ value attribute value to match against type selector
+ fixed_header string, name of fixed header, or None
+ attr_set string, name of attribute set, or None
+ """
+ def __init__(self, family, yaml):
+ super().__init__(family, yaml)
+
+ self.value = yaml.get('value')
+ self.fixed_header = yaml.get('fixed-header')
+ self.attr_set = yaml.get('attribute-set')
+
+
class SpecOperation(SpecElement):
"""Netlink Operation
@@ -365,6 +411,7 @@ class SpecFamily(SpecElement):
attr_sets dict of attribute sets
msgs dict of all messages (index by name)
+ sub_msgs dict of all sub messages (index by name)
ops dict of all valid requests / responses
ntfs dict of all async events
consts dict of all constants/enums
@@ -405,6 +452,7 @@ class SpecFamily(SpecElement):
jsonschema.validate(self.yaml, schema)
self.attr_sets = collections.OrderedDict()
+ self.sub_msgs = collections.OrderedDict()
self.msgs = collections.OrderedDict()
self.req_by_value = collections.OrderedDict()
self.rsp_by_value = collections.OrderedDict()
@@ -441,6 +489,9 @@ class SpecFamily(SpecElement):
def new_struct(self, elem):
return SpecStruct(self, elem)
+ def new_sub_message(self, elem):
+ return SpecSubMessage(self, elem);
+
def new_operation(self, elem, req_val, rsp_val):
return SpecOperation(self, elem, req_val, rsp_val)
@@ -529,6 +580,10 @@ class SpecFamily(SpecElement):
attr_set = self.new_attr_set(elem)
self.attr_sets[elem['name']] = attr_set
+ for elem in self.yaml.get('sub-messages', []):
+ sub_message = self.new_sub_message(elem)
+ self.sub_msgs[sub_message.name] = sub_message
+
if self.msg_id_model == 'unified':
self._dictify_ops_unified()
elif self.msg_id_model == 'directional':
diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h
new file mode 100644
index 000000000000..7491da8e7555
--- /dev/null
+++ b/tools/net/ynl/lib/ynl-priv.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+#ifndef __YNL_C_PRIV_H
+#define __YNL_C_PRIV_H 1
+
+#include <stddef.h>
+#include <libmnl/libmnl.h>
+#include <linux/types.h>
+
+/*
+ * YNL internals / low level stuff
+ */
+
+/* Generic mnl helper code */
+
+enum ynl_policy_type {
+ YNL_PT_REJECT = 1,
+ YNL_PT_IGNORE,
+ YNL_PT_NEST,
+ YNL_PT_FLAG,
+ YNL_PT_BINARY,
+ YNL_PT_U8,
+ YNL_PT_U16,
+ YNL_PT_U32,
+ YNL_PT_U64,
+ YNL_PT_UINT,
+ YNL_PT_NUL_STR,
+ YNL_PT_BITFIELD32,
+};
+
+struct ynl_policy_attr {
+ enum ynl_policy_type type;
+ unsigned int len;
+ const char *name;
+ struct ynl_policy_nest *nest;
+};
+
+struct ynl_policy_nest {
+ unsigned int max_attr;
+ struct ynl_policy_attr *table;
+};
+
+struct ynl_parse_arg {
+ struct ynl_sock *ys;
+ struct ynl_policy_nest *rsp_policy;
+ void *data;
+};
+
+struct ynl_dump_list_type {
+ struct ynl_dump_list_type *next;
+ unsigned char data[] __attribute__((aligned(8)));
+};
+extern struct ynl_dump_list_type *YNL_LIST_END;
+
+static inline bool ynl_dump_obj_is_last(void *obj)
+{
+ unsigned long uptr = (unsigned long)obj;
+
+ uptr -= offsetof(struct ynl_dump_list_type, data);
+ return uptr == (unsigned long)YNL_LIST_END;
+}
+
+static inline void *ynl_dump_obj_next(void *obj)
+{
+ unsigned long uptr = (unsigned long)obj;
+ struct ynl_dump_list_type *list;
+
+ uptr -= offsetof(struct ynl_dump_list_type, data);
+ list = (void *)uptr;
+ uptr = (unsigned long)list->next;
+ uptr += offsetof(struct ynl_dump_list_type, data);
+
+ return (void *)uptr;
+}
+
+struct ynl_ntf_base_type {
+ __u16 family;
+ __u8 cmd;
+ struct ynl_ntf_base_type *next;
+ void (*free)(struct ynl_ntf_base_type *ntf);
+ unsigned char data[] __attribute__((aligned(8)));
+};
+
+extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
+
+struct nlmsghdr *
+ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
+struct nlmsghdr *
+ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
+
+int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
+
+int ynl_recv_ack(struct ynl_sock *ys, int ret);
+int ynl_cb_null(const struct nlmsghdr *nlh, void *data);
+
+/* YNL specific helpers used by the auto-generated code */
+
+struct ynl_req_state {
+ struct ynl_parse_arg yarg;
+ mnl_cb_t cb;
+ __u32 rsp_cmd;
+};
+
+struct ynl_dump_state {
+ struct ynl_sock *ys;
+ struct ynl_policy_nest *rsp_policy;
+ void *first;
+ struct ynl_dump_list_type *last;
+ size_t alloc_sz;
+ mnl_cb_t cb;
+ __u32 rsp_cmd;
+};
+
+struct ynl_ntf_info {
+ struct ynl_policy_nest *policy;
+ mnl_cb_t cb;
+ size_t alloc_sz;
+ void (*free)(struct ynl_ntf_base_type *ntf);
+};
+
+int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
+ struct ynl_req_state *yrs);
+int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
+ struct ynl_dump_state *yds);
+
+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_payload_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.c b/tools/net/ynl/lib/ynl.c
index 830d25097009..c82a7f41b31c 100644
--- a/tools/net/ynl/lib/ynl.c
+++ b/tools/net/ynl/lib/ynl.c
@@ -145,8 +145,10 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
const struct nlattr *attr;
const char *str = NULL;
- if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) {
+ yerr_msg(ys, "%s", strerror(ys->err.code));
return MNL_CB_OK;
+ }
mnl_attr_for_each(attr, nlh, hlen) {
unsigned int len, type;
@@ -189,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
str ? " (" : "");
start = mnl_nlmsg_get_payload_offset(ys->nlh,
- sizeof(struct genlmsghdr));
+ ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh);
off = ys->err.attr_offs;
off -= sizeof(struct nlmsghdr);
- off -= sizeof(struct genlmsghdr);
+ off -= ys->family->hdr_len;
n += ynl_err_walk(ys, start, end, off, ys->req_policy,
&bad_attr[n], sizeof(bad_attr) - n, NULL);
@@ -215,14 +217,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
bad_attr[0] ? ", " : (str ? " (" : ""));
start = mnl_nlmsg_get_payload_offset(ys->nlh,
- sizeof(struct genlmsghdr));
+ ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh);
nest_pol = ys->req_policy;
if (tb[NLMSGERR_ATTR_MISS_NEST]) {
off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
off -= sizeof(struct nlmsghdr);
- off -= sizeof(struct genlmsghdr);
+ off -= ys->family->hdr_len;
n += ynl_err_walk(ys, start, end, off, ys->req_policy,
&miss_attr[n], sizeof(miss_attr) - n,
@@ -249,6 +251,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
yerr_msg(ys, "Kernel %s: %s%s",
ys->err.code ? "error" : "warning",
bad_attr, miss_attr);
+ else
+ yerr_msg(ys, "%s", strerror(ys->err.code));
return MNL_CB_OK;
}
diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h
index e974378e3b8c..ce77a6d76ce0 100644
--- a/tools/net/ynl/lib/ynl.h
+++ b/tools/net/ynl/lib/ynl.h
@@ -3,20 +3,10 @@
#define __YNL_C_H 1
#include <stddef.h>
-#include <libmnl/libmnl.h>
#include <linux/genetlink.h>
#include <linux/types.h>
-struct mnl_socket;
-struct nlmsghdr;
-
-/*
- * User facing code
- */
-
-struct ynl_ntf_base_type;
-struct ynl_ntf_info;
-struct ynl_sock;
+#include "ynl-priv.h"
enum ynl_error_code {
YNL_ERROR_NONE = 0,
@@ -54,6 +44,7 @@ struct ynl_error {
struct ynl_family {
/* private: */
const char *name;
+ size_t hdr_len;
const struct ynl_ntf_info *ntf_info;
unsigned int ntf_info_size;
};
@@ -116,140 +107,4 @@ static inline bool ynl_has_ntf(struct ynl_sock *ys)
struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
void ynl_ntf_free(struct ynl_ntf_base_type *ntf);
-
-/*
- * YNL internals / low level stuff
- */
-
-/* Generic mnl helper code */
-
-enum ynl_policy_type {
- YNL_PT_REJECT = 1,
- YNL_PT_IGNORE,
- YNL_PT_NEST,
- YNL_PT_FLAG,
- YNL_PT_BINARY,
- YNL_PT_U8,
- YNL_PT_U16,
- YNL_PT_U32,
- YNL_PT_U64,
- YNL_PT_UINT,
- YNL_PT_NUL_STR,
- YNL_PT_BITFIELD32,
-};
-
-struct ynl_policy_attr {
- enum ynl_policy_type type;
- unsigned int len;
- const char *name;
- struct ynl_policy_nest *nest;
-};
-
-struct ynl_policy_nest {
- unsigned int max_attr;
- struct ynl_policy_attr *table;
-};
-
-struct ynl_parse_arg {
- struct ynl_sock *ys;
- struct ynl_policy_nest *rsp_policy;
- void *data;
-};
-
-struct ynl_dump_list_type {
- struct ynl_dump_list_type *next;
- unsigned char data[] __attribute__((aligned(8)));
-};
-extern struct ynl_dump_list_type *YNL_LIST_END;
-
-static inline bool ynl_dump_obj_is_last(void *obj)
-{
- unsigned long uptr = (unsigned long)obj;
-
- uptr -= offsetof(struct ynl_dump_list_type, data);
- return uptr == (unsigned long)YNL_LIST_END;
-}
-
-static inline void *ynl_dump_obj_next(void *obj)
-{
- unsigned long uptr = (unsigned long)obj;
- struct ynl_dump_list_type *list;
-
- uptr -= offsetof(struct ynl_dump_list_type, data);
- list = (void *)uptr;
- uptr = (unsigned long)list->next;
- uptr += offsetof(struct ynl_dump_list_type, data);
-
- return (void *)uptr;
-}
-
-struct ynl_ntf_base_type {
- __u16 family;
- __u8 cmd;
- struct ynl_ntf_base_type *next;
- void (*free)(struct ynl_ntf_base_type *ntf);
- unsigned char data[] __attribute__((aligned(8)));
-};
-
-extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
-
-struct nlmsghdr *
-ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
-struct nlmsghdr *
-ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
-
-int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
-
-int ynl_recv_ack(struct ynl_sock *ys, int ret);
-int ynl_cb_null(const struct nlmsghdr *nlh, void *data);
-
-/* YNL specific helpers used by the auto-generated code */
-
-struct ynl_req_state {
- struct ynl_parse_arg yarg;
- mnl_cb_t cb;
- __u32 rsp_cmd;
-};
-
-struct ynl_dump_state {
- struct ynl_sock *ys;
- struct ynl_policy_nest *rsp_policy;
- void *first;
- struct ynl_dump_list_type *last;
- size_t alloc_sz;
- mnl_cb_t cb;
- __u32 rsp_cmd;
-};
-
-struct ynl_ntf_info {
- struct ynl_policy_nest *policy;
- mnl_cb_t cb;
- size_t alloc_sz;
- void (*free)(struct ynl_ntf_base_type *ntf);
-};
-
-int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
- struct ynl_req_state *yrs);
-int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
- struct ynl_dump_state *yds);
-
-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 92995bca14e1..1e10512b2117 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -98,12 +98,12 @@ class NlAttr:
}
def __init__(self, raw, offset):
- self._len, self._type = struct.unpack("HH", raw[offset:offset + 4])
+ self._len, self._type = struct.unpack("HH", raw[offset : offset + 4])
self.type = self._type & ~Netlink.NLA_TYPE_MASK
self.is_nest = self._type & Netlink.NLA_F_NESTED
self.payload_len = self._len
self.full_len = (self.payload_len + 3) & ~3
- self.raw = raw[offset + 4:offset + self.payload_len]
+ self.raw = raw[offset + 4 : offset + self.payload_len]
@classmethod
def get_format(cls, attr_type, byte_order=None):
@@ -154,7 +154,7 @@ class NlAttr:
for m in members:
# TODO: handle non-scalar members
if m.type == 'binary':
- decoded = self.raw[offset:offset+m['len']]
+ decoded = self.raw[offset : offset + m['len']]
offset += m['len']
elif m.type in NlAttr.type_formats:
format = self.get_format(m.type, m.byte_order)
@@ -170,10 +170,9 @@ class NlAttr:
class NlAttrs:
- def __init__(self, msg):
+ def __init__(self, msg, offset=0):
self.attrs = []
- offset = 0
while offset < len(msg):
attr = NlAttr(msg, offset)
offset += attr.full_len
@@ -193,12 +192,12 @@ class NlAttrs:
class NlMsg:
def __init__(self, msg, offset, attr_space=None):
- self.hdr = msg[offset:offset + 16]
+ self.hdr = msg[offset : offset + 16]
self.nl_len, self.nl_type, self.nl_flags, self.nl_seq, self.nl_portid = \
struct.unpack("IHHII", self.hdr)
- self.raw = msg[offset + 16:offset + self.nl_len]
+ self.raw = msg[offset + 16 : offset + self.nl_len]
self.error = 0
self.done = 0
@@ -371,8 +370,8 @@ class NetlinkProtocol:
fixed_header_size = 0
if ynl:
op = ynl.rsp_by_value[msg.cmd()]
- fixed_header_size = ynl._fixed_header_size(op)
- msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:])
+ fixed_header_size = ynl._fixed_header_size(op.fixed_header)
+ msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size)
return msg
def get_mcast_id(self, mcast_name, mcast_groups):
@@ -549,6 +548,37 @@ class YnlFamily(SpecFamily):
else:
rsp[name] = [decoded]
+ def _resolve_selector(self, attr_spec, vals):
+ sub_msg = attr_spec.sub_message
+ if sub_msg not in self.sub_msgs:
+ raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}")
+ sub_msg_spec = self.sub_msgs[sub_msg]
+
+ selector = attr_spec.selector
+ if selector not in vals:
+ raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'")
+ value = vals[selector]
+ if value not in sub_msg_spec.formats:
+ raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'")
+
+ spec = sub_msg_spec.formats[value]
+ return spec
+
+ def _decode_sub_msg(self, attr, attr_spec, rsp):
+ msg_format = self._resolve_selector(attr_spec, rsp)
+ decoded = {}
+ offset = 0
+ if msg_format.fixed_header:
+ decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header));
+ offset = self._fixed_header_size(msg_format.fixed_header)
+ if msg_format.attr_set:
+ if msg_format.attr_set in self.attr_sets:
+ subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set)
+ decoded.update(subdict)
+ else:
+ raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'")
+ return decoded
+
def _decode(self, attrs, space):
if space:
attr_space = self.attr_sets[space]
@@ -586,6 +616,8 @@ class YnlFamily(SpecFamily):
value = self._decode_enum(value, attr_spec)
selector = self._decode_enum(selector, attr_spec)
decoded = {"value": value, "selector": selector}
+ elif attr_spec["type"] == 'sub-message':
+ decoded = self._decode_sub_msg(attr, attr_spec, rsp)
else:
if not self.process_unknown:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
@@ -626,20 +658,23 @@ class YnlFamily(SpecFamily):
return
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
- offset = 20 + self._fixed_header_size(op)
+ offset = 20 + self._fixed_header_size(op.fixed_header)
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
extack['bad-attr-offs'])
if path:
del extack['bad-attr-offs']
extack['bad-attr'] = path
- def _fixed_header_size(self, op):
- if op.fixed_header:
- fixed_header_members = self.consts[op.fixed_header].members
+ def _fixed_header_size(self, name):
+ if name:
+ fixed_header_members = self.consts[name].members
size = 0
for m in fixed_header_members:
- format = NlAttr.get_format(m.type, m.byte_order)
- size += format.size
+ if m.type in ['pad', 'binary']:
+ size += m.len
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ size += format.size
return size
else:
return 0
@@ -649,12 +684,20 @@ class YnlFamily(SpecFamily):
fixed_header_attrs = dict()
offset = 0
for m in fixed_header_members:
- format = NlAttr.get_format(m.type, m.byte_order)
- [ value ] = format.unpack_from(msg.raw, offset)
- offset += format.size
- if m.enum:
- value = self._decode_enum(value, m)
- fixed_header_attrs[m.name] = value
+ value = None
+ if m.type == 'pad':
+ offset += m.len
+ elif m.type == 'binary':
+ value = msg.raw[offset : offset + m.len]
+ offset += m.len
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ [ value ] = format.unpack_from(msg.raw, offset)
+ offset += format.size
+ if value is not None:
+ if m.enum:
+ value = self._decode_enum(value, m)
+ fixed_header_attrs[m.name] = value
return fixed_header_attrs
def handle_ntf(self, decoded):
@@ -705,7 +748,7 @@ class YnlFamily(SpecFamily):
return op['do']['request']['attributes'].copy()
- def _op(self, method, vals, flags, dump=False):
+ def _op(self, method, vals, flags=None, dump=False):
op = self.ops[method]
nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK
@@ -721,8 +764,13 @@ class YnlFamily(SpecFamily):
fixed_header_members = self.consts[op.fixed_header].members
for m in fixed_header_members:
value = vals.pop(m.name) if m.name in vals else 0
- format = NlAttr.get_format(m.type, m.byte_order)
- msg += format.pack(value)
+ if m.type == 'pad':
+ msg += bytearray(m.len)
+ elif m.type == 'binary':
+ msg += bytes.fromhex(value)
+ else:
+ format = NlAttr.get_format(m.type, m.byte_order)
+ msg += format.pack(value)
for name, value in vals.items():
msg += self._add_attr(op.attr_set.name, name, value)
msg = _genl_msg_finalize(msg)
@@ -769,7 +817,7 @@ class YnlFamily(SpecFamily):
return rsp[0]
return rsp
- def do(self, method, vals, flags):
+ def do(self, method, vals, flags=None):
return self._op(method, vals, flags)
def dump(self, method, vals):