This patch introduces
 - "enable" configuration flag at port level
 - support for ENABLE_PORT and DISABLE_PORT TLV commands
---
 clock.c          |  6 +++-
 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, 161 insertions(+), 14 deletions(-)

diff --git a/clock.c b/clock.c
index e545a9b..d1ab880 100644
--- a/clock.c
+++ b/clock.c
@@ -1250,7 +1250,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

Reply via email to