Add new element ts_iface in struct interface to track real ts interface.

Add function rtnl_link_info() to get active interface. If no slave interface,
then use our own name as ts interface.

Also add new parameter ts_iface for function clock_link_status() to make aware
of interface change.

Signed-off-by: Hangbin Liu <liuhang...@gmail.com>
---
 clock.c  |   2 +-
 config.h |   1 +
 rtnl.c   | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 rtnl.h   |  33 ++++++++++++++++++-
 4 files changed, 142 insertions(+), 5 deletions(-)

diff --git a/clock.c b/clock.c
index 59b5f0c..5e9f2cd 100644
--- a/clock.c
+++ b/clock.c
@@ -326,7 +326,7 @@ static void clock_freq_est_reset(struct clock *c)
        c->fest.count = 0;
 }
 
-static void clock_link_status(void *ctx, int index, int linkup)
+static void clock_link_status(void *ctx, int index, int linkup, char *ts_iface)
 {
        struct clock *c = ctx;
        struct port *p;
diff --git a/config.h b/config.h
index 1cc7051..f0ae3fe 100644
--- a/config.h
+++ b/config.h
@@ -36,6 +36,7 @@
 struct interface {
        STAILQ_ENTRY(interface) list;
        char name[MAX_IFNAME_SIZE + 1];
+       char ts_iface[MAX_IFNAME_SIZE + 1];
        struct sk_ts_info ts_info;
 };
 
diff --git a/rtnl.c b/rtnl.c
index 39faeb7..971f273 100644
--- a/rtnl.c
+++ b/rtnl.c
@@ -18,8 +18,6 @@
  */
 #include <asm/types.h>
 #include <sys/socket.h> /* Must come before linux/netlink.h on some systems. */
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
 #include <net/if.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -84,6 +82,60 @@ 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);
+}
+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;
+}
+
+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 +144,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 +204,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 +242,33 @@ 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 failed;
+       }
+
+       fd = rtnl_open();
+       if (rtnl_link_query(fd, index))
+               goto failed;
+       if (rtnl_link_status(fd, NULL, iface->ts_iface))
+               goto failed;
+
+       /* 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;
+failed:
+       return -1;
+}
diff --git a/rtnl.h b/rtnl.h
index bd74cba..ed46cb7 100644
--- a/rtnl.h
+++ b/rtnl.h
@@ -20,7 +20,12 @@
 #ifndef HAVE_RTNL_H
 #define HAVE_RTNL_H
 
-typedef void (*rtnl_callback)(void *ctx, int index, int linkup);
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "config.h"
+
+typedef void (*rtnl_callback)(void *ctx, int index, int linkup, char *device);
 
 /**
  * Close a RT netlink socket.
@@ -38,6 +43,26 @@ int rtnl_close(int fd);
 int rtnl_link_query(int fd, unsigned int index);
 
 /**
+ * Parase the rtattr info
+ * @param tb     rtattr array.
+ * @param max    max type of ratttr.
+ * @param rta    rta header
+ * @param len    rta playload length
+ * @return       Zero on success, or -1 on error.
+ */
+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)))
+
+/**
+ * Parase the link info
+ * @param rta    rta header
+ * @param device interface name.
+ * @return       Zero on success, or -1 on error.
+ */
+int rtnl_linkinfo_parse(struct rtattr *rta, char *device);
+
+/**
  * Read kernel messages looking for a link up/down events.
  * @param fd   Readable socket obtained via rtnl_open().
  * @param cb   Callback function to be invoked on each event.
@@ -52,4 +77,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