43ff50
commit 17aa750a49ebaecfc7b063c770aa8d36f5078b2c
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Jul 10 15:39:28 2017 +0800
43ff50
43ff50
    rtnl: replace obsolete RTMGRP_LINK with RTNLGRP_LINK for nl groups
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/rtnl.c b/rtnl.c
43ff50
index 5cddc4b..d7a430d 100644
43ff50
--- a/rtnl.c
43ff50
+++ b/rtnl.c
43ff50
@@ -151,7 +151,7 @@ int rtnl_open(void)
43ff50
 
43ff50
 	memset(&sa, 0, sizeof(sa));
43ff50
 	sa.nl_family = AF_NETLINK;
43ff50
-	sa.nl_groups = RTMGRP_LINK;
43ff50
+	sa.nl_groups = RTNLGRP_LINK;
43ff50
 
43ff50
 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
43ff50
 	if (fd < 0) {
43ff50
commit c149a3dbc1b38e833de783ae863038562baca0fe
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Jul 10 15:39:29 2017 +0800
43ff50
43ff50
    port: add FD_RTNL event to track per-port status
43ff50
    
43ff50
    With rtnl socket we can track link status per port(except UDS port).
43ff50
    
43ff50
    We can make sure we get the correct interface and latest status with function
43ff50
    port_link_status().
43ff50
    
43ff50
    At the same time we need to set clock sde after link down. But we return
43ff50
    EV_FAULT_DETECTED in port_event(), which will not set clock sde. So we need
43ff50
    to set it in port_link_status().
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/clock.c b/clock.c
43ff50
index b6afba9..4c5c4e3 100644
43ff50
--- a/clock.c
43ff50
+++ b/clock.c
43ff50
@@ -1469,6 +1469,11 @@ struct PortIdentity clock_parent_identity(struct clock *c)
43ff50
 	return c->dad.pds.parentPortIdentity;
43ff50
 }
43ff50
 
43ff50
+void clock_set_sde(struct clock *c, int sde)
43ff50
+{
43ff50
+	c->sde = sde;
43ff50
+}
43ff50
+
43ff50
 int clock_poll(struct clock *c)
43ff50
 {
43ff50
 	int cnt, i;
43ff50
diff --git a/clock.h b/clock.h
43ff50
index fcd9328..49ecb76 100644
43ff50
--- a/clock.h
43ff50
+++ b/clock.h
43ff50
@@ -205,6 +205,13 @@ void clock_peer_delay(struct clock *c, tmv_t ppd, tmv_t req, tmv_t rx,
43ff50
 		      double nrr);
43ff50
 
43ff50
 /**
43ff50
+ * Set clock sde
43ff50
+ * @param c     A pointer to a clock instance obtained with clock_create().
43ff50
+ * @param sde   Pass one (1) if need a decision event and zero if not.
43ff50
+ */
43ff50
+void clock_set_sde(struct clock *c, int sde);
43ff50
+
43ff50
+/**
43ff50
  * Poll for events and dispatch them.
43ff50
  * @param c A pointer to a clock instance obtained with clock_create().
43ff50
  * @return  Zero on success, non-zero otherwise.
43ff50
diff --git a/fd.h b/fd.h
43ff50
index e328e98..23401f4 100644
43ff50
--- a/fd.h
43ff50
+++ b/fd.h
43ff50
@@ -31,6 +31,7 @@ enum {
43ff50
 	FD_QUALIFICATION_TIMER,
43ff50
 	FD_MANNO_TIMER,
43ff50
 	FD_SYNC_TX_TIMER,
43ff50
+	FD_RTNL,
43ff50
 	N_POLLFD,
43ff50
 };
43ff50
 
43ff50
diff --git a/port.c b/port.c
43ff50
index ec02825..2896d1a 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -23,6 +23,7 @@
43ff50
 #include <string.h>
43ff50
 #include <unistd.h>
43ff50
 #include <sys/queue.h>
43ff50
+#include <net/if.h>
43ff50
 
43ff50
 #include "bmc.h"
43ff50
 #include "clock.h"
43ff50
@@ -32,6 +33,7 @@
43ff50
 #include "phc.h"
43ff50
 #include "port.h"
43ff50
 #include "print.h"
43ff50
+#include "rtnl.h"
43ff50
 #include "sk.h"
43ff50
 #include "tlv.h"
43ff50
 #include "tmv.h"
43ff50
@@ -1458,7 +1460,9 @@ static void port_disable(struct port *p)
43ff50
 	for (i = 0; i < N_TIMER_FDS; i++) {
43ff50
 		close(p->fda.fd[FD_ANNOUNCE_TIMER + i]);
43ff50
 	}
43ff50
-	port_clear_fda(p, N_POLLFD);
43ff50
+
43ff50
+	/* Keep rtnl socket to get link status info. */
43ff50
+	port_clear_fda(p, FD_RTNL);
43ff50
 	clock_fda_changed(p->clock);
43ff50
 }
43ff50
 
43ff50
@@ -1502,6 +1506,14 @@ static int port_initialize(struct port *p)
43ff50
 	if (port_set_announce_tmo(p))
43ff50
 		goto no_tmo;
43ff50
 
43ff50
+	/* No need to open rtnl socket on UDS port. */
43ff50
+	if (transport_type(p->trp) != TRANS_UDS) {
43ff50
+		if (p->fda.fd[FD_RTNL] == -1)
43ff50
+			p->fda.fd[FD_RTNL] = rtnl_open();
43ff50
+		if (p->fda.fd[FD_RTNL] >= 0)
43ff50
+			rtnl_link_query(p->fda.fd[FD_RTNL]);
43ff50
+	}
43ff50
+
43ff50
 	port_nrate_initialize(p);
43ff50
 
43ff50
 	clock_fda_changed(p->clock);
43ff50
@@ -2025,6 +2037,10 @@ void port_close(struct port *p)
43ff50
 	if (port_is_enabled(p)) {
43ff50
 		port_disable(p);
43ff50
 	}
43ff50
+
43ff50
+	if (p->fda.fd[FD_RTNL] >= 0)
43ff50
+		rtnl_close(p->fda.fd[FD_RTNL]);
43ff50
+
43ff50
 	transport_destroy(p->trp);
43ff50
 	tsproc_destroy(p->tsproc);
43ff50
 	if (p->fault_fd >= 0)
43ff50
@@ -2204,6 +2220,24 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
43ff50
 	}
43ff50
 }
43ff50
 
43ff50
+static void port_link_status(void *ctx, int index, int linkup)
43ff50
+{
43ff50
+	struct port *p = ctx;
43ff50
+
43ff50
+	if (index != if_nametoindex(p->name) || p->link_status == linkup)
43ff50
+		return;
43ff50
+
43ff50
+	p->link_status = linkup;
43ff50
+	pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
43ff50
+
43ff50
+	/*
43ff50
+	 * A port going down can affect the BMCA result.
43ff50
+	 * Force a state decision event.
43ff50
+	 */
43ff50
+	if (!p->link_status)
43ff50
+		clock_set_sde(p->clock, 1);
43ff50
+}
43ff50
+
43ff50
 enum fsm_event port_event(struct port *p, int fd_index)
43ff50
 {
43ff50
 	enum fsm_event event = EV_NONE;
43ff50
@@ -2242,6 +2276,11 @@ enum fsm_event port_event(struct port *p, int fd_index)
43ff50
 		pr_debug("port %hu: master sync timeout", portnum(p));
43ff50
 		port_set_sync_tx_tmo(p);
43ff50
 		return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE;
43ff50
+
43ff50
+	case FD_RTNL:
43ff50
+		pr_debug("port %hu: received link status notification", portnum(p));
43ff50
+		rtnl_link_status(fd, port_link_status, p);
43ff50
+		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
43ff50
 	}
43ff50
 
43ff50
 	msg = msg_allocate();
43ff50
commit 25ec8a3b4e2222b394794ff830bd3583e9cf6c71
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Jul 10 15:39:30 2017 +0800
43ff50
43ff50
    clock: remove rtnl fd on clock
43ff50
    
43ff50
    Remove rtnl fd on clock since we track the link status per port now.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/clock.c b/clock.c
43ff50
index 4c5c4e3..354f038 100644
43ff50
--- a/clock.c
43ff50
+++ b/clock.c
43ff50
@@ -39,7 +39,6 @@
43ff50
 #include "servo.h"
43ff50
 #include "stats.h"
43ff50
 #include "print.h"
43ff50
-#include "rtnl.h"
43ff50
 #include "sk.h"
43ff50
 #include "tlv.h"
43ff50
 #include "tsproc.h"
43ff50
@@ -274,9 +273,6 @@ void clock_destroy(struct clock *c)
43ff50
 	LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
43ff50
 		clock_remove_port(c, p);
43ff50
 	}
43ff50
-	if (c->pollfd[0].fd >= 0) {
43ff50
-		rtnl_close(c->pollfd[0].fd);
43ff50
-	}
43ff50
 	port_close(c->uds_port);
43ff50
 	free(c->pollfd);
43ff50
 	hash_destroy(c->index2port, NULL);
43ff50
@@ -326,30 +322,6 @@ static void clock_freq_est_reset(struct clock *c)
43ff50
 	c->fest.count = 0;
43ff50
 }
43ff50
 
43ff50
-static void clock_link_status(void *ctx, int index, int linkup)
43ff50
-{
43ff50
-	struct clock *c = ctx;
43ff50
-	struct port *p;
43ff50
-	char key[16];
43ff50
-
43ff50
-	snprintf(key, sizeof(key), "%d", index);
43ff50
-	p = hash_lookup(c->index2port, key);
43ff50
-	if (!p) {
43ff50
-		return;
43ff50
-	}
43ff50
-	port_link_status_set(p, linkup);
43ff50
-	if (linkup) {
43ff50
-		port_dispatch(p, EV_FAULT_CLEARED, 0);
43ff50
-	} else {
43ff50
-		port_dispatch(p, EV_FAULT_DETECTED, 0);
43ff50
-		/*
43ff50
-		 * A port going down can affect the BMCA result.
43ff50
-		 * Force a state decision event.
43ff50
-		 */
43ff50
-		c->sde = 1;
43ff50
-	}
43ff50
-}
43ff50
-
43ff50
 static void clock_management_send_error(struct port *p,
43ff50
 					struct ptp_message *msg, int error_id)
43ff50
 {
43ff50
@@ -1133,10 +1105,6 @@ struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 		return NULL;
43ff50
 	}
43ff50
 
43ff50
-	/* Open a RT netlink socket. */
43ff50
-	c->pollfd[0].fd = rtnl_open();
43ff50
-	c->pollfd[0].events = POLLIN|POLLPRI;
43ff50
-
43ff50
 	/* Create the UDS interface. */
43ff50
 	c->uds_port = port_open(phc_index, timestamping, 0, udsif, c);
43ff50
 	if (!c->uds_port) {
43ff50
@@ -1164,9 +1132,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 		port_dispatch(p, EV_INITIALIZE, 0);
43ff50
 	}
43ff50
 	port_dispatch(c->uds_port, EV_INITIALIZE, 0);
43ff50
-	if (c->pollfd[0].fd >= 0) {
43ff50
-		rtnl_link_query(c->pollfd[0].fd);
43ff50
-	}
43ff50
+
43ff50
 	return c;
43ff50
 }
43ff50
 
43ff50
@@ -1231,12 +1197,9 @@ static int clock_resize_pollfd(struct clock *c, int new_nports)
43ff50
 {
43ff50
 	struct pollfd *new_pollfd;
43ff50
 
43ff50
-	/*
43ff50
-	 * Need to allocate one descriptor for RT netlink and one
43ff50
-	 * whole extra block of fds for UDS.
43ff50
-	 */
43ff50
+	/* Need to allocate one whole extra block of fds for UDS. */
43ff50
 	new_pollfd = realloc(c->pollfd,
43ff50
-			     (1 + (new_nports + 1) * N_CLOCK_PFD) *
43ff50
+			     (new_nports + 1) * N_CLOCK_PFD *
43ff50
 			     sizeof(struct pollfd));
43ff50
 	if (!new_pollfd)
43ff50
 		return -1;
43ff50
@@ -1261,7 +1224,7 @@ static void clock_fill_pollfd(struct pollfd *dest, struct port *p)
43ff50
 static void clock_check_pollfd(struct clock *c)
43ff50
 {
43ff50
 	struct port *p;
43ff50
-	struct pollfd *dest = c->pollfd + 1;
43ff50
+	struct pollfd *dest = c->pollfd;
43ff50
 
43ff50
 	if (c->pollfd_valid)
43ff50
 		return;
43ff50
@@ -1482,7 +1445,7 @@ int clock_poll(struct clock *c)
43ff50
 	struct port *p;
43ff50
 
43ff50
 	clock_check_pollfd(c);
43ff50
-	cnt = poll(c->pollfd, 1 + (c->nports + 1) * N_CLOCK_PFD, -1);
43ff50
+	cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);
43ff50
 	if (cnt < 0) {
43ff50
 		if (EINTR == errno) {
43ff50
 			return 0;
43ff50
@@ -1494,13 +1457,8 @@ int clock_poll(struct clock *c)
43ff50
 		return 0;
43ff50
 	}
43ff50
 
43ff50
-	/* Check the RT netlink. */
43ff50
 	cur = c->pollfd;
43ff50
-	if (cur->revents & (POLLIN|POLLPRI)) {
43ff50
-		rtnl_link_status(cur->fd, clock_link_status, c);
43ff50
-	}
43ff50
 
43ff50
-	cur++;
43ff50
 	LIST_FOREACH(p, &c->ports, list) {
43ff50
 		/* Let the ports handle their events. */
43ff50
 		for (i = 0; i < N_POLLFD; i++) {
43ff50
diff --git a/port.c b/port.c
43ff50
index 2896d1a..34837cc 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -2411,12 +2411,6 @@ int port_link_status_get(struct port *p)
43ff50
 	return p->link_status;
43ff50
 }
43ff50
 
43ff50
-void port_link_status_set(struct port *p, int up)
43ff50
-{
43ff50
-	p->link_status = up ? 1 : 0;
43ff50
-	pr_notice("port %hu: link %s", portnum(p), up ? "up" : "down");
43ff50
-}
43ff50
-
43ff50
 int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg)
43ff50
 {
43ff50
 	struct management_tlv *mgt;
43ff50
diff --git a/port.h b/port.h
43ff50
index b00bc64..60fd0a4 100644
43ff50
--- a/port.h
43ff50
+++ b/port.h
43ff50
@@ -132,13 +132,6 @@ int port_number(struct port *p);
43ff50
 int port_link_status_get(struct port *p);
43ff50
 
43ff50
 /**
43ff50
- * Sets the link status for a port.
43ff50
- * @param p        A port instance.
43ff50
- * @param up       Pass one (1) if the link is up and zero if down.
43ff50
- */
43ff50
-void port_link_status_set(struct port *p, int up);
43ff50
-
43ff50
-/**
43ff50
  * Manage a port according to a given message.
43ff50
  * @param p        A pointer previously obtained via port_open().
43ff50
  * @param ingress  The port on which 'msg' was received.
43ff50
commit 7c3f9579f0c230ee798644a26d664ebd3efc612f
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Jul 10 15:39:31 2017 +0800
43ff50
43ff50
    clock: remove hash table index2port
43ff50
    
43ff50
    Remove index2port since we don't need it now.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/clock.c b/clock.c
43ff50
index 354f038..da15882 100644
43ff50
--- a/clock.c
43ff50
+++ b/clock.c
43ff50
@@ -31,7 +31,6 @@
43ff50
 #include "clockcheck.h"
43ff50
 #include "foreign.h"
43ff50
 #include "filter.h"
43ff50
-#include "hash.h"
43ff50
 #include "missing.h"
43ff50
 #include "msg.h"
43ff50
 #include "phc.h"
43ff50
@@ -39,7 +38,6 @@
43ff50
 #include "servo.h"
43ff50
 #include "stats.h"
43ff50
 #include "print.h"
43ff50
-#include "sk.h"
43ff50
 #include "tlv.h"
43ff50
 #include "tsproc.h"
43ff50
 #include "uds.h"
43ff50
@@ -96,7 +94,6 @@ struct clock {
43ff50
 	int nports; /* does not include the UDS port */
43ff50
 	int last_port_number;
43ff50
 	int sde;
43ff50
-	struct hash *index2port;
43ff50
 	int free_running;
43ff50
 	int freq_est_interval;
43ff50
 	int grand_master_capable; /* for 802.1AS only */
43ff50
@@ -275,7 +272,6 @@ void clock_destroy(struct clock *c)
43ff50
 	}
43ff50
 	port_close(c->uds_port);
43ff50
 	free(c->pollfd);
43ff50
-	hash_destroy(c->index2port, NULL);
43ff50
 	if (c->clkid != CLOCK_REALTIME) {
43ff50
 		phc_close(c->clkid);
43ff50
 	}
43ff50
@@ -773,8 +769,6 @@ static int clock_add_port(struct clock *c, int phc_index,
43ff50
 			  struct interface *iface)
43ff50
 {
43ff50
 	struct port *p, *piter, *lastp = NULL;
43ff50
-	int fd, index;
43ff50
-	char key[16];
43ff50
 
43ff50
 	if (clock_resize_pollfd(c, c->nports + 1)) {
43ff50
 		return -1;
43ff50
@@ -795,24 +789,6 @@ static int clock_add_port(struct clock *c, int phc_index,
43ff50
 	c->nports++;
43ff50
 	clock_fda_changed(c);
43ff50
 
43ff50
-	/* Remember the index to port mapping, for link status tracking. */
43ff50
-	fd = sk_interface_fd();
43ff50
-	if (fd < 0) {
43ff50
-		return -1;
43ff50
-	}
43ff50
-	index = sk_interface_index(fd, iface->name);
43ff50
-	if (index < 0) {
43ff50
-		close(fd);
43ff50
-		return -1;
43ff50
-	}
43ff50
-	snprintf(key, sizeof(key), "%d", index);
43ff50
-	if (hash_insert(c->index2port, key, p)) {
43ff50
-		pr_err("failed to add port with index %d twice!", index);
43ff50
-		close(fd);
43ff50
-		return -1;
43ff50
-	}
43ff50
-	close(fd);
43ff50
-
43ff50
 	return 0;
43ff50
 }
43ff50
 
43ff50
@@ -1113,11 +1089,6 @@ struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 	}
43ff50
 	clock_fda_changed(c);
43ff50
 
43ff50
-	c->index2port = hash_create();
43ff50
-	if (!c->index2port) {
43ff50
-		pr_err("failed create index-to-port hash table");
43ff50
-		return NULL;
43ff50
-	}
43ff50
 	/* Create the ports. */
43ff50
 	STAILQ_FOREACH(iface, &config->interfaces, list) {
43ff50
 		if (clock_add_port(c, phc_index, timestamping, iface)) {
43ff50
commit 9e744d9e8a2dab6ec0ea5ece5ac25e7384264575
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:39 2017 +0800
43ff50
43ff50
    config: add new element ts_label in struct interface
43ff50
    
43ff50
    Add new element ts_label in struct interface to track real ts interface.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/config.h b/config.h
43ff50
index 1cc7051..c79855e 100644
43ff50
--- a/config.h
43ff50
+++ b/config.h
43ff50
@@ -36,6 +36,7 @@
43ff50
 struct interface {
43ff50
 	STAILQ_ENTRY(interface) list;
43ff50
 	char name[MAX_IFNAME_SIZE + 1];
43ff50
+	char ts_label[MAX_IFNAME_SIZE + 1];
43ff50
 	struct sk_ts_info ts_info;
43ff50
 };
43ff50
 
43ff50
commit 7e294a4d047654f746c3fcdff7bce512be149e37
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:40 2017 +0800
43ff50
43ff50
    port: track interface info in port
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/port.c b/port.c
43ff50
index 34837cc..849a7c1 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -68,6 +68,7 @@ struct nrate_estimator {
43ff50
 struct port {
43ff50
 	LIST_ENTRY(port) list;
43ff50
 	char *name;
43ff50
+	struct interface *iface;
43ff50
 	struct clock *clock;
43ff50
 	struct transport *trp;
43ff50
 	enum timestamp_type timestamping;
43ff50
@@ -2619,6 +2620,7 @@ struct port *port_open(int phc_index,
43ff50
 	}
43ff50
 
43ff50
 	p->name = interface->name;
43ff50
+	p->iface = interface;
43ff50
 	p->asymmetry = config_get_int(cfg, p->name, "delayAsymmetry");
43ff50
 	p->asymmetry <<= 16;
43ff50
 	p->announce_span = transport == TRANS_UDS ? 0 : ANNOUNCE_SPAN;
43ff50
commit 05bba46198cfc4ccfe0aff2e67e76d78898bbd96
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:41 2017 +0800
43ff50
43ff50
    rtnl: update rtgenmsg to ifinfomsg when request link info
43ff50
    
43ff50
    The previous function use general message and will dump all interfaces'
43ff50
    information. Now update with ifinfomsg so we could get specific interface's
43ff50
    information.
43ff50
    
43ff50
    We still could get all interfaces' info if set device to NULL.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/port.c b/port.c
43ff50
index 849a7c1..5b85d87 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -1512,7 +1512,7 @@ static int port_initialize(struct port *p)
43ff50
 		if (p->fda.fd[FD_RTNL] == -1)
43ff50
 			p->fda.fd[FD_RTNL] = rtnl_open();
43ff50
 		if (p->fda.fd[FD_RTNL] >= 0)
43ff50
-			rtnl_link_query(p->fda.fd[FD_RTNL]);
43ff50
+			rtnl_link_query(p->fda.fd[FD_RTNL], p->iface->name);
43ff50
 	}
43ff50
 
43ff50
 	port_nrate_initialize(p);
43ff50
diff --git a/rtnl.c b/rtnl.c
43ff50
index d7a430d..8ecf6fe 100644
43ff50
--- a/rtnl.c
43ff50
+++ b/rtnl.c
43ff50
@@ -42,7 +42,7 @@ int rtnl_close(int fd)
43ff50
 	return close(fd);
43ff50
 }
43ff50
 
43ff50
-int rtnl_link_query(int fd)
43ff50
+int rtnl_link_query(int fd, char *device)
43ff50
 {
43ff50
 	struct sockaddr_nl sa;
43ff50
 	struct msghdr msg;
43ff50
@@ -51,19 +51,21 @@ int rtnl_link_query(int fd)
43ff50
 
43ff50
 	struct {
43ff50
 		struct nlmsghdr hdr;
43ff50
-		struct rtgenmsg gen;
43ff50
+		struct ifinfomsg ifm;
43ff50
 	} __attribute__((packed)) request;
43ff50
 
43ff50
 	memset(&sa, 0, sizeof(sa));
43ff50
 	sa.nl_family = AF_NETLINK;
43ff50
 
43ff50
 	memset(&request, 0, sizeof(request));
43ff50
-	request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen));
43ff50
+	request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.ifm));
43ff50
 	request.hdr.nlmsg_type = RTM_GETLINK;
43ff50
-	request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
43ff50
+	request.hdr.nlmsg_flags = NLM_F_REQUEST;
43ff50
 	request.hdr.nlmsg_seq = 1;
43ff50
 	request.hdr.nlmsg_pid = 0;
43ff50
-	request.gen.rtgen_family = AF_UNSPEC;
43ff50
+	request.ifm.ifi_family = AF_UNSPEC;
43ff50
+	request.ifm.ifi_index = if_nametoindex(device ? device : "");
43ff50
+	request.ifm.ifi_change = 0xffffffff;
43ff50
 
43ff50
 	iov.iov_base = &request;
43ff50
 	iov.iov_len = sizeof(request);
43ff50
diff --git a/rtnl.h b/rtnl.h
43ff50
index f1871f2..5c93eec 100644
43ff50
--- a/rtnl.h
43ff50
+++ b/rtnl.h
43ff50
@@ -31,10 +31,11 @@ int rtnl_close(int fd);
43ff50
 
43ff50
 /**
43ff50
  * Request the link status from the kernel.
43ff50
- * @param fd  A socket obtained via rtnl_open().
43ff50
- * @return    Zero on success, non-zero otherwise.
43ff50
+ * @param fd     A socket obtained via rtnl_open().
43ff50
+ * @param device Interface name. Request all iface's status if set NULL.
43ff50
+ * @return       Zero on success, non-zero otherwise.
43ff50
  */
43ff50
-int rtnl_link_query(int fd);
43ff50
+int rtnl_link_query(int fd, char *device);
43ff50
 
43ff50
 /**
43ff50
  * Read kernel messages looking for a link up/down events.
43ff50
Backport of commit 80bc4d4c2f4d1c3c246091aa6f103bb7943202ec
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:42 2017 +0800
43ff50
43ff50
    rtnl: update function rtnl_link_status to get bond slave info
43ff50
    
43ff50
    Update function rtnl_link_status to get bond slave info. Pass the slave index
43ff50
    to call back functions. i.e. port_link_status.
43ff50
    
43ff50
    Also check the interface index of rtnl message in function rtnl_link_status.
43ff50
    Then we don't need to check it in port_link_status.
43ff50
    
43ff50
    [BACKPORT: not included] Add ifndef IFLA_BOND_MAX in case we build linuxptp
43ff50
    on kernel before v3.13-rc1.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/port.c b/port.c
43ff50
index 5b85d87..05fc321 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -2221,11 +2221,11 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
43ff50
 	}
43ff50
 }
43ff50
 
43ff50
-static void port_link_status(void *ctx, int index, int linkup)
43ff50
+static void port_link_status(void *ctx, int linkup, int ts_index)
43ff50
 {
43ff50
 	struct port *p = ctx;
43ff50
 
43ff50
-	if (index != if_nametoindex(p->name) || p->link_status == linkup)
43ff50
+	if (p->link_status == linkup)
43ff50
 		return;
43ff50
 
43ff50
 	p->link_status = linkup;
43ff50
@@ -2280,7 +2280,7 @@ enum fsm_event port_event(struct port *p, int fd_index)
43ff50
 
43ff50
 	case FD_RTNL:
43ff50
 		pr_debug("port %hu: received link status notification", portnum(p));
43ff50
-		rtnl_link_status(fd, port_link_status, p);
43ff50
+		rtnl_link_status(fd, p->name, port_link_status, p);
43ff50
 		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
43ff50
 	}
43ff50
 
43ff50
diff --git a/rtnl.c b/rtnl.c
43ff50
index 8ecf6fe..3419873 100644
43ff50
--- a/rtnl.c
43ff50
+++ b/rtnl.c
43ff50
@@ -84,15 +85,79 @@ int rtnl_link_query(int fd, char *device)
43ff50
 	return 0;
43ff50
 }
43ff50
 
43ff50
-int rtnl_link_status(int fd, rtnl_callback cb, void *ctx)
43ff50
+static inline __u32 rta_getattr_u32(const struct rtattr *rta)
43ff50
 {
43ff50
-	int index, len;
43ff50
+	return *(__u32 *)RTA_DATA(rta);
43ff50
+}
43ff50
+
43ff50
+static inline const char *rta_getattr_str(const struct rtattr *rta)
43ff50
+{
43ff50
+	return (const char *)RTA_DATA(rta);
43ff50
+}
43ff50
+
43ff50
+static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len)
43ff50
+{
43ff50
+	unsigned short type;
43ff50
+
43ff50
+	memset(tb, 0, sizeof(struct rtattr *) * max);
43ff50
+	while (RTA_OK(rta, len)) {
43ff50
+		type = rta->rta_type;
43ff50
+		if ((type < max) && (!tb[type]))
43ff50
+			tb[type] = rta;
43ff50
+		rta = RTA_NEXT(rta, len);
43ff50
+	}
43ff50
+	if (len) {
43ff50
+		pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len);
43ff50
+		return -1;
43ff50
+	}
43ff50
+
43ff50
+	return 0;
43ff50
+}
43ff50
+
43ff50
+static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta)
43ff50
+{
43ff50
+	return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
43ff50
+}
43ff50
+
43ff50
+static int rtnl_linkinfo_parse(struct rtattr *rta)
43ff50
+{
43ff50
+	int index = -1;
43ff50
+	const char *kind;
43ff50
+	struct rtattr *linkinfo[IFLA_INFO_MAX];
43ff50
+	struct rtattr *bond[IFLA_BOND_MAX];
43ff50
+
43ff50
+	if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0)
43ff50
+		return -1;
43ff50
+
43ff50
+	if (linkinfo[IFLA_INFO_KIND]) {
43ff50
+		kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
43ff50
+
43ff50
+		if (kind && !strncmp(kind, "bond", 4) &&
43ff50
+		    linkinfo[IFLA_INFO_DATA]) {
43ff50
+			if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX,
43ff50
+						 linkinfo[IFLA_INFO_DATA]) < 0)
43ff50
+				return -1;
43ff50
+
43ff50
+			if (bond[IFLA_BOND_ACTIVE_SLAVE]) {
43ff50
+				index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]);
43ff50
+			}
43ff50
+		}
43ff50
+	}
43ff50
+	return index;
43ff50
+}
43ff50
+
43ff50
+int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx)
43ff50
+{
43ff50
+	int index, len, link_up;
43ff50
+	int slave_index = -1;
43ff50
 	struct iovec iov;
43ff50
 	struct sockaddr_nl sa;
43ff50
 	struct msghdr msg;
43ff50
 	struct nlmsghdr *nh;
43ff50
 	struct ifinfomsg *info = NULL;
43ff50
+	struct rtattr *tb[IFLA_MAX+1];
43ff50
 
43ff50
+	index = if_nametoindex(device);
43ff50
 	if (!rtnl_buf) {
43ff50
 		rtnl_len = 4096;
43ff50
 		rtnl_buf = malloc(rtnl_len);
43ff50
@@ -135,14 +200,27 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx)
43ff50
 	nh = (struct nlmsghdr *) rtnl_buf;
43ff50
 
43ff50
 	for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
43ff50
-		if (nh->nlmsg_type == RTM_NEWLINK) {
43ff50
-			info = NLMSG_DATA(nh);
43ff50
-			index = info->ifi_index;
43ff50
-			pr_debug("interface index %d is %s", index,
43ff50
-				 info->ifi_flags & IFF_RUNNING ? "up" : "down");
43ff50
-			cb(ctx, index, info->ifi_flags & IFF_RUNNING ? 1 : 0);
43ff50
-		}
43ff50
+		if (nh->nlmsg_type != RTM_NEWLINK)
43ff50
+			continue;
43ff50
+
43ff50
+		info = NLMSG_DATA(nh);
43ff50
+		if (index != info->ifi_index)
43ff50
+			continue;
43ff50
+
43ff50
+		link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0;
43ff50
+		pr_debug("interface index %d is %s", index,
43ff50
+			 link_up ? "up" : "down");
43ff50
+
43ff50
+		rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info),
43ff50
+				  IFLA_PAYLOAD(nh));
43ff50
+
43ff50
+		if (tb[IFLA_LINKINFO])
43ff50
+			slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]);
43ff50
+
43ff50
+		if (cb)
43ff50
+			cb(ctx, link_up, slave_index);
43ff50
 	}
43ff50
+
43ff50
 	return 0;
43ff50
 }
43ff50
 
43ff50
diff --git a/rtnl.h b/rtnl.h
43ff50
index 5c93eec..6eced2d 100644
43ff50
--- a/rtnl.h
43ff50
+++ b/rtnl.h
43ff50
@@ -20,7 +20,7 @@
43ff50
 #ifndef HAVE_RTNL_H
43ff50
 #define HAVE_RTNL_H
43ff50
 
43ff50
-typedef void (*rtnl_callback)(void *ctx, int index, int linkup);
43ff50
+typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
43ff50
 
43ff50
 /**
43ff50
  * Close a RT netlink socket.
43ff50
@@ -39,12 +39,13 @@ int rtnl_link_query(int fd, char *device);
43ff50
 
43ff50
 /**
43ff50
  * Read kernel messages looking for a link up/down events.
43ff50
- * @param fd   Readable socket obtained via rtnl_open().
43ff50
- * @param cb   Callback function to be invoked on each event.
43ff50
- * @param ctx  Private context passed to the callback.
43ff50
- * @return     Zero on success, non-zero otherwise.
43ff50
+ * @param fd     Readable socket obtained via rtnl_open().
43ff50
+ * @param device The device which we need to get link info.
43ff50
+ * @param cb     Callback function to be invoked on each event.
43ff50
+ * @param ctx    Private context passed to the callback.
43ff50
+ * @return       Zero on success, non-zero otherwise.
43ff50
  */
43ff50
-int rtnl_link_status(int fd, rtnl_callback cb, void *ctx);
43ff50
+int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx);
43ff50
 
43ff50
 /**
43ff50
  * Open a RT netlink socket for monitoring link state.
43ff50
commit 6d1e2a62bdb4f6353e3a9006f2d603031f4648e6
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:43 2017 +0800
43ff50
43ff50
    rtnl: add function rtnl_get_ts_label to get interface ts_label info
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/rtnl.c b/rtnl.c
43ff50
index 3419873..cea936b 100644
43ff50
--- a/rtnl.c
43ff50
+++ b/rtnl.c
43ff50
@@ -43,6 +43,37 @@ int rtnl_close(int fd)
43ff50
 	return close(fd);
43ff50
 }
43ff50
 
43ff50
+static void rtnl_get_ts_label_callback(void *ctx, int linkup, int ts_index)
43ff50
+{
43ff50
+	int *dst = ctx;
43ff50
+	*dst = ts_index;
43ff50
+}
43ff50
+
43ff50
+int rtnl_get_ts_label(struct interface *iface)
43ff50
+{
43ff50
+	int err, fd;
43ff50
+	int ts_index = -1;
43ff50
+
43ff50
+	fd = rtnl_open();
43ff50
+	if (fd < 0)
43ff50
+		return fd;
43ff50
+
43ff50
+	err = rtnl_link_query(fd, iface->name);
43ff50
+	if (err) {
43ff50
+		goto no_info;
43ff50
+	}
43ff50
+
43ff50
+	rtnl_link_status(fd, iface->name, rtnl_get_ts_label_callback, &ts_index);
43ff50
+	if (ts_index > 0 && if_indextoname(ts_index, iface->ts_label))
43ff50
+		err = 0;
43ff50
+	else
43ff50
+		err = -1;
43ff50
+
43ff50
+no_info:
43ff50
+	rtnl_close(fd);
43ff50
+	return err;
43ff50
+}
43ff50
+
43ff50
 int rtnl_link_query(int fd, char *device)
43ff50
 {
43ff50
 	struct sockaddr_nl sa;
43ff50
diff --git a/rtnl.h b/rtnl.h
43ff50
index 6eced2d..2906d74 100644
43ff50
--- a/rtnl.h
43ff50
+++ b/rtnl.h
43ff50
@@ -20,6 +20,8 @@
43ff50
 #ifndef HAVE_RTNL_H
43ff50
 #define HAVE_RTNL_H
43ff50
 
43ff50
+#include "config.h"
43ff50
+
43ff50
 typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
43ff50
 
43ff50
 /**
43ff50
@@ -30,6 +32,13 @@ typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
43ff50
 int rtnl_close(int fd);
43ff50
 
43ff50
 /**
43ff50
+ * Get interface ts_label information
43ff50
+ * @param iface  struct interface.
43ff50
+ * @return       Zero on success, or -1 on error.
43ff50
+ */
43ff50
+int rtnl_get_ts_label(struct interface *iface);
43ff50
+
43ff50
+/**
43ff50
  * Request the link status from the kernel.
43ff50
  * @param fd     A socket obtained via rtnl_open().
43ff50
  * @param device Interface name. Request all iface's status if set NULL.
43ff50
commit b65b1d5f3b5d8e85e47e9cf19c2e5aa6dc2ebd77
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:44 2017 +0800
43ff50
43ff50
    port: update port link_status to enum
43ff50
    
43ff50
    Besides link up and down, we may also receive other rtnl messages, like
43ff50
    bond slave changed info, which link state keeps the same.
43ff50
    
43ff50
    So we should return EV_FAULT_CLEARED only when both LINK_UP and
43ff50
    LINK_STATE_CHANGED.
43ff50
    
43ff50
    When the link state keep the same, we should return EV_NONE.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/port.c b/port.c
43ff50
index 05fc321..81d52ff 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -56,6 +56,12 @@ enum syfu_event {
43ff50
 	FUP_MATCH,
43ff50
 };
43ff50
 
43ff50
+enum link_state {
43ff50
+	LINK_DOWN  = (1<<0),
43ff50
+	LINK_UP  = (1<<1),
43ff50
+	LINK_STATE_CHANGED = (1<<3),
43ff50
+};
43ff50
+
43ff50
 struct nrate_estimator {
43ff50
 	double ratio;
43ff50
 	tmv_t origin1;
43ff50
@@ -122,7 +128,7 @@ struct port {
43ff50
 	int                 path_trace_enabled;
43ff50
 	int                 rx_timestamp_offset;
43ff50
 	int                 tx_timestamp_offset;
43ff50
-	int                 link_status;
43ff50
+	enum link_state     link_status;
43ff50
 	struct fault_interval flt_interval_pertype[FT_CNT];
43ff50
 	enum fault_type     last_fault_type;
43ff50
 	unsigned int        versionNumber; /*UInteger4*/
43ff50
@@ -2224,18 +2230,21 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
43ff50
 static void port_link_status(void *ctx, int linkup, int ts_index)
43ff50
 {
43ff50
 	struct port *p = ctx;
43ff50
+	int link_state;
43ff50
 
43ff50
-	if (p->link_status == linkup)
43ff50
-		return;
43ff50
-
43ff50
-	p->link_status = linkup;
43ff50
-	pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
43ff50
+	link_state = linkup ? LINK_UP : LINK_DOWN;
43ff50
+	if (p->link_status & link_state) {
43ff50
+		p->link_status = link_state;
43ff50
+	} else {
43ff50
+		p->link_status = link_state | LINK_STATE_CHANGED;
43ff50
+		pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
43ff50
+	}
43ff50
 
43ff50
 	/*
43ff50
 	 * A port going down can affect the BMCA result.
43ff50
 	 * Force a state decision event.
43ff50
 	 */
43ff50
-	if (!p->link_status)
43ff50
+	if (p->link_status & LINK_DOWN)
43ff50
 		clock_set_sde(p->clock, 1);
43ff50
 }
43ff50
 
43ff50
@@ -2281,7 +2290,12 @@ enum fsm_event port_event(struct port *p, int fd_index)
43ff50
 	case FD_RTNL:
43ff50
 		pr_debug("port %hu: received link status notification", portnum(p));
43ff50
 		rtnl_link_status(fd, p->name, port_link_status, p);
43ff50
-		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
43ff50
+		if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))
43ff50
+			return EV_FAULT_CLEARED;
43ff50
+		else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED))
43ff50
+			return EV_FAULT_DETECTED;
43ff50
+		else
43ff50
+			return EV_NONE;
43ff50
 	}
43ff50
 
43ff50
 	msg = msg_allocate();
43ff50
@@ -2409,7 +2423,7 @@ int port_number(struct port *p)
43ff50
 
43ff50
 int port_link_status_get(struct port *p)
43ff50
 {
43ff50
-	return p->link_status;
43ff50
+	return !!(p->link_status & LINK_UP);
43ff50
 }
43ff50
 
43ff50
 int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg)
43ff50
@@ -2630,7 +2644,7 @@ struct port *port_open(int phc_index,
43ff50
 	p->path_trace_enabled = config_get_int(cfg, p->name, "path_trace_enabled");
43ff50
 	p->rx_timestamp_offset = config_get_int(cfg, p->name, "ingressLatency");
43ff50
 	p->tx_timestamp_offset = config_get_int(cfg, p->name, "egressLatency");
43ff50
-	p->link_status = 1;
43ff50
+	p->link_status = LINK_UP;
43ff50
 	p->clock = clock;
43ff50
 	p->trp = transport_create(cfg, transport);
43ff50
 	if (!p->trp)
43ff50
commit 1440f093847a79d0e80ea6b4bca011ddd87090d0
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:45 2017 +0800
43ff50
43ff50
    clock: add clock_required_modes to obtain the required time stamping mode
43ff50
    
43ff50
    Separate required_modes setting from clock_create so we can obtain the
43ff50
    required time stamping flags from other place.
43ff50
    
43ff50
    Add enum timestamping in struct clock to store the time stamping mode.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/clock.c b/clock.c
43ff50
index 9d224c9..5926a3c 100644
43ff50
--- a/clock.c
43ff50
+++ b/clock.c
43ff50
@@ -105,6 +105,7 @@ struct clock {
43ff50
 	int time_flags;  /* grand master role */
43ff50
 	int time_source; /* grand master role */
43ff50
 	enum servo_state servo_state;
43ff50
+	enum timestamp_type timestamping;
43ff50
 	tmv_t master_offset;
43ff50
 	tmv_t path_delay;
43ff50
 	tmv_t ingress_ts;
43ff50
@@ -803,6 +804,34 @@ static void clock_remove_port(struct clock *c, struct port *p)
43ff50
 	port_close(p);
43ff50
 }
43ff50
 
43ff50
+int clock_required_modes(struct clock *c)
43ff50
+{
43ff50
+	int required_modes = 0;
43ff50
+
43ff50
+	switch (c->timestamping) {
43ff50
+	case TS_SOFTWARE:
43ff50
+		required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE |
43ff50
+			SOF_TIMESTAMPING_RX_SOFTWARE |
43ff50
+			SOF_TIMESTAMPING_SOFTWARE;
43ff50
+		break;
43ff50
+	case TS_LEGACY_HW:
43ff50
+		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
43ff50
+			SOF_TIMESTAMPING_RX_HARDWARE |
43ff50
+			SOF_TIMESTAMPING_SYS_HARDWARE;
43ff50
+		break;
43ff50
+	case TS_HARDWARE:
43ff50
+	case TS_ONESTEP:
43ff50
+		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
43ff50
+			SOF_TIMESTAMPING_RX_HARDWARE |
43ff50
+			SOF_TIMESTAMPING_RAW_HARDWARE;
43ff50
+		break;
43ff50
+	default:
43ff50
+		break;
43ff50
+	}
43ff50
+
43ff50
+	return required_modes;
43ff50
+}
43ff50
+
43ff50
 struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 			   const char *phc_device)
43ff50
 {
43ff50
@@ -911,24 +940,8 @@ struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 	}
43ff50
 
43ff50
 	/* Check the time stamping mode on each interface. */
43ff50
-	switch (timestamping) {
43ff50
-	case TS_SOFTWARE:
43ff50
-		required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE |
43ff50
-			SOF_TIMESTAMPING_RX_SOFTWARE |
43ff50
-			SOF_TIMESTAMPING_SOFTWARE;
43ff50
-		break;
43ff50
-	case TS_LEGACY_HW:
43ff50
-		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
43ff50
-			SOF_TIMESTAMPING_RX_HARDWARE |
43ff50
-			SOF_TIMESTAMPING_SYS_HARDWARE;
43ff50
-		break;
43ff50
-	case TS_HARDWARE:
43ff50
-	case TS_ONESTEP:
43ff50
-		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
43ff50
-			SOF_TIMESTAMPING_RX_HARDWARE |
43ff50
-			SOF_TIMESTAMPING_RAW_HARDWARE;
43ff50
-		break;
43ff50
-	}
43ff50
+	c->timestamping = timestamping;
43ff50
+	required_modes = clock_required_modes(c);
43ff50
 	STAILQ_FOREACH(iface, &config->interfaces, list) {
43ff50
 		if (iface->ts_info.valid &&
43ff50
 		    ((iface->ts_info.so_timestamping & required_modes) != required_modes)) {
43ff50
diff --git a/clock.h b/clock.h
43ff50
index 49ecb76..986d363 100644
43ff50
--- a/clock.h
43ff50
+++ b/clock.h
43ff50
@@ -73,6 +73,14 @@ UInteger8 clock_class(struct clock *c);
43ff50
 struct config *clock_config(struct clock *c);
43ff50
 
43ff50
 /**
43ff50
+ * Obtains the required time stamping mode.
43ff50
+ * @param c  The clock instance.
43ff50
+ * @return   The value of required time stamping mode, which is a bit mask
43ff50
+ *           of SOF_TIMESTAMPING_ flags.
43ff50
+ */
43ff50
+int clock_required_modes(struct clock *c);
43ff50
+
43ff50
+/**
43ff50
  * Create a clock instance. There can only be one clock in any system,
43ff50
  * so subsequent calls will destroy the previous clock instance.
43ff50
  *
43ff50
commit 536a71031d5c7689fd186ff550dc11cf743e02cb
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:46 2017 +0800
43ff50
43ff50
    ptp4l: use ts label to get ts info
43ff50
    
43ff50
    Now the ts label will be either the bond active slave or the interface
43ff50
    name, which is the exactly interface we need to get ts info.
43ff50
    
43ff50
    When the link down/up or there is a fail over and ts_label changed, the
43ff50
    phc index may also changed. So we need to check get new ts info and check
43ff50
    clock_required_modes. We will set the link to LINK_DOWN by force if
43ff50
    the new ts_label's timestamp do not support required mode.
43ff50
    
43ff50
    If all good, then we set phc index to new one. Also sync clock interval
43ff50
    after switch phc.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/clock.c b/clock.c
43ff50
index 5926a3c..41c8f81 100644
43ff50
--- a/clock.c
43ff50
+++ b/clock.c
43ff50
@@ -38,6 +38,7 @@
43ff50
 #include "servo.h"
43ff50
 #include "stats.h"
43ff50
 #include "print.h"
43ff50
+#include "rtnl.h"
43ff50
 #include "tlv.h"
43ff50
 #include "tsproc.h"
43ff50
 #include "uds.h"
43ff50
@@ -832,6 +833,16 @@ int clock_required_modes(struct clock *c)
43ff50
 	return required_modes;
43ff50
 }
43ff50
 
43ff50
+/*
43ff50
+ * If we do not have a slave or the rtnl query failed, then use our
43ff50
+ * own interface name as the time stamping interface name.
43ff50
+ */
43ff50
+static void ensure_ts_label(struct interface *iface)
43ff50
+{
43ff50
+	if (iface->ts_label[0] == '\0')
43ff50
+		strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE);
43ff50
+}
43ff50
+
43ff50
 struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 			   const char *phc_device)
43ff50
 {
43ff50
@@ -943,6 +954,9 @@ struct clock *clock_create(enum clock_type type, struct config *config,
43ff50
 	c->timestamping = timestamping;
43ff50
 	required_modes = clock_required_modes(c);
43ff50
 	STAILQ_FOREACH(iface, &config->interfaces, list) {
43ff50
+		rtnl_get_ts_label(iface);
43ff50
+		ensure_ts_label(iface);
43ff50
+		sk_get_ts_info(iface->ts_label, &iface->ts_info);
43ff50
 		if (iface->ts_info.valid &&
43ff50
 		    ((iface->ts_info.so_timestamping & required_modes) != required_modes)) {
43ff50
 			pr_err("interface '%s' does not support "
43ff50
diff --git a/config.c b/config.c
43ff50
index e6fe676..bbaf36e 100644
43ff50
--- a/config.c
43ff50
+++ b/config.c
43ff50
@@ -633,7 +633,6 @@ struct interface *config_create_interface(char *name, struct config *cfg)
43ff50
 	}
43ff50
 
43ff50
 	strncpy(iface->name, name, MAX_IFNAME_SIZE);
43ff50
-	sk_get_ts_info(iface->name, &iface->ts_info);
43ff50
 	STAILQ_INSERT_TAIL(&cfg->interfaces, iface, list);
43ff50
 	cfg->n_interfaces++;
43ff50
 
43ff50
diff --git a/port.c b/port.c
43ff50
index 81d52ff..615c800 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -60,6 +60,7 @@ enum link_state {
43ff50
 	LINK_DOWN  = (1<<0),
43ff50
 	LINK_UP  = (1<<1),
43ff50
 	LINK_STATE_CHANGED = (1<<3),
43ff50
+	TS_LABEL_CHANGED  = (1<<4),
43ff50
 };
43ff50
 
43ff50
 struct nrate_estimator {
43ff50
@@ -2231,6 +2232,8 @@ static void port_link_status(void *ctx, int linkup, int ts_index)
43ff50
 {
43ff50
 	struct port *p = ctx;
43ff50
 	int link_state;
43ff50
+	char ts_label[MAX_IFNAME_SIZE + 1] = {0};
43ff50
+	int required_modes;
43ff50
 
43ff50
 	link_state = linkup ? LINK_UP : LINK_DOWN;
43ff50
 	if (p->link_status & link_state) {
43ff50
@@ -2240,6 +2243,39 @@ static void port_link_status(void *ctx, int linkup, int ts_index)
43ff50
 		pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
43ff50
 	}
43ff50
 
43ff50
+	/* ts_label changed */
43ff50
+	if (if_indextoname(ts_index, ts_label) && strcmp(p->iface->ts_label, ts_label)) {
43ff50
+		strncpy(p->iface->ts_label, ts_label, MAX_IFNAME_SIZE);
43ff50
+		p->link_status |= TS_LABEL_CHANGED;
43ff50
+		pr_notice("port %hu: ts label changed to %s", portnum(p), ts_label);
43ff50
+	}
43ff50
+
43ff50
+	/* Both link down/up and change ts_label may change phc index. */
43ff50
+	if (p->link_status & LINK_UP &&
43ff50
+	    (p->link_status & LINK_STATE_CHANGED || p->link_status & TS_LABEL_CHANGED)) {
43ff50
+		sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info);
43ff50
+
43ff50
+		/* Only switch phc with HW time stamping mode */
43ff50
+		if (p->phc_index >= 0 && p->iface->ts_info.valid) {
43ff50
+			required_modes = clock_required_modes(p->clock);
43ff50
+			if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) {
43ff50
+				pr_err("interface '%s' does not support requested "
43ff50
+				       "timestamping mode, set link status down by force.",
43ff50
+				       p->iface->ts_label);
43ff50
+				p->link_status = LINK_DOWN | LINK_STATE_CHANGED;
43ff50
+			} else if (p->phc_index != p->iface->ts_info.phc_index) {
43ff50
+				p->phc_index = p->iface->ts_info.phc_index;
43ff50
+
43ff50
+				if (clock_switch_phc(p->clock, p->phc_index)) {
43ff50
+					p->last_fault_type = FT_SWITCH_PHC;
43ff50
+					port_dispatch(p, EV_FAULT_DETECTED, 0);
43ff50
+					return;
43ff50
+				}
43ff50
+				clock_sync_interval(p->clock, p->log_sync_interval);
43ff50
+			}
43ff50
+		}
43ff50
+	}
43ff50
+
43ff50
 	/*
43ff50
 	 * A port going down can affect the BMCA result.
43ff50
 	 * Force a state decision event.
43ff50
@@ -2292,7 +2328,8 @@ enum fsm_event port_event(struct port *p, int fd_index)
43ff50
 		rtnl_link_status(fd, p->name, port_link_status, p);
43ff50
 		if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))
43ff50
 			return EV_FAULT_CLEARED;
43ff50
-		else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED))
43ff50
+		else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) ||
43ff50
+			 (p->link_status & TS_LABEL_CHANGED))
43ff50
 			return EV_FAULT_DETECTED;
43ff50
 		else
43ff50
 			return EV_NONE;
43ff50
commit 8923bcdf64c0c95bac7af977b867393bae69e7a1
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:47 2017 +0800
43ff50
43ff50
    transport: pass struct interface to transport_open
43ff50
    
43ff50
    Pass struct interface so we can use ts_iface in HW filter.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/pmc_common.c b/pmc_common.c
43ff50
index d92b0cd..447cf99 100644
43ff50
--- a/pmc_common.c
43ff50
+++ b/pmc_common.c
43ff50
@@ -67,6 +67,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
43ff50
 		       int zero_datalen)
43ff50
 {
43ff50
 	struct pmc *pmc;
43ff50
+	struct interface iface;
43ff50
 
43ff50
 	pmc = calloc(1, sizeof *pmc);
43ff50
 	if (!pmc)
43ff50
@@ -90,7 +91,9 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
43ff50
 		pr_err("failed to create transport");
43ff50
 		goto failed;
43ff50
 	}
43ff50
-	if (transport_open(pmc->transport, iface_name,
43ff50
+
43ff50
+	strncpy(iface.name, iface_name, MAX_IFNAME_SIZE);
43ff50
+	if (transport_open(pmc->transport, &iface,
43ff50
 			   &pmc->fdarray, TS_SOFTWARE)) {
43ff50
 		pr_err("failed to open transport");
43ff50
 		goto failed;
43ff50
diff --git a/port.c b/port.c
43ff50
index 615c800..1e3f474 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -1504,7 +1504,7 @@ static int port_initialize(struct port *p)
43ff50
 			goto no_timers;
43ff50
 		}
43ff50
 	}
43ff50
-	if (transport_open(p->trp, p->name, &p->fda, p->timestamping))
43ff50
+	if (transport_open(p->trp, p->iface, &p->fda, p->timestamping))
43ff50
 		goto no_tropen;
43ff50
 
43ff50
 	for (i = 0; i < N_TIMER_FDS; i++) {
43ff50
@@ -1547,7 +1547,7 @@ static int port_renew_transport(struct port *p)
43ff50
 	}
43ff50
 	transport_close(p->trp, &p->fda);
43ff50
 	port_clear_fda(p, FD_ANNOUNCE_TIMER);
43ff50
-	res = transport_open(p->trp, p->name, &p->fda, p->timestamping);
43ff50
+	res = transport_open(p->trp, p->iface, &p->fda, p->timestamping);
43ff50
 	/* Need to call clock_fda_changed even if transport_open failed in
43ff50
 	 * order to update clock to the now closed descriptors. */
43ff50
 	clock_fda_changed(p->clock);
43ff50
diff --git a/raw.c b/raw.c
43ff50
index 73e45b4..8b7bcf1 100644
43ff50
--- a/raw.c
43ff50
+++ b/raw.c
43ff50
@@ -198,15 +198,16 @@ static void addr_to_mac(void *mac, struct address *addr)
43ff50
 	memcpy(mac, &addr->sll.sll_addr, MAC_LEN);
43ff50
 }
43ff50
 
43ff50
-static int raw_open(struct transport *t, const char *name,
43ff50
+static int raw_open(struct transport *t, struct interface *iface,
43ff50
 		    struct fdarray *fda, enum timestamp_type ts_type)
43ff50
 {
43ff50
 	struct raw *raw = container_of(t, struct raw, t);
43ff50
 	unsigned char ptp_dst_mac[MAC_LEN];
43ff50
 	unsigned char p2p_dst_mac[MAC_LEN];
43ff50
 	int efd, gfd;
43ff50
-	char *str;
43ff50
+	char *str, *name;
43ff50
 
43ff50
+	name = iface->ts_label;
43ff50
 	str = config_get_string(t->cfg, name, "ptp_dst_mac");
43ff50
 	if (str2mac(str, ptp_dst_mac)) {
43ff50
 		pr_err("invalid ptp_dst_mac %s", str);
43ff50
diff --git a/transport.c b/transport.c
43ff50
index d24c05b..3541394 100644
43ff50
--- a/transport.c
43ff50
+++ b/transport.c
43ff50
@@ -31,10 +31,10 @@ int transport_close(struct transport *t, struct fdarray *fda)
43ff50
 	return t->close(t, fda);
43ff50
 }
43ff50
 
43ff50
-int transport_open(struct transport *t, const char *name,
43ff50
+int transport_open(struct transport *t, struct interface *iface,
43ff50
 		   struct fdarray *fda, enum timestamp_type tt)
43ff50
 {
43ff50
-	return t->open(t, name, fda, tt);
43ff50
+	return t->open(t, iface, fda, tt);
43ff50
 }
43ff50
 
43ff50
 int transport_recv(struct transport *t, int fd, struct ptp_message *msg)
43ff50
diff --git a/transport.h b/transport.h
43ff50
index 5d6ba98..15616bb 100644
43ff50
--- a/transport.h
43ff50
+++ b/transport.h
43ff50
@@ -27,6 +27,7 @@
43ff50
 #include "msg.h"
43ff50
 
43ff50
 struct config;
43ff50
+struct interface;
43ff50
 
43ff50
 /* Values from networkProtocol enumeration 7.4.1 Table 3 */
43ff50
 enum transport_type {
43ff50
@@ -54,7 +55,7 @@ struct transport;
43ff50
 
43ff50
 int transport_close(struct transport *t, struct fdarray *fda);
43ff50
 
43ff50
-int transport_open(struct transport *t, const char *name,
43ff50
+int transport_open(struct transport *t, struct interface *iface,
43ff50
 		   struct fdarray *fda, enum timestamp_type tt);
43ff50
 
43ff50
 int transport_recv(struct transport *t, int fd, struct ptp_message *msg);
43ff50
diff --git a/transport_private.h b/transport_private.h
43ff50
index b54f32a..7530896 100644
43ff50
--- a/transport_private.h
43ff50
+++ b/transport_private.h
43ff50
@@ -32,8 +32,8 @@ struct transport {
43ff50
 
43ff50
 	int (*close)(struct transport *t, struct fdarray *fda);
43ff50
 
43ff50
-	int (*open)(struct transport *t, const char *name, struct fdarray *fda,
43ff50
-		    enum timestamp_type tt);
43ff50
+	int (*open)(struct transport *t, struct interface *iface,
43ff50
+		    struct fdarray *fda, enum timestamp_type tt);
43ff50
 
43ff50
 	int (*recv)(struct transport *t, int fd, void *buf, int buflen,
43ff50
 		    struct address *addr, struct hw_timestamp *hwts);
43ff50
diff --git a/udp.c b/udp.c
43ff50
index 530a2ee..05c2ba0 100644
43ff50
--- a/udp.c
43ff50
+++ b/udp.c
43ff50
@@ -152,12 +152,13 @@ enum { MC_PRIMARY, MC_PDELAY };
43ff50
 
43ff50
 static struct in_addr mcast_addr[2];
43ff50
 
43ff50
-static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
43ff50
-		    enum timestamp_type ts_type)
43ff50
+static int udp_open(struct transport *t, struct interface *iface,
43ff50
+		    struct fdarray *fda, enum timestamp_type ts_type)
43ff50
 {
43ff50
 	struct udp *udp = container_of(t, struct udp, t);
43ff50
 	uint8_t event_dscp, general_dscp;
43ff50
 	int efd, gfd, ttl;
43ff50
+	char *name = iface->name;
43ff50
 
43ff50
 	ttl = config_get_int(t->cfg, name, "udp_ttl");
43ff50
 	udp->mac.len = 0;
43ff50
@@ -180,7 +181,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
43ff50
 	if (gfd < 0)
43ff50
 		goto no_general;
43ff50
 
43ff50
-	if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4))
43ff50
+	if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV4))
43ff50
 		goto no_timestamping;
43ff50
 
43ff50
 	if (sk_general_init(gfd))
43ff50
diff --git a/udp6.c b/udp6.c
43ff50
index 89e27bf..7551e3f 100644
43ff50
--- a/udp6.c
43ff50
+++ b/udp6.c
43ff50
@@ -160,12 +160,13 @@ enum { MC_PRIMARY, MC_PDELAY };
43ff50
 
43ff50
 static struct in6_addr mc6_addr[2];
43ff50
 
43ff50
-static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
43ff50
-		    enum timestamp_type ts_type)
43ff50
+static int udp6_open(struct transport *t, struct interface *iface,
43ff50
+		     struct fdarray *fda, enum timestamp_type ts_type)
43ff50
 {
43ff50
 	struct udp6 *udp6 = container_of(t, struct udp6, t);
43ff50
 	uint8_t event_dscp, general_dscp;
43ff50
 	int efd, gfd, hop_limit;
43ff50
+	char *name = iface->name;
43ff50
 
43ff50
 	hop_limit = config_get_int(t->cfg, name, "udp_ttl");
43ff50
 	udp6->mac.len = 0;
43ff50
@@ -190,7 +191,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
43ff50
 	if (gfd < 0)
43ff50
 		goto no_general;
43ff50
 
43ff50
-	if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6))
43ff50
+	if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV6))
43ff50
 		goto no_timestamping;
43ff50
 
43ff50
 	if (sk_general_init(gfd))
43ff50
diff --git a/uds.c b/uds.c
43ff50
index d5e8f50..7e11f63 100644
43ff50
--- a/uds.c
43ff50
+++ b/uds.c
43ff50
@@ -52,13 +52,14 @@ static int uds_close(struct transport *t, struct fdarray *fda)
43ff50
 	return 0;
43ff50
 }
43ff50
 
43ff50
-static int uds_open(struct transport *t, const char *name, struct fdarray *fda,
43ff50
+static int uds_open(struct transport *t, struct interface *iface, struct fdarray *fda,
43ff50
 		    enum timestamp_type tt)
43ff50
 {
43ff50
 	int fd, err;
43ff50
 	struct sockaddr_un sa;
43ff50
 	struct uds *uds = container_of(t, struct uds, t);
43ff50
 	char *uds_path = config_get_string(t->cfg, NULL, "uds_address");
43ff50
+	char *name = iface->name;
43ff50
 
43ff50
 	fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
43ff50
 	if (fd < 0) {
43ff50
commit cb53238d5d1a1b9319536b4df1edf237e428d931
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:48 2017 +0800
43ff50
43ff50
    phc2sys: split servo_add from function clock_add
43ff50
    
43ff50
    We also need this part in clock_reinit() later. So split it out of
43ff50
    function clock_add().
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/phc2sys.c b/phc2sys.c
43ff50
index e2b5c47..0472c68 100644
43ff50
--- a/phc2sys.c
43ff50
+++ b/phc2sys.c
43ff50
@@ -162,12 +162,45 @@ static clockid_t clock_open(char *device, int *phc_index)
43ff50
 	return clkid;
43ff50
 }
43ff50
 
43ff50
+static struct servo *servo_add(struct node *node, struct clock *clock)
43ff50
+{
43ff50
+	double ppb;
43ff50
+	int max_ppb;
43ff50
+	struct servo *servo;
43ff50
+
43ff50
+	clockadj_init(clock->clkid);
43ff50
+	ppb = clockadj_get_freq(clock->clkid);
43ff50
+	/* The reading may silently fail and return 0, reset the frequency to
43ff50
+	   make sure ppb is the actual frequency of the clock. */
43ff50
+	clockadj_set_freq(clock->clkid, ppb);
43ff50
+	if (clock->clkid == CLOCK_REALTIME) {
43ff50
+		sysclk_set_leap(0);
43ff50
+		max_ppb = sysclk_max_freq();
43ff50
+	} else {
43ff50
+		max_ppb = phc_max_adj(clock->clkid);
43ff50
+		if (!max_ppb) {
43ff50
+			pr_err("clock is not adjustable");
43ff50
+			return NULL;
43ff50
+		}
43ff50
+	}
43ff50
+
43ff50
+	servo = servo_create(phc2sys_config, node->servo_type,
43ff50
+			     -ppb, max_ppb, 0);
43ff50
+	if (!servo) {
43ff50
+		pr_err("Failed to create servo");
43ff50
+		return NULL;
43ff50
+	}
43ff50
+
43ff50
+	servo_sync_interval(servo, node->phc_interval);
43ff50
+
43ff50
+	return servo;
43ff50
+}
43ff50
+
43ff50
 static struct clock *clock_add(struct node *node, char *device)
43ff50
 {
43ff50
 	struct clock *c;
43ff50
 	clockid_t clkid = CLOCK_INVALID;
43ff50
-	int max_ppb, phc_index = -1;
43ff50
-	double ppb;
43ff50
+	int phc_index = -1;
43ff50
 
43ff50
 	if (device) {
43ff50
 		clkid = clock_open(device, &phc_index);
43ff50
@@ -211,25 +244,7 @@ static struct clock *clock_add(struct node *node, char *device)
43ff50
 		}
43ff50
 	}
43ff50
 
43ff50
-	clockadj_init(c->clkid);
43ff50
-	ppb = clockadj_get_freq(c->clkid);
43ff50
-	/* The reading may silently fail and return 0, reset the frequency to
43ff50
-	   make sure ppb is the actual frequency of the clock. */
43ff50
-	clockadj_set_freq(c->clkid, ppb);
43ff50
-	if (c->clkid == CLOCK_REALTIME) {
43ff50
-		sysclk_set_leap(0);
43ff50
-		max_ppb = sysclk_max_freq();
43ff50
-	} else {
43ff50
-		max_ppb = phc_max_adj(c->clkid);
43ff50
-		if (!max_ppb) {
43ff50
-			pr_err("clock is not adjustable");
43ff50
-			return NULL;
43ff50
-		}
43ff50
-	}
43ff50
-
43ff50
-	c->servo = servo_create(phc2sys_config, node->servo_type,
43ff50
-				-ppb, max_ppb, 0);
43ff50
-	servo_sync_interval(c->servo, node->phc_interval);
43ff50
+	c->servo = servo_add(node, c);
43ff50
 
43ff50
 	if (clkid != CLOCK_REALTIME)
43ff50
 		c->sysoff_supported = (SYSOFF_SUPPORTED ==
43ff50
commit 8a349e557c653d24b04b0545e2f179080e10731f
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:49 2017 +0800
43ff50
43ff50
    phc2sys: re-create clock clkid and servo when phc index changed
43ff50
    
43ff50
    When the clock device or phc index changed, the new phc device may have
43ff50
    different maximum adjustment. So we need to create a new clkid and servo
43ff50
    in clock_reinit().
43ff50
    
43ff50
    At the same time, we should not only do clock_reinit() when the new state
43ff50
    is PS_MASTER. We also need to reinit clock after a failover in slave mode(
43ff50
    the new state is PS_SLAVE). We can do clock_reinit() even in PS_FAULTY so
43ff50
    we can finish adjust offset before come back to PS_LISTENING. So I removed
43ff50
    the check and let's do clock_reinit() whenever there is a new state.
43ff50
    
43ff50
    And for servo reset, as Miroslav suggested, we will do it in these cases:
43ff50
    - the system clock is the new destination (master state)
43ff50
    - a PHC is the new destination (master state)
43ff50
    - a PHC is switched (in any state)
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/phc2sys.c b/phc2sys.c
43ff50
index 0472c68..5c54055 100644
43ff50
--- a/phc2sys.c
43ff50
+++ b/phc2sys.c
43ff50
@@ -128,6 +128,11 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
43ff50
 static int run_pmc_get_utc_offset(struct node *node, int timeout);
43ff50
 static void run_pmc_events(struct node *node);
43ff50
 
43ff50
+static int normalize_state(int state);
43ff50
+static int run_pmc_port_properties(struct node *node, int timeout,
43ff50
+				   unsigned int port,
43ff50
+				   int *state, int *tstamping, char *iface);
43ff50
+
43ff50
 static clockid_t clock_open(char *device, int *phc_index)
43ff50
 {
43ff50
 	struct sk_ts_info ts_info;
43ff50
@@ -309,15 +314,62 @@ static struct port *port_add(struct node *node, unsigned int number,
43ff50
 	return p;
43ff50
 }
43ff50
 
43ff50
-static void clock_reinit(struct clock *clock)
43ff50
+static void clock_reinit(struct node *node, struct clock *clock, int new_state)
43ff50
 {
43ff50
-	servo_reset(clock->servo);
43ff50
-	clock->servo_state = SERVO_UNLOCKED;
43ff50
+	int phc_index = -1, phc_switched = 0;
43ff50
+	int state, timestamping, ret = -1;
43ff50
+	struct port *p;
43ff50
+	struct servo *servo;
43ff50
+	struct sk_ts_info ts_info;
43ff50
+	char iface[IFNAMSIZ];
43ff50
+	clockid_t clkid = CLOCK_INVALID;
43ff50
 
43ff50
-	if (clock->offset_stats) {
43ff50
-		stats_reset(clock->offset_stats);
43ff50
-		stats_reset(clock->freq_stats);
43ff50
-		stats_reset(clock->delay_stats);
43ff50
+	LIST_FOREACH(p, &node->ports, list) {
43ff50
+		if (p->clock == clock) {
43ff50
+			ret = run_pmc_port_properties(node, 1000, p->number,
43ff50
+					              &state, &timestamping,
43ff50
+						      iface);
43ff50
+			if (ret > 0)
43ff50
+				p->state = normalize_state(state);
43ff50
+		}
43ff50
+	}
43ff50
+
43ff50
+	if (ret > 0 && timestamping != TS_SOFTWARE) {
43ff50
+		/* Check if device changed */
43ff50
+		if (strcmp(clock->device, iface)) {
43ff50
+			free(clock->device);
43ff50
+			clock->device = strdup(iface);
43ff50
+		}
43ff50
+		/* Check if phc index changed */
43ff50
+		if (!sk_get_ts_info(clock->device, &ts_info) &&
43ff50
+		    clock->phc_index != ts_info.phc_index) {
43ff50
+			clkid = clock_open(clock->device, &phc_index);
43ff50
+			if (clkid == CLOCK_INVALID)
43ff50
+				return;
43ff50
+
43ff50
+			phc_close(clock->clkid);
43ff50
+			clock->clkid = clkid;
43ff50
+			clock->phc_index = phc_index;
43ff50
+
43ff50
+			servo = servo_add(node, clock);
43ff50
+			if (servo) {
43ff50
+				servo_destroy(clock->servo);
43ff50
+				clock->servo = servo;
43ff50
+			}
43ff50
+
43ff50
+			phc_switched = 1;
43ff50
+		}
43ff50
+	}
43ff50
+
43ff50
+	if (new_state == PS_MASTER || phc_switched) {
43ff50
+		servo_reset(clock->servo);
43ff50
+		clock->servo_state = SERVO_UNLOCKED;
43ff50
+
43ff50
+		if (clock->offset_stats) {
43ff50
+			stats_reset(clock->offset_stats);
43ff50
+			stats_reset(clock->freq_stats);
43ff50
+			stats_reset(clock->delay_stats);
43ff50
+		}
43ff50
 	}
43ff50
 }
43ff50
 
43ff50
@@ -336,9 +388,7 @@ static void reconfigure(struct node *node)
43ff50
 		}
43ff50
 
43ff50
 		if (c->new_state) {
43ff50
-			if (c->new_state == PS_MASTER)
43ff50
-				clock_reinit(c);
43ff50
-
43ff50
+			clock_reinit(node, c, c->new_state);
43ff50
 			c->state = c->new_state;
43ff50
 			c->new_state = 0;
43ff50
 		}
43ff50
@@ -403,7 +453,7 @@ static void reconfigure(struct node *node)
43ff50
 	} else if (rt) {
43ff50
 		if (rt->state != PS_MASTER) {
43ff50
 			rt->state = PS_MASTER;
43ff50
-			clock_reinit(rt);
43ff50
+			clock_reinit(node, rt, rt->state);
43ff50
 		}
43ff50
 		pr_info("selecting %s for synchronization", rt->device);
43ff50
 	}
43ff50
commit 7092db303028d84574138c8199375dfde0b4e232
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Mon Oct 9 22:31:50 2017 +0800
43ff50
43ff50
    port: return timestamping iface in port properties
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/port.c b/port.c
43ff50
index 1e3f474..d8e29d5 100644
43ff50
--- a/port.c
43ff50
+++ b/port.c
43ff50
@@ -861,7 +861,7 @@ static int port_management_fill_response(struct port *target,
43ff50
 		else
43ff50
 			ppn->port_state = target->state;
43ff50
 		ppn->timestamping = target->timestamping;
43ff50
-		ptp_text_set(&ppn->interface, target->name);
43ff50
+		ptp_text_set(&ppn->interface, target->iface->ts_label);
43ff50
 		datalen = sizeof(*ppn) + ppn->interface.length;
43ff50
 		respond = 1;
43ff50
 		break;
43ff50
commit 5ce04f9bf366c6d62db5344a6553f87a99ea52ff
43ff50
Author: Hangbin Liu <liuhangbin@gmail.com>
43ff50
Date:   Wed Oct 18 20:31:38 2017 +0800
43ff50
43ff50
    phc2sys: update '-s' option
43ff50
    
43ff50
    Add description about bond interface.
43ff50
    
43ff50
    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
43ff50
43ff50
diff --git a/phc2sys.8 b/phc2sys.8
43ff50
index 2559c74..4fc4fa3 100644
43ff50
--- a/phc2sys.8
43ff50
+++ b/phc2sys.8
43ff50
@@ -94,7 +94,11 @@ together with the
43ff50
 option, the master clock is used only to correct the offset by whole number of
43ff50
 seconds, which cannot be fixed with PPS alone. Not compatible with the
43ff50
 .B \-a
43ff50
-option.
43ff50
+option. This option does not support bonded interface (e.g. bond0). If
43ff50
+.B ptp4l
43ff50
+has a port on an active-backup bond interface, the
43ff50
+.B \-a
43ff50
+option can be used to track the active interface.
43ff50
 .TP
43ff50
 .BI \-i " interface"
43ff50
 Performs the exact same function as
df78dc
df78dc
Backport of
df78dc
commit 742f8788211d2a861a0214e76449390b89ba55c2
df78dc
Author: Miroslav Lichvar <mlichvar@redhat.com>
df78dc
Date:   Fri Apr 13 17:11:56 2018 +0200
df78dc
df78dc
    rtnl: remove dependency on config.h.
df78dc
    
df78dc
    Change the rtnl_get_ts_label() function to accept the name of the master
df78dc
    interface and the buffer for the slave interface directly instead of the
df78dc
    struct interface from config.h.
df78dc
    
df78dc
    Also, rename the function to rtnl_get_ts_device().
df78dc
    
df78dc
    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
df78dc
df78dc
diff --git a/clock.c b/clock.c
df78dc
index 9ffb43e..afee960 100644
df78dc
--- a/clock.c
df78dc
+++ b/clock.c
df78dc
@@ -948,7 +948,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
df78dc
 	c->timestamping = timestamping;
df78dc
 	required_modes = clock_required_modes(c);
df78dc
 	STAILQ_FOREACH(iface, &config->interfaces, list) {
df78dc
-		rtnl_get_ts_label(iface);
df78dc
+		rtnl_get_ts_device(iface->name, iface->ts_label);
df78dc
 		ensure_ts_label(iface);
df78dc
 		sk_get_ts_info(iface->ts_label, &iface->ts_info);
df78dc
 		if (iface->ts_info.valid &&
df78dc
diff --git a/rtnl.c b/rtnl.c
df78dc
index cea936b..f9a572b 100644
df78dc
--- a/rtnl.c
df78dc
+++ b/rtnl.c
df78dc
@@ -43,13 +43,13 @@ int rtnl_close(int fd)
df78dc
 	return close(fd);
df78dc
 }
df78dc
 
df78dc
-static void rtnl_get_ts_label_callback(void *ctx, int linkup, int ts_index)
df78dc
+static void rtnl_get_ts_device_callback(void *ctx, int linkup, int ts_index)
df78dc
 {
df78dc
 	int *dst = ctx;
df78dc
 	*dst = ts_index;
df78dc
 }
df78dc
 
df78dc
-int rtnl_get_ts_label(struct interface *iface)
df78dc
+int rtnl_get_ts_device(char *device, char *ts_device)
df78dc
 {
df78dc
 	int err, fd;
df78dc
 	int ts_index = -1;
df78dc
@@ -58,13 +58,13 @@ int rtnl_get_ts_label(struct interface *iface)
df78dc
 	if (fd < 0)
df78dc
 		return fd;
df78dc
 
df78dc
-	err = rtnl_link_query(fd, iface->name);
df78dc
+	err = rtnl_link_query(fd, device);
df78dc
 	if (err) {
df78dc
 		goto no_info;
df78dc
 	}
df78dc
 
df78dc
-	rtnl_link_status(fd, iface->name, rtnl_get_ts_label_callback, &ts_index);
df78dc
-	if (ts_index > 0 && if_indextoname(ts_index, iface->ts_label))
df78dc
+	rtnl_link_status(fd, device, rtnl_get_ts_device_callback, &ts_index);
df78dc
+	if (ts_index > 0 && if_indextoname(ts_index, ts_device))
df78dc
 		err = 0;
df78dc
 	else
df78dc
 		err = -1;
df78dc
diff --git a/rtnl.h b/rtnl.h
df78dc
index 2906d74..f877cd2 100644
df78dc
--- a/rtnl.h
df78dc
+++ b/rtnl.h
df78dc
@@ -20,8 +20,6 @@
df78dc
 #ifndef HAVE_RTNL_H
df78dc
 #define HAVE_RTNL_H
df78dc
 
df78dc
-#include "config.h"
df78dc
-
df78dc
 typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
df78dc
 
df78dc
 /**
df78dc
@@ -32,11 +30,14 @@ typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
df78dc
 int rtnl_close(int fd);
df78dc
 
df78dc
 /**
df78dc
- * Get interface ts_label information
df78dc
- * @param iface  struct interface.
df78dc
- * @return       Zero on success, or -1 on error.
df78dc
+ * Get name of the slave interface which timestamps packets going through
df78dc
+ * a master interface (e.g. bond0)
df78dc
+ * @param device    Name of the master interface.
df78dc
+ * @param ts_device Buffer for the name of the slave interface, which must be
df78dc
+ *                  at least IF_NAMESIZE bytes long.
df78dc
+ * @return          Zero on success, or -1 on error.
df78dc
  */
df78dc
-int rtnl_get_ts_label(struct interface *iface);
df78dc
+int rtnl_get_ts_device(char *device, char *ts_device);
df78dc
 
df78dc
 /**
df78dc
  * Request the link status from the kernel.
df78dc
df78dc
commit e5ba2dae5f102a66e152b96f9cc7b06aff4b90b5
df78dc
Author: Miroslav Lichvar <mlichvar@redhat.com>
df78dc
Date:   Fri Apr 13 17:11:57 2018 +0200
df78dc
df78dc
    timemaster: add support for bonded interfaces.
df78dc
    
df78dc
    Use the rtnl_get_ts_device() function to get the name of the slave
df78dc
    interface which will be timestamping PTP packets and use it instead of
df78dc
    the master interface to check the timestamping capabilities and PHC.
df78dc
    
df78dc
    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
df78dc
df78dc
diff --git a/makefile b/makefile
df78dc
index 6f5321c..17189e6 100644
df78dc
--- a/makefile
df78dc
+++ b/makefile
df78dc
@@ -60,7 +60,7 @@ hwstamp_ctl: hwstamp_ctl.o version.o
df78dc
 
df78dc
 phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o print.o version.o
df78dc
 
df78dc
-timemaster: print.o sk.o timemaster.o util.o version.o
df78dc
+timemaster: print.o rtnl.o sk.o timemaster.o util.o version.o
df78dc
 
df78dc
 version.o: .version version.sh $(filter-out version.d,$(DEPEND))
df78dc
 
df78dc
diff --git a/timemaster.c b/timemaster.c
df78dc
index cda2d90..fc3ba31 100644
df78dc
--- a/timemaster.c
df78dc
+++ b/timemaster.c
df78dc
@@ -23,6 +23,7 @@
df78dc
 #include <libgen.h>
df78dc
 #include <limits.h>
df78dc
 #include <linux/net_tstamp.h>
df78dc
+#include <net/if.h>
df78dc
 #include <signal.h>
df78dc
 #include <spawn.h>
df78dc
 #include <stdarg.h>
df78dc
@@ -35,6 +36,7 @@
df78dc
 #include <unistd.h>
df78dc
 
df78dc
 #include "print.h"
df78dc
+#include "rtnl.h"
df78dc
 #include "sk.h"
df78dc
 #include "util.h"
df78dc
 #include "version.h"
df78dc
@@ -674,6 +676,7 @@ static int add_ptp_source(struct ptp_domain *source,
df78dc
 {
df78dc
 	struct config_file *config_file;
df78dc
 	char **command, *uds_path, **interfaces, *message_tag;
df78dc
+	char ts_interface[IF_NAMESIZE];
df78dc
 	int i, j, num_interfaces, *phc, *phcs, hw_ts, sw_ts;
df78dc
 	struct sk_ts_info ts_info;
df78dc
 
df78dc
@@ -696,26 +699,38 @@ static int add_ptp_source(struct ptp_domain *source,
df78dc
 	for (i = 0; i < num_interfaces; i++) {
df78dc
 		phcs[i] = -1;
df78dc
 
df78dc
+		/*
df78dc
+		 * if it is a bonded interface, use the name of the active
df78dc
+		 * slave interface (which will be timestamping packets)
df78dc
+		 */
df78dc
+		if (!rtnl_get_ts_device(source->interfaces[i], ts_interface)) {
df78dc
+			pr_debug("slave interface of %s: %s",
df78dc
+				 source->interfaces[i], ts_interface);
df78dc
+		} else {
df78dc
+			snprintf(ts_interface, sizeof(ts_interface), "%s",
df78dc
+				 source->interfaces[i]);
df78dc
+		}
df78dc
+
df78dc
 		/* check if the interface has a usable PHC */
df78dc
-		if (sk_get_ts_info(source->interfaces[i], &ts_info)) {
df78dc
+		if (sk_get_ts_info(ts_interface, &ts_info)) {
df78dc
 			pr_err("failed to get time stamping info for %s",
df78dc
-			       source->interfaces[i]);
df78dc
+			       ts_interface);
df78dc
 			free(phcs);
df78dc
 			return 1;
df78dc
 		}
df78dc
 
df78dc
 		if (((ts_info.so_timestamping & hw_ts) != hw_ts)) {
df78dc
-			pr_debug("interface %s: no PHC", source->interfaces[i]);
df78dc
+			pr_debug("interface %s: no PHC", ts_interface);
df78dc
 			if ((ts_info.so_timestamping & sw_ts) != sw_ts) {
df78dc
 				pr_err("time stamping not supported on %s",
df78dc
-				       source->interfaces[i]);
df78dc
+				       ts_interface);
df78dc
 				free(phcs);
df78dc
 				return 1;
df78dc
 			}
df78dc
 			continue;
df78dc
 		}
df78dc
 
df78dc
-		pr_debug("interface %s: PHC %d", source->interfaces[i],
df78dc
+		pr_debug("interface %s: PHC %d", ts_interface,
df78dc
 			 ts_info.phc_index);
df78dc
 
df78dc
 		/* and the PHC isn't already used in another source */