Virtual PTP port is for unidirectional tranfer of phase/time interface
on a PTP clock.
When associated with an external input signal, a virtual PTP port allows
this external interface to participate in the PTP protocol.
As an input, this external port can participate in the source selection
with an associated virtual Erbest using the associated virtual PTP port.

As per G.8275 (Annex-B) including virtual PTP ports on a PTP clock. This
virtual port will be used to support Assisted Partial Timing Support
(APTS), Inter Working Function (IWF)  between different clock_domains.

Signed-off-by: Greg Armstrong <greg.armstrong...@renesas.com>
Signed-off-by: Leon Goldin <leon.goldin...@renesas.com>
Signed-off-by: Vipin Sharma <vipin.sha...@syncmonk.net>
Signed-off-by: Devasish Dey <devasish....@syncmonk.net>

v2->v3:
    - Using UDS sockets for virtual PTP ports.
v1->v2:
    - Amended the commit message.
---
 clock.c             | 58 ++++++++++++++++++++++++++++++++++++++++++++-
 config.c            |  2 ++
 configs/default.cfg |  2 +-
 port.c              | 10 ++++++--
 ptp4l.8             |  5 ++++
 sk.c                |  1 +
 transport.c         |  1 +
 transport.h         |  1 +
 uds.c               | 33 +++++++++++++++++++-------
 util.c              |  2 ++
 10 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/clock.c b/clock.c
index d37bb87..eba0833 100644
--- a/clock.c
+++ b/clock.c
@@ -97,9 +97,10 @@ struct clock {
        LIST_HEAD(ports_head, port) ports;
        struct port *uds_rw_port;
        struct port *uds_ro_port;
+       struct port *vport_port;
        struct pollfd *pollfd;
        int pollfd_valid;
-       int nports; /* does not include the two UDS ports */
+       int nports; /* does not include the two UDS ports + 1 Virtual Port */
        int last_port_number;
        int sde;
        int free_running;
@@ -133,6 +134,7 @@ struct clock {
        struct clockcheck *sanity_check;
        struct interface *uds_rw_if;
        struct interface *uds_ro_if;
+       struct interface *vport_if;
        LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
        struct monitor *slave_event_monitor;
        int step_window_counter;
@@ -272,6 +274,7 @@ void clock_destroy(struct clock *c)
 
        interface_destroy(c->uds_rw_if);
        interface_destroy(c->uds_ro_if);
+       interface_destroy(c->vport_if);
        clock_flush_subscriptions(c);
        LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
                clock_remove_port(c, p);
@@ -901,6 +904,7 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
        int phc_index, conf_phc_index, required_modes = 0;
        struct clock *c = &the_clock;
        const char *uds_ifname;
+       const char *vport_ifname;
        struct port *p;
        unsigned char oui[OUI_LEN];
        struct interface *iface;
@@ -1094,6 +1098,32 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
                return NULL;
        }
 
+       /* Configure the Virtual Port. */
+       vport_ifname = config_get_string(config, NULL, "vport_address");
+       if (vport_ifname && vport_ifname[0]) {
+               c->vport_if = interface_create(vport_ifname);
+               if (config_set_section_int(config, interface_name(c->vport_if),
+                                          "announceReceiptTimeout", 2)) {
+                       return NULL;
+               }
+               if (config_set_section_int(config,
+                                          interface_name(c->vport_if),
+                                          "delay_mechanism",
+                                          DM_NO_MECHANISM)) {
+                       return NULL;
+               }
+               if (config_set_section_int(config,
+                                          interface_name(c->vport_if),
+                                          "network_transport",
+                                          TRANS_VPORT)) {
+                       return NULL;
+               }
+               if (config_set_section_int(config, interface_name(c->vport_if),
+                                          "delay_filter_length", 1)) {
+                       return NULL;
+               }
+       }
+
        c->config = config;
        c->free_running = config_get_int(config, NULL, "free_running");
        c->freq_est_interval = config_get_int(config, NULL, 
"freq_est_interval");
@@ -1231,6 +1261,17 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
                pr_err("failed to open the UDS-RO port");
                return NULL;
        }
+
+       if (c->vport_if) {
+               c->vport_port = port_open(phc_device, phc_index, timestamping, 
0,
+                                          c->vport_if, c);
+               if (!c->vport_port) {
+                       pr_err("failed to open the Virtual port");
+                       return NULL;
+               }
+               LIST_INSERT_HEAD(&c->ports, c->vport_port, list);
+               c->nports++;
+       }
        clock_fda_changed(c);
 
        c->slave_event_monitor = monitor_create(config, c->uds_rw_port);
@@ -1254,6 +1295,9 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
        }
        port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0);
        port_dispatch(c->uds_ro_port, EV_INITIALIZE, 0);
+       if (c->vport_port) {
+               port_dispatch(c->vport_port, EV_INITIALIZE, 0);
+       }
 
        return c;
 }
@@ -1670,6 +1714,18 @@ int clock_poll(struct clock *c)
                        /* sde is not expected on the UDS-RO port */
                }
        }
+       /* Check the Virtual port. */
+       if (c->vport_port) {
+               cur += N_CLOCK_PFD;
+               for (i = 0; i < N_POLLFD; i++) {
+                       if (cur[i].revents & (POLLIN|POLLPRI)) {
+                               event = port_event(c->vport_port, i);
+                               if (event == EV_STATE_DECISION_EVENT) {
+                                       c->sde = 1;
+                               }
+                       }
+               }
+       }
 
        if (c->sde) {
                handle_state_decision_event(c);
diff --git a/config.c b/config.c
index b5cf397..aeae356 100644
--- a/config.c
+++ b/config.c
@@ -193,6 +193,7 @@ static struct config_enum nw_trans_enu[] = {
        { "L2",    TRANS_IEEE_802_3 },
        { "UDPv4", TRANS_UDP_IPV4   },
        { "UDPv6", TRANS_UDP_IPV6   },
+       { "vPort", TRANS_VPORT   },
        { NULL, 0 },
 };
 
@@ -345,6 +346,7 @@ struct config_item config_tab[] = {
        GLOB_ITEM_STR("userDescription", ""),
        GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
        GLOB_ITEM_INT("verbose", 0, 0, 1),
+       GLOB_ITEM_STR("vport_address", ""),
        GLOB_ITEM_INT("write_phase_mode", 0, 0, 1),
 };
 
diff --git a/configs/default.cfg b/configs/default.cfg
index 1b5b806..ea1fa79 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -94,7 +94,7 @@ udp6_scope            0x0E
 uds_address            /var/run/ptp4l
 uds_file_mode          0660
 uds_ro_address         /var/run/ptp4lro
-uds_ro_file_mode               0666
+uds_ro_file_mode       0666
 #
 # Default interface options
 #
diff --git a/port.c b/port.c
index 871ad68..020e2c5 100644
--- a/port.c
+++ b/port.c
@@ -57,6 +57,7 @@ enum syfu_event {
 
 static int port_is_ieee8021as(struct port *p);
 static int port_is_uds(struct port *p);
+static int port_is_vport(struct port *p);
 static void port_nrate_initialize(struct port *p);
 
 static int announce_compare(struct ptp_message *m1, struct ptp_message *m2)
@@ -822,6 +823,11 @@ static int port_is_uds(struct port *p)
        return transport_type(p->trp) == TRANS_UDS;
 }
 
+static int port_is_vport(struct port *p)
+{
+       return transport_type(p->trp) == TRANS_VPORT;
+}
+
 static void port_management_send_error(struct port *p, struct port *ingress,
                                       struct ptp_message *msg, int error_id)
 {
@@ -3266,8 +3272,8 @@ struct port *port_open(const char *phc_device,
                p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : 
ptp_fsm;
        }
 
-       if (port_is_uds(p)) {
-               ; /* UDS cannot have a PHC. */
+       if (port_is_uds(p) || port_is_vport(p)) {
+               ; /* UDS & VPORT cannot have a PHC. */
        } else if (!interface_tsinfo_valid(interface)) {
                pr_warning("%s: get_ts_info not supported", p->log_name);
        } else if (p->phc_index >= 0 &&
diff --git a/ptp4l.8 b/ptp4l.8
index 1268802..a0479f6 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -658,6 +658,11 @@ File mode of the second (read-only) UNIX domain socket 
used for receiving
 local management messages. The mode should be specified as an octal number,
 i.e. it should start with a 0 literal. The default mode is 0666.
 .TP
+.B vport_address
+Specifies the address of the UNIX domain socket for communicating with the
+virtual PTP port on a PTP clock as defined in the G.8275 Annex B. The default
+is NULL
+.TP
 .B dscp_event
 Defines the Differentiated Services Codepoint (DSCP) to be used for PTP
 event messages. Must be a value between 0 and 63. There are several media
diff --git a/sk.c b/sk.c
index 80075be..d24fc4c 100644
--- a/sk.c
+++ b/sk.c
@@ -508,6 +508,7 @@ int sk_timestamping_init(int fd, const char *device, enum 
timestamp_type type,
                case TRANS_CONTROLNET:
                case TRANS_PROFINET:
                case TRANS_UDS:
+               case TRANS_VPORT:
                        return -1;
                }
                err = hwts_init(fd, device, filter1, filter2, tx_type);
diff --git a/transport.c b/transport.c
index 9366fbf..3fdb6c2 100644
--- a/transport.c
+++ b/transport.c
@@ -104,6 +104,7 @@ struct transport *transport_create(struct config *cfg,
        struct transport *t = NULL;
        switch (type) {
        case TRANS_UDS:
+       case TRANS_VPORT:
                t = uds_transport_create();
                break;
        case TRANS_UDP_IPV4:
diff --git a/transport.h b/transport.h
index 7a7f87b..a4c73d3 100644
--- a/transport.h
+++ b/transport.h
@@ -39,6 +39,7 @@ enum transport_type {
        TRANS_DEVICENET,
        TRANS_CONTROLNET,
        TRANS_PROFINET,
+       TRANS_VPORT,
 };
 
 /**
diff --git a/uds.c b/uds.c
index 6d39dc8..a890c38 100644
--- a/uds.c
+++ b/uds.c
@@ -31,6 +31,7 @@
 #include "transport_private.h"
 #include "uds.h"
 
+#define VPORT_FILE_MODE (0660)
 struct uds {
        struct transport t;
        struct address address;
@@ -50,11 +51,13 @@ static int uds_close(struct transport *t, struct fdarray 
*fda)
        return 0;
 }
 
-static int uds_open(struct transport *t, struct interface *iface, struct 
fdarray *fda,
+static int uds_open(struct transport *t,
+                   struct interface *iface,
+                   struct fdarray *fda,
                    enum timestamp_type tt)
 {
-       char *uds_ro_path = config_get_string(t->cfg, NULL, "uds_ro_address");
-       char *uds_path = config_get_string(t->cfg, NULL, "uds_address");
+       char *uds_ro_path;
+       char *uds_path;
        struct uds *uds = container_of(t, struct uds, t);
        const char *name = interface_name(iface);
        const char* file_mode_cfg;
@@ -62,6 +65,24 @@ static int uds_open(struct transport *t, struct interface 
*iface, struct fdarray
        mode_t file_mode;
        int fd, err;
 
+       switch (t->type) {
+       case TRANS_UDS:
+               uds_ro_path = config_get_string(t->cfg, NULL, "uds_ro_address");
+               uds_path = config_get_string(t->cfg, NULL, "uds_address");
+               file_mode_cfg = "uds_file_mode";
+               // The RO UDS socket has a separate configuration for file mode
+               if (0 == strncmp(name, uds_ro_path, MAX_IFNAME_SIZE))
+                       file_mode_cfg = "uds_ro_file_mode";
+               file_mode = (mode_t)config_get_int(t->cfg, name, file_mode_cfg);
+               break;
+       case TRANS_VPORT:
+               uds_path = config_get_string(t->cfg, NULL, "vport_address");
+               file_mode = VPORT_FILE_MODE;
+               break;
+       default:
+               break;
+       }
+
        fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
        if (fd < 0) {
                pr_err("uds: failed to create socket: %m");
@@ -80,12 +101,6 @@ static int uds_open(struct transport *t, struct interface 
*iface, struct fdarray
                return -1;
        }
 
-       file_mode_cfg = "uds_file_mode";
-       // The RO UDS socket has a separate configuration for file mode
-       if (0 == strncmp(name, uds_ro_path, MAX_IFNAME_SIZE))
-               file_mode_cfg = "uds_ro_file_mode";
-       file_mode = (mode_t)config_get_int(t->cfg, name, file_mode_cfg);
-
        /* For client use, pre load the server path. */
        memset(&sa, 0, sizeof(sa));
        sa.sun_family = AF_LOCAL;
diff --git a/util.c b/util.c
index a59b559..8077084 100644
--- a/util.c
+++ b/util.c
@@ -114,6 +114,7 @@ int addreq(enum transport_type type, struct address *a, 
struct address *b)
        case TRANS_DEVICENET:
        case TRANS_CONTROLNET:
        case TRANS_PROFINET:
+       case TRANS_VPORT:
        default:
                pr_err("sorry, cannot compare addresses for this transport");
                return 0;
@@ -280,6 +281,7 @@ int str2addr(enum transport_type type, const char *s, 
struct address *addr)
        case TRANS_DEVICENET:
        case TRANS_CONTROLNET:
        case TRANS_PROFINET:
+       case TRANS_VPORT:
                pr_err("sorry, cannot convert addresses for this transport");
                return -1;
        case TRANS_UDP_IPV4:
-- 
2.25.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to