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> --- incdefs.sh | 4 +++ missing.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rtnl.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ rtnl.h | 9 +++++ 4 files changed, 199 insertions(+) diff --git a/incdefs.sh b/incdefs.sh index 19e620e..21333e5 100755 --- a/incdefs.sh +++ b/incdefs.sh @@ -86,6 +86,10 @@ kernel_flags() if grep -q HWTSTAMP_TX_ONESTEP_P2P ${prefix}${tstamp}; then printf " -DHAVE_ONESTEP_P2P" fi + + if grep -q SOF_TIMESTAMPING_BIND_PHC ${prefix}${tstamp}; then + printf " -DHAVE_VCLOCKS" + fi } flags="$(user_flags)$(kernel_flags)" diff --git a/missing.h b/missing.h index 89cb513..14aa1e6 100644 --- a/missing.h +++ b/missing.h @@ -251,6 +251,107 @@ enum { #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) #endif /*NLA_TYPE_MAX*/ +#ifndef ETHTOOL_GENL_NAME +#define ETHTOOL_GENL_NAME "ethtool" +#define ETHTOOL_GENL_VERSION 1 +#endif + +#ifndef HAVE_VCLOCKS +enum { + ETHTOOL_MSG_USER_NONE, + ETHTOOL_MSG_STRSET_GET, + ETHTOOL_MSG_LINKINFO_GET, + ETHTOOL_MSG_LINKINFO_SET, + ETHTOOL_MSG_LINKMODES_GET, + ETHTOOL_MSG_LINKMODES_SET, + ETHTOOL_MSG_LINKSTATE_GET, + ETHTOOL_MSG_DEBUG_GET, + ETHTOOL_MSG_DEBUG_SET, + ETHTOOL_MSG_WOL_GET, + ETHTOOL_MSG_WOL_SET, + ETHTOOL_MSG_FEATURES_GET, + ETHTOOL_MSG_FEATURES_SET, + ETHTOOL_MSG_PRIVFLAGS_GET, + ETHTOOL_MSG_PRIVFLAGS_SET, + ETHTOOL_MSG_RINGS_GET, + ETHTOOL_MSG_RINGS_SET, + ETHTOOL_MSG_CHANNELS_GET, + ETHTOOL_MSG_CHANNELS_SET, + ETHTOOL_MSG_COALESCE_GET, + ETHTOOL_MSG_COALESCE_SET, + ETHTOOL_MSG_PAUSE_GET, + ETHTOOL_MSG_PAUSE_SET, + ETHTOOL_MSG_EEE_GET, + ETHTOOL_MSG_EEE_SET, + ETHTOOL_MSG_TSINFO_GET, + ETHTOOL_MSG_CABLE_TEST_ACT, + ETHTOOL_MSG_CABLE_TEST_TDR_ACT, + ETHTOOL_MSG_TUNNEL_INFO_GET, + ETHTOOL_MSG_FEC_GET, + ETHTOOL_MSG_FEC_SET, + ETHTOOL_MSG_MODULE_EEPROM_GET, + ETHTOOL_MSG_STATS_GET, + ETHTOOL_MSG_PHC_VCLOCKS_GET, +}; + +enum { + ETHTOOL_MSG_KERNEL_NONE, + ETHTOOL_MSG_STRSET_GET_REPLY, + ETHTOOL_MSG_LINKINFO_GET_REPLY, + ETHTOOL_MSG_LINKINFO_NTF, + ETHTOOL_MSG_LINKMODES_GET_REPLY, + ETHTOOL_MSG_LINKMODES_NTF, + ETHTOOL_MSG_LINKSTATE_GET_REPLY, + ETHTOOL_MSG_DEBUG_GET_REPLY, + ETHTOOL_MSG_DEBUG_NTF, + ETHTOOL_MSG_WOL_GET_REPLY, + ETHTOOL_MSG_WOL_NTF, + ETHTOOL_MSG_FEATURES_GET_REPLY, + ETHTOOL_MSG_FEATURES_SET_REPLY, + ETHTOOL_MSG_FEATURES_NTF, + ETHTOOL_MSG_PRIVFLAGS_GET_REPLY, + ETHTOOL_MSG_PRIVFLAGS_NTF, + ETHTOOL_MSG_RINGS_GET_REPLY, + ETHTOOL_MSG_RINGS_NTF, + ETHTOOL_MSG_CHANNELS_GET_REPLY, + ETHTOOL_MSG_CHANNELS_NTF, + ETHTOOL_MSG_COALESCE_GET_REPLY, + ETHTOOL_MSG_COALESCE_NTF, + ETHTOOL_MSG_PAUSE_GET_REPLY, + ETHTOOL_MSG_PAUSE_NTF, + ETHTOOL_MSG_EEE_GET_REPLY, + ETHTOOL_MSG_EEE_NTF, + ETHTOOL_MSG_TSINFO_GET_REPLY, + ETHTOOL_MSG_CABLE_TEST_NTF, + ETHTOOL_MSG_CABLE_TEST_TDR_NTF, + ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY, + ETHTOOL_MSG_FEC_GET_REPLY, + ETHTOOL_MSG_FEC_NTF, + ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, + ETHTOOL_MSG_STATS_GET_REPLY, + ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY, +}; + +enum { + ETHTOOL_A_HEADER_UNSPEC, + ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */ + ETHTOOL_A_HEADER_DEV_NAME, /* string */ + ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */ + __ETHTOOL_A_HEADER_CNT, + ETHTOOL_A_HEADER_MAX = __ETHTOOL_A_HEADER_CNT - 1 +}; + +enum { + ETHTOOL_A_PHC_VCLOCKS_UNSPEC, + ETHTOOL_A_PHC_VCLOCKS_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_PHC_VCLOCKS_NUM, /* u32 */ + ETHTOOL_A_PHC_VCLOCKS_INDEX, /* array, s32 */ + __ETHTOOL_A_PHC_VCLOCKS_CNT, + ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1) +}; + +#endif /* HAVE_VCLOCKS */ + #ifdef __UCLIBC__ #if (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L) && \ diff --git a/rtnl.c b/rtnl.c index f8bdbe6..fa02388 100644 --- a/rtnl.c +++ b/rtnl.c @@ -19,6 +19,9 @@ #include <asm/types.h> #include <sys/socket.h> /* Must come before linux/netlink.h on some systems. */ #include <linux/netlink.h> +#ifdef HAVE_VCLOCKS +#include <linux/ethtool_netlink.h> +#endif #include <linux/rtnetlink.h> #include <linux/genetlink.h> #include <linux/if_team.h> @@ -465,3 +468,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 0; + + gf_id = genl_get_family_id(fd, ETHTOOL_GENL_NAME); + if (gf_id < 0) { + pr_debug("ethtool netlink not supported"); + 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.35.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel