diff --git a/SOURCES/linuxptp-bonding.patch b/SOURCES/linuxptp-bonding.patch
new file mode 100644
index 0000000..b3737bb
--- /dev/null
+++ b/SOURCES/linuxptp-bonding.patch
@@ -0,0 +1,1671 @@
+commit 17aa750a49ebaecfc7b063c770aa8d36f5078b2c
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Jul 10 15:39:28 2017 +0800
+
+    rtnl: replace obsolete RTMGRP_LINK with RTNLGRP_LINK for nl groups
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/rtnl.c b/rtnl.c
+index 5cddc4b..d7a430d 100644
+--- a/rtnl.c
++++ b/rtnl.c
+@@ -151,7 +151,7 @@ int rtnl_open(void)
+ 
+ 	memset(&sa, 0, sizeof(sa));
+ 	sa.nl_family = AF_NETLINK;
+-	sa.nl_groups = RTMGRP_LINK;
++	sa.nl_groups = RTNLGRP_LINK;
+ 
+ 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ 	if (fd < 0) {
+commit c149a3dbc1b38e833de783ae863038562baca0fe
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Jul 10 15:39:29 2017 +0800
+
+    port: add FD_RTNL event to track per-port status
+    
+    With rtnl socket we can track link status per port(except UDS port).
+    
+    We can make sure we get the correct interface and latest status with function
+    port_link_status().
+    
+    At the same time we need to set clock sde after link down. But we return
+    EV_FAULT_DETECTED in port_event(), which will not set clock sde. So we need
+    to set it in port_link_status().
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index b6afba9..4c5c4e3 100644
+--- a/clock.c
++++ b/clock.c
+@@ -1469,6 +1469,11 @@ struct PortIdentity clock_parent_identity(struct clock *c)
+ 	return c->dad.pds.parentPortIdentity;
+ }
+ 
++void clock_set_sde(struct clock *c, int sde)
++{
++	c->sde = sde;
++}
++
+ int clock_poll(struct clock *c)
+ {
+ 	int cnt, i;
+diff --git a/clock.h b/clock.h
+index fcd9328..49ecb76 100644
+--- a/clock.h
++++ b/clock.h
+@@ -205,6 +205,13 @@ void clock_peer_delay(struct clock *c, tmv_t ppd, tmv_t req, tmv_t rx,
+ 		      double nrr);
+ 
+ /**
++ * Set clock sde
++ * @param c     A pointer to a clock instance obtained with clock_create().
++ * @param sde   Pass one (1) if need a decision event and zero if not.
++ */
++void clock_set_sde(struct clock *c, int sde);
++
++/**
+  * Poll for events and dispatch them.
+  * @param c A pointer to a clock instance obtained with clock_create().
+  * @return  Zero on success, non-zero otherwise.
+diff --git a/fd.h b/fd.h
+index e328e98..23401f4 100644
+--- a/fd.h
++++ b/fd.h
+@@ -31,6 +31,7 @@ enum {
+ 	FD_QUALIFICATION_TIMER,
+ 	FD_MANNO_TIMER,
+ 	FD_SYNC_TX_TIMER,
++	FD_RTNL,
+ 	N_POLLFD,
+ };
+ 
+diff --git a/port.c b/port.c
+index ec02825..2896d1a 100644
+--- a/port.c
++++ b/port.c
+@@ -23,6 +23,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/queue.h>
++#include <net/if.h>
+ 
+ #include "bmc.h"
+ #include "clock.h"
+@@ -32,6 +33,7 @@
+ #include "phc.h"
+ #include "port.h"
+ #include "print.h"
++#include "rtnl.h"
+ #include "sk.h"
+ #include "tlv.h"
+ #include "tmv.h"
+@@ -1458,7 +1460,9 @@ static void port_disable(struct port *p)
+ 	for (i = 0; i < N_TIMER_FDS; i++) {
+ 		close(p->fda.fd[FD_ANNOUNCE_TIMER + i]);
+ 	}
+-	port_clear_fda(p, N_POLLFD);
++
++	/* Keep rtnl socket to get link status info. */
++	port_clear_fda(p, FD_RTNL);
+ 	clock_fda_changed(p->clock);
+ }
+ 
+@@ -1502,6 +1506,14 @@ static int port_initialize(struct port *p)
+ 	if (port_set_announce_tmo(p))
+ 		goto no_tmo;
+ 
++	/* No need to open rtnl socket on UDS port. */
++	if (transport_type(p->trp) != TRANS_UDS) {
++		if (p->fda.fd[FD_RTNL] == -1)
++			p->fda.fd[FD_RTNL] = rtnl_open();
++		if (p->fda.fd[FD_RTNL] >= 0)
++			rtnl_link_query(p->fda.fd[FD_RTNL]);
++	}
++
+ 	port_nrate_initialize(p);
+ 
+ 	clock_fda_changed(p->clock);
+@@ -2025,6 +2037,10 @@ void port_close(struct port *p)
+ 	if (port_is_enabled(p)) {
+ 		port_disable(p);
+ 	}
++
++	if (p->fda.fd[FD_RTNL] >= 0)
++		rtnl_close(p->fda.fd[FD_RTNL]);
++
+ 	transport_destroy(p->trp);
+ 	tsproc_destroy(p->tsproc);
+ 	if (p->fault_fd >= 0)
+@@ -2204,6 +2220,24 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	}
+ }
+ 
++static void port_link_status(void *ctx, int index, int linkup)
++{
++	struct port *p = ctx;
++
++	if (index != if_nametoindex(p->name) || p->link_status == linkup)
++		return;
++
++	p->link_status = linkup;
++	pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
++
++	/*
++	 * A port going down can affect the BMCA result.
++	 * Force a state decision event.
++	 */
++	if (!p->link_status)
++		clock_set_sde(p->clock, 1);
++}
++
+ enum fsm_event port_event(struct port *p, int fd_index)
+ {
+ 	enum fsm_event event = EV_NONE;
+@@ -2242,6 +2276,11 @@ enum fsm_event port_event(struct port *p, int fd_index)
+ 		pr_debug("port %hu: master sync timeout", portnum(p));
+ 		port_set_sync_tx_tmo(p);
+ 		return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE;
++
++	case FD_RTNL:
++		pr_debug("port %hu: received link status notification", portnum(p));
++		rtnl_link_status(fd, port_link_status, p);
++		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
+ 	}
+ 
+ 	msg = msg_allocate();
+commit 25ec8a3b4e2222b394794ff830bd3583e9cf6c71
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Jul 10 15:39:30 2017 +0800
+
+    clock: remove rtnl fd on clock
+    
+    Remove rtnl fd on clock since we track the link status per port now.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index 4c5c4e3..354f038 100644
+--- a/clock.c
++++ b/clock.c
+@@ -39,7 +39,6 @@
+ #include "servo.h"
+ #include "stats.h"
+ #include "print.h"
+-#include "rtnl.h"
+ #include "sk.h"
+ #include "tlv.h"
+ #include "tsproc.h"
+@@ -274,9 +273,6 @@ void clock_destroy(struct clock *c)
+ 	LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
+ 		clock_remove_port(c, p);
+ 	}
+-	if (c->pollfd[0].fd >= 0) {
+-		rtnl_close(c->pollfd[0].fd);
+-	}
+ 	port_close(c->uds_port);
+ 	free(c->pollfd);
+ 	hash_destroy(c->index2port, NULL);
+@@ -326,30 +322,6 @@ static void clock_freq_est_reset(struct clock *c)
+ 	c->fest.count = 0;
+ }
+ 
+-static void clock_link_status(void *ctx, int index, int linkup)
+-{
+-	struct clock *c = ctx;
+-	struct port *p;
+-	char key[16];
+-
+-	snprintf(key, sizeof(key), "%d", index);
+-	p = hash_lookup(c->index2port, key);
+-	if (!p) {
+-		return;
+-	}
+-	port_link_status_set(p, linkup);
+-	if (linkup) {
+-		port_dispatch(p, EV_FAULT_CLEARED, 0);
+-	} else {
+-		port_dispatch(p, EV_FAULT_DETECTED, 0);
+-		/*
+-		 * A port going down can affect the BMCA result.
+-		 * Force a state decision event.
+-		 */
+-		c->sde = 1;
+-	}
+-}
+-
+ static void clock_management_send_error(struct port *p,
+ 					struct ptp_message *msg, int error_id)
+ {
+@@ -1133,10 +1105,6 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 		return NULL;
+ 	}
+ 
+-	/* Open a RT netlink socket. */
+-	c->pollfd[0].fd = rtnl_open();
+-	c->pollfd[0].events = POLLIN|POLLPRI;
+-
+ 	/* Create the UDS interface. */
+ 	c->uds_port = port_open(phc_index, timestamping, 0, udsif, c);
+ 	if (!c->uds_port) {
+@@ -1164,9 +1132,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 		port_dispatch(p, EV_INITIALIZE, 0);
+ 	}
+ 	port_dispatch(c->uds_port, EV_INITIALIZE, 0);
+-	if (c->pollfd[0].fd >= 0) {
+-		rtnl_link_query(c->pollfd[0].fd);
+-	}
++
+ 	return c;
+ }
+ 
+@@ -1231,12 +1197,9 @@ static int clock_resize_pollfd(struct clock *c, int new_nports)
+ {
+ 	struct pollfd *new_pollfd;
+ 
+-	/*
+-	 * Need to allocate one descriptor for RT netlink and one
+-	 * whole extra block of fds for UDS.
+-	 */
++	/* Need to allocate one whole extra block of fds for UDS. */
+ 	new_pollfd = realloc(c->pollfd,
+-			     (1 + (new_nports + 1) * N_CLOCK_PFD) *
++			     (new_nports + 1) * N_CLOCK_PFD *
+ 			     sizeof(struct pollfd));
+ 	if (!new_pollfd)
+ 		return -1;
+@@ -1261,7 +1224,7 @@ static void clock_fill_pollfd(struct pollfd *dest, struct port *p)
+ static void clock_check_pollfd(struct clock *c)
+ {
+ 	struct port *p;
+-	struct pollfd *dest = c->pollfd + 1;
++	struct pollfd *dest = c->pollfd;
+ 
+ 	if (c->pollfd_valid)
+ 		return;
+@@ -1482,7 +1445,7 @@ int clock_poll(struct clock *c)
+ 	struct port *p;
+ 
+ 	clock_check_pollfd(c);
+-	cnt = poll(c->pollfd, 1 + (c->nports + 1) * N_CLOCK_PFD, -1);
++	cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);
+ 	if (cnt < 0) {
+ 		if (EINTR == errno) {
+ 			return 0;
+@@ -1494,13 +1457,8 @@ int clock_poll(struct clock *c)
+ 		return 0;
+ 	}
+ 
+-	/* Check the RT netlink. */
+ 	cur = c->pollfd;
+-	if (cur->revents & (POLLIN|POLLPRI)) {
+-		rtnl_link_status(cur->fd, clock_link_status, c);
+-	}
+ 
+-	cur++;
+ 	LIST_FOREACH(p, &c->ports, list) {
+ 		/* Let the ports handle their events. */
+ 		for (i = 0; i < N_POLLFD; i++) {
+diff --git a/port.c b/port.c
+index 2896d1a..34837cc 100644
+--- a/port.c
++++ b/port.c
+@@ -2411,12 +2411,6 @@ int port_link_status_get(struct port *p)
+ 	return p->link_status;
+ }
+ 
+-void port_link_status_set(struct port *p, int up)
+-{
+-	p->link_status = up ? 1 : 0;
+-	pr_notice("port %hu: link %s", portnum(p), up ? "up" : "down");
+-}
+-
+ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg)
+ {
+ 	struct management_tlv *mgt;
+diff --git a/port.h b/port.h
+index b00bc64..60fd0a4 100644
+--- a/port.h
++++ b/port.h
+@@ -132,13 +132,6 @@ int port_number(struct port *p);
+ int port_link_status_get(struct port *p);
+ 
+ /**
+- * Sets the link status for a port.
+- * @param p        A port instance.
+- * @param up       Pass one (1) if the link is up and zero if down.
+- */
+-void port_link_status_set(struct port *p, int up);
+-
+-/**
+  * Manage a port according to a given message.
+  * @param p        A pointer previously obtained via port_open().
+  * @param ingress  The port on which 'msg' was received.
+commit 7c3f9579f0c230ee798644a26d664ebd3efc612f
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Jul 10 15:39:31 2017 +0800
+
+    clock: remove hash table index2port
+    
+    Remove index2port since we don't need it now.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index 354f038..da15882 100644
+--- a/clock.c
++++ b/clock.c
+@@ -31,7 +31,6 @@
+ #include "clockcheck.h"
+ #include "foreign.h"
+ #include "filter.h"
+-#include "hash.h"
+ #include "missing.h"
+ #include "msg.h"
+ #include "phc.h"
+@@ -39,7 +38,6 @@
+ #include "servo.h"
+ #include "stats.h"
+ #include "print.h"
+-#include "sk.h"
+ #include "tlv.h"
+ #include "tsproc.h"
+ #include "uds.h"
+@@ -96,7 +94,6 @@ struct clock {
+ 	int nports; /* does not include the UDS port */
+ 	int last_port_number;
+ 	int sde;
+-	struct hash *index2port;
+ 	int free_running;
+ 	int freq_est_interval;
+ 	int grand_master_capable; /* for 802.1AS only */
+@@ -275,7 +272,6 @@ void clock_destroy(struct clock *c)
+ 	}
+ 	port_close(c->uds_port);
+ 	free(c->pollfd);
+-	hash_destroy(c->index2port, NULL);
+ 	if (c->clkid != CLOCK_REALTIME) {
+ 		phc_close(c->clkid);
+ 	}
+@@ -773,8 +769,6 @@ static int clock_add_port(struct clock *c, int phc_index,
+ 			  struct interface *iface)
+ {
+ 	struct port *p, *piter, *lastp = NULL;
+-	int fd, index;
+-	char key[16];
+ 
+ 	if (clock_resize_pollfd(c, c->nports + 1)) {
+ 		return -1;
+@@ -795,24 +789,6 @@ static int clock_add_port(struct clock *c, int phc_index,
+ 	c->nports++;
+ 	clock_fda_changed(c);
+ 
+-	/* Remember the index to port mapping, for link status tracking. */
+-	fd = sk_interface_fd();
+-	if (fd < 0) {
+-		return -1;
+-	}
+-	index = sk_interface_index(fd, iface->name);
+-	if (index < 0) {
+-		close(fd);
+-		return -1;
+-	}
+-	snprintf(key, sizeof(key), "%d", index);
+-	if (hash_insert(c->index2port, key, p)) {
+-		pr_err("failed to add port with index %d twice!", index);
+-		close(fd);
+-		return -1;
+-	}
+-	close(fd);
+-
+ 	return 0;
+ }
+ 
+@@ -1113,11 +1089,6 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	}
+ 	clock_fda_changed(c);
+ 
+-	c->index2port = hash_create();
+-	if (!c->index2port) {
+-		pr_err("failed create index-to-port hash table");
+-		return NULL;
+-	}
+ 	/* Create the ports. */
+ 	STAILQ_FOREACH(iface, &config->interfaces, list) {
+ 		if (clock_add_port(c, phc_index, timestamping, iface)) {
+commit 9e744d9e8a2dab6ec0ea5ece5ac25e7384264575
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:39 2017 +0800
+
+    config: add new element ts_label in struct interface
+    
+    Add new element ts_label in struct interface to track real ts interface.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/config.h b/config.h
+index 1cc7051..c79855e 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_label[MAX_IFNAME_SIZE + 1];
+ 	struct sk_ts_info ts_info;
+ };
+ 
+commit 7e294a4d047654f746c3fcdff7bce512be149e37
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:40 2017 +0800
+
+    port: track interface info in port
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/port.c b/port.c
+index 34837cc..849a7c1 100644
+--- a/port.c
++++ b/port.c
+@@ -68,6 +68,7 @@ struct nrate_estimator {
+ struct port {
+ 	LIST_ENTRY(port) list;
+ 	char *name;
++	struct interface *iface;
+ 	struct clock *clock;
+ 	struct transport *trp;
+ 	enum timestamp_type timestamping;
+@@ -2619,6 +2620,7 @@ struct port *port_open(int phc_index,
+ 	}
+ 
+ 	p->name = interface->name;
++	p->iface = interface;
+ 	p->asymmetry = config_get_int(cfg, p->name, "delayAsymmetry");
+ 	p->asymmetry <<= 16;
+ 	p->announce_span = transport == TRANS_UDS ? 0 : ANNOUNCE_SPAN;
+commit 05bba46198cfc4ccfe0aff2e67e76d78898bbd96
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:41 2017 +0800
+
+    rtnl: update rtgenmsg to ifinfomsg when request link info
+    
+    The previous function use general message and will dump all interfaces'
+    information. Now update with ifinfomsg so we could get specific interface's
+    information.
+    
+    We still could get all interfaces' info if set device to NULL.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/port.c b/port.c
+index 849a7c1..5b85d87 100644
+--- a/port.c
++++ b/port.c
+@@ -1512,7 +1512,7 @@ static int port_initialize(struct port *p)
+ 		if (p->fda.fd[FD_RTNL] == -1)
+ 			p->fda.fd[FD_RTNL] = rtnl_open();
+ 		if (p->fda.fd[FD_RTNL] >= 0)
+-			rtnl_link_query(p->fda.fd[FD_RTNL]);
++			rtnl_link_query(p->fda.fd[FD_RTNL], p->iface->name);
+ 	}
+ 
+ 	port_nrate_initialize(p);
+diff --git a/rtnl.c b/rtnl.c
+index d7a430d..8ecf6fe 100644
+--- a/rtnl.c
++++ b/rtnl.c
+@@ -42,7 +42,7 @@ int rtnl_close(int fd)
+ 	return close(fd);
+ }
+ 
+-int rtnl_link_query(int fd)
++int rtnl_link_query(int fd, char *device)
+ {
+ 	struct sockaddr_nl sa;
+ 	struct msghdr msg;
+@@ -51,19 +51,21 @@ int rtnl_link_query(int fd)
+ 
+ 	struct {
+ 		struct nlmsghdr hdr;
+-		struct rtgenmsg gen;
++		struct ifinfomsg ifm;
+ 	} __attribute__((packed)) request;
+ 
+ 	memset(&sa, 0, sizeof(sa));
+ 	sa.nl_family = AF_NETLINK;
+ 
+ 	memset(&request, 0, sizeof(request));
+-	request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen));
++	request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.ifm));
+ 	request.hdr.nlmsg_type = RTM_GETLINK;
+-	request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
++	request.hdr.nlmsg_flags = NLM_F_REQUEST;
+ 	request.hdr.nlmsg_seq = 1;
+ 	request.hdr.nlmsg_pid = 0;
+-	request.gen.rtgen_family = AF_UNSPEC;
++	request.ifm.ifi_family = AF_UNSPEC;
++	request.ifm.ifi_index = if_nametoindex(device ? device : "");
++	request.ifm.ifi_change = 0xffffffff;
+ 
+ 	iov.iov_base = &request;
+ 	iov.iov_len = sizeof(request);
+diff --git a/rtnl.h b/rtnl.h
+index f1871f2..5c93eec 100644
+--- a/rtnl.h
++++ b/rtnl.h
+@@ -31,10 +31,11 @@ int rtnl_close(int fd);
+ 
+ /**
+  * Request the link status from the kernel.
+- * @param fd  A socket obtained via rtnl_open().
+- * @return    Zero on success, non-zero otherwise.
++ * @param fd     A socket obtained via rtnl_open().
++ * @param device Interface name. Request all iface's status if set NULL.
++ * @return       Zero on success, non-zero otherwise.
+  */
+-int rtnl_link_query(int fd);
++int rtnl_link_query(int fd, char *device);
+ 
+ /**
+  * Read kernel messages looking for a link up/down events.
+Backport of commit 80bc4d4c2f4d1c3c246091aa6f103bb7943202ec
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:42 2017 +0800
+
+    rtnl: update function rtnl_link_status to get bond slave info
+    
+    Update function rtnl_link_status to get bond slave info. Pass the slave index
+    to call back functions. i.e. port_link_status.
+    
+    Also check the interface index of rtnl message in function rtnl_link_status.
+    Then we don't need to check it in port_link_status.
+    
+    [BACKPORT: not included] Add ifndef IFLA_BOND_MAX in case we build linuxptp
+    on kernel before v3.13-rc1.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/port.c b/port.c
+index 5b85d87..05fc321 100644
+--- a/port.c
++++ b/port.c
+@@ -2221,11 +2221,11 @@ 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 linkup, int ts_index)
+ {
+ 	struct port *p = ctx;
+ 
+-	if (index != if_nametoindex(p->name) || p->link_status == linkup)
++	if (p->link_status == linkup)
+ 		return;
+ 
+ 	p->link_status = linkup;
+@@ -2280,7 +2280,7 @@ enum fsm_event port_event(struct port *p, int fd_index)
+ 
+ 	case FD_RTNL:
+ 		pr_debug("port %hu: received link status notification", portnum(p));
+-		rtnl_link_status(fd, port_link_status, p);
++		rtnl_link_status(fd, p->name, port_link_status, p);
+ 		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
+ 	}
+ 
+diff --git a/rtnl.c b/rtnl.c
+index 8ecf6fe..3419873 100644
+--- a/rtnl.c
++++ b/rtnl.c
+@@ -84,15 +85,79 @@ int rtnl_link_query(int fd, char *device)
+ 	return 0;
+ }
+ 
+-int rtnl_link_status(int fd, rtnl_callback cb, void *ctx)
++static inline __u32 rta_getattr_u32(const struct rtattr *rta)
+ {
+-	int index, len;
++	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);
++	while (RTA_OK(rta, len)) {
++		type = rta->rta_type;
++		if ((type < max) && (!tb[type]))
++			tb[type] = rta;
++		rta = RTA_NEXT(rta, len);
++	}
++	if (len) {
++		pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len);
++		return -1;
++	}
++
++	return 0;
++}
++
++static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta)
++{
++	return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
++}
++
++static int rtnl_linkinfo_parse(struct rtattr *rta)
++{
++	int index = -1;
++	const char *kind;
++	struct rtattr *linkinfo[IFLA_INFO_MAX];
++	struct rtattr *bond[IFLA_BOND_MAX];
++
++	if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0)
++		return -1;
++
++	if (linkinfo[IFLA_INFO_KIND]) {
++		kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
++
++		if (kind && !strncmp(kind, "bond", 4) &&
++		    linkinfo[IFLA_INFO_DATA]) {
++			if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX,
++						 linkinfo[IFLA_INFO_DATA]) < 0)
++				return -1;
++
++			if (bond[IFLA_BOND_ACTIVE_SLAVE]) {
++				index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]);
++			}
++		}
++	}
++	return index;
++}
++
++int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx)
++{
++	int index, len, link_up;
++	int slave_index = -1;
+ 	struct iovec iov;
+ 	struct sockaddr_nl sa;
+ 	struct msghdr msg;
+ 	struct nlmsghdr *nh;
+ 	struct ifinfomsg *info = NULL;
++	struct rtattr *tb[IFLA_MAX+1];
+ 
++	index = if_nametoindex(device);
+ 	if (!rtnl_buf) {
+ 		rtnl_len = 4096;
+ 		rtnl_buf = malloc(rtnl_len);
+@@ -135,14 +200,27 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx)
+ 	nh = (struct nlmsghdr *) rtnl_buf;
+ 
+ 	for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
+-		if (nh->nlmsg_type == RTM_NEWLINK) {
+-			info = NLMSG_DATA(nh);
+-			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);
+-		}
++		if (nh->nlmsg_type != RTM_NEWLINK)
++			continue;
++
++		info = NLMSG_DATA(nh);
++		if (index != info->ifi_index)
++			continue;
++
++		link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0;
++		pr_debug("interface index %d is %s", index,
++			 link_up ? "up" : "down");
++
++		rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info),
++				  IFLA_PAYLOAD(nh));
++
++		if (tb[IFLA_LINKINFO])
++			slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]);
++
++		if (cb)
++			cb(ctx, link_up, slave_index);
+ 	}
++
+ 	return 0;
+ }
+ 
+diff --git a/rtnl.h b/rtnl.h
+index 5c93eec..6eced2d 100644
+--- a/rtnl.h
++++ b/rtnl.h
+@@ -20,7 +20,7 @@
+ #ifndef HAVE_RTNL_H
+ #define HAVE_RTNL_H
+ 
+-typedef void (*rtnl_callback)(void *ctx, int index, int linkup);
++typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
+ 
+ /**
+  * Close a RT netlink socket.
+@@ -39,12 +39,13 @@ int rtnl_link_query(int fd, 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.
+- * @param ctx  Private context passed to the callback.
+- * @return     Zero on success, non-zero otherwise.
++ * @param fd     Readable socket obtained via rtnl_open().
++ * @param device The device which we need to get link info.
++ * @param cb     Callback function to be invoked on each event.
++ * @param ctx    Private context passed to the callback.
++ * @return       Zero on success, non-zero otherwise.
+  */
+-int rtnl_link_status(int fd, rtnl_callback cb, void *ctx);
++int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx);
+ 
+ /**
+  * Open a RT netlink socket for monitoring link state.
+commit 6d1e2a62bdb4f6353e3a9006f2d603031f4648e6
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:43 2017 +0800
+
+    rtnl: add function rtnl_get_ts_label to get interface ts_label info
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/rtnl.c b/rtnl.c
+index 3419873..cea936b 100644
+--- a/rtnl.c
++++ b/rtnl.c
+@@ -43,6 +43,37 @@ int rtnl_close(int fd)
+ 	return close(fd);
+ }
+ 
++static void rtnl_get_ts_label_callback(void *ctx, int linkup, int ts_index)
++{
++	int *dst = ctx;
++	*dst = ts_index;
++}
++
++int rtnl_get_ts_label(struct interface *iface)
++{
++	int err, fd;
++	int ts_index = -1;
++
++	fd = rtnl_open();
++	if (fd < 0)
++		return fd;
++
++	err = rtnl_link_query(fd, iface->name);
++	if (err) {
++		goto no_info;
++	}
++
++	rtnl_link_status(fd, iface->name, rtnl_get_ts_label_callback, &ts_index);
++	if (ts_index > 0 && if_indextoname(ts_index, iface->ts_label))
++		err = 0;
++	else
++		err = -1;
++
++no_info:
++	rtnl_close(fd);
++	return err;
++}
++
+ int rtnl_link_query(int fd, char *device)
+ {
+ 	struct sockaddr_nl sa;
+diff --git a/rtnl.h b/rtnl.h
+index 6eced2d..2906d74 100644
+--- a/rtnl.h
++++ b/rtnl.h
+@@ -20,6 +20,8 @@
+ #ifndef HAVE_RTNL_H
+ #define HAVE_RTNL_H
+ 
++#include "config.h"
++
+ typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
+ 
+ /**
+@@ -30,6 +32,13 @@ typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index);
+ int rtnl_close(int fd);
+ 
+ /**
++ * Get interface ts_label information
++ * @param iface  struct interface.
++ * @return       Zero on success, or -1 on error.
++ */
++int rtnl_get_ts_label(struct interface *iface);
++
++/**
+  * Request the link status from the kernel.
+  * @param fd     A socket obtained via rtnl_open().
+  * @param device Interface name. Request all iface's status if set NULL.
+commit b65b1d5f3b5d8e85e47e9cf19c2e5aa6dc2ebd77
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:44 2017 +0800
+
+    port: update port link_status to enum
+    
+    Besides link up and down, we may also receive other rtnl messages, like
+    bond slave changed info, which link state keeps the same.
+    
+    So we should return EV_FAULT_CLEARED only when both LINK_UP and
+    LINK_STATE_CHANGED.
+    
+    When the link state keep the same, we should return EV_NONE.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/port.c b/port.c
+index 05fc321..81d52ff 100644
+--- a/port.c
++++ b/port.c
+@@ -56,6 +56,12 @@ enum syfu_event {
+ 	FUP_MATCH,
+ };
+ 
++enum link_state {
++	LINK_DOWN  = (1<<0),
++	LINK_UP  = (1<<1),
++	LINK_STATE_CHANGED = (1<<3),
++};
++
+ struct nrate_estimator {
+ 	double ratio;
+ 	tmv_t origin1;
+@@ -122,7 +128,7 @@ struct port {
+ 	int                 path_trace_enabled;
+ 	int                 rx_timestamp_offset;
+ 	int                 tx_timestamp_offset;
+-	int                 link_status;
++	enum link_state     link_status;
+ 	struct fault_interval flt_interval_pertype[FT_CNT];
+ 	enum fault_type     last_fault_type;
+ 	unsigned int        versionNumber; /*UInteger4*/
+@@ -2224,18 +2230,21 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ static void port_link_status(void *ctx, int linkup, int ts_index)
+ {
+ 	struct port *p = ctx;
++	int link_state;
+ 
+-	if (p->link_status == linkup)
+-		return;
+-
+-	p->link_status = linkup;
+-	pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
++	link_state = linkup ? LINK_UP : LINK_DOWN;
++	if (p->link_status & link_state) {
++		p->link_status = link_state;
++	} else {
++		p->link_status = link_state | LINK_STATE_CHANGED;
++		pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
++	}
+ 
+ 	/*
+ 	 * A port going down can affect the BMCA result.
+ 	 * Force a state decision event.
+ 	 */
+-	if (!p->link_status)
++	if (p->link_status & LINK_DOWN)
+ 		clock_set_sde(p->clock, 1);
+ }
+ 
+@@ -2281,7 +2290,12 @@ enum fsm_event port_event(struct port *p, int fd_index)
+ 	case FD_RTNL:
+ 		pr_debug("port %hu: received link status notification", portnum(p));
+ 		rtnl_link_status(fd, p->name, port_link_status, p);
+-		return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
++		if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))
++			return EV_FAULT_CLEARED;
++		else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED))
++			return EV_FAULT_DETECTED;
++		else
++			return EV_NONE;
+ 	}
+ 
+ 	msg = msg_allocate();
+@@ -2409,7 +2423,7 @@ int port_number(struct port *p)
+ 
+ int port_link_status_get(struct port *p)
+ {
+-	return p->link_status;
++	return !!(p->link_status & LINK_UP);
+ }
+ 
+ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg)
+@@ -2630,7 +2644,7 @@ struct port *port_open(int phc_index,
+ 	p->path_trace_enabled = config_get_int(cfg, p->name, "path_trace_enabled");
+ 	p->rx_timestamp_offset = config_get_int(cfg, p->name, "ingressLatency");
+ 	p->tx_timestamp_offset = config_get_int(cfg, p->name, "egressLatency");
+-	p->link_status = 1;
++	p->link_status = LINK_UP;
+ 	p->clock = clock;
+ 	p->trp = transport_create(cfg, transport);
+ 	if (!p->trp)
+commit 1440f093847a79d0e80ea6b4bca011ddd87090d0
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:45 2017 +0800
+
+    clock: add clock_required_modes to obtain the required time stamping mode
+    
+    Separate required_modes setting from clock_create so we can obtain the
+    required time stamping flags from other place.
+    
+    Add enum timestamping in struct clock to store the time stamping mode.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index 9d224c9..5926a3c 100644
+--- a/clock.c
++++ b/clock.c
+@@ -105,6 +105,7 @@ struct clock {
+ 	int time_flags;  /* grand master role */
+ 	int time_source; /* grand master role */
+ 	enum servo_state servo_state;
++	enum timestamp_type timestamping;
+ 	tmv_t master_offset;
+ 	tmv_t path_delay;
+ 	tmv_t ingress_ts;
+@@ -803,6 +804,34 @@ static void clock_remove_port(struct clock *c, struct port *p)
+ 	port_close(p);
+ }
+ 
++int clock_required_modes(struct clock *c)
++{
++	int required_modes = 0;
++
++	switch (c->timestamping) {
++	case TS_SOFTWARE:
++		required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE |
++			SOF_TIMESTAMPING_RX_SOFTWARE |
++			SOF_TIMESTAMPING_SOFTWARE;
++		break;
++	case TS_LEGACY_HW:
++		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
++			SOF_TIMESTAMPING_RX_HARDWARE |
++			SOF_TIMESTAMPING_SYS_HARDWARE;
++		break;
++	case TS_HARDWARE:
++	case TS_ONESTEP:
++		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
++			SOF_TIMESTAMPING_RX_HARDWARE |
++			SOF_TIMESTAMPING_RAW_HARDWARE;
++		break;
++	default:
++		break;
++	}
++
++	return required_modes;
++}
++
+ struct clock *clock_create(enum clock_type type, struct config *config,
+ 			   const char *phc_device)
+ {
+@@ -911,24 +940,8 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	}
+ 
+ 	/* Check the time stamping mode on each interface. */
+-	switch (timestamping) {
+-	case TS_SOFTWARE:
+-		required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE |
+-			SOF_TIMESTAMPING_RX_SOFTWARE |
+-			SOF_TIMESTAMPING_SOFTWARE;
+-		break;
+-	case TS_LEGACY_HW:
+-		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
+-			SOF_TIMESTAMPING_RX_HARDWARE |
+-			SOF_TIMESTAMPING_SYS_HARDWARE;
+-		break;
+-	case TS_HARDWARE:
+-	case TS_ONESTEP:
+-		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
+-			SOF_TIMESTAMPING_RX_HARDWARE |
+-			SOF_TIMESTAMPING_RAW_HARDWARE;
+-		break;
+-	}
++	c->timestamping = timestamping;
++	required_modes = clock_required_modes(c);
+ 	STAILQ_FOREACH(iface, &config->interfaces, list) {
+ 		if (iface->ts_info.valid &&
+ 		    ((iface->ts_info.so_timestamping & required_modes) != required_modes)) {
+diff --git a/clock.h b/clock.h
+index 49ecb76..986d363 100644
+--- a/clock.h
++++ b/clock.h
+@@ -73,6 +73,14 @@ UInteger8 clock_class(struct clock *c);
+ struct config *clock_config(struct clock *c);
+ 
+ /**
++ * Obtains the required time stamping mode.
++ * @param c  The clock instance.
++ * @return   The value of required time stamping mode, which is a bit mask
++ *           of SOF_TIMESTAMPING_ flags.
++ */
++int clock_required_modes(struct clock *c);
++
++/**
+  * Create a clock instance. There can only be one clock in any system,
+  * so subsequent calls will destroy the previous clock instance.
+  *
+commit 536a71031d5c7689fd186ff550dc11cf743e02cb
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:46 2017 +0800
+
+    ptp4l: use ts label to get ts info
+    
+    Now the ts label will be either the bond active slave or the interface
+    name, which is the exactly interface we need to get ts info.
+    
+    When the link down/up or there is a fail over and ts_label changed, the
+    phc index may also changed. So we need to check get new ts info and check
+    clock_required_modes. We will set the link to LINK_DOWN by force if
+    the new ts_label's timestamp do not support required mode.
+    
+    If all good, then we set phc index to new one. Also sync clock interval
+    after switch phc.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index 5926a3c..41c8f81 100644
+--- a/clock.c
++++ b/clock.c
+@@ -38,6 +38,7 @@
+ #include "servo.h"
+ #include "stats.h"
+ #include "print.h"
++#include "rtnl.h"
+ #include "tlv.h"
+ #include "tsproc.h"
+ #include "uds.h"
+@@ -832,6 +833,16 @@ int clock_required_modes(struct clock *c)
+ 	return required_modes;
+ }
+ 
++/*
++ * If we do not have a slave or the rtnl query failed, then use our
++ * own interface name as the time stamping interface name.
++ */
++static void ensure_ts_label(struct interface *iface)
++{
++	if (iface->ts_label[0] == '\0')
++		strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE);
++}
++
+ struct clock *clock_create(enum clock_type type, struct config *config,
+ 			   const char *phc_device)
+ {
+@@ -943,6 +954,9 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	c->timestamping = timestamping;
+ 	required_modes = clock_required_modes(c);
+ 	STAILQ_FOREACH(iface, &config->interfaces, list) {
++		rtnl_get_ts_label(iface);
++		ensure_ts_label(iface);
++		sk_get_ts_info(iface->ts_label, &iface->ts_info);
+ 		if (iface->ts_info.valid &&
+ 		    ((iface->ts_info.so_timestamping & required_modes) != required_modes)) {
+ 			pr_err("interface '%s' does not support "
+diff --git a/config.c b/config.c
+index e6fe676..bbaf36e 100644
+--- a/config.c
++++ b/config.c
+@@ -633,7 +633,6 @@ struct interface *config_create_interface(char *name, struct config *cfg)
+ 	}
+ 
+ 	strncpy(iface->name, name, MAX_IFNAME_SIZE);
+-	sk_get_ts_info(iface->name, &iface->ts_info);
+ 	STAILQ_INSERT_TAIL(&cfg->interfaces, iface, list);
+ 	cfg->n_interfaces++;
+ 
+diff --git a/port.c b/port.c
+index 81d52ff..615c800 100644
+--- a/port.c
++++ b/port.c
+@@ -60,6 +60,7 @@ enum link_state {
+ 	LINK_DOWN  = (1<<0),
+ 	LINK_UP  = (1<<1),
+ 	LINK_STATE_CHANGED = (1<<3),
++	TS_LABEL_CHANGED  = (1<<4),
+ };
+ 
+ struct nrate_estimator {
+@@ -2231,6 +2232,8 @@ static void port_link_status(void *ctx, int linkup, int ts_index)
+ {
+ 	struct port *p = ctx;
+ 	int link_state;
++	char ts_label[MAX_IFNAME_SIZE + 1] = {0};
++	int required_modes;
+ 
+ 	link_state = linkup ? LINK_UP : LINK_DOWN;
+ 	if (p->link_status & link_state) {
+@@ -2240,6 +2243,39 @@ static void port_link_status(void *ctx, int linkup, int ts_index)
+ 		pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down");
+ 	}
+ 
++	/* ts_label changed */
++	if (if_indextoname(ts_index, ts_label) && strcmp(p->iface->ts_label, ts_label)) {
++		strncpy(p->iface->ts_label, ts_label, MAX_IFNAME_SIZE);
++		p->link_status |= TS_LABEL_CHANGED;
++		pr_notice("port %hu: ts label changed to %s", portnum(p), ts_label);
++	}
++
++	/* Both link down/up and change ts_label may change phc index. */
++	if (p->link_status & LINK_UP &&
++	    (p->link_status & LINK_STATE_CHANGED || p->link_status & TS_LABEL_CHANGED)) {
++		sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info);
++
++		/* Only switch phc with HW time stamping mode */
++		if (p->phc_index >= 0 && p->iface->ts_info.valid) {
++			required_modes = clock_required_modes(p->clock);
++			if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) {
++				pr_err("interface '%s' does not support requested "
++				       "timestamping mode, set link status down by force.",
++				       p->iface->ts_label);
++				p->link_status = LINK_DOWN | LINK_STATE_CHANGED;
++			} else if (p->phc_index != p->iface->ts_info.phc_index) {
++				p->phc_index = p->iface->ts_info.phc_index;
++
++				if (clock_switch_phc(p->clock, p->phc_index)) {
++					p->last_fault_type = FT_SWITCH_PHC;
++					port_dispatch(p, EV_FAULT_DETECTED, 0);
++					return;
++				}
++				clock_sync_interval(p->clock, p->log_sync_interval);
++			}
++		}
++	}
++
+ 	/*
+ 	 * A port going down can affect the BMCA result.
+ 	 * Force a state decision event.
+@@ -2292,7 +2328,8 @@ enum fsm_event port_event(struct port *p, int fd_index)
+ 		rtnl_link_status(fd, p->name, port_link_status, p);
+ 		if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))
+ 			return EV_FAULT_CLEARED;
+-		else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED))
++		else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) ||
++			 (p->link_status & TS_LABEL_CHANGED))
+ 			return EV_FAULT_DETECTED;
+ 		else
+ 			return EV_NONE;
+commit 8923bcdf64c0c95bac7af977b867393bae69e7a1
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:47 2017 +0800
+
+    transport: pass struct interface to transport_open
+    
+    Pass struct interface so we can use ts_iface in HW filter.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/pmc_common.c b/pmc_common.c
+index d92b0cd..447cf99 100644
+--- a/pmc_common.c
++++ b/pmc_common.c
+@@ -67,6 +67,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
+ 		       int zero_datalen)
+ {
+ 	struct pmc *pmc;
++	struct interface iface;
+ 
+ 	pmc = calloc(1, sizeof *pmc);
+ 	if (!pmc)
+@@ -90,7 +91,9 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
+ 		pr_err("failed to create transport");
+ 		goto failed;
+ 	}
+-	if (transport_open(pmc->transport, iface_name,
++
++	strncpy(iface.name, iface_name, MAX_IFNAME_SIZE);
++	if (transport_open(pmc->transport, &iface,
+ 			   &pmc->fdarray, TS_SOFTWARE)) {
+ 		pr_err("failed to open transport");
+ 		goto failed;
+diff --git a/port.c b/port.c
+index 615c800..1e3f474 100644
+--- a/port.c
++++ b/port.c
+@@ -1504,7 +1504,7 @@ static int port_initialize(struct port *p)
+ 			goto no_timers;
+ 		}
+ 	}
+-	if (transport_open(p->trp, p->name, &p->fda, p->timestamping))
++	if (transport_open(p->trp, p->iface, &p->fda, p->timestamping))
+ 		goto no_tropen;
+ 
+ 	for (i = 0; i < N_TIMER_FDS; i++) {
+@@ -1547,7 +1547,7 @@ static int port_renew_transport(struct port *p)
+ 	}
+ 	transport_close(p->trp, &p->fda);
+ 	port_clear_fda(p, FD_ANNOUNCE_TIMER);
+-	res = transport_open(p->trp, p->name, &p->fda, p->timestamping);
++	res = transport_open(p->trp, p->iface, &p->fda, p->timestamping);
+ 	/* Need to call clock_fda_changed even if transport_open failed in
+ 	 * order to update clock to the now closed descriptors. */
+ 	clock_fda_changed(p->clock);
+diff --git a/raw.c b/raw.c
+index 73e45b4..8b7bcf1 100644
+--- a/raw.c
++++ b/raw.c
+@@ -198,15 +198,16 @@ static void addr_to_mac(void *mac, struct address *addr)
+ 	memcpy(mac, &addr->sll.sll_addr, MAC_LEN);
+ }
+ 
+-static int raw_open(struct transport *t, const char *name,
++static int raw_open(struct transport *t, struct interface *iface,
+ 		    struct fdarray *fda, enum timestamp_type ts_type)
+ {
+ 	struct raw *raw = container_of(t, struct raw, t);
+ 	unsigned char ptp_dst_mac[MAC_LEN];
+ 	unsigned char p2p_dst_mac[MAC_LEN];
+ 	int efd, gfd;
+-	char *str;
++	char *str, *name;
+ 
++	name = iface->ts_label;
+ 	str = config_get_string(t->cfg, name, "ptp_dst_mac");
+ 	if (str2mac(str, ptp_dst_mac)) {
+ 		pr_err("invalid ptp_dst_mac %s", str);
+diff --git a/transport.c b/transport.c
+index d24c05b..3541394 100644
+--- a/transport.c
++++ b/transport.c
+@@ -31,10 +31,10 @@ int transport_close(struct transport *t, struct fdarray *fda)
+ 	return t->close(t, fda);
+ }
+ 
+-int transport_open(struct transport *t, const char *name,
++int transport_open(struct transport *t, struct interface *iface,
+ 		   struct fdarray *fda, enum timestamp_type tt)
+ {
+-	return t->open(t, name, fda, tt);
++	return t->open(t, iface, fda, tt);
+ }
+ 
+ int transport_recv(struct transport *t, int fd, struct ptp_message *msg)
+diff --git a/transport.h b/transport.h
+index 5d6ba98..15616bb 100644
+--- a/transport.h
++++ b/transport.h
+@@ -27,6 +27,7 @@
+ #include "msg.h"
+ 
+ struct config;
++struct interface;
+ 
+ /* Values from networkProtocol enumeration 7.4.1 Table 3 */
+ enum transport_type {
+@@ -54,7 +55,7 @@ struct transport;
+ 
+ int transport_close(struct transport *t, struct fdarray *fda);
+ 
+-int transport_open(struct transport *t, const char *name,
++int transport_open(struct transport *t, struct interface *iface,
+ 		   struct fdarray *fda, enum timestamp_type tt);
+ 
+ int transport_recv(struct transport *t, int fd, struct ptp_message *msg);
+diff --git a/transport_private.h b/transport_private.h
+index b54f32a..7530896 100644
+--- a/transport_private.h
++++ b/transport_private.h
+@@ -32,8 +32,8 @@ struct transport {
+ 
+ 	int (*close)(struct transport *t, struct fdarray *fda);
+ 
+-	int (*open)(struct transport *t, const char *name, struct fdarray *fda,
+-		    enum timestamp_type tt);
++	int (*open)(struct transport *t, struct interface *iface,
++		    struct fdarray *fda, enum timestamp_type tt);
+ 
+ 	int (*recv)(struct transport *t, int fd, void *buf, int buflen,
+ 		    struct address *addr, struct hw_timestamp *hwts);
+diff --git a/udp.c b/udp.c
+index 530a2ee..05c2ba0 100644
+--- a/udp.c
++++ b/udp.c
+@@ -152,12 +152,13 @@ enum { MC_PRIMARY, MC_PDELAY };
+ 
+ static struct in_addr mcast_addr[2];
+ 
+-static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
+-		    enum timestamp_type ts_type)
++static int udp_open(struct transport *t, struct interface *iface,
++		    struct fdarray *fda, enum timestamp_type ts_type)
+ {
+ 	struct udp *udp = container_of(t, struct udp, t);
+ 	uint8_t event_dscp, general_dscp;
+ 	int efd, gfd, ttl;
++	char *name = iface->name;
+ 
+ 	ttl = config_get_int(t->cfg, name, "udp_ttl");
+ 	udp->mac.len = 0;
+@@ -180,7 +181,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
+ 	if (gfd < 0)
+ 		goto no_general;
+ 
+-	if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4))
++	if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV4))
+ 		goto no_timestamping;
+ 
+ 	if (sk_general_init(gfd))
+diff --git a/udp6.c b/udp6.c
+index 89e27bf..7551e3f 100644
+--- a/udp6.c
++++ b/udp6.c
+@@ -160,12 +160,13 @@ enum { MC_PRIMARY, MC_PDELAY };
+ 
+ static struct in6_addr mc6_addr[2];
+ 
+-static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
+-		    enum timestamp_type ts_type)
++static int udp6_open(struct transport *t, struct interface *iface,
++		     struct fdarray *fda, enum timestamp_type ts_type)
+ {
+ 	struct udp6 *udp6 = container_of(t, struct udp6, t);
+ 	uint8_t event_dscp, general_dscp;
+ 	int efd, gfd, hop_limit;
++	char *name = iface->name;
+ 
+ 	hop_limit = config_get_int(t->cfg, name, "udp_ttl");
+ 	udp6->mac.len = 0;
+@@ -190,7 +191,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
+ 	if (gfd < 0)
+ 		goto no_general;
+ 
+-	if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6))
++	if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV6))
+ 		goto no_timestamping;
+ 
+ 	if (sk_general_init(gfd))
+diff --git a/uds.c b/uds.c
+index d5e8f50..7e11f63 100644
+--- a/uds.c
++++ b/uds.c
+@@ -52,13 +52,14 @@ static int uds_close(struct transport *t, struct fdarray *fda)
+ 	return 0;
+ }
+ 
+-static int uds_open(struct transport *t, const char *name, struct fdarray *fda,
++static int uds_open(struct transport *t, struct interface *iface, struct fdarray *fda,
+ 		    enum timestamp_type tt)
+ {
+ 	int fd, err;
+ 	struct sockaddr_un sa;
+ 	struct uds *uds = container_of(t, struct uds, t);
+ 	char *uds_path = config_get_string(t->cfg, NULL, "uds_address");
++	char *name = iface->name;
+ 
+ 	fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ 	if (fd < 0) {
+commit cb53238d5d1a1b9319536b4df1edf237e428d931
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:48 2017 +0800
+
+    phc2sys: split servo_add from function clock_add
+    
+    We also need this part in clock_reinit() later. So split it out of
+    function clock_add().
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/phc2sys.c b/phc2sys.c
+index e2b5c47..0472c68 100644
+--- a/phc2sys.c
++++ b/phc2sys.c
+@@ -162,12 +162,45 @@ static clockid_t clock_open(char *device, int *phc_index)
+ 	return clkid;
+ }
+ 
++static struct servo *servo_add(struct node *node, struct clock *clock)
++{
++	double ppb;
++	int max_ppb;
++	struct servo *servo;
++
++	clockadj_init(clock->clkid);
++	ppb = clockadj_get_freq(clock->clkid);
++	/* The reading may silently fail and return 0, reset the frequency to
++	   make sure ppb is the actual frequency of the clock. */
++	clockadj_set_freq(clock->clkid, ppb);
++	if (clock->clkid == CLOCK_REALTIME) {
++		sysclk_set_leap(0);
++		max_ppb = sysclk_max_freq();
++	} else {
++		max_ppb = phc_max_adj(clock->clkid);
++		if (!max_ppb) {
++			pr_err("clock is not adjustable");
++			return NULL;
++		}
++	}
++
++	servo = servo_create(phc2sys_config, node->servo_type,
++			     -ppb, max_ppb, 0);
++	if (!servo) {
++		pr_err("Failed to create servo");
++		return NULL;
++	}
++
++	servo_sync_interval(servo, node->phc_interval);
++
++	return servo;
++}
++
+ static struct clock *clock_add(struct node *node, char *device)
+ {
+ 	struct clock *c;
+ 	clockid_t clkid = CLOCK_INVALID;
+-	int max_ppb, phc_index = -1;
+-	double ppb;
++	int phc_index = -1;
+ 
+ 	if (device) {
+ 		clkid = clock_open(device, &phc_index);
+@@ -211,25 +244,7 @@ static struct clock *clock_add(struct node *node, char *device)
+ 		}
+ 	}
+ 
+-	clockadj_init(c->clkid);
+-	ppb = clockadj_get_freq(c->clkid);
+-	/* The reading may silently fail and return 0, reset the frequency to
+-	   make sure ppb is the actual frequency of the clock. */
+-	clockadj_set_freq(c->clkid, ppb);
+-	if (c->clkid == CLOCK_REALTIME) {
+-		sysclk_set_leap(0);
+-		max_ppb = sysclk_max_freq();
+-	} else {
+-		max_ppb = phc_max_adj(c->clkid);
+-		if (!max_ppb) {
+-			pr_err("clock is not adjustable");
+-			return NULL;
+-		}
+-	}
+-
+-	c->servo = servo_create(phc2sys_config, node->servo_type,
+-				-ppb, max_ppb, 0);
+-	servo_sync_interval(c->servo, node->phc_interval);
++	c->servo = servo_add(node, c);
+ 
+ 	if (clkid != CLOCK_REALTIME)
+ 		c->sysoff_supported = (SYSOFF_SUPPORTED ==
+commit 8a349e557c653d24b04b0545e2f179080e10731f
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:49 2017 +0800
+
+    phc2sys: re-create clock clkid and servo when phc index changed
+    
+    When the clock device or phc index changed, the new phc device may have
+    different maximum adjustment. So we need to create a new clkid and servo
+    in clock_reinit().
+    
+    At the same time, we should not only do clock_reinit() when the new state
+    is PS_MASTER. We also need to reinit clock after a failover in slave mode(
+    the new state is PS_SLAVE). We can do clock_reinit() even in PS_FAULTY so
+    we can finish adjust offset before come back to PS_LISTENING. So I removed
+    the check and let's do clock_reinit() whenever there is a new state.
+    
+    And for servo reset, as Miroslav suggested, we will do it in these cases:
+    - the system clock is the new destination (master state)
+    - a PHC is the new destination (master state)
+    - a PHC is switched (in any state)
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/phc2sys.c b/phc2sys.c
+index 0472c68..5c54055 100644
+--- a/phc2sys.c
++++ b/phc2sys.c
+@@ -128,6 +128,11 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
+ static int run_pmc_get_utc_offset(struct node *node, int timeout);
+ static void run_pmc_events(struct node *node);
+ 
++static int normalize_state(int state);
++static int run_pmc_port_properties(struct node *node, int timeout,
++				   unsigned int port,
++				   int *state, int *tstamping, char *iface);
++
+ static clockid_t clock_open(char *device, int *phc_index)
+ {
+ 	struct sk_ts_info ts_info;
+@@ -309,15 +314,62 @@ static struct port *port_add(struct node *node, unsigned int number,
+ 	return p;
+ }
+ 
+-static void clock_reinit(struct clock *clock)
++static void clock_reinit(struct node *node, struct clock *clock, int new_state)
+ {
+-	servo_reset(clock->servo);
+-	clock->servo_state = SERVO_UNLOCKED;
++	int phc_index = -1, phc_switched = 0;
++	int state, timestamping, ret = -1;
++	struct port *p;
++	struct servo *servo;
++	struct sk_ts_info ts_info;
++	char iface[IFNAMSIZ];
++	clockid_t clkid = CLOCK_INVALID;
+ 
+-	if (clock->offset_stats) {
+-		stats_reset(clock->offset_stats);
+-		stats_reset(clock->freq_stats);
+-		stats_reset(clock->delay_stats);
++	LIST_FOREACH(p, &node->ports, list) {
++		if (p->clock == clock) {
++			ret = run_pmc_port_properties(node, 1000, p->number,
++					              &state, &timestamping,
++						      iface);
++			if (ret > 0)
++				p->state = normalize_state(state);
++		}
++	}
++
++	if (ret > 0 && timestamping != TS_SOFTWARE) {
++		/* Check if device changed */
++		if (strcmp(clock->device, iface)) {
++			free(clock->device);
++			clock->device = strdup(iface);
++		}
++		/* Check if phc index changed */
++		if (!sk_get_ts_info(clock->device, &ts_info) &&
++		    clock->phc_index != ts_info.phc_index) {
++			clkid = clock_open(clock->device, &phc_index);
++			if (clkid == CLOCK_INVALID)
++				return;
++
++			phc_close(clock->clkid);
++			clock->clkid = clkid;
++			clock->phc_index = phc_index;
++
++			servo = servo_add(node, clock);
++			if (servo) {
++				servo_destroy(clock->servo);
++				clock->servo = servo;
++			}
++
++			phc_switched = 1;
++		}
++	}
++
++	if (new_state == PS_MASTER || phc_switched) {
++		servo_reset(clock->servo);
++		clock->servo_state = SERVO_UNLOCKED;
++
++		if (clock->offset_stats) {
++			stats_reset(clock->offset_stats);
++			stats_reset(clock->freq_stats);
++			stats_reset(clock->delay_stats);
++		}
+ 	}
+ }
+ 
+@@ -336,9 +388,7 @@ static void reconfigure(struct node *node)
+ 		}
+ 
+ 		if (c->new_state) {
+-			if (c->new_state == PS_MASTER)
+-				clock_reinit(c);
+-
++			clock_reinit(node, c, c->new_state);
+ 			c->state = c->new_state;
+ 			c->new_state = 0;
+ 		}
+@@ -403,7 +453,7 @@ static void reconfigure(struct node *node)
+ 	} else if (rt) {
+ 		if (rt->state != PS_MASTER) {
+ 			rt->state = PS_MASTER;
+-			clock_reinit(rt);
++			clock_reinit(node, rt, rt->state);
+ 		}
+ 		pr_info("selecting %s for synchronization", rt->device);
+ 	}
+commit 7092db303028d84574138c8199375dfde0b4e232
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Mon Oct 9 22:31:50 2017 +0800
+
+    port: return timestamping iface in port properties
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/port.c b/port.c
+index 1e3f474..d8e29d5 100644
+--- a/port.c
++++ b/port.c
+@@ -861,7 +861,7 @@ static int port_management_fill_response(struct port *target,
+ 		else
+ 			ppn->port_state = target->state;
+ 		ppn->timestamping = target->timestamping;
+-		ptp_text_set(&ppn->interface, target->name);
++		ptp_text_set(&ppn->interface, target->iface->ts_label);
+ 		datalen = sizeof(*ppn) + ppn->interface.length;
+ 		respond = 1;
+ 		break;
+commit 5ce04f9bf366c6d62db5344a6553f87a99ea52ff
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Wed Oct 18 20:31:38 2017 +0800
+
+    phc2sys: update '-s' option
+    
+    Add description about bond interface.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/phc2sys.8 b/phc2sys.8
+index 2559c74..4fc4fa3 100644
+--- a/phc2sys.8
++++ b/phc2sys.8
+@@ -94,7 +94,11 @@ together with the
+ option, the master clock is used only to correct the offset by whole number of
+ seconds, which cannot be fixed with PPS alone. Not compatible with the
+ .B \-a
+-option.
++option. This option does not support bonded interface (e.g. bond0). If
++.B ptp4l
++has a port on an active-backup bond interface, the
++.B \-a
++option can be used to track the active interface.
+ .TP
+ .BI \-i " interface"
+ Performs the exact same function as
diff --git a/SOURCES/linuxptp-ipoib.patch b/SOURCES/linuxptp-ipoib.patch
new file mode 100644
index 0000000..1c62978
--- /dev/null
+++ b/SOURCES/linuxptp-ipoib.patch
@@ -0,0 +1,225 @@
+commit 7546434030d456b13b2eda6138f183ac3bf29751
+Author: Feras Daoud <ferasda@mellanox.com>
+Date:   Wed Aug 9 18:27:32 2017 +0300
+
+    ptp4l: Add IPoIB interface support for ptp4l
+    
+    The current implementation of ptp4l always assumes 6 octets MAC
+    address, which is correct for Ethernet interfaces but not for IPoIB
+    interfaces (that have 20 octets MAC), therefore running ptp4l over
+    IPoIB interface does not function correctly.
+    
+    In Infiniband, every interface has three identifiers:
+    GUID, GID, and LID.
+    The GUID is similar in concept to a MAC address. From RFC4392:
+    The EUI-64 portion of a GID is referred to as the Global Unique
+    Identifier (GUID) and is the only persistent identifier of a port.
+    
+    Therefore, to support IPoIB interfaces, the GUID of the port should
+    be used instead of the MAC.
+    This patch checks the interface type before creating the clock identity,
+    for Infiniband ports, it retrieves the GUID of the port using sysfs
+    and use it to create the clock identity.
+    
+    sysfs method was chosen since the GUID is the 6 lsb bytes of
+    the 20 byte device address, and SIOCGIFHWADDR ioctl call returns
+    the 14 msb bytes of the device address, so it is not possible to
+    get the GUID using SIOCGIFHWADDR ioctl call.
+    
+    [ RC: fixed trivial coding style error, space after switch keyword. ]
+    
+    Signed-off-by: Feras Daoud <ferasda@mellanox.com>
+    Reviewed-by: Alex Vesker <valex@mellanox.com>
+
+diff --git a/address.h b/address.h
+index 7578f91..35ef05f 100644
+--- a/address.h
++++ b/address.h
+@@ -24,6 +24,7 @@
+ #include <netpacket/packet.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <net/if_arp.h>
+ 
+ struct address {
+ 	socklen_t len;
+diff --git a/ether.h b/ether.h
+index ce3d663..8ec9669 100644
+--- a/ether.h
++++ b/ether.h
+@@ -22,7 +22,13 @@
+ 
+ #include <stdint.h>
+ 
+-#define MAC_LEN 6
++#define EUI48 6
++#define EUI64 8
++
++#define MAC_LEN  EUI48
++#define GUID_LEN EUI64
++
++#define GUID_OFFSET 36
+ 
+ typedef uint8_t eth_addr[MAC_LEN];
+ 
+diff --git a/sk.c b/sk.c
+index 63ec206..0cf55c5 100644
+--- a/sk.c
++++ b/sk.c
+@@ -159,10 +159,55 @@ failed:
+ 	return -1;
+ }
+ 
++static int sk_interface_guidaddr(const char *name, unsigned char *guid)
++{
++	char file_name[64], buf[64], addr[8];
++	FILE *f;
++	char *err;
++	int res;
++
++	snprintf(file_name, sizeof buf, "/sys/class/net/%s/address", name);
++	f = fopen(file_name, "r");
++	if (!f) {
++		pr_err("failed to open %s: %m", buf);
++		return -1;
++	}
++
++	/* Set the file position to the beginning of the GUID */
++	res = fseek(f, GUID_OFFSET, SEEK_SET);
++	if (res) {
++		pr_err("fseek failed: %m");
++		goto error;
++	}
++
++	err = fgets(buf, sizeof buf, f);
++	if (err == NULL) {
++		pr_err("fseek failed: %m");
++		goto error;
++	}
++
++	res = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
++			   &addr[0], &addr[1], &addr[2], &addr[3],
++			   &addr[4], &addr[5], &addr[6], &addr[7]);
++	if (res != GUID_LEN) {
++		pr_err("sscanf failed: %m");
++		goto error;
++	}
++
++	memcpy(guid, addr, GUID_LEN);
++	fclose(f);
++
++	return 0;
++
++error:
++	fclose(f);
++	return -1;
++}
++
+ int sk_interface_macaddr(const char *name, struct address *mac)
+ {
+ 	struct ifreq ifreq;
+-	int err, fd;
++	int err, fd, type;
+ 
+ 	memset(&ifreq, 0, sizeof(ifreq));
+ 	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1);
+@@ -180,9 +225,23 @@ int sk_interface_macaddr(const char *name, struct address *mac)
+ 		return -1;
+ 	}
+ 
++	/* Get interface type */
++	type = ifreq.ifr_hwaddr.sa_family;
++	switch (type) {
++		case ARPHRD_INFINIBAND:
++			err = sk_interface_guidaddr(name, mac->sll.sll_addr);
++			if (err) {
++				pr_err("fail to get address using sysfs: %m");
++				return -1;
++			}
++			mac->sll.sll_halen = EUI64;
++			break;
++		default:
++			memcpy(mac->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
++			mac->sll.sll_halen = EUI48;
++	}
++
+ 	mac->sll.sll_family = AF_PACKET;
+-	mac->sll.sll_halen = MAC_LEN;
+-	memcpy(mac->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
+ 	mac->len = sizeof(mac->sll);
+ 	close(fd);
+ 	return 0;
+diff --git a/util.c b/util.c
+index 2b880ff..62f2638 100644
+--- a/util.c
++++ b/util.c
+@@ -135,14 +135,32 @@ int generate_clock_identity(struct ClockIdentity *ci, const char *name)
+ 
+ 	if (sk_interface_macaddr(name, &addr))
+ 		return -1;
+-	ci->id[0] = addr.sll.sll_addr[0];
+-	ci->id[1] = addr.sll.sll_addr[1];
+-	ci->id[2] = addr.sll.sll_addr[2];
+-	ci->id[3] = 0xFF;
+-	ci->id[4] = 0xFE;
+-	ci->id[5] = addr.sll.sll_addr[3];
+-	ci->id[6] = addr.sll.sll_addr[4];
+-	ci->id[7] = addr.sll.sll_addr[5];
++
++	switch (addr.sll.sll_halen) {
++		case EUI48:
++			ci->id[0] = addr.sll.sll_addr[0];
++			ci->id[1] = addr.sll.sll_addr[1];
++			ci->id[2] = addr.sll.sll_addr[2];
++			ci->id[3] = 0xFF;
++			ci->id[4] = 0xFE;
++			ci->id[5] = addr.sll.sll_addr[3];
++			ci->id[6] = addr.sll.sll_addr[4];
++			ci->id[7] = addr.sll.sll_addr[5];
++			break;
++		case EUI64:
++			ci->id[0] = addr.sll.sll_addr[0];
++			ci->id[1] = addr.sll.sll_addr[1];
++			ci->id[2] = addr.sll.sll_addr[2];
++			ci->id[3] = addr.sll.sll_addr[3];
++			ci->id[4] = addr.sll.sll_addr[4];
++			ci->id[5] = addr.sll.sll_addr[5];
++			ci->id[6] = addr.sll.sll_addr[6];
++			ci->id[7] = addr.sll.sll_addr[7];
++			break;
++		default:
++			return -1;
++	}
++
+ 	return 0;
+ }
+ 
+commit fd2646263f0fb1a31dde53e67ac24971ab1f90f4
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Mon Oct 16 11:29:48 2017 +0200
+
+    sk: don't leak socket when reading of IB GUID fails.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/sk.c b/sk.c
+index 0cf55c5..2c7593b 100644
+--- a/sk.c
++++ b/sk.c
+@@ -225,6 +225,8 @@ int sk_interface_macaddr(const char *name, struct address *mac)
+ 		return -1;
+ 	}
+ 
++	close(fd);
++
+ 	/* Get interface type */
+ 	type = ifreq.ifr_hwaddr.sa_family;
+ 	switch (type) {
+@@ -243,7 +245,6 @@ int sk_interface_macaddr(const char *name, struct address *mac)
+ 
+ 	mac->sll.sll_family = AF_PACKET;
+ 	mac->len = sizeof(mac->sll);
+-	close(fd);
+ 	return 0;
+ }
+ 
diff --git a/SOURCES/linuxptp-linkdown.patch b/SOURCES/linuxptp-linkdown.patch
index 34d1ae3..41c3918 100644
--- a/SOURCES/linuxptp-linkdown.patch
+++ b/SOURCES/linuxptp-linkdown.patch
@@ -1,4 +1,4 @@
-Backport of commit 73318c5b99571c8da01474ad665e2e2e06ab12bb
+commit 73318c5b99571c8da01474ad665e2e2e06ab12bb
 Author: Richard Cochran <richardcochran@gmail.com>
 Date:   Sun Feb 5 18:31:27 2017 +0100
 
@@ -11,9 +11,10 @@ Date:   Sun Feb 5 18:31:27 2017 +0100
     Signed-off-by: Richard Cochran <richardcochran@gmail.com>
     Reported-by: Henry Jesuiter <Henry.Jesuiter@alcnetworx.de>
 
-diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c
---- linuxptp-1.8/clock.c.linkdown	2017-03-15 08:37:03.017542152 +0100
-+++ linuxptp-1.8/clock.c	2017-03-15 08:42:53.238682318 +0100
+diff --git a/clock.c b/clock.c
+index f027305..6ec3e72 100644
+--- a/clock.c
++++ b/clock.c
 @@ -96,6 +96,7 @@ struct clock {
  	int pollfd_valid;
  	int nports; /* does not include the UDS port */
@@ -22,7 +23,7 @@ diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c
  	struct hash *index2port;
  	int free_running;
  	int freq_est_interval;
-@@ -341,6 +342,11 @@ static void clock_link_status(void *ctx,
+@@ -341,6 +342,11 @@ static void clock_link_status(void *ctx, int index, int linkup)
  		port_dispatch(p, EV_FAULT_CLEARED, 0);
  	} else {
  		port_dispatch(p, EV_FAULT_DETECTED, 0);
@@ -34,16 +35,16 @@ diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c
  	}
  }
  
-@@ -1465,7 +1471,7 @@ struct PortIdentity clock_parent_identit
+@@ -1463,7 +1469,7 @@ struct PortIdentity clock_parent_identity(struct clock *c)
  
  int clock_poll(struct clock *c)
  {
--	int cnt, err, i, sde = 0;
-+	int cnt, err, i;
+-	int cnt, i, sde = 0;
++	int cnt, i;
  	enum fsm_event event;
  	struct pollfd *cur;
  	struct port *p;
-@@ -1496,9 +1502,9 @@ int clock_poll(struct clock *c)
+@@ -1494,9 +1500,9 @@ int clock_poll(struct clock *c)
  			if (cur[i].revents & (POLLIN|POLLPRI)) {
  				event = port_event(p, i);
  				if (EV_STATE_DECISION_EVENT == event)
@@ -52,10 +53,10 @@ diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c
  				if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event)
 -					sde = 1;
 +					c->sde = 1;
- 				err = port_dispatch(p, event, 0);
+ 				port_dispatch(p, event, 0);
  				/* Clear any fault after a little while. */
  				if (PS_FAULTY == port_state(p)) {
-@@ -1527,13 +1533,14 @@ int clock_poll(struct clock *c)
+@@ -1525,13 +1531,14 @@ int clock_poll(struct clock *c)
  		if (cur[i].revents & (POLLIN|POLLPRI)) {
  			event = port_event(c->uds_port, i);
  			if (EV_STATE_DECISION_EVENT == event)
diff --git a/SOURCES/linuxptp-mgttlv.patch b/SOURCES/linuxptp-mgttlv.patch
new file mode 100644
index 0000000..646bf43
--- /dev/null
+++ b/SOURCES/linuxptp-mgttlv.patch
@@ -0,0 +1,50 @@
+commit 43b2f5d1207a010f1df67e101b129b09502371e2
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Fri May 12 15:36:45 2017 +0800
+
+    msg: use last_tlv if there is not enough room for another tlv
+    
+    If the len is not enought for another tlv process. e.g. one more bytes
+    padding at the end of message. And we set extra to NULL instead of
+    msg->last_tlv in tlv_post_recv(). Then the msg->last_tlv will not be
+    initialised. And program will crash if we read msg->last_tlv. e.g. in
+    function pmc_show().
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/msg.c b/msg.c
+index a38b815..4b3d926 100644
+--- a/msg.c
++++ b/msg.c
+@@ -140,7 +140,7 @@ static int suffix_post_recv(uint8_t *ptr, int len, struct tlv_extra *last)
+ 		}
+ 		len -= tlv->length;
+ 		ptr += tlv->length;
+-		err = tlv_post_recv(tlv, len ? NULL : last);
++		err = tlv_post_recv(tlv, len > sizeof(struct TLV) ? NULL : last);
+ 		if (err)
+ 			return err;
+ 	}
+commit 95b5a13cb2787b6a436ad395bb4931d1661e59a7
+Author: Hangbin Liu <liuhangbin@gmail.com>
+Date:   Tue May 23 14:49:55 2017 +0800
+
+    pmc: goto out when get unknown management tlv
+    
+    If handle unknown management tlv. The management message id and format are
+    also unknown, thus we may crash due to access unknown area.
+    
+    Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
+
+diff --git a/pmc.c b/pmc.c
+index cefa771..af9cc63 100644
+--- a/pmc.c
++++ b/pmc.c
+@@ -217,6 +217,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
+ 		goto out;
+ 	} else {
+ 		fprintf(fp, "unknown-tlv ");
++		goto out;
+ 	}
+ 	mgt = (struct management_tlv *) msg->management.suffix;
+ 	if (mgt->length == 2 && mgt->id != TLV_NULL_MANAGEMENT) {
diff --git a/SOURCES/linuxptp-multiport.patch b/SOURCES/linuxptp-multiport.patch
new file mode 100644
index 0000000..8f9568c
--- /dev/null
+++ b/SOURCES/linuxptp-multiport.patch
@@ -0,0 +1,77 @@
+commit ac92a711614c413b75a4963eab95cd1aa2de8293
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Mon Mar 27 17:43:06 2017 +0200
+
+    phc2sys: don't synchronize clock to itself.
+    
+    When ptp4l is using multiple interfaces sharing the same clock, phc2sys
+    in the automatic mode should not try to synchronize them to each other.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+    Reported-by: Stefan Lange <s.lange@gateware.de>
+
+diff --git a/phc2sys.c b/phc2sys.c
+index aa4186b..4c8b552 100644
+--- a/phc2sys.c
++++ b/phc2sys.c
+@@ -72,6 +72,7 @@
+ struct clock {
+ 	LIST_ENTRY(clock) list;
+ 	clockid_t clkid;
++	int phc_index;
+ 	int sysoff_supported;
+ 	int is_utc;
+ 	int dest_only;
+@@ -127,7 +128,7 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
+ static int run_pmc_get_utc_offset(struct node *node, int timeout);
+ static void run_pmc_events(struct node *node);
+ 
+-static clockid_t clock_open(char *device)
++static clockid_t clock_open(char *device, int *phc_index)
+ {
+ 	struct sk_ts_info ts_info;
+ 	char phc_device[16];
+@@ -157,6 +158,7 @@ static clockid_t clock_open(char *device)
+ 	clkid = phc_open(phc_device);
+ 	if (clkid == CLOCK_INVALID)
+ 		fprintf(stderr, "cannot open %s: %m\n", device);
++	*phc_index = ts_info.phc_index;
+ 	return clkid;
+ }
+ 
+@@ -164,11 +166,11 @@ static struct clock *clock_add(struct node *node, char *device)
+ {
+ 	struct clock *c;
+ 	clockid_t clkid = CLOCK_INVALID;
+-	int max_ppb;
++	int max_ppb, phc_index = -1;
+ 	double ppb;
+ 
+ 	if (device) {
+-		clkid = clock_open(device);
++		clkid = clock_open(device, &phc_index);
+ 		if (clkid == CLOCK_INVALID)
+ 			return NULL;
+ 	}
+@@ -179,6 +181,7 @@ static struct clock *clock_add(struct node *node, char *device)
+ 		return NULL;
+ 	}
+ 	c->clkid = clkid;
++	c->phc_index = phc_index;
+ 	c->servo_state = SERVO_UNLOCKED;
+ 	c->device = strdup(device);
+ 
+@@ -638,6 +641,13 @@ static int do_loop(struct node *node, int subscriptions)
+ 			if (!update_needed(clock))
+ 				continue;
+ 
++			/* don't try to synchronize the clock to itself */
++			if (clock->clkid == node->master->clkid ||
++			    (clock->phc_index >= 0 &&
++			     clock->phc_index == node->master->phc_index) ||
++			    !strcmp(clock->device, node->master->device))
++				continue;
++
+ 			if (clock->clkid == CLOCK_REALTIME &&
+ 			    node->master->sysoff_supported) {
+ 				/* use sysoff */
diff --git a/SOURCES/linuxptp-portdispatch.patch b/SOURCES/linuxptp-portdispatch.patch
new file mode 100644
index 0000000..2bb09c1
--- /dev/null
+++ b/SOURCES/linuxptp-portdispatch.patch
@@ -0,0 +1,434 @@
+commit 10d4e7f8b0525bbf72981e3e5fcf0c10833a7631
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Tue Jan 3 20:55:18 2017 +0100
+
+    port: Make the finite state machine into a function variable.
+    
+    This allows adding new FSM flavors in the future.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/port.c b/port.c
+index a1ad6f6..afe0057 100644
+--- a/port.c
++++ b/port.c
+@@ -94,6 +94,8 @@ struct port {
+ 	unsigned int pdr_missing;
+ 	unsigned int multiple_seq_pdr_count;
+ 	unsigned int multiple_pdr_detected;
++	enum port_state (*state_machine)(enum port_state state,
++					 enum fsm_event event, int mdiff);
+ 	/* portDS */
+ 	struct PortIdentity portIdentity;
+ 	enum port_state     state; /*portState*/
+@@ -2142,10 +2144,8 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 		if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) {
+ 			port_slave_priority_warning(p);
+ 		}
+-		next = ptp_slave_fsm(p->state, event, mdiff);
+-	} else {
+-		next = ptp_fsm(p->state, event, mdiff);
+ 	}
++	next = p->state_machine(p->state, event, mdiff);
+ 
+ 	if (!fault_interval(p, last_fault_type(p), &i) &&
+ 	    ((i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) ||
+@@ -2555,6 +2555,7 @@ struct port *port_open(int phc_index,
+ 
+ 	memset(p, 0, sizeof(*p));
+ 
++	p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : ptp_fsm;
+ 	p->phc_index = phc_index;
+ 	p->jbod = config_get_int(cfg, interface->name, "boundary_clock_jbod");
+ 	transport = config_get_int(cfg, interface->name, "network_transport");
+
+commit 80a28a9dc322f28b991effc44ec1c5362a598281
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Tue Jan 3 20:55:33 2017 +0100
+
+    Change a misleading fault handling function signature.
+    
+    Looking at the fault logic in port_dispatch(), you might think that
+    the function, fault_interval(), checks whether a fault is active, but
+    you would be wrong, since that function always returns zero.
+    
+    This patch removes the superfluous input error checking inside of
+    fault_interval() and changes the return type to void, making the
+    actual behavior explicit.  Dropping the input check is safe because
+    that function has exactly two callers, both of whom always provide
+    valid inputs.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/port.c b/port.c
+index afe0057..6c9aa72 100644
+--- a/port.c
++++ b/port.c
+@@ -205,16 +205,11 @@ enum fault_type last_fault_type(struct port *port)
+ 	return port->last_fault_type;
+ }
+ 
+-int fault_interval(struct port *port, enum fault_type ft,
+-	struct fault_interval *i)
++void fault_interval(struct port *port, enum fault_type ft,
++		    struct fault_interval *i)
+ {
+-	if (!port || !i)
+-		return -EINVAL;
+-	if (ft < 0 || ft >= FT_CNT)
+-		return -EINVAL;
+ 	i->type = port->flt_interval_pertype[ft].type;
+ 	i->val = port->flt_interval_pertype[ft].val;
+-	return 0;
+ }
+ 
+ int port_fault_fd(struct port *port)
+@@ -2147,9 +2142,9 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	}
+ 	next = p->state_machine(p->state, event, mdiff);
+ 
+-	if (!fault_interval(p, last_fault_type(p), &i) &&
+-	    ((i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) ||
+-	     (i.val == 0 && i.type == FTMO_LINEAR_SECONDS)))
++	fault_interval(p, last_fault_type(p), &i);
++	if ((i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) ||
++	     (i.val == 0 && i.type == FTMO_LINEAR_SECONDS))
+ 		fri_asap = 1;
+ 	if (PS_INITIALIZING == next || (PS_FAULTY == next && fri_asap)) {
+ 		/*
+diff --git a/port.h b/port.h
+index 19dec4a..d2e0865 100644
+--- a/port.h
++++ b/port.h
+@@ -318,9 +318,8 @@ enum fault_type last_fault_type(struct port *port);
+  * @param port        A port instance.
+  * @param ft          Fault type.
+  * @param i           Pointer to the struct which will be filled in.
+- * @return Zero on success, non-zero otherwise.
+  */
+-int fault_interval(struct port *port, enum fault_type ft,
+-	struct fault_interval *i);
++void fault_interval(struct port *port, enum fault_type ft,
++		    struct fault_interval *i);
+ 
+ #endif
+
+commit 1f66948d3853c8b08c7f52c9c8daecb361164a43
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Tue Jan 3 20:55:42 2017 +0100
+
+    Make the fault handling code more readable.
+    
+    The code that decides whether a fault qualifies for ASAP treatment is
+    a tangle of logical operators.  This patch replaces the open coded
+    logic with a helper function whose name makes the intent clear.  This
+    is a cosmetic change only.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/port.c b/port.c
+index 6c9aa72..02dbabb 100644
+--- a/port.c
++++ b/port.c
+@@ -161,6 +161,19 @@ static void announce_to_dataset(struct ptp_message *m, struct port *p,
+ 	out->receiver     = p->portIdentity;
+ }
+ 
++static int clear_fault_asap(struct fault_interval *faint)
++{
++	switch (faint->type) {
++	case FTMO_LINEAR_SECONDS:
++		return faint->val == 0 ? 1 : 0;
++	case FTMO_LOG2_SECONDS:
++		return faint->val == FRI_ASAP ? 1 : 0;
++	case FTMO_CNT:
++		return 0;
++	}
++	return 0;
++}
++
+ static int msg_current(struct ptp_message *m, struct timespec now)
+ {
+ 	int64_t t1, t2, tmo;
+@@ -2143,9 +2156,9 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	next = p->state_machine(p->state, event, mdiff);
+ 
+ 	fault_interval(p, last_fault_type(p), &i);
+-	if ((i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) ||
+-	     (i.val == 0 && i.type == FTMO_LINEAR_SECONDS))
++	if (clear_fault_asap(&i)) {
+ 		fri_asap = 1;
++	}
+ 	if (PS_INITIALIZING == next || (PS_FAULTY == next && fri_asap)) {
+ 		/*
+ 		 * This is a special case. Since we initialize the
+
+commit 01ee947457813078f63d606c310818d6dedb4ca3
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Tue Jan 3 20:55:50 2017 +0100
+
+    Disentangle initialization from fault clearing.
+    
+    Although leaving the INITIALIZING state and clearing the FAULTY state
+    ASAP both result in a port entering the LISTENING state, still there
+    is no benefit from conflating the two.  In the FAULTY case, the
+    current code actually skips the INITIALIZING state altogether.
+    
+    This patch separates the two cases resulting in two benefits.  First,
+    the check for ASAP fault status is only made when a fault is actually
+    present, unlike the present unconditional check.  Second, this change
+    will allow us to cleanly support alternative state machines later on.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/port.c b/port.c
+index 02dbabb..ebe7342 100644
+--- a/port.c
++++ b/port.c
+@@ -2145,8 +2145,6 @@ static void port_p2p_transition(struct port *p, enum port_state next)
+ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ {
+ 	enum port_state next;
+-	struct fault_interval i;
+-	int fri_asap = 0;
+ 
+ 	if (clock_slave_only(p->clock)) {
+ 		if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) {
+@@ -2155,11 +2153,15 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	}
+ 	next = p->state_machine(p->state, event, mdiff);
+ 
+-	fault_interval(p, last_fault_type(p), &i);
+-	if (clear_fault_asap(&i)) {
+-		fri_asap = 1;
++	if (PS_FAULTY == next) {
++		struct fault_interval i;
++		fault_interval(p, last_fault_type(p), &i);
++		if (clear_fault_asap(&i)) {
++			pr_notice("port %hu: clearing fault immediately", portnum(p));
++			next = PS_INITIALIZING;
++		}
+ 	}
+-	if (PS_INITIALIZING == next || (PS_FAULTY == next && fri_asap)) {
++	if (PS_INITIALIZING == next) {
+ 		/*
+ 		 * This is a special case. Since we initialize the
+ 		 * port immediately, we can skip right to listening
+
+commit b738afb6044a8c59310fc13f646c8f5c4dcf2963
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Thu Oct 27 15:20:36 2016 +0200
+
+    fsm: Make the transition out of INITIALIZING part of the FSM code.
+    
+    The state machines in 1588 do not specify an event that causes a transition
+    out of the initializing state.  This was left as a local issue.  For this
+    transition, the current code assigns the next state outside of the FSM.  But
+    doing so prevents an alternative FSM to handle this transition differently.
+    
+    By introducing a new event, this patch places this transition where it
+    belongs, namely under the control of the FSM code,
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/fsm.c b/fsm.c
+index d1423e7..ce6efad 100644
+--- a/fsm.c
++++ b/fsm.c
+@@ -27,7 +27,16 @@ enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff)
+ 
+ 	switch (state) {
+ 	case PS_INITIALIZING:
+-		next = PS_LISTENING;
++		switch (event) {
++		case EV_FAULT_DETECTED:
++			next = PS_FAULTY;
++			break;
++		case EV_INIT_COMPLETE:
++			next = PS_LISTENING;
++			break;
++		default:
++			break;
++		}
+ 		break;
+ 
+ 	case PS_FAULTY:
+@@ -220,7 +229,16 @@ enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event,
+ 
+ 	switch (state) {
+ 	case PS_INITIALIZING:
+-		next = PS_LISTENING;
++		switch (event) {
++		case EV_FAULT_DETECTED:
++			next = PS_FAULTY;
++			break;
++		case EV_INIT_COMPLETE:
++			next = PS_LISTENING;
++			break;
++		default:
++			break;
++		}
+ 		break;
+ 
+ 	case PS_FAULTY:
+diff --git a/fsm.h b/fsm.h
+index 5d4ae91..0616daa 100644
+--- a/fsm.h
++++ b/fsm.h
+@@ -48,6 +48,7 @@ enum fsm_event {
+ 	EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ 	EV_SYNCHRONIZATION_FAULT,
+ 	EV_MASTER_CLOCK_SELECTED,
++	EV_INIT_COMPLETE,
+ 	EV_RS_MASTER,
+ 	EV_RS_GRAND_MASTER,
+ 	EV_RS_SLAVE,
+diff --git a/port.c b/port.c
+index ebe7342..5f1646b 100644
+--- a/port.c
++++ b/port.c
+@@ -2120,6 +2120,7 @@ static void port_p2p_transition(struct port *p, enum port_state next)
+ 		break;
+ 	case PS_LISTENING:
+ 		port_set_announce_tmo(p);
++		port_set_delay_tmo(p);
+ 		break;
+ 	case PS_PRE_MASTER:
+ 		port_set_qualification_tmo(p);
+@@ -2158,7 +2159,7 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 		fault_interval(p, last_fault_type(p), &i);
+ 		if (clear_fault_asap(&i)) {
+ 			pr_notice("port %hu: clearing fault immediately", portnum(p));
+-			next = PS_INITIALIZING;
++			next = p->state_machine(next, EV_FAULT_CLEARED, 0);
+ 		}
+ 	}
+ 	if (PS_INITIALIZING == next) {
+@@ -2170,14 +2171,12 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 		if (port_is_enabled(p)) {
+ 			port_disable(p);
+ 		}
+-		next = port_initialize(p) ? PS_FAULTY : PS_LISTENING;
+-		port_show_transition(p, next, event);
+-		p->state = next;
+-		if (next == PS_LISTENING && p->delayMechanism == DM_P2P) {
+-			port_set_delay_tmo(p);
++		if (port_initialize(p)) {
++			event = EV_FAULT_DETECTED;
++		} else {
++			event = EV_INIT_COMPLETE;
+ 		}
+-		port_notify_event(p, NOTIFY_PORT_STATE);
+-		return 1;
++		next = p->state_machine(next, event, 0);
+ 	}
+ 
+ 	if (next == p->state)
+diff --git a/util.c b/util.c
+index 594b49f..2b880ff 100644
+--- a/util.c
++++ b/util.c
+@@ -61,6 +61,7 @@ const char *ev_str[] = {
+ 	"ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES",
+ 	"SYNCHRONIZATION_FAULT",
+ 	"MASTER_CLOCK_SELECTED",
++	"INIT_COMPLETE",
+ 	"RS_MASTER",
+ 	"RS_GRAND_MASTER",
+ 	"RS_SLAVE",
+
+commit 6b471d45edfdfa835a9115ce4be96d92f100e2ac
+Author: Richard Cochran <richardcochran@gmail.com>
+Date:   Sun Feb 5 18:25:18 2017 +0100
+
+    port: Change port_dispatch() into a void function.
+    
+    This global function used to return an error code, but now it always
+    returns zero.  This patch converts the function signature to return void
+    and simplifies the main clock loop by removing the useless test.
+    
+    Signed-off-by: Richard Cochran <richardcochran@gmail.com>
+
+diff --git a/clock.c b/clock.c
+index a6a1a1a..f027305 100644
+--- a/clock.c
++++ b/clock.c
+@@ -1463,7 +1463,7 @@ struct PortIdentity clock_parent_identity(struct clock *c)
+ 
+ int clock_poll(struct clock *c)
+ {
+-	int cnt, err, i, sde = 0;
++	int cnt, i, sde = 0;
+ 	enum fsm_event event;
+ 	struct pollfd *cur;
+ 	struct port *p;
+@@ -1490,14 +1490,14 @@ int clock_poll(struct clock *c)
+ 	cur++;
+ 	LIST_FOREACH(p, &c->ports, list) {
+ 		/* Let the ports handle their events. */
+-		for (i = err = 0; i < N_POLLFD && !err; i++) {
++		for (i = 0; i < N_POLLFD; i++) {
+ 			if (cur[i].revents & (POLLIN|POLLPRI)) {
+ 				event = port_event(p, i);
+ 				if (EV_STATE_DECISION_EVENT == event)
+ 					sde = 1;
+ 				if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event)
+ 					sde = 1;
+-				err = port_dispatch(p, event, 0);
++				port_dispatch(p, event, 0);
+ 				/* Clear any fault after a little while. */
+ 				if (PS_FAULTY == port_state(p)) {
+ 					clock_fault_timeout(p, 1);
+diff --git a/port.c b/port.c
+index 5f1646b..0f99b1b 100644
+--- a/port.c
++++ b/port.c
+@@ -2143,7 +2143,7 @@ static void port_p2p_transition(struct port *p, enum port_state next)
+ 	};
+ }
+ 
+-int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
++void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ {
+ 	enum port_state next;
+ 
+@@ -2180,7 +2180,7 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	}
+ 
+ 	if (next == p->state)
+-		return 0;
++		return;
+ 
+ 	port_show_transition(p, next, event);
+ 
+@@ -2196,12 +2196,11 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
+ 	if (p->jbod && next == PS_UNCALIBRATED) {
+ 		if (clock_switch_phc(p->clock, p->phc_index)) {
+ 			p->last_fault_type = FT_SWITCH_PHC;
+-			return port_dispatch(p, EV_FAULT_DETECTED, 0);
++			port_dispatch(p, EV_FAULT_DETECTED, 0);
++			return;
+ 		}
+ 		clock_sync_interval(p->clock, p->log_sync_interval);
+ 	}
+-
+-	return 0;
+ }
+ 
+ enum fsm_event port_event(struct port *p, int fd_index)
+diff --git a/port.h b/port.h
+index d2e0865..b00bc64 100644
+--- a/port.h
++++ b/port.h
+@@ -69,10 +69,8 @@ struct foreign_clock *port_compute_best(struct port *port);
+  * @param port A pointer previously obtained via port_open().
+  * @param event One of the @a fsm_event codes.
+  * @param mdiff Whether a new master has been selected.
+- * @return Zero if the port's file descriptor array is still valid,
+- *         and non-zero if it has become invalid.
+  */
+-int port_dispatch(struct port *p, enum fsm_event event, int mdiff);
++void port_dispatch(struct port *p, enum fsm_event event, int mdiff);
+ 
+ /**
+  * Generates state machine events based on activity on a port's file
diff --git a/SPECS/linuxptp.spec b/SPECS/linuxptp.spec
index 194c6c5..44ed08c 100644
--- a/SPECS/linuxptp.spec
+++ b/SPECS/linuxptp.spec
@@ -3,7 +3,7 @@
 %global clknetsim_ver ce89a1
 Name:		linuxptp
 Version:	1.8
-Release:	3%{?dist}.1
+Release:	5%{?dist}
 Summary:	PTP implementation for Linux
 
 Group:		System Environment/Base
@@ -28,10 +28,20 @@ Patch2:		linuxptp-messagetag.patch
 Patch3:		linuxptp-swtscheck.patch
 # fix leaks of sockets in error handling
 Patch4:		linuxptp-closesocket.patch
-# force BMC election when link goes down
-Patch5:		linuxptp-linkdown.patch
+# update port dispatch code (needed by other patches)
+Patch5:		linuxptp-portdispatch.patch
 # Fix phc2sys to check both the state and new_state variables of the clock
-Patch6:   linuxptp-statechange.patch
+Patch6:		linuxptp-statechange.patch
+# fix handling of unknown/invalid management TLVs in pmc
+Patch7:		linuxptp-mgttlv.patch
+# add support for IP over InfiniBand
+Patch8:		linuxptp-ipoib.patch
+# force BMC election when link goes down
+Patch9:		linuxptp-linkdown.patch
+# fix phc2sys to not synchronize clock to itself
+Patch10:	linuxptp-multiport.patch
+# add support for active-backup bonding
+Patch11:	linuxptp-bonding.patch
 
 BuildRequires:	systemd-units
 
@@ -52,8 +62,13 @@ Supporting legacy APIs and other platforms is not a goal.
 %patch2 -p1 -b .messagetag
 %patch3 -p1 -b .swtscheck
 %patch4 -p1 -b .closesocket
-%patch5 -p1 -b .linkdown
+%patch5 -p1 -b .portdispatch
 %patch6 -p1 -b .statechange
+%patch7 -p1 -b .mgttlv
+%patch8 -p1 -b .ipoib
+%patch9 -p1 -b .linkdown
+%patch10 -p1 -b .multiport
+%patch11 -p1 -b .bonding
 mv linuxptp-testsuite-%{testsuite_ver}* testsuite
 mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim
 
@@ -112,8 +127,13 @@ PATH=..:$PATH ./run
 %{_mandir}/man8/*.8*
 
 %changelog
-* Fri Sep 08 2017 Michal Ruprich <mruprich@redhat.com> 1.8-3.1
-- Resolves: #1489425 - Race condition in phc2sys
+* Tue Oct 24 2017 Miroslav Lichvar <mlichvar@redhat.com> 1.8-5
+- add support for active-backup bonding (#1002657)
+- add support for IP over InfiniBand (#1472880)
+- fix handling of unknown/invalid management TLVs in pmc (#1459446 #1459449)
+
+* Thu Sep 07 2017 Michal Ruprich <mruprich@redhat.com> - 1.8-4
+- Resolves: #1487522 - Race condition in phc2sys
 
 * Wed Mar 15 2017 Miroslav Lichvar <mlichvar@redhat.com> 1.8-3
 - fix backport of linkdown patch