Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F97397650
D38283.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D38283.diff
View Options
diff --git a/share/man/man4/netlink.4 b/share/man/man4/netlink.4
--- a/share/man/man4/netlink.4
+++ b/share/man/man4/netlink.4
@@ -217,6 +217,10 @@
string TLV with the textual error description, optionally followed by the
.Dv NLMSGERR_ATTR_OFFS
TLV, indicating the offset from the message start that triggered an error.
+Some operations may return additional metadata encapsulated in the
+.Dv NLMSGERR_ATTR_COOKIE
+TLV.
+The metadata format is specific to the operation.
If the operation reply is a multipart message, then no
.Dv NLMSG_ERROR
reply is generated, only a
diff --git a/share/man/man4/rtnetlink.4 b/share/man/man4/rtnetlink.4
--- a/share/man/man4/rtnetlink.4
+++ b/share/man/man4/rtnetlink.4
@@ -284,6 +284,13 @@
Creates a new interface.
The only mandatory TLV is
.Dv IFLA_IFNAME .
+The following attributes are returned inside the nested
+.Dv NLMSGERR_ATTR_COOKIE :
+.Pp
+.Bd -literal -offset indent -compact
+IFLA_NEW_IFINDEX (uint32) created interface index
+IFLA_IFNAME (string) created interface name
+.Ed
.Ss RTM_DELLINK
Deletes the interface specified by
.Dv IFLA_IFNAME .
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -71,6 +71,7 @@
uint32_t err_off; /* error offset from hdr start */
int error; /* last operation error */
char *err_msg; /* Description of last error */
+ struct nlattr *cookie; /* NLA to return to the userspace */
bool strict; /* Strict parsing required */
};
@@ -198,6 +199,9 @@
bool nlmsg_report_err_offset(struct nl_pstate *npt, uint32_t off);
+void nlmsg_report_cookie(struct nl_pstate *npt, struct nlattr *nla);
+void nlmsg_report_cookie_u32(struct nl_pstate *npt, uint32_t val);
+
/*
* Have it inline so compiler can optimize field accesses into
* the list of direct function calls without iteration.
diff --git a/sys/netlink/netlink_message_parser.c b/sys/netlink/netlink_message_parser.c
--- a/sys/netlink/netlink_message_parser.c
+++ b/sys/netlink/netlink_message_parser.c
@@ -78,6 +78,25 @@
return (true);
}
+void
+nlmsg_report_cookie(struct nl_pstate *npt, struct nlattr *nla)
+{
+ MPASS(nla->nla_type == NLMSGERR_ATTR_COOKIE);
+ MPASS(nla->nla_len >= sizeof(struct nlattr));
+ npt->cookie = nla;
+}
+
+void
+nlmsg_report_cookie_u32(struct nl_pstate *npt, uint32_t val)
+{
+ struct nlattr *nla = npt_alloc(npt, sizeof(*nla) + sizeof(uint32_t));
+
+ nla->nla_type = NLMSGERR_ATTR_COOKIE;
+ nla->nla_len = sizeof(*nla) + sizeof(uint32_t);
+ memcpy(nla + 1, &val, sizeof(uint32_t));
+ nlmsg_report_cookie(npt, nla);
+}
+
static const struct nlattr_parser *
search_states(const struct nlattr_parser *ps, int pslen, int key)
{
diff --git a/sys/netlink/netlink_message_writer.h b/sys/netlink/netlink_message_writer.h
--- a/sys/netlink/netlink_message_writer.h
+++ b/sys/netlink/netlink_message_writer.h
@@ -163,6 +163,27 @@
}
#define nlmsg_reserve_attr(_ns, _at, _t) ((_t *)_nlmsg_reserve_attr(_ns, _at, NLA_ALIGN(sizeof(_t))))
+static inline bool
+nlattr_add_nla(struct nl_writer *nw, const struct nlattr *nla_src)
+{
+ MPASS(nla_src->nla_len >= sizeof(struct nlattr));
+
+ int required_len = NLA_ALIGN(nla_src->nla_len);
+ if (__predict_false(nw->offset + required_len > nw->alloc_len)) {
+ if (!nlmsg_refill_buffer(nw, required_len))
+ return (false);
+ }
+
+ struct nlattr *nla = (struct nlattr *)(&nw->data[nw->offset]);
+ if ((nla_src->nla_len % 4) != 0) {
+ /* clear padding bytes */
+ bzero((char *)nla + nla_src->nla_len - 4, 4);
+ }
+ memcpy(nla, nla_src, nla_src->nla_len);
+ nw->offset += required_len;
+ return (true);
+}
+
static inline bool
nlattr_add(struct nl_writer *nw, int attr_type, int attr_len, const void *data)
{
@@ -188,6 +209,16 @@
return (true);
}
+static inline bool
+nlattr_add_raw(struct nl_writer *nw, const struct nlattr *nla_src)
+{
+ int attr_len = nla_src->nla_len - sizeof(struct nlattr);
+
+ MPASS(attr_len >= 0);
+
+ return (nlattr_add(nw, nla_src->nla_type, attr_len, (const void *)(nla_src + 1)));
+}
+
static inline bool
nlattr_add_u8(struct nl_writer *nw, int attrtype, uint8_t value)
{
diff --git a/sys/netlink/netlink_message_writer.c b/sys/netlink/netlink_message_writer.c
--- a/sys/netlink/netlink_message_writer.c
+++ b/sys/netlink/netlink_message_writer.c
@@ -643,10 +643,6 @@
if ((npt->err_msg || npt->err_off) && nlp->nl_flags & NLF_EXT_ACK)
nl_flags |= NLM_F_ACK_TLVS;
- /*
- * TODO: handle cookies
- */
-
NL_LOG(LOG_DEBUG3, "acknowledging message type %d seq %d",
hdr->nlmsg_type, hdr->nlmsg_seq);
@@ -662,6 +658,8 @@
nlattr_add_string(nw, NLMSGERR_ATTR_MSG, npt->err_msg);
if (npt->err_off != 0 && nlp->nl_flags & NLF_EXT_ACK)
nlattr_add_u32(nw, NLMSGERR_ATTR_OFFS, npt->err_off);
+ if (npt->cookie != NULL)
+ nlattr_add_raw(nw, npt->cookie);
if (nlmsg_end(nw))
return;
diff --git a/sys/netlink/route/iface_drivers.c b/sys/netlink/route/iface_drivers.c
--- a/sys/netlink/route/iface_drivers.c
+++ b/sys/netlink/route/iface_drivers.c
@@ -109,6 +109,41 @@
return (0);
}
+/*
+ * Saves the resulting ifindex and ifname to report them
+ * to userland along with the operation result.
+ * NLA format:
+ * NLMSGERR_ATTR_COOKIE(nested)
+ * IFLA_NEW_IFINDEX(u32)
+ * IFLA_IFNAME(string)
+ */
+static void
+store_cookie(struct nl_pstate *npt, struct ifnet *ifp)
+{
+ int ifname_len = strlen(if_name(ifp));
+ uint32_t ifindex = (uint32_t)ifp->if_index;
+
+ int nla_len = sizeof(struct nlattr) * 3 +
+ sizeof(ifindex) + NL_ITEM_ALIGN(ifname_len + 1);
+ struct nlattr *nla_cookie = npt_alloc(npt, nla_len);
+
+ /* Nested TLV */
+ nla_cookie->nla_len = nla_len;
+ nla_cookie->nla_type = NLMSGERR_ATTR_COOKIE;
+
+ struct nlattr *nla = nla_cookie + 1;
+ nla->nla_len = sizeof(struct nlattr) + sizeof(ifindex);
+ nla->nla_type = IFLA_NEW_IFINDEX;
+ memcpy(NLA_DATA(nla), &ifindex, sizeof(ifindex));
+
+ nla = NLA_NEXT(nla);
+ nla->nla_len = sizeof(struct nlattr) + ifname_len + 1;
+ nla->nla_type = IFLA_IFNAME;
+ strlcpy(NLA_DATA(nla), if_name(ifp), ifname_len + 1);
+
+ nlmsg_report_cookie(npt, nla_cookie);
+}
+
/*
* Generic creation interface handler.
* Responsible for creating interfaces w/o parameters and setting
@@ -135,6 +170,8 @@
if (!success)
return (EINVAL);
error = modify_generic(ifp, lattrs, bm, nlp, npt);
+ if (error == 0)
+ store_cookie(npt, ifp);
if_rele(ifp);
}
diff --git a/tests/atf_python/sys/net/netlink.py b/tests/atf_python/sys/net/netlink.py
--- a/tests/atf_python/sys/net/netlink.py
+++ b/tests/atf_python/sys/net/netlink.py
@@ -950,58 +950,68 @@
return ret
-rtnl_route_attrs = [
- AttrDescr(RtattrType.RTA_DST, NlAttrIp),
- AttrDescr(RtattrType.RTA_SRC, NlAttrIp),
- AttrDescr(RtattrType.RTA_IIF, NlAttrIfindex),
- AttrDescr(RtattrType.RTA_OIF, NlAttrIfindex),
- AttrDescr(RtattrType.RTA_GATEWAY, NlAttrTable),
- AttrDescr(RtattrType.RTA_VIA, NlAttrVia),
- AttrDescr(RtattrType.RTA_NH_ID, NlAttrNhId),
- AttrDescr(
- RtattrType.RTA_METRICS,
- NlAttrNested,
- [
- AttrDescr(NlRtaxType.RTAX_MTU, NlAttrU32),
- ],
- ),
-]
-
-nldone_attrs = []
-
-nlerr_attrs = [
- AttrDescr(NlErrattrType.NLMSGERR_ATTR_MSG, NlAttrStr),
- AttrDescr(NlErrattrType.NLMSGERR_ATTR_OFFS, NlAttrU32),
-]
-
-rtnl_ifla_attrs = [
- AttrDescr(IflattrType.IFLA_ADDRESS, NlAttrMac),
- AttrDescr(IflattrType.IFLA_BROADCAST, NlAttrMac),
- AttrDescr(IflattrType.IFLA_IFNAME, NlAttrStr),
- AttrDescr(IflattrType.IFLA_MTU, NlAttrU32),
- AttrDescr(IflattrType.IFLA_PROMISCUITY, NlAttrU32),
- AttrDescr(IflattrType.IFLA_OPERSTATE, NlAttrU8),
- AttrDescr(IflattrType.IFLA_CARRIER, NlAttrU8),
- AttrDescr(IflattrType.IFLA_IFALIAS, NlAttrStr),
- AttrDescr(IflattrType.IFLA_STATS64, NlAttrIfStats),
- AttrDescr(
- IflattrType.IFLA_LINKINFO,
- NlAttrNested,
- [
- AttrDescr(IflinkInfo.IFLA_INFO_KIND, NlAttrStr),
- AttrDescr(IflinkInfo.IFLA_INFO_DATA, NlAttr),
- ],
- ),
-]
-
-rtnl_ifa_attrs = [
- AttrDescr(IfattrType.IFA_ADDRESS, NlAttrIp),
- AttrDescr(IfattrType.IFA_LOCAL, NlAttrIp),
- AttrDescr(IfattrType.IFA_LABEL, NlAttrStr),
- AttrDescr(IfattrType.IFA_BROADCAST, NlAttrIp),
- AttrDescr(IfattrType.IFA_ANYCAST, NlAttrIp),
- AttrDescr(IfattrType.IFA_FLAGS, NlAttrU32),
-]
+rtnl_route_attrs = prepare_attrs_map(
+ [
+ AttrDescr(RtattrType.RTA_DST, NlAttrIp),
+ AttrDescr(RtattrType.RTA_SRC, NlAttrIp),
+ AttrDescr(RtattrType.RTA_IIF, NlAttrIfindex),
+ AttrDescr(RtattrType.RTA_OIF, NlAttrIfindex),
+ AttrDescr(RtattrType.RTA_GATEWAY, NlAttrTable),
+ AttrDescr(RtattrType.RTA_VIA, NlAttrVia),
+ AttrDescr(RtattrType.RTA_NH_ID, NlAttrNhId),
+ AttrDescr(
+ RtattrType.RTA_METRICS,
+ NlAttrNested,
+ [
+ AttrDescr(NlRtaxType.RTAX_MTU, NlAttrU32),
+ ],
+ ),
+ ]
+)
+
+nldone_attrs = prepare_attrs_map([])
+
+nlerr_attrs = prepare_attrs_map(
+ [
+ AttrDescr(NlErrattrType.NLMSGERR_ATTR_MSG, NlAttrStr),
+ AttrDescr(NlErrattrType.NLMSGERR_ATTR_OFFS, NlAttrU32),
+ AttrDescr(NlErrattrType.NLMSGERR_ATTR_COOKIE, NlAttr),
+ ]
+)
+
+rtnl_ifla_attrs = prepare_attrs_map(
+ [
+ AttrDescr(IflattrType.IFLA_ADDRESS, NlAttrMac),
+ AttrDescr(IflattrType.IFLA_BROADCAST, NlAttrMac),
+ AttrDescr(IflattrType.IFLA_IFNAME, NlAttrStr),
+ AttrDescr(IflattrType.IFLA_MTU, NlAttrU32),
+ AttrDescr(IflattrType.IFLA_PROMISCUITY, NlAttrU32),
+ AttrDescr(IflattrType.IFLA_OPERSTATE, NlAttrU8),
+ AttrDescr(IflattrType.IFLA_CARRIER, NlAttrU8),
+ AttrDescr(IflattrType.IFLA_IFALIAS, NlAttrStr),
+ AttrDescr(IflattrType.IFLA_STATS64, NlAttrIfStats),
+ AttrDescr(IflattrType.IFLA_NEW_IFINDEX, NlAttrU32),
+ AttrDescr(
+ IflattrType.IFLA_LINKINFO,
+ NlAttrNested,
+ [
+ AttrDescr(IflinkInfo.IFLA_INFO_KIND, NlAttrStr),
+ AttrDescr(IflinkInfo.IFLA_INFO_DATA, NlAttr),
+ ],
+ ),
+ ]
+)
+
+rtnl_ifa_attrs = prepare_attrs_map(
+ [
+ AttrDescr(IfattrType.IFA_ADDRESS, NlAttrIp),
+ AttrDescr(IfattrType.IFA_LOCAL, NlAttrIp),
+ AttrDescr(IfattrType.IFA_LABEL, NlAttrStr),
+ AttrDescr(IfattrType.IFA_BROADCAST, NlAttrIp),
+ AttrDescr(IfattrType.IFA_ANYCAST, NlAttrIp),
+ AttrDescr(IfattrType.IFA_FLAGS, NlAttrU32),
+ ]
+)
class BaseNetlinkMessage(object):
@@ -1140,7 +1150,7 @@
raise
return self
- def _parse_attrs(self, data: bytes, attr_map):
+ def parse_attrs(self, data: bytes, attr_map):
ret = []
off = 0
while len(data) - off >= 4:
@@ -1157,7 +1167,7 @@
val = v["ad"].cls.from_bytes(data[off : off + nla_len], v["ad"].val)
if "child" in v:
# nested
- attrs, _ = self._parse_attrs(data[off : off + nla_len], v["child"])
+ attrs, _ = self.parse_attrs(data[off : off + nla_len], v["child"])
val = NlAttrNested(raw_nla_type, attrs)
else:
# unknown attribute
@@ -1167,7 +1177,7 @@
return ret, off
def parse_nla_list(self, data: bytes) -> List[NlAttr]:
- return self._parse_attrs(data, self.nl_attrs_map)
+ return self.parse_attrs(data, self.nl_attrs_map)
def print_message(self):
self.print_nl_header(self.nl_hdr)
@@ -1178,7 +1188,7 @@
class NetlinkDoneMessage(StdNetlinkMessage):
messages = [NlMsgType.NLMSG_DONE.value]
- nl_attrs_map = prepare_attrs_map(nldone_attrs)
+ nl_attrs_map = nldone_attrs
@property
def error_code(self):
@@ -1197,7 +1207,7 @@
class NetlinkErrorMessage(StdNetlinkMessage):
messages = [NlMsgType.NLMSG_ERROR.value]
- nl_attrs_map = prepare_attrs_map(nlerr_attrs)
+ nl_attrs_map = nlerr_attrs
@property
def error_code(self):
@@ -1217,6 +1227,10 @@
return nla.u32
return None
+ @property
+ def cookie(self):
+ return self.get_nla(NlErrattrType.NLMSGERR_ATTR_COOKIE)
+
def parse_base_header(self, data):
if len(data) < sizeof(Nlmsgerr):
raise ValueError("length less than nlmsgerr header")
@@ -1257,7 +1271,7 @@
NlRtMsgType.RTM_DELROUTE.value,
NlRtMsgType.RTM_GETROUTE.value,
]
- nl_attrs_map = prepare_attrs_map(rtnl_route_attrs)
+ nl_attrs_map = rtnl_route_attrs
def __init__(self, helper, nlm_type):
super().__init__(helper, nlm_type)
@@ -1297,7 +1311,7 @@
NlRtMsgType.RTM_DELLINK.value,
NlRtMsgType.RTM_GETLINK.value,
]
- nl_attrs_map = prepare_attrs_map(rtnl_ifla_attrs)
+ nl_attrs_map = rtnl_ifla_attrs
def __init__(self, helper, nlm_type):
super().__init__(helper, nlm_type)
@@ -1329,7 +1343,7 @@
NlRtMsgType.RTM_DELADDR.value,
NlRtMsgType.RTM_GETADDR.value,
]
- nl_attrs_map = prepare_attrs_map(rtnl_ifa_attrs)
+ nl_attrs_map = rtnl_ifa_attrs
def __init__(self, helper, nlm_type):
super().__init__(helper, nlm_type)
diff --git a/tests/sys/netlink/test_rtnl_iface.py b/tests/sys/netlink/test_rtnl_iface.py
--- a/tests/sys/netlink/test_rtnl_iface.py
+++ b/tests/sys/netlink/test_rtnl_iface.py
@@ -17,6 +17,7 @@
from atf_python.sys.net.netlink import NlmNewFlags
from atf_python.sys.net.netlink import NlMsgType
from atf_python.sys.net.netlink import NlRtMsgType
+from atf_python.sys.net.netlink import rtnl_ifla_attrs
from atf_python.sys.net.vnet import SingleVnetTestTemplate
@@ -91,6 +92,40 @@
self.get_interface_byname("lo10")
+ @pytest.mark.require_user("root")
+ def test_create_iface_plain_retvals(self):
+ """Tests loopback creation w/o any parameters"""
+ flags = NlmNewFlags.NLM_F_EXCL.value | NlmNewFlags.NLM_F_CREATE.value
+ msg = NetlinkIflaMessage(self.helper, NlRtMsgType.RTM_NEWLINK.value)
+ msg.nl_hdr.nlmsg_flags = (
+ flags | NlmBaseFlags.NLM_F_ACK.value | NlmBaseFlags.NLM_F_REQUEST.value
+ )
+ msg.add_nla(NlAttrStr(IflattrType.IFLA_IFNAME, "lo10"))
+ msg.add_nla(
+ NlAttrNested(
+ IflattrType.IFLA_LINKINFO,
+ [
+ NlAttrStrn(IflinkInfo.IFLA_INFO_KIND, "lo"),
+ ],
+ )
+ )
+
+ rx_msg = self.get_reply(msg)
+ assert rx_msg.is_type(NlMsgType.NLMSG_ERROR)
+ assert rx_msg.error_code == 0
+ assert rx_msg.cookie is not None
+ nla_list, _ = rx_msg.parse_attrs(bytes(rx_msg.cookie)[4:], rtnl_ifla_attrs)
+ nla_map = {n.nla_type: n for n in nla_list}
+ assert IflattrType.IFLA_IFNAME.value in nla_map
+ assert nla_map[IflattrType.IFLA_IFNAME.value].text == "lo10"
+ assert IflattrType.IFLA_NEW_IFINDEX.value in nla_map
+ assert nla_map[IflattrType.IFLA_NEW_IFINDEX.value].u32 > 0
+
+ lo_msg = self.get_interface_byname("lo10")
+ assert (
+ lo_msg.base_hdr.ifi_index == nla_map[IflattrType.IFLA_NEW_IFINDEX.value].u32
+ )
+
@pytest.mark.require_user("root")
def test_create_iface_attrs(self):
"""Tests interface creation with additional properties"""
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 30, 2:03 AM (20 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13162996
Default Alt Text
D38283.diff (15 KB)
Attached To
Mode
D38283: netlink: return optional metadata with the operation result.
Attached
Detach File
Event Timeline
Log In to Comment