Add function rtnl_link_info() to get bond's active interface. If there is no slave interface, then use our own name as ts interface.
Also add new parameter ts_iface for call back function port_link_status() to make aware of interface change. Signed-off-by: Hangbin Liu <liuhang...@gmail.com> --- port.c | 2 +- rtnl.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- rtnl.h | 10 +++++- 3 files changed, 131 insertions(+), 3 deletions(-) diff --git a/port.c b/port.c index 21ab3ea..834eb45 100644 --- a/port.c +++ b/port.c @@ -2221,7 +2221,7 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) } } -static void port_link_status(void *ctx, int index, int linkup) +static void port_link_status(void *ctx, int index, int linkup, char *ts_iface) { struct port *p = ctx; diff --git a/rtnl.c b/rtnl.c index 04e1918..b499467 100644 --- a/rtnl.c +++ b/rtnl.c @@ -31,6 +31,9 @@ static int rtnl_len; static char *rtnl_buf; +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len); +#define rtnl_nested_rtattr_parse(tb, max, rta) \ + (rtnl_rtattr_parse((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) int rtnl_close(int fd) { @@ -84,6 +87,62 @@ int rtnl_link_query(int fd, unsigned int if_index) return 0; } +static inline __u32 rta_getattr_u32(const struct rtattr *rta) +{ + return *(__u32 *)RTA_DATA(rta); +} + +static inline const char *rta_getattr_str(const struct rtattr *rta) +{ + return (const char *)RTA_DATA(rta); +} + +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + type = rta->rta_type; + if ((type <= max) && (!tb[type])) + tb[type] = rta; + rta = RTA_NEXT(rta, len); + } + if (len) + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); + return 0; +} + +static int rtnl_linkinfo_parse(struct rtattr *rta, char *device) +{ + int index; + struct rtattr *linkinfo[IFLA_INFO_MAX + 1]; + struct rtattr *bond[IFLA_BOND_MAX + 1]; + + rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta); + + if (linkinfo[IFLA_INFO_KIND]) { + const char *kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); + + if (kind && !strncmp(kind, "bond", 4) && + linkinfo[IFLA_INFO_DATA]) { + rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, + linkinfo[IFLA_INFO_DATA]); + + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); + + if (!if_indextoname(index, device)) { + pr_err("failed to get device name: %m"); + return -1; + } + } + } + } + return 0; +} + int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) { int index, len; @@ -92,6 +151,18 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) struct msghdr msg; struct nlmsghdr *nh; struct ifinfomsg *info = NULL; + char *device; + struct rtattr *tb[IFLA_MAX+1]; + + if (cb) + device = calloc(1, sizeof(MAX_IFNAME_SIZE + 1)); + else + device = (char *)ctx; + + if (!device) { + fprintf(stderr, "rtnl: no enought memory for device name\n"); + return -1; + } if (!rtnl_buf) { rtnl_len = 4096; @@ -140,7 +211,18 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) index = info->ifi_index; pr_debug("interface index %d is %s", index, info->ifi_flags & IFF_RUNNING ? "up" : "down"); - cb(ctx, index, info->ifi_flags & IFF_RUNNING ? 1 : 0); + + rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info), + IFLA_PAYLOAD(nh)); + + if (tb[IFLA_LINKINFO]) + rtnl_linkinfo_parse(tb[IFLA_LINKINFO], device); + + if (cb) { + cb(ctx, index, info->ifi_flags & IFF_RUNNING ? 1 : 0, device); + free(device); + } + } } return 0; @@ -167,3 +249,41 @@ int rtnl_open(void) } return fd; } + +int rtnl_link_info(struct interface *iface) +{ + int fd, index; + + index = if_nametoindex(iface->name); + + if (index == 0) { + pr_err("failed to get interface %s index: %m", iface->name); + goto no_fd; + } + + fd = rtnl_open(); + if (fd < 0) + goto no_fd; + + if (rtnl_link_query(fd, index)) + goto no_info; + if (rtnl_link_status(fd, NULL, iface->ts_iface)) + goto no_info; + + /* If we do not have a slave, then use our own interface name + * as ts_iface + */ + if (iface->ts_iface[0] == '\0') + strncpy(iface->ts_iface, iface->name, MAX_IFNAME_SIZE); + + rtnl_close(fd); + return 0; + +no_info: + rtnl_close(fd); +no_fd: + if (iface->ts_iface[0] == '\0') + strncpy(iface->ts_iface, iface->name, MAX_IFNAME_SIZE); + + return -1; +} diff --git a/rtnl.h b/rtnl.h index b4db40e..c382088 100644 --- a/rtnl.h +++ b/rtnl.h @@ -20,7 +20,9 @@ #ifndef HAVE_RTNL_H #define HAVE_RTNL_H -typedef void (*rtnl_callback)(void *ctx, int index, int linkup); +#include "config.h" + +typedef void (*rtnl_callback)(void *ctx, int index, int linkup, char *device); /** * Close a RT netlink socket. @@ -52,4 +54,10 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx); */ int rtnl_open(void); +/** + * Get interface link status and ts_iface information + * @param iface struct interface. + * @return Zero on success, or -1 on error. + */ +int rtnl_link_info(struct interface *iface); #endif -- 2.5.5 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel