This patch introduces - "enable" configuration flag at port level - support for ENABLE_PORT and DISABLE_PORT TLV commands --- clock.c | 8 +++++- config.c | 1 + designated_fsm.c | 36 ++++++++++++++++++++--- e2e_tc.c | 11 +++++++ fd.h | 1 + p2p_tc.c | 11 +++++++ pmc_common.c | 9 +++--- port.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-- port.h | 19 +++++++++++++ port_private.h | 4 ++- ptp4l.8 | 3 ++ 11 files changed, 163 insertions(+), 14 deletions(-)
diff --git a/clock.c b/clock.c index e545a9b..b5e24ad 100644 --- a/clock.c +++ b/clock.c @@ -1009,12 +1009,14 @@ struct clock *clock_create(enum clock_type type, struct config *config, interface_set_label(iface, ts_label); interface_ensure_tslabel(iface); interface_get_tsinfo(iface); +#if 0 if (interface_tsinfo_valid(iface) && !interface_tsmodes_supported(iface, required_modes)) { pr_err("interface '%s' does not support requested timestamping mode", interface_name(iface)); return NULL; } +#endif } iface = STAILQ_FIRST(&config->interfaces); @@ -1250,7 +1252,11 @@ struct clock *clock_create(enum clock_type type, struct config *config, c->dds.numberPorts = c->nports; LIST_FOREACH(p, &c->ports, list) { - port_dispatch(p, EV_INITIALIZE, 0); + if (port_enable(p)) { + port_dispatch(p, EV_INITIALIZE, 0); + } else { + port_dispatch(p, EV_DESIGNATED_DISABLED, 0); + } } port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0); port_dispatch(c->uds_ro_port, EV_INITIALIZE, 0); diff --git a/config.c b/config.c index 4472d3d..b32e0a3 100644 --- a/config.c +++ b/config.c @@ -242,6 +242,7 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("dscp_event", 0, 0, 63), GLOB_ITEM_INT("dscp_general", 0, 0, 63), GLOB_ITEM_INT("domainNumber", 0, 0, 127), + PORT_ITEM_INT("enable", 1, 0, 1), PORT_ITEM_INT("egressLatency", 0, INT_MIN, INT_MAX), PORT_ITEM_INT("fault_badpeernet_interval", 16, INT32_MIN, INT32_MAX), PORT_ITEM_INT("fault_reset_interval", 4, INT8_MIN, INT8_MAX), diff --git a/designated_fsm.c b/designated_fsm.c index d19158b..c6bb692 100644 --- a/designated_fsm.c +++ b/designated_fsm.c @@ -44,16 +44,34 @@ enum port_state designated_master_fsm(enum port_state state, break; case PS_FAULTY: - if (event == EV_FAULT_CLEARED) { + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_CLEARED: next = PS_INITIALIZING; + break; + default: + break; } break; + case PS_DISABLED: + if (EV_DESIGNATED_ENABLED == event) + next = PS_INITIALIZING; + break; + case PS_MASTER: - if (event == EV_FAULT_DETECTED) { + switch (event) { + case EV_FAULT_DETECTED: next = PS_FAULTY; + break; + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + default: + break; } - break; default: break; @@ -85,13 +103,23 @@ enum port_state designated_slave_fsm(enum port_state state, break; case PS_FAULTY: - if (event == EV_FAULT_CLEARED) { + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_CLEARED: next = PS_INITIALIZING; + break; + default: + break; } break; case PS_SLAVE: switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; case EV_FAULT_DETECTED: next = PS_FAULTY; break; diff --git a/e2e_tc.c b/e2e_tc.c index 2f8e821..dea482f 100644 --- a/e2e_tc.c +++ b/e2e_tc.c @@ -124,6 +124,8 @@ enum fsm_event e2e_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("%s: received link status notification", p->log_name); rtnl_link_status(fd, p->name, port_link_status, p); + if (!p->enable) + return EV_NONE; if (p->link_status == (LINK_UP|LINK_STATE_CHANGED)) { return EV_FAULT_CLEARED; } else if ((p->link_status == (LINK_DOWN|LINK_STATE_CHANGED)) || @@ -132,6 +134,15 @@ enum fsm_event e2e_event(struct port *p, int fd_index) } else { return EV_NONE; } + + case FD_PORT_ENABLE: + pr_debug("%s: received port enable/disable notification", p->log_name); + if (!port_enable_changed(fd, p)) + return EV_NONE; + else if (p->enable) + return EV_DESIGNATED_ENABLED; + else + return EV_DESIGNATED_DISABLED; } msg = msg_allocate(); diff --git a/fd.h b/fd.h index 16420d7..f60e208 100644 --- a/fd.h +++ b/fd.h @@ -40,6 +40,7 @@ enum { FD_UNICAST_REQ_TIMER, FD_UNICAST_SRV_TIMER, FD_RTNL, + FD_PORT_ENABLE, N_POLLFD, }; diff --git a/p2p_tc.c b/p2p_tc.c index 75cb3b9..b2863d2 100644 --- a/p2p_tc.c +++ b/p2p_tc.c @@ -127,6 +127,8 @@ enum fsm_event p2p_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("%s: received link status notification", p->log_name); rtnl_link_status(fd, p->name, port_link_status, p); + if (!p->enable) + return EV_NONE; if (p->link_status == (LINK_UP|LINK_STATE_CHANGED)) { return EV_FAULT_CLEARED; } else if ((p->link_status == (LINK_DOWN|LINK_STATE_CHANGED)) || @@ -135,6 +137,15 @@ enum fsm_event p2p_event(struct port *p, int fd_index) } else { return EV_NONE; } + + case FD_PORT_ENABLE: + pr_debug("%s: received port enable/disable notification", p->log_name); + if (!port_enable_changed(fd, p)) + return EV_NONE; + else if (p->enable) + return EV_DESIGNATED_ENABLED; + else + return EV_DESIGNATED_DISABLED; } msg = msg_allocate(); diff --git a/pmc_common.c b/pmc_common.c index c7d8bed..af1de95 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -119,8 +119,8 @@ struct management_id idtab[] = { { "ANNOUNCE_RECEIPT_TIMEOUT", TLV_ANNOUNCE_RECEIPT_TIMEOUT, do_get_action }, { "LOG_SYNC_INTERVAL", TLV_LOG_SYNC_INTERVAL, do_get_action }, { "VERSION_NUMBER", TLV_VERSION_NUMBER, do_get_action }, - { "ENABLE_PORT", TLV_ENABLE_PORT, not_supported }, - { "DISABLE_PORT", TLV_DISABLE_PORT, not_supported }, + { "ENABLE_PORT", TLV_ENABLE_PORT, do_cmd_action }, + { "DISABLE_PORT", TLV_DISABLE_PORT, do_cmd_action }, { "UNICAST_NEGOTIATION_ENABLE", TLV_UNICAST_NEGOTIATION_ENABLE, not_supported }, { "UNICAST_MASTER_TABLE", TLV_UNICAST_MASTER_TABLE, not_supported }, { "UNICAST_MASTER_MAX_TABLE_SIZE", TLV_UNICAST_MASTER_MAX_TABLE_SIZE, not_supported }, @@ -297,13 +297,12 @@ static void do_cmd_action(struct pmc *pmc, int action, int index, char *str) idtab[index].name); return; } -/* switch (code) { - case TLV_XXXX: + case TLV_ENABLE_PORT: + case TLV_DISABLE_PORT: pmc_send_cmd_action(pmc, code); break; } -*/ } static void not_supported(struct pmc *pmc, int action, int index, char *str) diff --git a/port.c b/port.c index 10bb9e1..adbef50 100644 --- a/port.c +++ b/port.c @@ -18,6 +18,7 @@ */ #include <arpa/inet.h> #include <errno.h> +#include <fcntl.h> #include <malloc.h> #include <stdlib.h> #include <string.h> @@ -2396,6 +2397,12 @@ void port_close(struct port *p) if (p->fault_fd >= 0) { close(p->fault_fd); } + if (p->enable_ev_fd >=0) { + close(p->enable_ev_fd); + } + if (p->fda.fd[FD_PORT_ENABLE] >=0) { + close(p->fda.fd[FD_PORT_ENABLE]); + } free(p->log_name); free(p); } @@ -2619,6 +2626,30 @@ void port_link_status(void *ctx, int linkup, int ts_index) clock_set_sde(p->clock, 1); } +int port_enable_changed(int fd, struct port *p) +{ + int enable; + + if (read(fd, &enable, sizeof(enable)) != sizeof(enable)) { + pr_err("%s: Unable to receince enable/disable event", p->log_name); + return 0; + } + + enable = !!enable; // normalize value; + + if (enable == p->enable) + return 0; + + p->enable = enable; + + return 1; +} + +int port_enable(struct port *p) +{ + return p->enable; +} + enum fsm_event port_event(struct port *p, int fd_index) { return p->event(p, fd_index); @@ -2696,6 +2727,8 @@ static enum fsm_event bc_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("%s: received link status notification", p->log_name); rtnl_link_status(fd, p->name, port_link_status, p); + if (!p->enable) + return EV_NONE; if (p->link_status == (LINK_UP | LINK_STATE_CHANGED)) return EV_FAULT_CLEARED; else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) || @@ -2703,6 +2736,15 @@ static enum fsm_event bc_event(struct port *p, int fd_index) return EV_FAULT_DETECTED; else return EV_NONE; + + case FD_PORT_ENABLE: + pr_debug("%s: received port enable/disable notification", p->log_name); + if (!port_enable_changed(fd, p)) + return EV_NONE; + else if (p->enable) + return EV_DESIGNATED_ENABLED; + else + return EV_DESIGNATED_DISABLED; } msg = msg_allocate(); @@ -2862,6 +2904,7 @@ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) { struct management_tlv *mgt; UInteger16 target = msg->management.targetPortIdentity.portNumber; + int enable; if (target != portnum(p) && target != 0xffff) { return 0; @@ -2884,6 +2927,15 @@ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) } switch (mgt->id) { + case TLV_ENABLE_PORT: + case TLV_DISABLE_PORT: + // raise port enable/disable change event + enable = (mgt->id == TLV_ENABLE_PORT); + if (write(p->enable_ev_fd, &enable, sizeof(enable)) != sizeof(enable)) { + pr_err("%s: Unable to forward port %s change envent", p->log_name, enable ? "enable" : "disable"); + } + break; + case TLV_NULL_MANAGEMENT: case TLV_CLOCK_DESCRIPTION: case TLV_PORT_DATA_SET: @@ -2891,8 +2943,6 @@ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) case TLV_ANNOUNCE_RECEIPT_TIMEOUT: case TLV_LOG_SYNC_INTERVAL: case TLV_VERSION_NUMBER: - case TLV_ENABLE_PORT: - case TLV_DISABLE_PORT: case TLV_UNICAST_NEGOTIATION_ENABLE: case TLV_UNICAST_MASTER_TABLE: case TLV_UNICAST_MASTER_MAX_TABLE_SIZE: @@ -3039,6 +3089,7 @@ struct port *port_open(const char *phc_device, struct config *cfg = clock_config(clock); struct port *p = malloc(sizeof(*p)); int i; + int enable_fds[2]; if (!p) { return NULL; @@ -3119,6 +3170,7 @@ struct port *port_open(const char *phc_device, } p->iface = interface; + p->enable = config_get_int(cfg, p->name, "enable"); p->asymmetry = config_get_int(cfg, p->name, "delayAsymmetry"); p->asymmetry <<= 16; p->announce_span = port_is_uds(p) ? 0 : ANNOUNCE_SPAN; @@ -3137,7 +3189,11 @@ struct port *port_open(const char *phc_device, p->timestamping = timestamping; p->portIdentity.clockIdentity = clock_identity(clock); p->portIdentity.portNumber = number; - p->state = PS_INITIALIZING; + if (p->enable) { + p->state = PS_INITIALIZING; + } else { + p->state = PS_DISABLED; + } p->delayMechanism = config_get_int(cfg, p->name, "delay_mechanism"); p->versionNumber = PTP_MAJOR_VERSION; p->slave_event_monitor = clock_slave_monitor(clock); @@ -3201,8 +3257,16 @@ struct port *port_open(const char *phc_device, goto err_tsproc; } } + if (pipe2(enable_fds, O_DIRECT | O_NONBLOCK) < 0) { + pr_err("unable to open event fd: %m"); + goto err_fd_port_enable; + } + p->fda.fd[FD_PORT_ENABLE] = enable_fds[0]; + p->enable_ev_fd = enable_fds[1]; + return p; +err_fd_port_enable: err_tsproc: tsproc_destroy(p->tsproc); err_uc_service: @@ -3227,6 +3291,10 @@ int port_state_update(struct port *p, enum fsm_event event, int mdiff) { enum port_state next = p->state_machine(p->state, event, mdiff); + if (PS_DISABLED == next) { + port_disable(p); + } + if (PS_FAULTY == next) { struct fault_interval i; fault_interval(p, last_fault_type(p), &i); diff --git a/port.h b/port.h index 37a4e19..05f3bb1 100644 --- a/port.h +++ b/port.h @@ -75,6 +75,25 @@ struct foreign_clock *port_compute_best(struct port *port); */ void port_dispatch(struct port *p, enum fsm_event event, int mdiff); +/** + * Return portEnable changes. This may cause a state transition on the + * port, with the associated side effect. + * + * @param fd, Event file descriptor. + * @param port A pointer previously obtained via port_open(). + * @return true if the portEnable changed, false otherwise. + */ +int port_enable_changed(int fd, struct port *p); + +/** + * Return portEnable status. This may cause a state transition on the + * port, with the associated side effect. + * + * @param port A pointer previously obtained via port_open(). + * @return true if the portEnable changed, false otherwise. + */ +int port_enable(struct port *p); + /** * Generates state machine events based on activity on a port's file * descriptors. diff --git a/port_private.h b/port_private.h index 2a98ef4..d62e795 100644 --- a/port_private.h +++ b/port_private.h @@ -69,6 +69,7 @@ struct port { enum timestamp_type timestamping; struct fdarray fda; int fault_fd; + int enable_ev_fd; int phc_index; int phc_from_cmdline; @@ -119,7 +120,7 @@ struct port { UInteger8 transportSpecific; UInteger8 localPriority; Integer8 initialLogSyncInterval; - Integer8 operLogSyncInterval; + Integer8 operLogSyncInterval; Integer8 logSyncInterval; Enumeration8 delayMechanism; Integer8 logMinPdelayReqInterval; @@ -129,6 +130,7 @@ struct port { int follow_up_info; int freq_est_interval; int hybrid_e2e; + int enable; int master_only; int match_transport_specific; int msg_interval_request; diff --git a/ptp4l.8 b/ptp4l.8 index fe9e150..f9c3f65 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -143,6 +143,9 @@ See UNICAST DISCOVERY OPTIONS, below. .SH PORT OPTIONS .TP +.B enable +When 0 the port is kept disabled. When 1 the port activaly partecipate +to protocol. The default is 1 (enabled). .B delayAsymmetry The time difference in nanoseconds of the transmit and receive paths. This value should be positive when the server-to-client -- 2.31.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel