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 interface for virtual PTP port support.
v1->v2:
    - amended commit message
    - updated ts2phc.8
---
 makefile       |   7 +-
 ts2phc.8       |  70 ++++++++++++
 ts2phc_vport.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++
 ts2phc_vport.h |  28 +++++
 4 files changed, 383 insertions(+), 3 deletions(-)
 create mode 100644 ts2phc_vport.c
 create mode 100644 ts2phc_vport.h

diff --git a/makefile b/makefile
index 5295b60..cd15559 100644
--- a/makefile
+++ b/makefile
@@ -27,7 +27,8 @@ FILTERS       = filter.o mave.o mmedian.o
 SERVOS = linreg.o ntpshm.o nullf.o pi.o servo.o
 TRANSP = raw.o transport.o udp.o udp6.o uds.o
 TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_pps_source.o \
- ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o 
ts2phc_pps_source.o
+ ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o \
+ ts2phc_pps_source.o ts2phc_vport.o
 OBJ    = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
  e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \
  port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \
@@ -68,8 +69,8 @@ phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o 
print.o version.o
 
 timemaster: phc.o print.o rtnl.o sk.o timemaster.o util.o version.o
 
-ts2phc: config.o clockadj.o hash.o interface.o phc.o print.o $(SERVOS) sk.o \
- $(TS2PHC) util.o version.o
+ts2phc: config.o clockadj.o hash.o msg.o tlv.o interface.o phc.o print.o 
$(SERVOS) sk.o \
+ $(TS2PHC) $(TRANSP) util.o version.o
 
 version.o: .version version.sh $(filter-out version.d,$(DEPEND))
 
diff --git a/ts2phc.8 b/ts2phc.8
index 690c462..4166766 100644
--- a/ts2phc.8
+++ b/ts2phc.8
@@ -145,6 +145,76 @@ by changing the clock frequency instead of stepping the 
clock. When
 set to 0.0, the servo will never step the clock except on start.
 The default is 0.0.
 .TP
+.B vport_address
+Specifies the address of the UNIX domain socket for communicating with the
+virtual PTP port to a PTP clock as defined in the G.8275 Annex B. The default
+is NULL
+.TP
+.B utc_offset
+The current offset between TAI and UTC.
+The default is 37.
+.TP
+.B transportSpecific
+The transport specific field. Must be in the range 0 to 255.
+The default is 0.
+.TP
+.B domainNumber
+The domain attribute of the local clock.
+The default is 0.
+.TP
+.B logSyncInterval
+The mean time interval between Sync messages. A shorter interval may improve
+accuracy of the local clock. It's specified as a power of two in seconds.
+The default is 0 (1 second).
+.TP
+.B logAnnounceInterval
+The mean time interval between Announce messages. A shorter interval makes
+ptp4l react faster to the changes in the client/server hierarchy. The interval
+should be the same in the whole domain. It's specified as a power of two in
+seconds.
+.TP
+.B priorty1
+The priority1 attribute of the local clock. It is used in the PTP server
+selection algorithm, lower values take precedence. Must be in the range 0 to
+255.
+The default is 128.
+.TP
+.B priorty2
+The priority2 attribute of the local clock. It is used in the PTP server
+selection algorithm, lower values take precedence. Must be in the range 0 to
+255.
+The default is 128.
+.TP
+.B timeSource
+The time source is a single byte code that gives an idea of the kind
+of local clock in use. The value is purely informational, having no
+effect on the outcome of the Best Master Clock algorithm, and is
+advertised when the clock becomes grand master.
+.TP
+.B clockClass
+The clockClass attribute of the local clock. It denotes the traceability of the
+time distributed by the grandmaster clock.
+The default is 248.
+.TP
+.B clockAccuracy
+The clockAccuracy attribute of the local clock. It is used in the PTP server
+selection algorithm.
+The default is 0xFE.
+.TP
+.B clockIdenitity
+The clockIdentity attribute of the local clock.
+The clockIdentity is an 8-octet array and should in this configuration be
+written in textual form, see default. It should be unique since it is used to
+identify the specific clock.
+If default is used or if not set at all, the clockIdentity will be automtically
+generated.
+The default is "000000.0000.000000"
+.TP
+.B offsetScaledLogVariance
+The offsetScaledLogVariance attribute of the local clock. It characterizes the
+stability of the clock.
+The default is 0xFFFF.
+.TP
 .B ts2phc.nmea_remote_host, ts2phc.nmea_remote_port
 Specifies the remote host providing ToD information when using the
 "nmea" PPS signal source.  Note that if these two options are both
diff --git a/ts2phc_vport.c b/ts2phc_vport.c
new file mode 100644
index 0000000..539c48f
--- /dev/null
+++ b/ts2phc_vport.c
@@ -0,0 +1,281 @@
+/**
+ * @file ts2phc_vport.c
+ * @note Copyright (C) 2022 SyncMonk Technologies <servi...@syncmonk.net>
+ * @note SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "address.h"
+#include "ts2phc_vport.h"
+#include "print.h"
+#include "port.h"
+#include "transport.h"
+
+#define RECORDS_PER_MESSAGE 1
+
+struct ts2phc_vport_message {
+       struct ptp_message *msg;
+       int records_per_msg;
+       int count;
+};
+
+struct ts2phc_vport {
+       struct fdarray fda;
+       struct transport *trp;
+       struct interface *iface;
+       struct ts2phc_vport_message announce;
+       struct ts2phc_vport_message sync;
+       struct {
+               UInteger16 announce;
+               UInteger16 sync;
+       } seqnum;
+       struct PortIdentity portIdentity;
+       Integer16 utcOffset;
+       UInteger8 priority1;
+       struct ClockQuality clockQuality;
+       UInteger8 priority2;
+       struct ClockIdentity clockIdentity;
+       UInteger8 transportSpecific;
+       UInteger8 domainNumber;
+       UInteger8 flags;
+       Integer8 logAnnounceInterval;
+       Integer8 logSyncInterval;
+       Enumeration8 timeSource;
+};
+
+static bool ts2phc_vport_active(struct ts2phc_vport *ts2phc_vport)
+{
+       return ts2phc_vport->trp ? true : false;
+}
+
+static int ts2phc_vport_forward(struct ts2phc_vport *port, struct ptp_message 
*msg)
+{
+       int cnt;
+       if (msg_pre_send(msg)) {
+               return -1;
+       }
+       cnt = transport_sendto(port->trp, &port->fda, TRANS_GENERAL, msg);
+       if (cnt <= 0) {
+               pr_debug("failed to send message to ts2phc_vport: ");
+       }
+
+       msg->header.sequenceId++;
+       return 0;
+}
+
+static int ts2phc_vport_init_announce(struct ts2phc_vport *p,
+                                     struct address address)
+{
+
+       struct ptp_message *msg;
+
+       msg = msg_allocate();
+       if (!msg) {
+               return -1;
+       }
+
+       msg->hwts.type = TS_ONESTEP;
+       msg->header.tsmt               = ANNOUNCE | p->transportSpecific;
+       msg->header.ver                = PTP_VERSION;
+       msg->header.messageLength      = sizeof(struct announce_msg);
+       msg->header.domainNumber       = p->domainNumber;
+       msg->header.sourcePortIdentity = p->portIdentity;
+       msg->header.sequenceId         = p->seqnum.announce++;
+       msg->header.control            = CTL_OTHER;
+       msg->header.logMessageInterval = p->logAnnounceInterval;
+       msg->header.flagField[1]       = p->flags | PTP_TIMESCALE;
+
+       msg->announce.currentUtcOffset        = p->utcOffset;
+       msg->announce.grandmasterPriority1    = p->priority1;
+       msg->announce.grandmasterClockQuality = p->clockQuality;
+       msg->announce.grandmasterPriority2    = p->priority2;
+       msg->announce.grandmasterIdentity     = p->clockIdentity;
+       msg->announce.stepsRemoved            = 0;
+       msg->announce.timeSource              = p->timeSource;
+       msg->address = address;
+
+       p->announce.msg = msg;
+
+       return 0;
+}
+
+static int ts2phc_vport_init_sync(struct ts2phc_vport *p,
+                                 struct address address)
+{
+
+       struct ptp_message *msg;
+
+       msg = msg_allocate();
+       if (!msg) {
+               return -1;
+       }
+       msg->hwts.type = TS_ONESTEP;
+       msg->header.tsmt               = SYNC | p->transportSpecific;
+       msg->header.ver                = PTP_VERSION;
+       msg->header.messageLength      = sizeof(struct sync_msg);
+       msg->header.domainNumber       = p->domainNumber;
+       msg->header.sourcePortIdentity = p->portIdentity;
+       msg->header.sequenceId         = p->seqnum.sync++;
+       msg->header.control            = CTL_SYNC;
+       msg->header.logMessageInterval = p->logSyncInterval;
+       msg->address = address;
+
+       p->sync.msg = msg;
+
+       return 0;
+}
+
+struct ts2phc_vport *ts2phc_vport_create(struct config *config)
+{
+       struct ts2phc_vport *ts2phc_vport;
+       struct address address;
+       struct sockaddr_un sa;
+
+       ts2phc_vport = calloc(1, sizeof(*ts2phc_vport));
+       if (!ts2phc_vport) {
+               return NULL;
+       }
+       const char *iface_name;
+
+       iface_name = config_get_string(config, NULL, "vport_address");
+       if (!iface_name || !iface_name[0]) {
+               /* Return an inactive ts2phc_vport. */
+               return ts2phc_vport;
+       }
+       memset(&sa, 0, sizeof(sa));
+       sa.sun_family = AF_LOCAL;
+       snprintf(sa.sun_path, sizeof(sa.sun_path) - 1, "%s", iface_name);
+       address.sun = sa;
+       address.len = sizeof(sa);
+
+       ts2phc_vport->trp = transport_create(config, TRANS_VPORT);
+       if (!ts2phc_vport->trp) {
+               pr_err("failed to create transport");
+               free(ts2phc_vport);
+               return NULL;
+       }
+
+       ts2phc_vport->iface = interface_create(iface_name);
+       if (!ts2phc_vport->iface) {
+               pr_err("failed to create interface");
+               goto failed;
+       }
+
+       if (transport_open(ts2phc_vport->trp, ts2phc_vport->iface,
+                          &ts2phc_vport->fda, TS_SOFTWARE)) {
+               pr_err("failed to open transport");
+               goto no_trans_open;
+       }
+
+       ts2phc_vport->utcOffset =
+               config_get_int(config, NULL, "utc_offset");
+       ts2phc_vport->transportSpecific =
+               config_get_int(config, NULL, "transportSpecific") << 4;
+       ts2phc_vport->domainNumber =
+               config_get_int(config, NULL, "domainNumber");
+
+       ts2phc_vport->logSyncInterval =
+               config_get_int(config, NULL, "logSyncInterval");
+       ts2phc_vport->logAnnounceInterval =
+               config_get_int(config, NULL, "logAnnounceInterval");
+
+       ts2phc_vport->priority1  =
+               config_get_int(config, NULL, "priority1");
+       ts2phc_vport->priority2  =
+               config_get_int(config, NULL, "priority2");
+       ts2phc_vport->timeSource =
+               config_get_int(config, NULL, "timeSource");
+
+       ts2phc_vport->clockQuality.clockClass =
+                       config_get_int(config, NULL, "clockClass");
+       ts2phc_vport->clockQuality.clockAccuracy =
+                       config_get_int(config, NULL, "clockAccuracy");
+       ts2phc_vport->clockQuality.offsetScaledLogVariance =
+                       config_get_int(config, NULL, "offsetScaledLogVariance");
+
+       if (strcmp(config_get_string(config, NULL, "clockIdentity"),
+                  "000000.0000.000000") == 0) {
+               pr_warning("vPort clockIdentity 000000.0000.000000");
+       } else {
+               if (str2cid(config_get_string(config, NULL, "clockIdentity"),
+                                             &ts2phc_vport->clockIdentity)) {
+                       pr_err("failed to set clock identity");
+                       return NULL;
+               }
+       }
+
+       ts2phc_vport->portIdentity.clockIdentity = ts2phc_vport->clockIdentity;
+
+       if (ts2phc_vport_init_announce(ts2phc_vport, address)) {
+               goto no_trans_open;
+       }
+       if (ts2phc_vport_init_sync(ts2phc_vport, address)) {
+               msg_put(ts2phc_vport->announce.msg);
+               goto no_trans_open;
+       }
+
+       return ts2phc_vport;
+
+no_trans_open:
+       interface_destroy(ts2phc_vport->iface);
+failed:
+       if (ts2phc_vport->trp)
+               transport_destroy(ts2phc_vport->trp);
+       free(ts2phc_vport);
+       return NULL;
+}
+
+void ts2phc_vport_destroy(struct ts2phc_vport *ts2phc_vport)
+{
+       if (ts2phc_vport->announce.msg) {
+               msg_put(ts2phc_vport->announce.msg);
+       }
+       if (ts2phc_vport->sync.msg) {
+               msg_put(ts2phc_vport->sync.msg);
+       }
+       free(ts2phc_vport);
+}
+
+int ts2phc_vport_tx_sync(struct ts2phc_vport *ts2phc_vport,
+                         tmv_t t1, tmv_t corr, tmv_t t2)
+{
+       struct ptp_message *msg;
+       int err;
+       struct address address;
+
+       if (!ts2phc_vport_active(ts2phc_vport)) {
+               return 0;
+       }
+
+       msg = ts2phc_vport->sync.msg;
+       address = msg->address;
+       ts2phc_vport->sync.count++;
+
+       err = ts2phc_vport_forward(ts2phc_vport, msg);
+       msg_put(msg);
+       ts2phc_vport_init_announce(ts2phc_vport, address);
+       return err;
+}
+
+
+int ts2phc_vport_tx_announce(struct ts2phc_vport *ts2phc_vport)
+{
+       struct ptp_message *msg;
+       int err;
+       struct address address;
+
+       if (!ts2phc_vport_active(ts2phc_vport)) {
+               return 0;
+       }
+
+       msg = ts2phc_vport->announce.msg;
+       address = msg->address;
+       ts2phc_vport->announce.count++;
+
+       err = ts2phc_vport_forward(ts2phc_vport, msg);
+       msg_put(msg);
+       ts2phc_vport_init_announce(ts2phc_vport, address);
+       return err;
+}
diff --git a/ts2phc_vport.h b/ts2phc_vport.h
new file mode 100644
index 0000000..de97fbd
--- /dev/null
+++ b/ts2phc_vport.h
@@ -0,0 +1,28 @@
+/**
+ * @file ts2phc_vport.h
+ * @note Copyright (C) 2021 SyncMonk Technologies <servi...@syncmonk.net>
+ * @note SPDX-License-Identifier: GPL-2.0+
+ *
+ * Also, for each author's protection and ours, we want to make certain that
+ * everyone understands that there is no warranty for this free software.
+ * If the software is modified by someone else and passed on, we want its
+ * recipients to know that what they have is not the original, so that any
+ * problems introduced by others will not reflect on the original authors'
+ * reputations.
+ */
+#ifndef HAVE_TS2PHC_VPORT_H
+#define HAVE_TS2PHC_VPORT_H
+
+#include "config.h"
+#include "port.h"
+#include "tmv.h"
+
+struct ts2phc_vport;
+
+struct ts2phc_vport *ts2phc_vport_create(struct config *config);
+
+void ts2phc_vport_destroy(struct ts2phc_vport *ts2phc_vport);
+
+int ts2phc_vport_tx_announce (struct ts2phc_vport *ts2phc_vport);
+
+#endif
-- 
2.25.1



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

Reply via email to