Signed-off-by: Greg Armstrong <[email protected]>
Signed-off-by: Leon Goldin <[email protected]>
Signed-off-by: Vipin Sharma <[email protected]>
Signed-off-by: Devasish Dey <[email protected]>
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 <[email protected]>
+ * @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 <[email protected]>
+ * @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
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel