Page MenuHomeFreeBSD

D38283.diff
No OneTemporary

D38283.diff

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

Mime Type
text/plain
Expires
Mon, Sep 30, 3:35 AM (22 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13162996
Default Alt Text
D38283.diff (15 KB)

Event Timeline