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;