Add a function using ethtool netlink to check whether a PHC is a virtual clock of an interface.
Signed-off-by: Miroslav Lichvar <mlich...@redhat.com> Acked-by: Hangbin Liu <liuhang...@gmail.com> --- rtnl.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtnl.h | 9 +++++++ 2 files changed, 92 insertions(+) diff --git a/rtnl.c b/rtnl.c index f8bdbe6..0039d07 100644 --- a/rtnl.c +++ b/rtnl.c @@ -19,6 +19,7 @@ #include <asm/types.h> #include <sys/socket.h> /* Must come before linux/netlink.h on some systems. */ #include <linux/netlink.h> +#include <linux/ethtool_netlink.h> #include <linux/rtnetlink.h> #include <linux/genetlink.h> #include <linux/if_team.h> @@ -465,3 +466,85 @@ no_info: nl_close(fd); return index; } + +static int rtnl_search_vclocks(struct rtattr *attr, int phc_index) +{ + int i, len = RTA_PAYLOAD(attr); + + for (i = 0; i < len / sizeof (__s32); i++) { + if (((__s32 *)RTA_DATA(attr))[i] == phc_index) + return 1; + } + + return 0; +} + +int rtnl_iface_has_vclock(const char *device, int phc_index) +{ + struct rtattr *tb[ETHTOOL_A_PHC_VCLOCKS_MAX + 1]; + int index, fd, gf_id, len, ret = 0; + struct genlmsghdr *gnlh; + struct nlmsghdr *nlh; + char msg[BUF_SIZE]; + struct { + struct nlattr attr; + uint32_t index; + } req; + + index = if_nametoindex(device); + + fd = nl_open(NETLINK_GENERIC); + if (fd < 0) + return fd; + + gf_id = genl_get_family_id(fd, ETHTOOL_GENL_NAME); + if (gf_id < 0) { + pr_err("get genl family failed"); + goto no_info; + } + + req.attr.nla_len = sizeof(req); + req.attr.nla_type = ETHTOOL_A_HEADER_DEV_INDEX; + req.index = index; + + len = genl_send_msg(fd, gf_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, + ETHTOOL_GENL_VERSION, + NLA_F_NESTED | ETHTOOL_A_PHC_VCLOCKS_HEADER, + &req, sizeof(req)); + + if (len < 0) { + pr_err("send vclock request failed: %m"); + goto no_info; + } + + len = recv(fd, msg, sizeof(msg), 0); + if (len < 0) { + pr_err("recv vclock failed: %m"); + goto no_info; + } + + for (nlh = (struct nlmsghdr *) msg; NLMSG_OK(nlh, len); + nlh = NLMSG_NEXT(nlh, len)) { + if (nlh->nlmsg_type != gf_id) + continue; + + gnlh = (struct genlmsghdr *) NLMSG_DATA(nlh); + if (gnlh->cmd != ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY) + continue; + + if (rtnl_rtattr_parse(tb, ETHTOOL_A_PHC_VCLOCKS_MAX, + (struct rtattr *) GENLMSG_DATA(msg), + NLMSG_PAYLOAD(nlh, GENL_HDRLEN))) + continue; + + if (tb[ETHTOOL_A_PHC_VCLOCKS_INDEX]) { + ret = rtnl_search_vclocks(tb[ETHTOOL_A_PHC_VCLOCKS_INDEX], + phc_index); + break; + } + } + +no_info: + nl_close(fd); + return ret; +} diff --git a/rtnl.h b/rtnl.h index 8fef4a9..96fee29 100644 --- a/rtnl.h +++ b/rtnl.h @@ -59,6 +59,15 @@ int rtnl_link_query(int fd, const char *device); */ int rtnl_link_status(int fd, const char *device, rtnl_callback cb, void *ctx); +/** + * Check if the PHC is a virtual clock of the interface (i.e. sockets bound to + * the interface also need to be bound to the clock). + * @param device Name of the interface. + * @param phc_index Index of the clock to check. + * @return 1 if true, otherwise 0. + */ +int rtnl_iface_has_vclock(const char *device, int phc_index); + /** * Open a RT netlink socket for monitoring link state. * @return A valid socket, or -1 on error. -- 2.34.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel