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

Reply via email to