|
From: <wow...@us...> - 2015-10-13 21:23:32
|
Revision: 589
http://sourceforge.net/p/ptpd/code/589
Author: wowczarek
Date: 2015-10-13 21:23:29 +0000 (Tue, 13 Oct 2015)
Log Message:
-----------
- config defaults moved to separate source
configdefaults.c
- added support for hard-coded configuration templates,
with initial templates defined - to be finalised
- added support for user variables in configuration:
variables:name=value, used as @name@ elsewhere
- man pages built-in help updated accordingly
- added -t [templates] to use, and -T to show
available templates
- implemented dictionary_replace(dict, char*, char*)
Modified Paths:
--------------
trunk/INSTALL
trunk/src/Makefile.am
trunk/src/constants.h
trunk/src/dep/daemonconfig.c
trunk/src/dep/daemonconfig.h
trunk/src/dep/iniparser/AUTHORS
trunk/src/dep/iniparser/dictionary.c
trunk/src/dep/iniparser/dictionary.h
trunk/src/ptpd2.8.in
trunk/src/ptpd2.conf.5.in
Added Paths:
-----------
trunk/src/dep/configdefaults.c
trunk/src/dep/configdefaults.h
Modified: trunk/INSTALL
===================================================================
--- trunk/INSTALL 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/INSTALL 2015-10-13 21:23:29 UTC (rev 589)
@@ -17,6 +17,9 @@
(optional but recommended) - required for Ethernet transport
and generally recommended for message performance
+ *NOTE: Libpcap seems to be broken on OpenSolaris / OmniOS,
+ builds and runs, but no data is being received.
+
3. SNMP libraries (optional) - will allow building with SNMP
support
@@ -41,6 +44,12 @@
described below. Running ./configure --help will show all available
options.
+ *NOTE* On QNX systems, the configure script may not accept the
+ 'rm' command implementation available, so if it complains,
+ run ./configure with the following environment variable:
+
+ export ACCEPT_INFERIOR_RM_PROGRAM=yes
+
========= configure script options for ptpd ========================
* To disable the statistics code in order to lower computational
@@ -96,6 +105,26 @@
./configure --disable-so-timestamping
+ * To enable experimental options use:
+
+ ./configure --enable-experimental-options
+
+ This enables:
+
+ - running SO_TIMESTAMPING without verifying if NIC driver
+ supports the given timestamping options
+ - running message intervals outside of PTP specification
+
+ *NOTE* On QNX systems, when experimental options are enabled,
+ a clock_gettime approximation using CPU clock counter and
+ attaching to IRQ0 is used, and this is also used to retrieve
+ packet RX and TX timestamps, ignoring PCAP timestamps and
+ socket options. This is recommended for best performance,
+ but requires more testing before becoming the default.
+ by default in QNX, clock is incremented in ticks that
+ can be as long as 10 milliseconds, and PCAP and socket
+ timestamps are only accurate to several milliseconds.
+
5. make
6. Read the manual pages ptpd2(8) and ptpd2.conf(5). The man pages
Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/Makefile.am 2015-10-13 21:23:29 UTC (rev 589)
@@ -44,6 +44,8 @@
dep/iniparser/iniparser.h \
dep/iniparser/dictionary.c \
dep/iniparser/iniparser.c \
+ dep/configdefaults.h \
+ dep/configdefaults.c \
dep/daemonconfig.h \
dep/daemonconfig.c \
dep/startup.c \
Modified: trunk/src/constants.h
===================================================================
--- trunk/src/constants.h 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/constants.h 2015-10-13 21:23:29 UTC (rev 589)
@@ -64,7 +64,7 @@
/* number of announces we need to lose until a time out occurs. Thus it is 12 seconds */
#define DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT 6 /* 3 by default */
-#define DEFAULT_FAILURE_WAITTIME 10 /* sleep for 5 seconds on failure once operational */
+#define DEFAULT_FAILURE_WAITTIME 10 /* sleep for 10 seconds on failure once operational */
#define DEFAULT_QUALIFICATION_TIMEOUT 2
#define DEFAULT_FOREIGN_MASTER_TIME_WINDOW 4
Added: trunk/src/dep/configdefaults.c
===================================================================
--- trunk/src/dep/configdefaults.c (rev 0)
+++ trunk/src/dep/configdefaults.c 2015-10-13 21:23:29 UTC (rev 589)
@@ -0,0 +1,570 @@
+/*-
+ * Copyright (c) 2013-2015 Wojciech Owczarek,
+ *
+ * All Rights Reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file configtemplates.c
+ * @date Mon Oct 12 03:25:32 2015
+ *
+ * @brief Definitions of configuration templates
+ *
+ */
+
+#include "../ptpd.h"
+
+#define CONFIG_ISTRUE(key) \
+ (iniparser_getboolean(dict,key,FALSE)==TRUE)
+
+#define IS_QUIET()\
+ ( CONFIG_ISTRUE("%quiet%:%quiet%") )
+
+/*
+ * static definition of configuration templates - maximum 100 settings per template,
+ * as defined in configtemplates.h. Template for a template below.
+ */
+
+/* =============== configuration templates begin ===============*/
+
+static const ConfigTemplate configTemplates[] = {
+
+ { "g8265-e2e-master", {
+ {"ptpengine:preset", "masteronly"},
+ {"ptpengine:ip_mode", "unicast"},
+ {"ptpengine:unicast_negotiation", "y"},
+ {"ptpengine:domain", "4"},
+ {"ptpengine:disable_bmca", "y"},
+ {"ptpentine:delay_mechanism", "E2E"},
+ {"ptpengine:log_sync_interval", "-6"},
+ {"ptpengine:log_delayreq_interval", "-6"},
+ {"ptpengine:announce_receipt_timeout", "3"},
+ {"ptpengine:priority1", "128"},
+ {"ptpengine:priority2", "128"},
+ {NULL}}
+ },
+
+ { "g8265-e2e-slave", {
+ {"ptpengine:preset", "slaveonly"},
+ {"ptpengine:ip_mode", "unicast"},
+ {"ptpengine:unicast_negotiation", "y"},
+ {"ptpengine:domain", "4"},
+ {"ptpengine:delay_mechanism", "E2E"},
+ {"ptpengine:announce_receipt_timeout", "3"},
+ {NULL}}
+ },
+
+ { "layer2-p2p-master", {
+ {"ptpengine:transport","ethernet"},
+ {"ptpengine:delay_mechanism","P2P"},
+ {"ptpengine:preset","masteronly"},
+// {"",""},
+ {NULL}}
+ },
+
+ { "layer2-p2p-slave", {
+ {"ptpengine:transport","ethernet"},
+ {"ptpengine:delay_mechanism","E2E"},
+ {"ptpengine:preset","slaveonly"},
+// {"",""},
+ {NULL}}
+ },
+
+ { "valid-utc-properties", {
+ {"ptpengine:ptp_timescale","PTP"},
+ {"ptpengine:time_traceable","y"},
+ {"ptpengine:frequency_traceable","y"},
+ {"clock:leap_seconds_file",""},
+ {NULL}}
+ },
+
+ { "full-logging", {
+ {"global:log_status", "y"},
+ {"global:status_file", "/var/run/ptpd2.status"},
+ {"global:statistics_log_interval", "1"},
+ {"global:lock_file", "/var/run/ptpd2.pid"},
+ {"global:log_statistics", "y"},
+ {"global:statistics_file", "/var/log/ptpd2.statistics"},
+// {"global:statistics_file_truncate", "n"},
+ {"global:log_file", "/var/log/ptpd2.log"},
+ {"global:statistics_timestamp_format", "both"},
+ {NULL}}
+ },
+
+ { "full-logging-instance", {
+ {"global:log_status", "y"},
+ {"global:status_file", "/var/run/ptpd2.%instance%.status"},
+ {"global:statistics_log_interval", "1"},
+ {"global:lock_file", "/var/run/ptpd2.%instance%.pid"},
+ {"global:log_statistics", "y"},
+ {"global:statistics_file", "/var/log/ptpd2.%instance%.statistics"},
+// {"global:statistics_file_truncate", "n"},
+ {"global:log_file", "/var/log/ptpd2.%instance%.log"},
+ {"global:statistics_timestamp_format", "both"},
+ {NULL}}
+ },
+
+
+ {NULL}
+};
+
+/* =============== configuration templates end ===============*/
+
+/* template of a template looks like this... */
+
+/*
+ { "template-name", {
+ {"section:key","value"},
+ {"",""},
+ {NULL}}
+ },
+
+ { "", {
+ {"",""},
+ {"",""},
+ {NULL}}
+ },
+
+
+*/
+
+/* Load all rtOpts defaults */
+void
+loadDefaultSettings( RunTimeOpts* rtOpts )
+{
+
+ /* Wipe the memory first to avoid unconsistent behaviour - no need to set Boolean to FALSE, int to 0 etc. */
+ memset(rtOpts, 0, sizeof(RunTimeOpts));
+
+ rtOpts->logAnnounceInterval = DEFAULT_ANNOUNCE_INTERVAL;
+ rtOpts->logSyncInterval = DEFAULT_SYNC_INTERVAL;
+ rtOpts->logMinPdelayReqInterval = DEFAULT_PDELAYREQ_INTERVAL;
+ rtOpts->clockQuality.clockAccuracy = DEFAULT_CLOCK_ACCURACY;
+ rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
+ rtOpts->clockQuality.offsetScaledLogVariance = DEFAULT_CLOCK_VARIANCE;
+ rtOpts->priority1 = DEFAULT_PRIORITY1;
+ rtOpts->priority2 = DEFAULT_PRIORITY2;
+ rtOpts->domainNumber = DEFAULT_DOMAIN_NUMBER;
+ rtOpts->portNumber = NUMBER_PORTS;
+
+ rtOpts->anyDomain = FALSE;
+
+ rtOpts->transport = UDP_IPV4;
+
+ /* timePropertiesDS */
+ rtOpts->timeProperties.currentUtcOffsetValid = DEFAULT_UTC_VALID;
+ rtOpts->timeProperties.currentUtcOffset = DEFAULT_UTC_OFFSET;
+ rtOpts->timeProperties.timeSource = INTERNAL_OSCILLATOR;
+ rtOpts->timeProperties.timeTraceable = FALSE;
+ rtOpts->timeProperties.frequencyTraceable = FALSE;
+ rtOpts->timeProperties.ptpTimescale = TRUE;
+
+ rtOpts->ipMode = IPMODE_MULTICAST;
+ rtOpts->dot2AS = FALSE;
+
+ rtOpts->disableUdpChecksums = TRUE;
+
+ rtOpts->unicastNegotiation = FALSE;
+ rtOpts->unicastNegotiationListening = FALSE;
+ rtOpts->disableBMCA = FALSE;
+ rtOpts->unicastGrantDuration = 300;
+ rtOpts->unicastAcceptAny = FALSE;
+ rtOpts->unicastPortMask = 0;
+
+ rtOpts->noAdjust = NO_ADJUST; // false
+ rtOpts->logStatistics = TRUE;
+ rtOpts->statisticsTimestamp = TIMESTAMP_DATETIME;
+
+ rtOpts->periodicUpdates = FALSE; /* periodically log a status update */
+
+ /* Deep display of all packets seen by the daemon */
+ rtOpts->displayPackets = FALSE;
+
+ rtOpts->s = DEFAULT_DELAY_S;
+ rtOpts->inboundLatency.nanoseconds = DEFAULT_INBOUND_LATENCY;
+ rtOpts->outboundLatency.nanoseconds = DEFAULT_OUTBOUND_LATENCY;
+ rtOpts->max_foreign_records = DEFAULT_MAX_FOREIGN_RECORDS;
+ rtOpts->nonDaemon = FALSE;
+
+ /*
+ * defaults for new options
+ */
+ rtOpts->ignore_delayreq_interval_master = FALSE;
+ rtOpts->do_IGMP_refresh = TRUE;
+ rtOpts->useSysLog = FALSE;
+ rtOpts->announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
+#ifdef RUNTIME_DEBUG
+ rtOpts->debug_level = LOG_INFO; /* by default debug messages as disabled, but INFO messages and below are printed */
+#endif
+ rtOpts->ttl = 64;
+ rtOpts->delayMechanism = DEFAULT_DELAY_MECHANISM;
+ rtOpts->noResetClock = DEFAULT_NO_RESET_CLOCK;
+ rtOpts->stepOnce = FALSE;
+ rtOpts->stepForce = FALSE;
+#ifdef HAVE_LINUX_RTC_H
+ rtOpts->setRtc = FALSE;
+#endif /* HAVE_LINUX_RTC_H */
+
+ rtOpts->clearCounters = FALSE;
+ rtOpts->statisticsLogInterval = 0;
+
+ rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;
+ rtOpts->logMinDelayReqInterval = DEFAULT_DELAYREQ_INTERVAL;
+ rtOpts->autoDelayReqInterval = TRUE;
+ rtOpts->masterRefreshInterval = 60;
+
+ /* maximum values for unicast negotiation */
+ rtOpts->logMaxPdelayReqInterval = 5;
+ rtOpts->logMaxDelayReqInterval = 5;
+ rtOpts->logMaxSyncInterval = 5;
+ rtOpts->logMaxAnnounceInterval = 5;
+
+ rtOpts->drift_recovery_method = DRIFT_KERNEL;
+ strncpy(rtOpts->lockDirectory, DEFAULT_LOCKDIR, PATH_MAX);
+ strncpy(rtOpts->driftFile, DEFAULT_DRIFTFILE, PATH_MAX);
+/* strncpy(rtOpts->lockFile, DEFAULT_LOCKFILE, PATH_MAX); */
+ rtOpts->autoLockFile = FALSE;
+ rtOpts->snmp_enabled = FALSE;
+ /* This will only be used if the "none" preset is configured */
+#ifndef PTPD_SLAVE_ONLY
+ rtOpts->slaveOnly = FALSE;
+#else
+ rtOpts->slaveOnly = TRUE;
+#endif /* PTPD_SLAVE_ONLY */
+ /* Otherwise default to slave only via the preset */
+ rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
+ rtOpts->pidAsClockId = FALSE;
+
+ /* highest possible */
+ rtOpts->logLevel = LOG_ALL;
+
+ /* ADJ_FREQ_MAX by default */
+ rtOpts->servoMaxPpb = ADJ_FREQ_MAX / 1000;
+ /* kP and kI are scaled to 10000 and are gains now - values same as originally */
+ rtOpts->servoKP = 0.1;
+ rtOpts->servoKI = 0.001;
+
+ rtOpts->servoDtMethod = DT_CONSTANT;
+ /* when measuring dT, use a maximum of 5 sync intervals (would correspond to avg 20% discard rate) */
+ rtOpts->servoMaxdT = 5.0;
+
+ /* disabled by default */
+ rtOpts->announceTimeoutGracePeriod = 0;
+
+ /* currentUtcOffsetValid compatibility flags */
+ rtOpts->alwaysRespectUtcOffset = TRUE;
+ rtOpts->preferUtcValid = FALSE;
+ rtOpts->requireUtcValid = FALSE;
+
+ /* Try 46 for expedited forwarding */
+ rtOpts->dscpValue = 0;
+
+#if (defined(linux) && defined(HAVE_SCHED_H)) || defined(HAVE_SYS_CPUSET_H) || defined (__QNXNTO__)
+ rtOpts-> cpuNumber = -1;
+#endif /* (linux && HAVE_SCHED_H) || HAVE_SYS_CPUSET_H*/
+
+#ifdef PTPD_STATISTICS
+
+ rtOpts->oFilterMSConfig.enabled = FALSE;
+ rtOpts->oFilterMSConfig.discard = TRUE;
+ rtOpts->oFilterMSConfig.autoTune = TRUE;
+ rtOpts->oFilterMSConfig.stepDelay = FALSE;
+ rtOpts->oFilterMSConfig.alwaysFilter = FALSE;
+ rtOpts->oFilterMSConfig.stepThreshold = 1000000;
+ rtOpts->oFilterMSConfig.stepLevel = 500000;
+ rtOpts->oFilterMSConfig.capacity = 20;
+ rtOpts->oFilterMSConfig.threshold = 1.0;
+ rtOpts->oFilterMSConfig.weight = 1;
+ rtOpts->oFilterMSConfig.minPercent = 20;
+ rtOpts->oFilterMSConfig.maxPercent = 95;
+ rtOpts->oFilterMSConfig.thresholdStep = 0.1;
+ rtOpts->oFilterMSConfig.minThreshold = 0.1;
+ rtOpts->oFilterMSConfig.maxThreshold = 5.0;
+ rtOpts->oFilterMSConfig.delayCredit = 200;
+ rtOpts->oFilterMSConfig.creditIncrement = 10;
+ rtOpts->oFilterMSConfig.maxDelay = 1500;
+
+ rtOpts->oFilterSMConfig.enabled = FALSE;
+ rtOpts->oFilterSMConfig.discard = TRUE;
+ rtOpts->oFilterSMConfig.autoTune = TRUE;
+ rtOpts->oFilterSMConfig.stepDelay = FALSE;
+ rtOpts->oFilterSMConfig.alwaysFilter = FALSE;
+ rtOpts->oFilterSMConfig.stepThreshold = 1000000;
+ rtOpts->oFilterSMConfig.stepLevel = 500000;
+ rtOpts->oFilterSMConfig.capacity = 20;
+ rtOpts->oFilterSMConfig.threshold = 1.0;
+ rtOpts->oFilterSMConfig.weight = 1;
+ rtOpts->oFilterSMConfig.minPercent = 20;
+ rtOpts->oFilterSMConfig.maxPercent = 95;
+ rtOpts->oFilterSMConfig.thresholdStep = 0.1;
+ rtOpts->oFilterSMConfig.minThreshold = 0.1;
+ rtOpts->oFilterSMConfig.maxThreshold = 5.0;
+ rtOpts->oFilterSMConfig.delayCredit = 200;
+ rtOpts->oFilterSMConfig.creditIncrement = 10;
+ rtOpts->oFilterSMConfig.maxDelay = 1500;
+
+ rtOpts->filterMSOpts.enabled = FALSE;
+ rtOpts->filterMSOpts.filterType = FILTER_MIN;
+ rtOpts->filterMSOpts.windowSize = 4;
+ rtOpts->filterMSOpts.windowType = WINDOW_SLIDING;
+
+ rtOpts->filterSMOpts.enabled = FALSE;
+ rtOpts->filterSMOpts.filterType = FILTER_MIN;
+ rtOpts->filterSMOpts.windowSize = 4;
+ rtOpts->filterSMOpts.windowType = WINDOW_SLIDING;
+
+ /* How often refresh statistics (seconds) */
+ rtOpts->statsUpdateInterval = 30;
+ /* Servo stability detection settings follow */
+ rtOpts->servoStabilityDetection = FALSE;
+ /* Stability threshold (ppb) - observed drift std dev value considered stable */
+ rtOpts->servoStabilityThreshold = 10;
+ /* How many consecutive statsUpdateInterval periods of observed drift std dev within threshold means stable servo */
+ rtOpts->servoStabilityPeriod = 1;
+ /* How many minutes without servo stabilisation means servo has not stabilised */
+ rtOpts->servoStabilityTimeout = 10;
+ /* How long to wait for one-way delay prefiltering */
+ rtOpts->calibrationDelay = 0;
+ /* if set to TRUE and maxDelay is defined, only check against threshold if servo is stable */
+ rtOpts->maxDelayStableOnly = FALSE;
+ /* if set to non-zero, reset slave if more than this amount of consecutive delay measurements was above maxDelay */
+ rtOpts->maxDelayMaxRejected = 0;
+#endif
+
+ /* status file options */
+ rtOpts->statusFileUpdateInterval = 1;
+
+ /* panic mode options */
+ rtOpts->enablePanicMode = FALSE;
+ rtOpts->panicModeDuration = 2;
+ rtOpts->panicModeExitThreshold = 0;
+
+ /* full network reset after 5 times in listening */
+ rtOpts->maxListen = 5;
+
+ rtOpts->panicModeReleaseClock = FALSE;
+ rtOpts->ntpOptions.enableEngine = FALSE;
+ rtOpts->ntpOptions.enableControl = FALSE;
+ rtOpts->ntpOptions.enableFailover = FALSE;
+ rtOpts->ntpOptions.failoverTimeout = 120;
+ rtOpts->ntpOptions.checkInterval = 15;
+ rtOpts->ntpOptions.keyId = 0;
+ strncpy(rtOpts->ntpOptions.hostAddress,"localhost",MAXHOSTNAMELEN); /* not configurable, but could be */
+ rtOpts->preferNTP = FALSE;
+
+ rtOpts->leapSecondPausePeriod = 5;
+ /* by default, announce the leap second 12 hours before the event:
+ * Clause 9.4 paragraph 5 */
+ rtOpts->leapSecondNoticePeriod = 43200;
+ rtOpts->leapSecondHandling = LEAP_ACCEPT;
+ rtOpts->leapSecondSmearPeriod = 86400;
+
+/* timing domain */
+ rtOpts->idleTimeout = 120; /* idle timeout */
+ rtOpts->electionDelay = 15; /* anti-flapping delay */
+
+/* Log file settings */
+
+ rtOpts->statisticsLog.logID = "statistics";
+ rtOpts->statisticsLog.openMode = "a+";
+ rtOpts->statisticsLog.logFP = NULL;
+ rtOpts->statisticsLog.truncateOnReopen = FALSE;
+ rtOpts->statisticsLog.unlinkOnClose = FALSE;
+ rtOpts->statisticsLog.maxSize = 0;
+
+ rtOpts->recordLog.logID = "record";
+ rtOpts->recordLog.openMode = "a+";
+ rtOpts->recordLog.logFP = NULL;
+ rtOpts->recordLog.truncateOnReopen = FALSE;
+ rtOpts->recordLog.unlinkOnClose = FALSE;
+ rtOpts->recordLog.maxSize = 0;
+
+ rtOpts->eventLog.logID = "log";
+ rtOpts->eventLog.openMode = "a+";
+ rtOpts->eventLog.logFP = NULL;
+ rtOpts->eventLog.truncateOnReopen = FALSE;
+ rtOpts->eventLog.unlinkOnClose = FALSE;
+ rtOpts->eventLog.maxSize = 0;
+
+ rtOpts->statusLog.logID = "status";
+ rtOpts->statusLog.openMode = "w";
+ strncpy(rtOpts->statusLog.logPath, DEFAULT_STATUSFILE, PATH_MAX);
+ rtOpts->statusLog.logFP = NULL;
+ rtOpts->statusLog.truncateOnReopen = FALSE;
+ rtOpts->statusLog.unlinkOnClose = TRUE;
+
+/* Management message support settings */
+ rtOpts->managementEnabled = TRUE;
+ rtOpts->managementSetEnable = FALSE;
+
+/* IP ACL settings */
+
+ rtOpts->timingAclEnabled = FALSE;
+ rtOpts->managementAclEnabled = FALSE;
+ rtOpts->timingAclOrder = ACL_DENY_PERMIT;
+ rtOpts->managementAclOrder = ACL_DENY_PERMIT;
+
+ // by default we don't check Sync message sequence continuity
+ rtOpts->syncSequenceChecking = FALSE;
+ rtOpts->clockUpdateTimeout = 0;
+
+}
+
+/* The PtpEnginePreset structure for reference:
+
+typedef struct {
+
+ char* presetName;
+ Boolean slaveOnly;
+ Boolean noAdjust;
+ UInteger8_option clockClass;
+
+} PtpEnginePreset;
+*/
+
+PtpEnginePreset
+getPtpPreset(int presetNumber, RunTimeOpts* rtOpts)
+{
+
+ PtpEnginePreset ret;
+
+ memset(&ret,0,sizeof(ret));
+
+ switch(presetNumber) {
+
+ case PTP_PRESET_SLAVEONLY:
+ ret.presetName="slaveonly";
+ ret.slaveOnly = TRUE;
+ ret.noAdjust = FALSE;
+ ret.clockClass.minValue = SLAVE_ONLY_CLOCK_CLASS;
+ ret.clockClass.maxValue = SLAVE_ONLY_CLOCK_CLASS;
+ ret.clockClass.defaultValue = SLAVE_ONLY_CLOCK_CLASS;
+ break;
+ case PTP_PRESET_MASTERSLAVE:
+ ret.presetName = "masterslave";
+ ret.slaveOnly = FALSE;
+ ret.noAdjust = FALSE;
+ ret.clockClass.minValue = 128;
+ ret.clockClass.maxValue = 254;
+ ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS;
+ break;
+ case PTP_PRESET_MASTERONLY:
+ ret.presetName = "masteronly";
+ ret.slaveOnly = FALSE;
+ ret.noAdjust = TRUE;
+ ret.clockClass.minValue = 0;
+ ret.clockClass.maxValue = 127;
+ ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
+ break;
+ default:
+ ret.presetName = "none";
+ ret.slaveOnly = rtOpts->slaveOnly;
+ ret.noAdjust = rtOpts->noAdjust;
+ ret.clockClass.minValue = 0;
+ ret.clockClass.maxValue = 255;
+ ret.clockClass.defaultValue = rtOpts->clockQuality.clockClass;
+ }
+
+ return ret;
+}
+
+
+/* split list to tokens, look for each template and apply it if found */
+int
+applyConfigTemplates(char *templateNames, dictionary *dict) {
+
+ ConfigTemplate *template = NULL;
+ TemplateOption *option = NULL;
+ char *templateName = NULL;
+ Boolean found = 0;
+
+ char* stash;
+ char* text_;
+ char* text__;
+
+ if(dict == NULL) {
+ return 0;
+ }
+
+ if(strlen(templateNames)==0) return 0;
+
+ text_=strdup(templateNames);
+
+ for(text__=text_;; text__=NULL) {
+
+ templateName=strtok_r(text__,", ;\t",&stash);
+ if(templateName==NULL) break;
+
+ found = 0;
+ template = (ConfigTemplate*)configTemplates;
+ while(template->name != NULL) {
+ if(!strcmp(template->name, templateName)) {
+ DBG("Loading config template %s\n", template->name);
+ option = (TemplateOption*)template->options;
+ while(option->name != NULL) {
+ dictionary_set(dict, option->name, option->value);
+ DBG("----> %s = %s",option->name, option->value);
+ option++;
+ }
+ found = 1;
+ if (!IS_QUIET()) NOTICE("Applied configuration template \"%s\"\n", templateName);
+ break;
+ }
+ template++;
+ }
+
+ if(!found) {
+ if (!IS_QUIET()) WARNING("Configuration template \"%s\" not found\n", templateName);
+ }
+
+ }
+
+ if(text_ != NULL) {
+ free(text_);
+ }
+
+ return 0;
+
+}
+
+/* dump the list of templates provided */
+void
+dumpConfigTemplates() {
+
+ ConfigTemplate *template = NULL;
+ TemplateOption *option = NULL;
+
+ template = (ConfigTemplate*)configTemplates;
+ while(template->name != NULL) {
+ printf("Template: %s\n\n", template->name);
+ option = (TemplateOption*)template->options;
+ while(option->name != NULL) {
+ printf("\t\t%s=\"%s\"\n", option->name, option->value);
+ option++;
+ }
+ template++;
+ printf("\n");
+ }
+
+}
Added: trunk/src/dep/configdefaults.h
===================================================================
--- trunk/src/dep/configdefaults.h (rev 0)
+++ trunk/src/dep/configdefaults.h 2015-10-13 21:23:29 UTC (rev 589)
@@ -0,0 +1,49 @@
+/**
+ * @file configdefaults.h
+ *
+ * @brief definitions related to config templates and defaults
+ *
+ *
+ */
+
+#ifndef PTPD_CONFIGDEFAULTS_H_
+#define PTPD_CONFIGDEFAULTS_H_
+
+#include <stddef.h>
+#include "iniparser/iniparser.h"
+
+typedef struct {
+ char * name;
+ char * value;
+} TemplateOption;
+
+typedef struct {
+ char * name;
+ TemplateOption options[100];
+} ConfigTemplate;
+
+/* Structure defining a PTP engine preset */
+typedef struct {
+
+ char* presetName;
+ Boolean slaveOnly;
+ Boolean noAdjust;
+ UInteger8_option clockClass;
+
+} PtpEnginePreset;
+
+/* Preset definitions */
+enum {
+ PTP_PRESET_NONE,
+ PTP_PRESET_SLAVEONLY,
+ PTP_PRESET_MASTERSLAVE,
+ PTP_PRESET_MASTERONLY,
+ PTP_PRESET_MAX
+};
+
+void loadDefaultSettings( RunTimeOpts* rtOpts );
+int applyConfigTemplates(char *templateNames, dictionary *dict);
+PtpEnginePreset getPtpPreset(int presetNumber, RunTimeOpts* rtOpts);
+void dumpConfigTemplates();
+
+#endif /* PTPD_CONFIGDEFAULTS_H_ */
Modified: trunk/src/dep/daemonconfig.c
===================================================================
--- trunk/src/dep/daemonconfig.c 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/dep/daemonconfig.c 2015-10-13 21:23:29 UTC (rev 589)
@@ -797,348 +797,37 @@
}
}
printf("\n");
-}
-/* Load all rtOpts defaults */
-void
-loadDefaultSettings( RunTimeOpts* rtOpts )
-{
-
- /* Wipe the memory first to avoid unconsistent behaviour - no need to set Boolean to FALSE, int to 0 etc. */
- memset(rtOpts, 0, sizeof(RunTimeOpts));
-
- rtOpts->logAnnounceInterval = DEFAULT_ANNOUNCE_INTERVAL;
- rtOpts->logSyncInterval = DEFAULT_SYNC_INTERVAL;
- rtOpts->logMinPdelayReqInterval = DEFAULT_PDELAYREQ_INTERVAL;
- rtOpts->clockQuality.clockAccuracy = DEFAULT_CLOCK_ACCURACY;
- rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
- rtOpts->clockQuality.offsetScaledLogVariance = DEFAULT_CLOCK_VARIANCE;
- rtOpts->priority1 = DEFAULT_PRIORITY1;
- rtOpts->priority2 = DEFAULT_PRIORITY2;
- rtOpts->domainNumber = DEFAULT_DOMAIN_NUMBER;
- rtOpts->portNumber = NUMBER_PORTS;
-
- rtOpts->anyDomain = FALSE;
-
- rtOpts->transport = UDP_IPV4;
-
- /* timePropertiesDS */
- rtOpts->timeProperties.currentUtcOffsetValid = DEFAULT_UTC_VALID;
- rtOpts->timeProperties.currentUtcOffset = DEFAULT_UTC_OFFSET;
- rtOpts->timeProperties.timeSource = INTERNAL_OSCILLATOR;
- rtOpts->timeProperties.timeTraceable = FALSE;
- rtOpts->timeProperties.frequencyTraceable = FALSE;
- rtOpts->timeProperties.ptpTimescale = TRUE;
-
- rtOpts->ipMode = IPMODE_MULTICAST;
- rtOpts->dot2AS = FALSE;
-
- rtOpts->disableUdpChecksums = TRUE;
-
- rtOpts->unicastNegotiation = FALSE;
- rtOpts->unicastNegotiationListening = FALSE;
- rtOpts->disableBMCA = FALSE;
- rtOpts->unicastGrantDuration = 300;
- rtOpts->unicastAcceptAny = FALSE;
- rtOpts->unicastPortMask = 0;
-
- rtOpts->noAdjust = NO_ADJUST; // false
- rtOpts->logStatistics = TRUE;
- rtOpts->statisticsTimestamp = TIMESTAMP_DATETIME;
-
- rtOpts->periodicUpdates = FALSE; /* periodically log a status update */
-
- /* Deep display of all packets seen by the daemon */
- rtOpts->displayPackets = FALSE;
-
- rtOpts->s = DEFAULT_DELAY_S;
- rtOpts->inboundLatency.nanoseconds = DEFAULT_INBOUND_LATENCY;
- rtOpts->outboundLatency.nanoseconds = DEFAULT_OUTBOUND_LATENCY;
- rtOpts->max_foreign_records = DEFAULT_MAX_FOREIGN_RECORDS;
- rtOpts->nonDaemon = FALSE;
-
- /*
- * defaults for new options
- */
- rtOpts->ignore_delayreq_interval_master = FALSE;
- rtOpts->do_IGMP_refresh = TRUE;
- rtOpts->useSysLog = FALSE;
- rtOpts->announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
-#ifdef RUNTIME_DEBUG
- rtOpts->debug_level = LOG_INFO; /* by default debug messages as disabled, but INFO messages and below are printed */
-#endif
- rtOpts->ttl = 64;
- rtOpts->delayMechanism = DEFAULT_DELAY_MECHANISM;
- rtOpts->noResetClock = DEFAULT_NO_RESET_CLOCK;
- rtOpts->stepOnce = FALSE;
- rtOpts->stepForce = FALSE;
-#ifdef HAVE_LINUX_RTC_H
- rtOpts->setRtc = FALSE;
-#endif /* HAVE_LINUX_RTC_H */
-
- rtOpts->clearCounters = FALSE;
- rtOpts->statisticsLogInterval = 0;
-
- rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;
- rtOpts->logMinDelayReqInterval = DEFAULT_DELAYREQ_INTERVAL;
- rtOpts->autoDelayReqInterval = TRUE;
- rtOpts->masterRefreshInterval = 60;
-
- /* maximum values for unicast negotiation */
- rtOpts->logMaxPdelayReqInterval = 5;
- rtOpts->logMaxDelayReqInterval = 5;
- rtOpts->logMaxSyncInterval = 5;
- rtOpts->logMaxAnnounceInterval = 5;
-
-
-
- rtOpts->drift_recovery_method = DRIFT_KERNEL;
- strncpy(rtOpts->lockDirectory, DEFAULT_LOCKDIR, PATH_MAX);
- strncpy(rtOpts->driftFile, DEFAULT_DRIFTFILE, PATH_MAX);
-/* strncpy(rtOpts->lockFile, DEFAULT_LOCKFILE, PATH_MAX); */
- rtOpts->autoLockFile = FALSE;
- rtOpts->snmp_enabled = FALSE;
- /* This will only be used if the "none" preset is configured */
-#ifndef PTPD_SLAVE_ONLY
- rtOpts->slaveOnly = FALSE;
-#else
- rtOpts->slaveOnly = TRUE;
-#endif /* PTPD_SLAVE_ONLY */
- /* Otherwise default to slave only via the preset */
- rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
- rtOpts->pidAsClockId = FALSE;
-
- /* highest possible */
- rtOpts->logLevel = LOG_ALL;
-
- /* ADJ_FREQ_MAX by default */
- rtOpts->servoMaxPpb = ADJ_FREQ_MAX / 1000;
- /* kP and kI are scaled to 10000 and are gains now - values same as originally */
- rtOpts->servoKP = 0.1;
- rtOpts->servoKI = 0.001;
-
- rtOpts->servoDtMethod = DT_CONSTANT;
- /* when measuring dT, use a maximum of 5 sync intervals (would correspond to avg 20% discard rate) */
- rtOpts->servoMaxdT = 5.0;
-
- /* disabled by default */
- rtOpts->announceTimeoutGracePeriod = 0;
-
- /* currentUtcOffsetValid compatibility flags */
- rtOpts->alwaysRespectUtcOffset = TRUE;
- rtOpts->preferUtcValid = FALSE;
- rtOpts->requireUtcValid = FALSE;
-
- /* Try 46 for expedited forwarding */
- rtOpts->dscpValue = 0;
-
-#if (defined(linux) && defined(HAVE_SCHED_H)) || defined(HAVE_SYS_CPUSET_H) || defined (__QNXNTO__)
- rtOpts-> cpuNumber = -1;
-#endif /* (linux && HAVE_SCHED_H) || HAVE_SYS_CPUSET_H*/
-
-#ifdef PTPD_STATISTICS
-
- rtOpts->oFilterMSConfig.enabled = FALSE;
- rtOpts->oFilterMSConfig.discard = TRUE;
- rtOpts->oFilterMSConfig.autoTune = TRUE;
- rtOpts->oFilterMSConfig.stepDelay = FALSE;
- rtOpts->oFilterMSConfig.alwaysFilter = FALSE;
- rtOpts->oFilterMSConfig.stepThreshold = 1000000;
- rtOpts->oFilterMSConfig.stepLevel = 500000;
- rtOpts->oFilterMSConfig.capacity = 20;
- rtOpts->oFilterMSConfig.threshold = 1.0;
- rtOpts->oFilterMSConfig.weight = 1;
- rtOpts->oFilterMSConfig.minPercent = 20;
- rtOpts->oFilterMSConfig.maxPercent = 95;
- rtOpts->oFilterMSConfig.thresholdStep = 0.1;
- rtOpts->oFilterMSConfig.minThreshold = 0.1;
- rtOpts->oFilterMSConfig.maxThreshold = 5.0;
- rtOpts->oFilterMSConfig.delayCredit = 200;
- rtOpts->oFilterMSConfig.creditIncrement = 10;
- rtOpts->oFilterMSConfig.maxDelay = 1500;
-
- rtOpts->oFilterSMConfig.enabled = FALSE;
- rtOpts->oFilterSMConfig.discard = TRUE;
- rtOpts->oFilterSMConfig.autoTune = TRUE;
- rtOpts->oFilterSMConfig.stepDelay = FALSE;
- rtOpts->oFilterSMConfig.alwaysFilter = FALSE;
- rtOpts->oFilterSMConfig.stepThreshold = 1000000;
- rtOpts->oFilterSMConfig.stepLevel = 500000;
- rtOpts->oFilterSMConfig.capacity = 20;
- rtOpts->oFilterSMConfig.threshold = 1.0;
- rtOpts->oFilterSMConfig.weight = 1;
- rtOpts->oFilterSMConfig.minPercent = 20;
- rtOpts->oFilterSMConfig.maxPercent = 95;
- rtOpts->oFilterSMConfig.thresholdStep = 0.1;
- rtOpts->oFilterSMConfig.minThreshold = 0.1;
- rtOpts->oFilterSMConfig.maxThreshold = 5.0;
- rtOpts->oFilterSMConfig.delayCredit = 200;
- rtOpts->oFilterSMConfig.creditIncrement = 10;
- rtOpts->oFilterSMConfig.maxDelay = 1500;
-
- rtOpts->filterMSOpts.enabled = FALSE;
- rtOpts->filterMSOpts.filterType = FILTER_MIN;
- rtOpts->filterMSOpts.windowSize = 4;
- rtOpts->filterMSOpts.windowType = WINDOW_SLIDING;
-
- rtOpts->filterSMOpts.enabled = FALSE;
- rtOpts->filterSMOpts.filterType = FILTER_MIN;
- rtOpts->filterSMOpts.windowSize = 4;
- rtOpts->filterSMOpts.windowType = WINDOW_SLIDING;
-
- /* How often refresh statistics (seconds) */
- rtOpts->statsUpdateInterval = 30;
- /* Servo stability detection settings follow */
- rtOpts->servoStabilityDetection = FALSE;
- /* Stability threshold (ppb) - observed drift std dev value considered stable */
- rtOpts->servoStabilityThreshold = 10;
- /* How many consecutive statsUpdateInterval periods of observed drift std dev within threshold means stable servo */
- rtOpts->servoStabilityPeriod = 1;
- /* How many minutes without servo stabilisation means servo has not stabilised */
- rtOpts->servoStabilityTimeout = 10;
- /* How long to wait for one-way delay prefiltering */
- rtOpts->calibrationDelay = 0;
- /* if set to TRUE and maxDelay is defined, only check against threshold if servo is stable */
- rtOpts->maxDelayStableOnly = FALSE;
- /* if set to non-zero, reset slave if more than this amount of consecutive delay measurements was above maxDelay */
- rtOpts->maxDelayMaxRejected = 0;
-#endif
-
- /* status file options */
- rtOpts->statusFileUpdateInterval = 1;
-
- /* panic mode options */
- rtOpts->enablePanicMode = FALSE;
- rtOpts->panicModeDuration = 2;
- rtOpts->panicModeExitThreshold = 0;
-
- /* full network reset after 5 times in listening */
- rtOpts->maxListen = 5;
-
- rtOpts->panicModeReleaseClock = FALSE;
- rtOpts->ntpOptions.enableEngine = FALSE;
- rtOpts->ntpOptions.enableControl = FALSE;
- rtOpts->ntpOptions.enableFailover = FALSE;
- rtOpts->ntpOptions.failoverTimeout = 120;
- rtOpts->ntpOptions.checkInterval = 15;
- rtOpts->ntpOptions.keyId = 0;
- strncpy(rtOpts->ntpOptions.hostAddress,"localhost",MAXHOSTNAMELEN); /* not configurable, but could be */
- rtOpts->preferNTP = FALSE;
-
- rtOpts->leapSecondPausePeriod = 5;
- /* by default, announce the leap second 12 hours before the event:
- * Clause 9.4 paragraph 5 */
- rtOpts->leapSecondNoticePeriod = 43200;
- rtOpts->leapSecondHandling = LEAP_ACCEPT;
- rtOpts->leapSecondSmearPeriod = 86400;
-
-/* timing domain */
- rtOpts->idleTimeout = 120; /* idle timeout */
- rtOpts->electionDelay = 15; /* anti-flapping delay */
-
-/* Log file settings */
-
- rtOpts->statisticsLog.logID = "statistics";
- rtOpts->statisticsLog.openMode = "a+";
- rtOpts->statisticsLog.logFP = NULL;
- rtOpts->statisticsLog.truncateOnReopen = FALSE;
- rtOpts->statisticsLog.unlinkOnClose = FALSE;
- rtOpts->statisticsLog.maxSize = 0;
-
- rtOpts->recordLog.logID = "record";
- rtOpts->recordLog.openMode = "a+";
- rtOpts->recordLog.logFP = NULL;
- rtOpts->recordLog.truncateOnReopen = FALSE;
- rtOpts->recordLog.unlinkOnClose = FALSE;
- rtOpts->recordLog.maxSize = 0;
-
- rtOpts->eventLog.logID = "log";
- rtOpts->eventLog.openMode = "a+";
- rtOpts->eventLog.logFP = NULL;
- rtOpts->eventLog.truncateOnReopen = FALSE;
- rtOpts->eventLog.unlinkOnClose = FALSE;
- rtOpts->eventLog.maxSize = 0;
-
- rtOpts->statusLog.logID = "status";
- rtOpts->statusLog.openMode = "w";
- strncpy(rtOpts->statusLog.logPath, DEFAULT_STATUSFILE, PATH_MAX);
- rtOpts->statusLog.logFP = NULL;
- rtOpts->statusLog.truncateOnReopen = FALSE;
- rtOpts->statusLog.unlinkOnClose = TRUE;
-
-/* Management message support settings */
- rtOpts->managementEnabled = TRUE;
- rtOpts->managementSetEnable = FALSE;
-
-/* IP ACL settings */
-
- rtOpts->timingAclEnabled = FALSE;
- rtOpts->managementAclEnabled = FALSE;
- rtOpts->timingAclOrder = ACL_DENY_PERMIT;
- rtOpts->managementAclOrder = ACL_DENY_PERMIT;
-
- // by default we don't check Sync message sequence continuity
- rtOpts->syncSequenceChecking = FALSE;
- rtOpts->clockUpdateTimeout = 0;
-
}
-/* The PtpEnginePreset structure for reference:
-
-typedef struct {
-
- char* presetName;
- Boolean slaveOnly;
- Boolean noAdjust;
- UInteger8_option clockClass;
-
-} PtpEnginePreset;
-*/
-
-PtpEnginePreset
-getPtpPreset(int presetNumber, RunTimeOpts* rtOpts)
+static void
+parseUserVariables(dictionary *dict, dictionary *target)
{
- PtpEnginePreset ret;
+ int i = 0;
+ char *search, *replace, *key;
+ char varname[100];
- memset(&ret,0,sizeof(ret));
+ memset(varname, 0, sizeof(varname));
- switch(presetNumber) {
+ if(dict == NULL) return;
- case PTP_PRESET_SLAVEONLY:
- ret.presetName="slaveonly";
- ret.slaveOnly = TRUE;
- ret.noAdjust = FALSE;
- ret.clockClass.minValue = SLAVE_ONLY_CLOCK_CLASS;
- ret.clockClass.maxValue = SLAVE_ONLY_CLOCK_CLASS;
- ret.clockClass.defaultValue = SLAVE_ONLY_CLOCK_CLASS;
- break;
- case PTP_PRESET_MASTERSLAVE:
- ret.presetName = "masterslave";
- ret.slaveOnly = FALSE;
- ret.noAdjust = FALSE;
- ret.clockClass.minValue = 128;
- ret.clockClass.maxValue = 254;
- ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS;
- break;
- case PTP_PRESET_MASTERONLY:
- ret.presetName = "masteronly";
- ret.slaveOnly = FALSE;
- ret.noAdjust = TRUE;
- ret.clockClass.minValue = 0;
- ret.clockClass.maxValue = 127;
- ret.clockClass.defaultValue = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
- break;
- default:
- ret.presetName = "none";
- ret.slaveOnly = rtOpts->slaveOnly;
- ret.noAdjust = rtOpts->noAdjust;
- ret.clockClass.minValue = 0;
- ret.clockClass.maxValue = 255;
- ret.clockClass.defaultValue = rtOpts->clockQuality.clockClass;
+ for(i = 0; i < dict->n; i++) {
+ key = dict->key[i];
+ /* key starts with "variables" */
+ if(strstr(key,"variables:") == key) {
+ /* this cannot fail if we are here */
+ search = strstr(key,":");
+ search++;
+ replace = dictionary_get(dict, key, "");
+ snprintf(varname, sizeof(varname), "@%s@", search);
+ DBG("replacing %s with %s in config\n", varname, replace);
+ dictionary_replace(dict, varname, replace);
+ dictionary_set(target, key, replace);
}
- return ret;
+ }
+
}
/**
@@ -1198,6 +887,7 @@
* is complete and free of any unknown options. In the end, warning
* is issued for unknown options. On any errors, NULL is returned
*/
+
dictionary* target = dictionary_new(0);
Boolean parseResult = TRUE;
@@ -1208,6 +898,19 @@
INFO("Checking configuration\n");
}
+ /*
+ * apply the configuration template(s) as statically defined in configdefaults.c
+ * The list of templates is a comma, space or tab separated names. Any templates
+ * are applied before anything else: so any settings after this can override
+ */
+ if (CONFIG_ISPRESENT("global:config_templates")) {
+ applyConfigTemplates(dictionary_get(dict, "global:config_templates", ""), dict);
+ /* also set the template names in the target dictionary */
+ dictionary_set(target, "global:config_templates", dictionary_get(dict, "global:config_templates", ""));
+ }
+
+ parseUserVariables(dict, target);
+
/* ============= BEGIN CONFIG MAPPINGS, TRIGGERS AND DEPENDENCIES =========== */
/* ===== ptpengine section ===== */
@@ -2822,15 +2525,17 @@
{"long-help", no_argument, 0, 'H'},
{"explain", required_argument, 0, 'e'},
{"default-config", optional_argument, 0, 'O'},
+ {"templates", required_argument, 0, 't'},
+ {"show-templates", no_argument, 0, 'T'},
{"unicast", optional_argument, 0, 'U'},
{"unicast-negotiation", optional_argument, 0, 'g'},
{"unicast-destinations", required_argument, 0, 'u'},
{0, 0 , 0, 0}
};
- while ((c = getopt_long(argc, argv, "?c:kb:i:d:sgmGMWyUu:nf:S:r:DvCVHhe:Y:tOLEPAaR:l:p", long_options, &opt_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "?c:kb:i:d:sgmGMWyUu:nf:S:r:DvCVHTt:he:Y:tOLEPAaR:l:p", long_options, &opt_index)) != -1) {
#else
- while ((c = getopt(argc, argv, "?c:kb:i:d:sgmGMWyUu:nf:S:r:DvCVHhe:Y:tOLEPAaR:l:p")) != -1) {
+ while ((c = getopt(argc, argv, "?c:kb:i:d:sgmGMWyUu:nf:S:r:DvCVHTt:he:Y:tOLEPAaR:l:p")) != -1) {
#endif
switch(c) {
/* non-config options first */
@@ -2856,6 +2561,9 @@
case 'O':
printDefaultConfig();
return FALSE;
+ case 'T':
+ dumpConfigTemplates();
+ return FALSE;
/* regular ptpd options */
/* config file path */
@@ -2911,8 +2619,6 @@
dictionary_set(dict,"ptpengine:ip_mode", "unicast");
dictionary_set(dict,"ptpengine:unicast_destinations", optarg);
break;
- case 't':
- WARN_DEPRECATED('t', 'n', "noadjust", "clock:no_adjust");
case 'n':
dictionary_set(dict,"clock:no_adjust", "Y");
break;
@@ -2924,6 +2630,8 @@
case 'S':
dictionary_set(dict,"global:statistics_file", optarg);
break;
+ case 't':
+ dictionary_set(dict,"global:config_templates", optarg);
/* Override delay request interval from master */
case 'a':
dictionary_set(dict,"ptpengine:log_delayreq_override", "Y");
@@ -3067,6 +2775,9 @@
"-R --lock-directory [path] Directory to store lock files\n"
"-f --log-file [path] global:log_file=[path] Log file\n"
"-S --statistics-file [path] global:statistics_file=[path] Statistics file\n"
+ "-T --show-templates display available configuration templates\n"
+ "-t --templates [name],[name],[...]\n"
+ " apply configuration template(s) - see man(5) ptpd2.conf\n"
"\n"
"Basic PTP protocol and daemon configuration options: \n"
"\n"
@@ -3145,6 +2856,18 @@
printPresetHelp();
printf("\n"
+ " Configuration templates available (see man(5) ptpd2.conf):\n"
+ "\n usage:\n"
+ " -t [name],[name],...\n"
+ " --templates [name],[name],...\n"
+ " --global:config_templates=[name],[name],...\n\n");
+
+ dumpConfigTemplates();
+
+ printf("========================\n");
+
+
+ printf("\n"
"Possible internal states:\n"
" init: INITIALIZING\n"
" flt: FAULTY\n"
Modified: trunk/src/dep/daemonconfig.h
===================================================================
--- trunk/src/dep/daemonconfig.h 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/dep/daemonconfig.h 2015-10-13 21:23:29 UTC (rev 589)
@@ -10,6 +10,7 @@
#define PTPD_DAEMONCONFIG_H_
#include "iniparser/iniparser.h"
+#include "configdefaults.h"
/* Config reload - component restart status flags */
@@ -41,31 +42,9 @@
#define LOG2_HELP "(expressed as log 2 i.e. -1=0.5s, 0=1s, 1=2s etc.)"
-/* Structure defining a PTP engine preset */
-typedef struct {
-
- char* presetName;
- Boolean slaveOnly;
- Boolean noAdjust;
- UInteger8_option clockClass;
-
-} PtpEnginePreset;
-
-/* Preset definitions */
-enum {
- PTP_PRESET_NONE,
- PTP_PRESET_SLAVEONLY,
- PTP_PRESET_MASTERSLAVE,
- PTP_PRESET_MASTERONLY,
- PTP_PRESET_MAX
-};
-
-
-void loadDefaultSettings(RunTimeOpts*);
Boolean loadConfigFile (dictionary**, RunTimeOpts*);
void loadCommandLineKeys(dictionary*, int, char**);
Boolean loadCommandLineOptions(RunTimeOpts*, dictionary*, int, char** , Integer16*);
-PtpEnginePreset getPtpPreset(int presetNumber, RunTimeOpts* rtOpts);
dictionary* parseConfig (dictionary*, RunTimeOpts*);
int reloadConfig ( RunTimeOpts*, PtpClock* );
Boolean compareConfig(dictionary* source, dictionary* target);
Modified: trunk/src/dep/iniparser/AUTHORS
===================================================================
--- trunk/src/dep/iniparser/AUTHORS 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/dep/iniparser/AUTHORS 2015-10-13 21:23:29 UTC (rev 589)
@@ -4,3 +4,4 @@
not kept track of all the people who contributed. Let them be thanked
for their ideas, code, suggestions, corrections, enhancements!
+Further enhancements by Wojciech Owczarek for the PTPd project
Modified: trunk/src/dep/iniparser/dictionary.c
===================================================================
--- trunk/src/dep/iniparser/dictionary.c 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/dep/iniparser/dictionary.c 2015-10-13 21:23:29 UTC (rev 589)
@@ -326,6 +326,85 @@
/*-------------------------------------------------------------------------*/
/**
+ @brief Replace string in all values of a dictionary
+ @param d dictionary object to modify.
+ @param search string to be replaced
+ @param replace string to replace with
+ @return void
+
+ This function globally replaces all occurrences of one string in the ditcionary
+ with another in key values.
+
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_replace(dictionary * d, const char * search, const char * replace)
+{
+
+ int bufsize = MAXVALSZ;
+ char out[bufsize+1];
+ char *in = NULL;
+ char *val = NULL;
+ char *found = NULL;
+ int i = 0, j = 0;
+ int maxcount = 0;
+ char *pos = NULL;
+ char *data = NULL;
+
+ if (search==NULL || replace==NULL ) return;
+
+ for(i = 0; i < d->n; i++) {
+ memset(out, 0, bufsize+1);
+ /* skip if the key is null or is a section */
+ if(d->key[i] == NULL || strstr(d->key[i],":") == NULL)
+ continue;
+
+ val = dictionary_get(d, d->key[i], "");
+ data = strdup(val);
+ in = data;
+ found=strstr(in, search);
+
+ if(found != NULL) {
+ do {
+ pos=found;
+
+ for (j=0; j < strlen(search); j++) {
+ *pos='\0';
+ pos++;
+ }
+ maxcount = bufsize - strlen(out);
+ maxcount = (maxcount < 0) ? 0 : maxcount;
+ strncat(out,in,maxcount);
+
+ maxcount = bufsize - strlen(out);
+ maxcount = (maxcount < 0) ? 0 : maxcount;
+ strncat(out,replace,maxcount);
+
+ in = pos;
+
+ found=strstr(in, search);
+
+ } while (found != NULL);
+
+ if(*pos != 0) {
+ maxcount = bufsize - strlen(out);
+ maxcount = (maxcount < 0) ? 0 : maxcount;
+ strncat(out,pos,maxcount);
+ }
+
+ dictionary_set(d, d->key[i], out);
+// printf("Replaced token \"%s\" with \"%s\": \"%s\" -> \"%s\"\n",
+// search, replace, val, out);
+ }
+ free(data);
+
+ }
+
+
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
Modified: trunk/src/dep/iniparser/dictionary.h
===================================================================
--- trunk/src/dep/iniparser/dictionary.h 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/dep/iniparser/dictionary.h 2015-10-13 21:23:29 UTC (rev 589)
@@ -155,7 +155,21 @@
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key);
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Replace string in all values of a dictionary
+ @param d dictionary object to modify.
+ @param search string to be replaced
+ @param replace string to replace with
+ @return void
+ This function globally replaces all occurrences of one string in the ditcionary
+ with another in key values.
+
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_replace(dictionary * d, const char * search, const char * replace);
+
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
Modified: trunk/src/ptpd2.8.in
===================================================================
--- trunk/src/ptpd2.8.in 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/ptpd2.8.in 2015-10-13 21:23:29 UTC (rev 589)
@@ -78,6 +78,16 @@
.TP
\fB-S --statistics-file \fIPATH\fR
Path to statistics file (also \fIglobal:statistics_file\fR)
+.TP
+\fB-T --show-templates
+Display built-in configuration templates
+.TP
+\fB-t --templates \fI[name],[name],...\fR
+Apply one or more configuration templates in this order (\fIsee man(5) ptpd2.conf\fR)
+.TP
+\fB-S --statistics-file \fIPATH\fR
+Path to statistics file (also \fIglobal:statistics_file\fR)
+
.SH BASIC PTP PROTOCOL OPTIONS
.TP
\fB-i --interface \fIDEV\fR
Modified: trunk/src/ptpd2.conf.5.in
===================================================================
--- trunk/src/ptpd2.conf.5.in 2015-10-12 16:57:43 UTC (rev 588)
+++ trunk/src/ptpd2.conf.5.in 2015-10-13 21:23:29 UTC (rev 589)
@@ -19,14 +19,12 @@
PTPd will always attempt to test settings before applying them and once running, will never exit as
a result of configuration errors. If it does exit during config refresh, this is most likely a bug.
-.SH PRIORITY
+.SH COMMAND-LINE PRIORITY
Any setting passed as a command line parameter will always take priority over the configuration file,
so once ptpd is running, those settings cannot be changed - a warning will be logged on every
attempt to change those settings using the configuration file.
.SH CONFIGURATION SECTIONS
-
-.TP
.B ptpengine
PTP protocol specific configuration
.TP
@@ -42,10 +40,36 @@
.B ntpengine
NTP control configuration
.TP
+.B variables
+User-defined variables
+.SH USER-DEFINED VARIABLES
+To allow for easier management and automated generation of configuration, PTPd supports user variables,
+which can be defined in the configuration file or in command line. They are defined as \fIvariables:[name]=[value]\fR,
+or if using .ini style format, in the \fI[variables]\fR section. Once defined, a variable can be referred to
+in the remaining configuration settings as \fI@name@\fR, and is substituted with the value of the variable
+
+\fBExample\fR:
+
+variables:instance=server15
+
+global:status_file=/var/run/ptpd2.@instance@.status
+
+global:log_file=/var/run/ptpd2.@instance@.status
+
+\fBNote:\fR for the same effect, ptpd can be run from command line, such as \fI --config=/path/to/file --variables:instance=server15\fR
+
+.SH CONFIGURATION TEMPLATES
+As of version 2.3.1.1, ptpd enables the user to minimise the configuration effort for common scenarios, using built-in templates.
+A template is a named set of pre-defined settings whic are prepended before any other settings, so user can still overwrite
+settings provided by the template. To use this feature, set \fIglobal:config_templates=[name],[name],...\fR in the configuration file,
+or run ptpd with \fI--global:config_templates=[name],[name],...\fR. Multiple templates can be specified, separated by comma, space
+or tab; they are applied in the order they are provided, so template settings override any overlapping settings from previous
+templates specified.
+
+To see the list of available templates, run ptpd with \fI-T\fR or \fI--templates\fR
+
.SH CONFIGURATION VARIABLES
-.BR
-.TP
.RS 0
.TP 8
\fBptpengine:interface [\fISTRING\fB]\fR
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|