original files of m241
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
|
||||
/* constants_dep.h */
|
||||
|
||||
#ifndef CONSTANTS_DEP_H
|
||||
#define CONSTANTS_DEP_H
|
||||
|
||||
/**
|
||||
*\file
|
||||
* \brief Plateform-dependent constants definition
|
||||
*
|
||||
* This header defines all includes and constants which are plateform-dependent
|
||||
*
|
||||
* ptpdv2 is only implemented for linux, NetBSD and FreeBSD
|
||||
*/
|
||||
|
||||
/* platform dependent */
|
||||
|
||||
|
||||
#ifdef VXWORKS_OS /* copied from below linux part with some modification*/
|
||||
#include <net/ethernet.h>
|
||||
#include <hostLib.h>
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include<netinet/in.h>
|
||||
#include<net/if.h>
|
||||
#include<net/if_arp.h>
|
||||
#include <ifaddrs.h>
|
||||
#define IFACE_NAME_LENGTH IF_NAMESIZE
|
||||
#define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
|
||||
|
||||
#define IFCONF_LENGTH 10
|
||||
|
||||
#endif /* VXWORKS_OS */
|
||||
|
||||
|
||||
#ifdef HAVE_MACHINE_ENDIAN_H
|
||||
# include <machine/endian.h>
|
||||
#endif /* HAVE_MACHINE_ENDIAN_H */
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif /* HAVE_ENDIAN_H */
|
||||
|
||||
#ifdef HAVE_SYS_ISA_DEFS_H
|
||||
# include <sys/isa_defs.h>
|
||||
#endif /* HAVE_SYS_ISA_DEFS_H */
|
||||
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN || defined(_LITTLE_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define PTPD_LSBF
|
||||
# elif BYTE_ORDER == BIG_ENDIAN || defined(_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define PTPD_MSBF
|
||||
# endif
|
||||
|
||||
#define CLOCK_IDENTITY_LENGTH 8
|
||||
#define ADJ_FREQ_MAX 500000
|
||||
|
||||
/* UDP/IPv4 dependent */
|
||||
#ifndef INADDR_LOOPBACK
|
||||
#define INADDR_LOOPBACK 0x7f000001UL
|
||||
#endif
|
||||
|
||||
#define SUBDOMAIN_ADDRESS_LENGTH 4
|
||||
#define PORT_ADDRESS_LENGTH 2
|
||||
#define PTP_UUID_LENGTH 6
|
||||
#define CLOCK_IDENTITY_LENGTH 8
|
||||
#define FLAG_FIELD_LENGTH 2
|
||||
|
||||
#define PACKET_SIZE 300 /* ptpdv1 value kept because of use of TLV...*/
|
||||
#define PACKET_BEGIN_UDP (ETHER_HDR_LEN + sizeof(struct ip) + \
|
||||
sizeof(struct udphdr))
|
||||
#define PACKET_BEGIN_ETHER (ETHER_HDR_LEN)
|
||||
|
||||
#define PTP_EVENT_PORT 319
|
||||
#define PTP_GENERAL_PORT 320
|
||||
|
||||
#define DEFAULT_PTP_DOMAIN_ADDRESS "224.0.1.129"
|
||||
#define PEER_PTP_DOMAIN_ADDRESS "224.0.0.107"
|
||||
|
||||
/* 802.3 Support */
|
||||
|
||||
#define PTP_ETHER_DST "01:1b:19:00:00:00"
|
||||
#define PTP_ETHER_TYPE 0x88f7
|
||||
#define PTP_ETHER_PEER "01:80:c2:00:00:0E"
|
||||
|
||||
/* dummy clock driver designation in preparation for generic clock driver API */
|
||||
#define DEFAULT_CLOCKDRIVER "kernelclock"
|
||||
/* default lock file location and mode */
|
||||
#define DEFAULT_LOCKMODE F_WRLCK
|
||||
#define DEFAULT_LOCKDIR "/var/run"
|
||||
#define DEFAULT_LOCKFILE_NAME PTPD_PROGNAME".lock"
|
||||
/*define DEFAULT_LOCKFILE_PATH DEFAULT_LOCKDIR"/"DEFAULT_LOCKFILE_NAME */
|
||||
#define DEFAULT_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
|
||||
|
||||
/* default drift file location */
|
||||
#define DEFAULT_DRIFTFILE "/etc/"PTPD_PROGNAME"_"DEFAULT_CLOCKDRIVER".drift"
|
||||
|
||||
/* default status file location */
|
||||
#define DEFAULT_STATUSFILE DEFAULT_LOCKDIR"/"PTPD_PROGNAME".status"
|
||||
|
||||
/* Highest log level (default) catches all */
|
||||
#define LOG_ALL LOG_DEBUGV
|
||||
|
||||
/* drift recovery metod for use with -F */
|
||||
enum {
|
||||
DRIFT_RESET = 0,
|
||||
DRIFT_KERNEL,
|
||||
DRIFT_FILE
|
||||
};
|
||||
/* IP transmission mode */
|
||||
enum {
|
||||
IPMODE_MULTICAST = 0,
|
||||
IPMODE_UNICAST,
|
||||
IPMODE_HYBRID,
|
||||
#if 0
|
||||
IPMODE_UNICAST_SIGNALING
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* servo dT calculation mode */
|
||||
enum {
|
||||
DT_NONE,
|
||||
DT_CONSTANT,
|
||||
DT_MEASURED
|
||||
};
|
||||
|
||||
#define MM_STARTING_BOUNDARY_HOPS 0x7fff
|
||||
|
||||
/* others */
|
||||
|
||||
/* bigger screen size constants */
|
||||
#define SCREEN_BUFSZ 228
|
||||
#define SCREEN_MAXSZ 180
|
||||
|
||||
/* default size for string buffers */
|
||||
#define BUF_SIZE 1000
|
||||
|
||||
#define NANOSECONDS_MAX 999999999
|
||||
|
||||
/* limit operator messages to once every X seconds */
|
||||
#define OPERATOR_MESSAGES_INTERVAL 300.0
|
||||
|
||||
#define MAXTIMESTR 32
|
||||
|
||||
#endif /*CONSTANTS_DEP_H_*/
|
||||
@@ -0,0 +1,379 @@
|
||||
/*-
|
||||
* Copyright (c) 2016-2017 Wind River Systems, Inc,
|
||||
* Copyright (c) 2013-2014 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
25jan17,xxy Add support for TSN Clocks and Timers (F6548)
|
||||
19aug16,xxy Fix overflow in PTP servo.(V7NET-1086)
|
||||
15aug16,xxy Add PTP features.(F6696)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file daemonconfig.c
|
||||
* @date Sun May 27 00:45:32 2013
|
||||
*
|
||||
* @brief Code to handle configuration file and default settings
|
||||
*
|
||||
* Functions in this file deal with config file parsing, reloading,
|
||||
* loading default parameters, parsing command-line options, printing
|
||||
* help output, etc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
|
||||
|
||||
|
||||
/* 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->ptp_profile = PTP_DEFAULT_PROFILE;
|
||||
rtOpts->announceInterval = DEFAULT_ANNOUNCE_INTERVAL;
|
||||
rtOpts->syncInterval = 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->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 = FALSE;
|
||||
|
||||
rtOpts->ip_mode = IPMODE_MULTICAST;
|
||||
|
||||
rtOpts->noAdjust = NO_ADJUST; /* false */
|
||||
rtOpts->logStatistics = FALSE;
|
||||
|
||||
/* Deep display of all packets seen by the daemon */
|
||||
rtOpts->displayPackets = FALSE;
|
||||
/* rtOpts->unicastAddress */
|
||||
|
||||
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->offset_first_updated = FALSE; */
|
||||
|
||||
/*
|
||||
* defaults for new options
|
||||
*/
|
||||
rtOpts->ignore_delayreq_interval_master = FALSE;
|
||||
rtOpts->do_IGMP_refresh = TRUE;
|
||||
rtOpts->announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
|
||||
rtOpts->debug_level = PTP_DEBUG_LEVEL_0;
|
||||
rtOpts->ttl = 64;
|
||||
rtOpts->delayMechanism = DEFAULT_DELAY_MECHANISM;
|
||||
rtOpts->noResetClock = DEFAULT_NO_RESET_CLOCK;
|
||||
rtOpts->stepOnce = FALSE;
|
||||
rtOpts->stepForce = FALSE;
|
||||
rtOpts->oneStepMode = FALSE;
|
||||
|
||||
rtOpts->clearCounters = FALSE;
|
||||
rtOpts->statisticsLogInterval = 0;
|
||||
|
||||
rtOpts->initial_delayreq = DEFAULT_DELAYREQ_INTERVAL;
|
||||
rtOpts->subsequent_delayreq = DEFAULT_DELAYREQ_INTERVAL; /* this will be updated if -g is given*/
|
||||
rtOpts->autoDelayReqInterval = TRUE;
|
||||
rtOpts->masterRefreshInterval = 60;
|
||||
|
||||
rtOpts->drift_recovery_method = DRIFT_KERNEL;
|
||||
|
||||
rtOpts->snmp_enabled = FALSE;
|
||||
/* This will only be used if the "none" preset is configured */
|
||||
rtOpts->slaveOnly = FALSE;
|
||||
/* Otherwise default to slave only via the preset */
|
||||
rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
|
||||
|
||||
/* highest possible */
|
||||
rtOpts->logLevel = LOG_ALL;
|
||||
|
||||
/* ADJ_FREQ_MAX by default */
|
||||
rtOpts->servoMaxPpb = ADJ_FREQ_MAX ;
|
||||
/* kP and kI are scaled to 10000 and are gains now - values same as originally */
|
||||
rtOpts->servoKP = 0.7;
|
||||
rtOpts->servoKI = 0.3;
|
||||
|
||||
rtOpts->servoDtMethod = DT_MEASURED;
|
||||
/* 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;
|
||||
rtOpts->alwaysRespectUtcOffset = FALSE;
|
||||
rtOpts->preferUtcValid = FALSE;
|
||||
rtOpts->requireUtcValid = FALSE;
|
||||
|
||||
/* Try 46 for expedited forwarding */
|
||||
rtOpts->dscpValue = 0;
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IT HAPPENS HERE
|
||||
*
|
||||
* Map all options from @dict dictionary to corresponding @rtopts fields,
|
||||
* using existing @rtopts fields as defaults. Return a dictionary free
|
||||
* of unknown options, with explicitly set defaults.
|
||||
* NOTE: when adding options, also map them in checkSubsystemRestart to
|
||||
* ensure correct config reload behaviour.
|
||||
*/
|
||||
void parseConfig (RunTimeOpts *rtOpts )
|
||||
{
|
||||
|
||||
Boolean parseResult = TRUE;
|
||||
|
||||
PtpEnginePreset ptpPreset;
|
||||
|
||||
|
||||
/* ==== Any additional logic should go here ===== */
|
||||
|
||||
rtOpts->ifaceName = rtOpts->primaryIfaceName;
|
||||
|
||||
/* Check timing packet ACLs */
|
||||
if (rtOpts->timingAclEnabled)
|
||||
{
|
||||
|
||||
int pResult, dResult;
|
||||
|
||||
if ((pResult = maskParser(rtOpts->timingAclPermitText, NULL)) == -1)
|
||||
printf("Error while parsing timing permit access list: \"%s\"\n",
|
||||
rtOpts->timingAclPermitText);
|
||||
|
||||
if ((dResult = maskParser(rtOpts->timingAclDenyText, NULL)) == -1)
|
||||
printf("Error while parsing timing deny access list: \"%s\"\n",
|
||||
rtOpts->timingAclDenyText);
|
||||
|
||||
/* -1 = ACL format error*/
|
||||
if (pResult == -1 || dResult == -1)
|
||||
{
|
||||
parseResult = FALSE;
|
||||
rtOpts->timingAclEnabled = FALSE;
|
||||
}
|
||||
|
||||
/* 0 = no entries - we simply don't match */
|
||||
if (pResult == 0 && dResult == 0)
|
||||
{
|
||||
rtOpts->timingAclEnabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check management message ACLs */
|
||||
if (rtOpts->managementAclEnabled)
|
||||
{
|
||||
|
||||
int pResult, dResult;
|
||||
|
||||
if ((pResult = maskParser(rtOpts->managementAclPermitText, NULL)) == -1)
|
||||
printf("Error while parsing management permit access list: \"%s\"\n",
|
||||
rtOpts->managementAclPermitText);
|
||||
|
||||
if ((dResult = maskParser(rtOpts->managementAclDenyText, NULL)) == -1)
|
||||
printf("Error while parsing management deny access list: \"%s\"\n",
|
||||
rtOpts->managementAclDenyText);
|
||||
|
||||
/* -1 = ACL format error*/
|
||||
if (pResult == -1 || dResult == -1)
|
||||
{
|
||||
parseResult = FALSE;
|
||||
rtOpts->managementAclEnabled = FALSE;
|
||||
}
|
||||
|
||||
/* 0 = no entries - we simply don't match */
|
||||
if (pResult == 0 && dResult == 0)
|
||||
{
|
||||
rtOpts->managementAclEnabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shift DSCP to accept the 6-bit value */
|
||||
rtOpts->dscpValue = rtOpts->dscpValue << 2;
|
||||
|
||||
/*
|
||||
* We're in hybrid mode and we haven't specified the delay request interval:
|
||||
* use override with a default value
|
||||
*/
|
||||
if ((rtOpts->ip_mode == IPMODE_HYBRID))
|
||||
{
|
||||
rtOpts->ignore_delayreq_interval_master = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're in unicast slave-capable mode and we haven't specified the delay request interval:
|
||||
* use override with a default value
|
||||
*/
|
||||
if ((rtOpts->ip_mode == IPMODE_UNICAST &&
|
||||
rtOpts->clockQuality.clockClass > 127))
|
||||
{
|
||||
rtOpts->ignore_delayreq_interval_master = TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ==== END additional logic */
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @file daemonconfig.h
|
||||
*
|
||||
* @brief definitions related to config file handling.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PTPD_DAEMONCONFIG_H_
|
||||
#define PTPD_DAEMONCONFIG_H_
|
||||
|
||||
|
||||
/* Config reload - component restart status flags */
|
||||
|
||||
/* No restart required - can continue with new config */
|
||||
#define PTPD_RESTART_NONE 1 << 0
|
||||
/* PTP port datasetw can be updated without restarting FSM */
|
||||
#define PTPD_UPDATE_DATASETS 1 << 1
|
||||
/* PTP FSM port re-initialisation required (PTP_INITIALIZING) */
|
||||
#define PTPD_RESTART_PROTOCOL 1 << 2
|
||||
/* Network config changed: PTP_INITIALIZING handles this so far */
|
||||
#define PTPD_RESTART_NETWORK 1 << 3
|
||||
/* Logging config changes: log files need closed / reopened */
|
||||
#define PTPD_RESTART_LOGGING 1 << 4
|
||||
/* Configuration changes need checking lock files */
|
||||
#define PTPD_CHECK_LOCKS 1 << 5
|
||||
/* CPU core has changed */
|
||||
#define PTPD_CHANGE_CPUAFFINITY 1 << 6
|
||||
/* Configuration changes require daemon restart */
|
||||
#define PTPD_RESTART_DAEMON 1 << 7
|
||||
|
||||
|
||||
#define PTPD_RESTART_ACLS 1 << 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*);
|
||||
|
||||
PtpEnginePreset getPtpPreset(int presetNumber, RunTimeOpts* rtOpts);
|
||||
void parseConfig (RunTimeOpts*);
|
||||
|
||||
#endif /*PTPD_DAEMONCONFIG_H_*/
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#ifndef DATATYPES_DEP_H_
|
||||
#define DATATYPES_DEP_H_
|
||||
|
||||
/**
|
||||
*\file
|
||||
* \brief Implementation specific datatype
|
||||
|
||||
*/
|
||||
/*typedef enum {FALSE_VALUE=0, TRUE_VALUE} Boolean;*/
|
||||
typedef uint32_t Boolean;
|
||||
typedef char Octet;
|
||||
typedef int8_t Integer8;
|
||||
typedef int16_t Integer16;
|
||||
typedef int32_t Integer32;
|
||||
typedef uint8_t UInteger8;
|
||||
typedef uint16_t UInteger16;
|
||||
typedef uint32_t UInteger32;
|
||||
typedef uint16_t Enumeration16;
|
||||
typedef unsigned char Enumeration8;
|
||||
typedef unsigned char Enumeration4;
|
||||
typedef unsigned char Enumeration4Upper;
|
||||
typedef unsigned char Enumeration4Lower;
|
||||
typedef unsigned char UInteger4;
|
||||
typedef unsigned char UInteger4Upper;
|
||||
typedef unsigned char UInteger4Lower;
|
||||
typedef unsigned char Nibble;
|
||||
typedef unsigned char NibbleUpper;
|
||||
typedef unsigned char NibbleLower;
|
||||
|
||||
/**
|
||||
* \brief Implementation specific of UInteger48 type
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t lsb;
|
||||
uint16_t msb;
|
||||
} UInteger48;
|
||||
|
||||
/**
|
||||
* \brief Implementation specific of Integer64 type
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t lsb;
|
||||
int32_t msb;
|
||||
} Integer64;
|
||||
|
||||
/**
|
||||
* \brief Struct used to average the offset from master
|
||||
*
|
||||
* The FIR filtering of the offset from master input is a simple, two-sample average
|
||||
*/
|
||||
typedef struct {
|
||||
Integer32 nsec_prev, y;
|
||||
} offset_from_master_filter;
|
||||
|
||||
/**
|
||||
* \brief Struct used to average the one way delay
|
||||
*
|
||||
* It is a variable cutoff/delay low-pass, infinite impulse response (IIR) filter.
|
||||
*
|
||||
* The one-way delay filter has the difference equation: s*y[n] - (s-1)*y[n-1] = x[n]/2 + x[n-1]/2, where increasing the stiffness (s) lowers the cutoff and increases the delay.
|
||||
*/
|
||||
typedef struct {
|
||||
Integer32 nsec_prev, y;
|
||||
Integer32 s_exp;
|
||||
} one_way_delay_filter;
|
||||
|
||||
/**
|
||||
* \brief Struct containing interface information and capabilities
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int flags;
|
||||
int addressFamily;
|
||||
Boolean hasHwAddress;
|
||||
Boolean hasAfAddress;
|
||||
unsigned char hwAddress[14];
|
||||
struct sockaddr afAddress;
|
||||
} InterfaceInfo;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Struct describing network transport data
|
||||
*/
|
||||
typedef struct {
|
||||
Integer32 eventSock, generalSock;
|
||||
Integer32 multicastAddr, peerMulticastAddr,unicastAddr;
|
||||
|
||||
/* Interface address and capability descriptor */
|
||||
InterfaceInfo interfaceInfo;
|
||||
char ethName[32];
|
||||
int ethIndex;
|
||||
void * ethCookie;
|
||||
struct Ip_sockaddr_ll layer2addr;
|
||||
|
||||
/* used by IGMP refresh */
|
||||
struct in_addr interfaceAddr;
|
||||
/* Typically MAC address - outer 6 octers of ClockIdendity */
|
||||
Octet interfaceID[ETHER_ADDR_LEN];
|
||||
/* used for Hybrid mode */
|
||||
Integer32 lastRecvAddr;
|
||||
|
||||
uint64_t sentPackets;
|
||||
uint64_t receivedPackets;
|
||||
|
||||
Integer32 headerOffset;
|
||||
|
||||
/* used for tracking the last TTL set */
|
||||
int ttlGeneral;
|
||||
int ttlEvent;
|
||||
Boolean joinedMulticast;
|
||||
struct ether_addr etherDest;
|
||||
struct ether_addr peerEtherDest;
|
||||
Boolean txTimestampFailure;
|
||||
|
||||
Ipv4AccessList* timingAcl;
|
||||
Ipv4AccessList* managementAcl;
|
||||
|
||||
} NetPath;
|
||||
|
||||
typedef struct {
|
||||
|
||||
char* logID;
|
||||
char* openMode;
|
||||
char logPath[PATH_MAX];
|
||||
FILE* logFP;
|
||||
|
||||
Boolean logEnabled;
|
||||
Boolean truncateOnReopen;
|
||||
Boolean unlinkOnClose;
|
||||
|
||||
UInteger32 maxSize;
|
||||
UInteger32 fileSize;
|
||||
int maxFiles;
|
||||
|
||||
} LogFileHandler;
|
||||
|
||||
|
||||
typedef struct{
|
||||
|
||||
UInteger8 minValue;
|
||||
UInteger8 maxValue;
|
||||
UInteger8 defaultValue;
|
||||
|
||||
} UInteger8_option;
|
||||
|
||||
typedef struct{
|
||||
|
||||
Integer32 minValue;
|
||||
Integer32 maxValue;
|
||||
Integer32 defaultValue;
|
||||
|
||||
} Integer32_option;
|
||||
|
||||
typedef struct{
|
||||
|
||||
UInteger32 minValue;
|
||||
UInteger32 maxValue;
|
||||
UInteger32 defaultValue;
|
||||
|
||||
} UInteger32_option;
|
||||
|
||||
typedef struct{
|
||||
|
||||
Integer16 minValue;
|
||||
Integer16 maxValue;
|
||||
Integer16 defaultValue;
|
||||
|
||||
} Integer16_option;
|
||||
|
||||
typedef struct{
|
||||
|
||||
UInteger16 minValue;
|
||||
UInteger16 maxValue;
|
||||
UInteger16 defaultValue;
|
||||
|
||||
} UInteger16_option;
|
||||
|
||||
#ifndef _WRS_CONFIG_ARCH_i86
|
||||
#if (_BYTE_ORDER == _BIG_ENDIAN)
|
||||
typedef union
|
||||
{
|
||||
double value;
|
||||
struct
|
||||
{
|
||||
UInteger32 msw;
|
||||
UInteger32 lsw;
|
||||
} parts;
|
||||
} ieee_double_shape_type;
|
||||
#else
|
||||
typedef union
|
||||
{
|
||||
double value;
|
||||
struct
|
||||
{
|
||||
UInteger32 lsw;
|
||||
UInteger32 msw;
|
||||
} parts;
|
||||
} ieee_double_shape_type;
|
||||
#endif
|
||||
|
||||
/* Get two 32 bit ints from a double. */
|
||||
#define EXTRACT_WORDS(ix0,ix1,d) \
|
||||
do { \
|
||||
ieee_double_shape_type ew_u; \
|
||||
ew_u.value = (d); \
|
||||
(ix0) = ew_u.parts.msw; \
|
||||
(ix1) = ew_u.parts.lsw; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Set a double from two 32 bit ints. */
|
||||
|
||||
#define INSERT_WORDS(d,ix0,ix1) \
|
||||
do { \
|
||||
ieee_double_shape_type iw_u; \
|
||||
iw_u.parts.msw = (ix0); \
|
||||
iw_u.parts.lsw = (ix1); \
|
||||
(d) = iw_u.value; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*DATATYPES_DEP_H_*/
|
||||
@@ -0,0 +1,493 @@
|
||||
/*-
|
||||
* Copyright (c) 2013-2014 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 ipv4_acl.c
|
||||
* @date Sun Oct 13 21:02:23 2013
|
||||
*
|
||||
* @brief Code to handle IPv4 access control lists
|
||||
*
|
||||
* Functions in this file parse, create and match IPv4 ACLs.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
#include "string.h"
|
||||
|
||||
/**
|
||||
* strdup + free are used across code using strtok_r, so as to
|
||||
* protect the original string, as strtok* modify it.
|
||||
*/
|
||||
|
||||
/* count tokens in string delimited by delim */
|
||||
static int countTokens(const char* text, const char* delim) {
|
||||
|
||||
int count=0;
|
||||
char* stash = NULL;
|
||||
char* text_;
|
||||
char* text__;
|
||||
|
||||
if(text==NULL || delim==NULL)
|
||||
return 0;
|
||||
|
||||
text_=strdup(text);
|
||||
|
||||
for(text__=text_,count=0;strtok_r(text__,delim, &stash) != NULL; text__=NULL) {
|
||||
count++;
|
||||
}
|
||||
free(text_);
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/* Parse a dotted-decimal string into an uint8_t array - return -1 on error */
|
||||
static int ipToArray(const char* text, uint8_t dest[], int maxOctets, Boolean isMask)
|
||||
{
|
||||
|
||||
char* text_;
|
||||
char* text__;
|
||||
char* subtoken;
|
||||
char* stash = NULL;
|
||||
char* endptr;
|
||||
long octet;
|
||||
|
||||
int count = 0;
|
||||
int result = 0;
|
||||
|
||||
memset(&dest[0], 0, maxOctets * sizeof(uint8_t));
|
||||
|
||||
text_=strdup(text);
|
||||
|
||||
for(text__=text_;;text__=NULL) {
|
||||
|
||||
if(count > maxOctets) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
subtoken = strtok_r(text__,".",&stash);
|
||||
|
||||
if(subtoken == NULL)
|
||||
goto end;
|
||||
|
||||
errno = 0;
|
||||
octet=strtol(subtoken,&endptr,10);
|
||||
if(errno!=0 || !IN_RANGE(octet,0,255)) {
|
||||
result = -1;
|
||||
goto end;
|
||||
|
||||
}
|
||||
|
||||
dest[count++] = (uint8_t)octet;
|
||||
|
||||
/* If we're parsing a mask and an octet is less than 0xFF, whole rest is zeros */
|
||||
if(isMask && octet < 255)
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
free(text_);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* Parse a single net mask into an AclEntry */
|
||||
static int parseAclEntry(const char* line, AclEntry* acl) {
|
||||
|
||||
int result = 1;
|
||||
char* stash;
|
||||
char* text_;
|
||||
char* token;
|
||||
char* endptr;
|
||||
long octet = 0;
|
||||
|
||||
uint8_t net_octets[4];
|
||||
uint8_t mask_octets[4];
|
||||
|
||||
if(line == NULL || acl == NULL)
|
||||
return -1;
|
||||
|
||||
if(countTokens(line,"/") == 0)
|
||||
return -1;
|
||||
|
||||
text_=strdup(line);
|
||||
|
||||
token=strtok_r(text_,"/",&stash);
|
||||
|
||||
if((countTokens(token,".") > 4) ||
|
||||
(countTokens(token,".") < 1) ||
|
||||
(ipToArray(token,net_octets,4,0) < 0)) {
|
||||
result=-1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
acl->network = (net_octets[0] << 24) | (net_octets[1] << 16) | ( net_octets[2] << 8) | net_octets[3];
|
||||
|
||||
token=strtok_r(NULL,"/",&stash);
|
||||
|
||||
if(token == NULL) {
|
||||
acl->netmask=32;
|
||||
acl->bitmask=~0;
|
||||
} else if(countTokens(token,".") == 1) {
|
||||
errno = 0;
|
||||
octet = strtol(token,&endptr,10);
|
||||
if(errno != 0 || !IN_RANGE(octet,0,32)) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(octet == 0)
|
||||
acl->bitmask = 0;
|
||||
else
|
||||
acl->bitmask = ~0 << (32 - octet);
|
||||
acl->netmask = (uint16_t)octet;
|
||||
|
||||
} else if((countTokens(token,".") > 4) ||
|
||||
(ipToArray(token,mask_octets,4,1) < 0)) {
|
||||
result=-1;
|
||||
goto end;
|
||||
} else {
|
||||
|
||||
acl->bitmask = (mask_octets[0] << 24) | (mask_octets[1] << 16) | ( mask_octets[2] << 8) | mask_octets[3];
|
||||
uint32_t tmp = acl->bitmask;
|
||||
int count = 0;
|
||||
for(tmp = acl->bitmask;tmp<<count;count++);
|
||||
acl->netmask=count;
|
||||
}
|
||||
|
||||
end:
|
||||
free(text_);
|
||||
|
||||
acl->network &= acl->bitmask;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* qsort() compare function for sorting ACL entries */
|
||||
static int
|
||||
cmpAclEntry(const void *p1, const void *p2)
|
||||
{
|
||||
|
||||
const AclEntry *left = p1;
|
||||
const AclEntry *right = p2;
|
||||
|
||||
if(left->network > right->network)
|
||||
return 1;
|
||||
if(left->network < right->network)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Parse an ACL string into an aclEntry table and return number of entries. output can be NULL */
|
||||
int
|
||||
maskParser(const char* input, AclEntry* output)
|
||||
{
|
||||
|
||||
char* token;
|
||||
char* stash;
|
||||
int found = 0;
|
||||
char* text_;
|
||||
char* text__;
|
||||
AclEntry tmp;
|
||||
|
||||
memset(&tmp,0,sizeof(AclEntry));
|
||||
|
||||
if(strlen(input)==0) return 0;
|
||||
|
||||
text_=strdup(input);
|
||||
|
||||
for(text__=text_;;text__=NULL) {
|
||||
|
||||
token=strtok_r(text__,", ;\t",&stash);
|
||||
if(token==NULL) break;
|
||||
|
||||
if(parseAclEntry(token,&tmp)<1) {
|
||||
|
||||
found = -1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(output != NULL)
|
||||
output[found]=tmp;
|
||||
|
||||
found++;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if((found>0) && (output != NULL))
|
||||
qsort(output, found, sizeof(AclEntry), cmpAclEntry);
|
||||
|
||||
/* We got input but found nothing - error */
|
||||
if (!found)
|
||||
found = -1;
|
||||
|
||||
free(text_);
|
||||
return found;
|
||||
|
||||
}
|
||||
|
||||
/* Create a maskTable from a text ACL */
|
||||
static MaskTable*
|
||||
createMaskTable(const char* input)
|
||||
{
|
||||
MaskTable* ret;
|
||||
int masksFound = maskParser(input, NULL);
|
||||
if(masksFound>=0) {
|
||||
ret=(MaskTable*)calloc(1,sizeof(MaskTable));
|
||||
if(ret == NULL)
|
||||
return NULL;
|
||||
ret->entries = (AclEntry*)calloc(masksFound, sizeof(AclEntry));
|
||||
if(ret->entries == NULL)
|
||||
{
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->numEntries = maskParser(input,ret->entries);
|
||||
return ret;
|
||||
} else {
|
||||
printf("Error while parsing access list: \"%s\"\n", input);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the contents of a single mask table */
|
||||
static void
|
||||
dumpMaskTable(MaskTable* table)
|
||||
{
|
||||
int i;
|
||||
uint32_t network;
|
||||
if(table == NULL)
|
||||
return;
|
||||
INFO("number of entries: %d\n",table->numEntries);
|
||||
if(table->entries != NULL) {
|
||||
for(i = 0; i < table->numEntries; i++) {
|
||||
AclEntry this = table->entries[i];
|
||||
#ifdef PTPD_MSBF
|
||||
network = this.network;
|
||||
#else
|
||||
network = htonl(this.network);
|
||||
#endif
|
||||
INFO("%d.%d.%d.%d/%d\t(0x%.8x/0x%.8x), matches: %d\n",
|
||||
*((uint8_t*)&network), *((uint8_t*)&network+1),
|
||||
*((uint8_t*)&network+2), *((uint8_t*)&network+3), this.netmask,
|
||||
this.network, this.bitmask, this.hitCount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Free a MaskTable structure */
|
||||
static void freeMaskTable(MaskTable** table)
|
||||
{
|
||||
if(*table == NULL)
|
||||
return;
|
||||
|
||||
if((*table)->entries != NULL) {
|
||||
free((*table)->entries);
|
||||
(*table)->entries = NULL;
|
||||
}
|
||||
free(*table);
|
||||
*table = NULL;
|
||||
}
|
||||
|
||||
/* Destroy an Ipv4AccessList structure */
|
||||
void
|
||||
freeIpv4AccessList(Ipv4AccessList** acl)
|
||||
{
|
||||
if(*acl == NULL)
|
||||
return;
|
||||
|
||||
freeMaskTable(&(*acl)->permitTable);
|
||||
freeMaskTable(&(*acl)->denyTable);
|
||||
|
||||
free(*acl);
|
||||
*acl = NULL;
|
||||
}
|
||||
|
||||
/* Structure initialisation for Ipv4AccessList */
|
||||
Ipv4AccessList*
|
||||
createIpv4AccessList(const char* permitList, const char* denyList, int processingOrder)
|
||||
{
|
||||
Ipv4AccessList* ret;
|
||||
ret = (Ipv4AccessList*)calloc(1,sizeof(Ipv4AccessList));
|
||||
if(ret == NULL)
|
||||
return NULL;
|
||||
ret->permitTable = createMaskTable(permitList);
|
||||
ret->denyTable = createMaskTable(denyList);
|
||||
if(ret->permitTable == NULL || ret->denyTable == NULL) {
|
||||
freeIpv4AccessList(&ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->processingOrder = processingOrder;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Match an IP address against a MaskTable */
|
||||
static int
|
||||
matchAddress(const uint32_t addr, MaskTable* table)
|
||||
{
|
||||
|
||||
int i;
|
||||
if(table == NULL || table->entries == NULL || table->numEntries==0)
|
||||
return -1;
|
||||
for(i = 0; i < table->numEntries; i++) {
|
||||
DBGV("addr: %08x, addr & mask: %08x, network: %08x\n",addr, table->entries[i].bitmask & addr, table->entries[i].network);
|
||||
if((table->entries[i].bitmask & addr) == table->entries[i].network) {
|
||||
table->entries[i].hitCount++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Test an IP address against an ACL */
|
||||
int
|
||||
matchIpv4AccessList(Ipv4AccessList* acl, const uint32_t addr)
|
||||
{
|
||||
|
||||
int ret;
|
||||
int matchPermit = 0;
|
||||
int matchDeny = 0;
|
||||
|
||||
/* Non-functional ACL permits everything */
|
||||
if(acl == NULL)
|
||||
return 1;
|
||||
|
||||
if(acl->permitTable != NULL)
|
||||
matchPermit = matchAddress(addr,acl->permitTable) > 0;
|
||||
|
||||
if(acl->denyTable != NULL)
|
||||
matchDeny = matchAddress(addr,acl->denyTable) > 0;
|
||||
|
||||
switch(acl->processingOrder) {
|
||||
case ACL_PERMIT_DENY:
|
||||
if(!matchPermit) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if(matchDeny) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
case ACL_DENY_PERMIT:
|
||||
if (matchDeny && !matchPermit) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if(ret)
|
||||
acl->passedCounter++;
|
||||
else
|
||||
acl->droppedCounter++;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Dump the contents and hit counters of an ACL */
|
||||
void dumpIpv4AccessList(Ipv4AccessList* acl)
|
||||
{
|
||||
|
||||
INFO("\n\n");
|
||||
if(acl == NULL) {
|
||||
INFO("(uninitialised ACL)\n");
|
||||
return;
|
||||
}
|
||||
switch(acl->processingOrder) {
|
||||
case ACL_DENY_PERMIT:
|
||||
INFO("ACL order: deny,permit\n");
|
||||
INFO("Passed packets: %d, dropped packets: %d\n",
|
||||
acl->passedCounter, acl->droppedCounter);
|
||||
INFO("--------\n");
|
||||
INFO("Deny list:\n");
|
||||
dumpMaskTable(acl->denyTable);
|
||||
INFO("--------\n");
|
||||
INFO("Permit list:\n");
|
||||
dumpMaskTable(acl->permitTable);
|
||||
break;
|
||||
case ACL_PERMIT_DENY:
|
||||
default:
|
||||
INFO("ACL order: permit,deny\n");
|
||||
INFO("Passed packets: %d, dropped packets: %d\n",
|
||||
acl->passedCounter, acl->droppedCounter);
|
||||
INFO("--------\n");
|
||||
INFO("Permit list:\n");
|
||||
dumpMaskTable(acl->permitTable);
|
||||
INFO("--------\n");
|
||||
INFO("Deny list:\n");
|
||||
dumpMaskTable(acl->denyTable);
|
||||
break;
|
||||
}
|
||||
INFO("\n\n");
|
||||
}
|
||||
|
||||
/* Clear counters in a MaskTable */
|
||||
static void
|
||||
clearMaskTableCounters(MaskTable* table)
|
||||
{
|
||||
|
||||
int i, count;
|
||||
if(table==NULL || table->numEntries==0)
|
||||
return;
|
||||
count = table->numEntries;
|
||||
|
||||
for(i=0; i<count; i++) {
|
||||
table->entries[i].hitCount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Clear ACL counter */
|
||||
void clearIpv4AccessListCounters(Ipv4AccessList* acl) {
|
||||
|
||||
if(acl == NULL)
|
||||
return;
|
||||
acl->passedCounter=0;
|
||||
acl->droppedCounter=0;
|
||||
clearMaskTableCounters(acl->permitTable);
|
||||
clearMaskTableCounters(acl->denyTable);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file ipv4_acl.h
|
||||
*
|
||||
* @brief definitions related to IPv4 access control list handling
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PTPD_IPV4_ACL_H_
|
||||
#define PTPD_IPV4_ACL_H_
|
||||
|
||||
#define IN_RANGE(num, min,max) \
|
||||
(num >= min && num <= max)
|
||||
|
||||
enum {
|
||||
ACL_PERMIT_DENY,
|
||||
ACL_DENY_PERMIT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t network;
|
||||
uint32_t bitmask;
|
||||
uint16_t netmask;
|
||||
uint32_t hitCount;
|
||||
} AclEntry;
|
||||
|
||||
typedef struct {
|
||||
int numEntries;
|
||||
AclEntry* entries;
|
||||
} MaskTable;
|
||||
|
||||
typedef struct {
|
||||
MaskTable* permitTable;
|
||||
MaskTable* denyTable;
|
||||
int processingOrder;
|
||||
uint32_t passedCounter;
|
||||
uint32_t droppedCounter;
|
||||
} Ipv4AccessList;
|
||||
|
||||
/* Parse string into AclEntry array */
|
||||
int maskParser(const char* input, AclEntry* output);
|
||||
/* Destroy an Ipv4AccessList structure */
|
||||
void freeIpv4AccessList(Ipv4AccessList** acl);
|
||||
/* Initialise an Ipv4AccessList structure */
|
||||
Ipv4AccessList* createIpv4AccessList(const char* permitList, const char* denyList, int processingOrder);
|
||||
/* Match on an IP address */
|
||||
int matchIpv4AccessList(Ipv4AccessList* acl, const uint32_t addr);
|
||||
/* Display the contents and hit counters of an access list */
|
||||
void dumpIpv4AccessList(Ipv4AccessList* acl);
|
||||
/* Clear counters */
|
||||
void clearIpv4AccessListCounters(Ipv4AccessList* acl);
|
||||
|
||||
#endif /* PTPD_IPV4_ACL_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* @file ptpd_dep.h
|
||||
*
|
||||
* @brief External definitions for inclusion elsewhere.
|
||||
*
|
||||
*
|
||||
*/
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
25jan17,xxy Add support for TSN Clocks and Timers (F6548)
|
||||
01nov16,myt Add PTP features.(F7726)
|
||||
15aug16,xxy Add PTP features.(F6696)
|
||||
13jun16,xxy Add PTP one-step hardware Tx timeStamp
|
||||
*/
|
||||
#ifndef PTPD_DEP_H_
|
||||
#define PTPD_DEP_H_
|
||||
|
||||
#ifdef RUNTIME_DEBUG
|
||||
#undef PTPD_DBGV
|
||||
#define PTPD_DBGV
|
||||
#endif
|
||||
|
||||
/** \name System messages*/
|
||||
/**\{*/
|
||||
|
||||
|
||||
/* Syslog ordering. We define extra debug levels above LOG_DEBUG for internal use - but message() doesn't pass these to SysLog */
|
||||
|
||||
/* extended from <sys/syslog.h> */
|
||||
#define LOG_DEBUG1 7
|
||||
#define LOG_DEBUG2 8
|
||||
#define LOG_DEBUG3 9
|
||||
#define LOG_DEBUGV 9
|
||||
|
||||
|
||||
#define EMERGENCY(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define ALERT(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define CRITICAL(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define ERROR_LOG(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define PERROR(x, ...) (void)printf( x " (strerror: %m)\n", ##__VA_ARGS__)
|
||||
#define WARNING(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define NOTIFY(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define NOTICE(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
#define INFO(x, ...) (void)printf( x, ##__VA_ARGS__)
|
||||
|
||||
#include <assert.h>
|
||||
#include <endCommon.h>
|
||||
|
||||
|
||||
/*
|
||||
list of per-module defines:
|
||||
|
||||
./dep/sys.c:#define PRINT_MAC_ADDRESSES
|
||||
./dep/timer.c:#define US_TIMER_INTERVAL 125000
|
||||
*/
|
||||
#define USE_BINDTODEVICE
|
||||
|
||||
|
||||
|
||||
/* enable this line to show debug numbers in nanoseconds instead of microseconds
|
||||
#define DEBUG_IN_NS */
|
||||
|
||||
#define DBG_UNIT_US (1000)
|
||||
#define DBG_UNIT_NS (1)
|
||||
|
||||
#ifdef DEBUG_IN_NS
|
||||
#define DBG_UNIT DBG_UNIT_NS
|
||||
#else
|
||||
#define DBG_UNIT DBG_UNIT_US
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef PTPD_DBGV
|
||||
#define DBGV(x, ...) printf( x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DBGV(x, ...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* new debug level DBG2:
|
||||
* this is above DBG(), but below DBGV() (to avoid changing hundreds of lines)
|
||||
*/
|
||||
|
||||
#ifdef PTPD_DBG2
|
||||
#define DBG2(x, ...) printf( x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DBG2(x, ...)
|
||||
#endif
|
||||
|
||||
#ifdef PTPD_DBG
|
||||
#define DBG(x, ...) printf( x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DBG(x, ...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/** \}*/
|
||||
|
||||
/** \name Endian corrections*/
|
||||
/**\{*/
|
||||
|
||||
#if defined(PTPD_MSBF)
|
||||
#define shift8(x,y) ( (x) << ((3-y)<<3) )
|
||||
#define shift16(x,y) ( (x) << ((1-y)<<4) )
|
||||
#elif defined(PTPD_LSBF)
|
||||
#define shift8(x,y) ( (x) << ((y)<<3) )
|
||||
#define shift16(x,y) ( (x) << ((y)<<4) )
|
||||
#endif
|
||||
|
||||
#define flip16(x) htons(x)
|
||||
#define flip32(x) htonl(x)
|
||||
|
||||
/* i don't know any target platforms that do not have htons and htonl,
|
||||
but here are generic funtions just in case */
|
||||
/*
|
||||
#if defined(PTPD_MSBF)
|
||||
#define flip16(x) (x)
|
||||
#define flip32(x) (x)
|
||||
#elif defined(PTPD_LSBF)
|
||||
static inline Integer16 flip16(Integer16 x)
|
||||
{
|
||||
return (((x) >> 8) & 0x00ff) | (((x) << 8) & 0xff00);
|
||||
}
|
||||
|
||||
static inline Integer32 flip32(x)
|
||||
{
|
||||
return (((x) >> 24) & 0x000000ff) | (((x) >> 8 ) & 0x0000ff00) |
|
||||
(((x) << 8 ) & 0x00ff0000) | (((x) << 24) & 0xff000000);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
/** \}*/
|
||||
|
||||
|
||||
/** \name Bit array manipulations*/
|
||||
/**\{*/
|
||||
|
||||
#define getFlag(x,y) !!( *(UInteger8*)((x)+((y)<8?1:0)) & (1<<((y)<8?(y):(y)-8)) )
|
||||
#define setFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) |= 1<<((y)<8?(y):(y)-8) )
|
||||
#define clearFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) &= ~(1<<((y)<8?(y):(y)-8)) )
|
||||
/** \}*/
|
||||
|
||||
/** \name msg.c
|
||||
*-Pack and unpack PTP messages */
|
||||
/**\{*/
|
||||
|
||||
void msgUnpackHeader(Octet * buf,MsgHeader*);
|
||||
void msgUnpackAnnounce (Octet * buf,MsgAnnounce*);
|
||||
void msgUnpackSync(Octet * buf,MsgSync*);
|
||||
void msgUnpackFollowUp(Octet * buf,MsgFollowUp*);
|
||||
void msgUnpackDelayReq(Octet * buf, MsgDelayReq * delayreq);
|
||||
void msgUnpackDelayResp(Octet * buf,MsgDelayResp *);
|
||||
void msgUnpackPDelayReq(Octet * buf,MsgPDelayReq*);
|
||||
void msgUnpackPDelayResp(Octet * buf,MsgPDelayResp*);
|
||||
void msgUnpackPDelayRespFollowUp(Octet * buf,MsgPDelayRespFollowUp*);
|
||||
void msgUnpackManagement(Octet * buf,MsgManagement*, MsgHeader*, PtpClock *ptpClock);
|
||||
void msgPackHeader(Octet * buf,PtpClock*);
|
||||
void msgPackAnnounce(Octet * buf,PtpClock*,RunTimeOpts *);
|
||||
void msgPackSync(Octet * buf,Timestamp*,PtpClock*,RunTimeOpts *);
|
||||
void msgPackFollowUp(Octet * buf,Timestamp*,PtpClock*, const UInteger16,RunTimeOpts *);
|
||||
void msgPackDelayReq(Octet * buf,Timestamp *,PtpClock *);
|
||||
void msgPackDelayResp(Octet * buf,MsgHeader *,Timestamp *,PtpClock *,RunTimeOpts *);
|
||||
void msgPackPDelayReq(Octet * buf,Timestamp*,PtpClock*,RunTimeOpts *);
|
||||
void msgPackPDelayResp(Octet * buf,MsgHeader*,Timestamp*,PtpClock*);
|
||||
void msgPackPDelayRespFollowUp(Octet * buf,MsgHeader*,Timestamp*,PtpClock*, const UInteger16);
|
||||
void msgPackManagement(Octet * buf,MsgManagement*,PtpClock*);
|
||||
void msgPackManagementRespAck(Octet *,MsgManagement*,PtpClock*);
|
||||
void msgPackManagementTLV(Octet *,MsgManagement*, PtpClock*);
|
||||
void msgPackManagementErrorStatusTLV(Octet *,MsgManagement*,PtpClock*);
|
||||
|
||||
void freeMMErrorStatusTLV(ManagementTLV*);
|
||||
void freeMMTLV(ManagementTLV*);
|
||||
|
||||
void msgDump(PtpClock *ptpClock);
|
||||
void msgDebugHeader(MsgHeader *header);
|
||||
void msgDebugSync(MsgSync *sync);
|
||||
void msgDebugAnnounce(MsgAnnounce *announce);
|
||||
void msgDebugDelayReq(MsgDelayReq *req);
|
||||
void msgDebugFollowUp(MsgFollowUp *follow);
|
||||
void msgDebugDelayResp(MsgDelayResp *resp);
|
||||
void msgDebugManagement(MsgManagement *manage);
|
||||
|
||||
void copyClockIdentity( ClockIdentity dest, ClockIdentity src);
|
||||
void copyPortIdentity( PortIdentity * dest, PortIdentity * src);
|
||||
|
||||
void unpackMsgManagement(Octet *, MsgManagement*, PtpClock*);
|
||||
void packMsgManagement(MsgManagement*, Octet *);
|
||||
void unpackManagementTLV(Octet*, MsgManagement*, PtpClock*);
|
||||
void packManagementTLV(ManagementTLV*, Octet*);
|
||||
void freeManagementTLV(MsgManagement*);
|
||||
void unpackMMClockDescription( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMClockDescription( MsgManagement*, Octet*);
|
||||
void freeMMClockDescription( MMClockDescription*);
|
||||
void unpackMMUserDescription( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMUserDescription( MsgManagement*, Octet*);
|
||||
void freeMMUserDescription( MMUserDescription*);
|
||||
void unpackMMErrorStatus( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMErrorStatus( MsgManagement*, Octet*);
|
||||
void freeMMErrorStatus( MMErrorStatus*);
|
||||
void unpackMMInitialize( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMInitialize( MsgManagement*, Octet*);
|
||||
void unpackMMDefaultDataSet( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMDefaultDataSet( MsgManagement*, Octet*);
|
||||
void unpackMMCurrentDataSet( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMCurrentDataSet( MsgManagement*, Octet*);
|
||||
void unpackMMParentDataSet( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMParentDataSet( MsgManagement*, Octet*);
|
||||
void unpackMMTimePropertiesDataSet( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMTimePropertiesDataSet( MsgManagement*, Octet*);
|
||||
void unpackMMPortDataSet( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMPortDataSet( MsgManagement*, Octet*);
|
||||
void unpackMMPriority1( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMPriority1( MsgManagement*, Octet*);
|
||||
void unpackMMPriority2( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMPriority2( MsgManagement*, Octet*);
|
||||
void unpackMMDomain( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMDomain( MsgManagement*, Octet*);
|
||||
void unpackMMSlaveOnly( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMSlaveOnly( MsgManagement*, Octet* );
|
||||
void unpackMMLogAnnounceInterval( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMLogAnnounceInterval( MsgManagement*, Octet*);
|
||||
void unpackMMAnnounceReceiptTimeout( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMAnnounceReceiptTimeout( MsgManagement*, Octet*);
|
||||
void unpackMMLogSyncInterval( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMLogSyncInterval( MsgManagement*, Octet*);
|
||||
void unpackMMVersionNumber( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMVersionNumber( MsgManagement*, Octet*);
|
||||
void unpackMMTime( Octet* buf, MsgManagement*, PtpClock * );
|
||||
UInteger16 packMMTime( MsgManagement*, Octet*);
|
||||
void unpackMMClockAccuracy( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMClockAccuracy( MsgManagement*, Octet*);
|
||||
void unpackMMUtcProperties( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMUtcProperties( MsgManagement*, Octet*);
|
||||
void unpackMMTraceabilityProperties( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMTraceabilityProperties( MsgManagement*, Octet*);
|
||||
void unpackMMDelayMechanism( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMDelayMechanism( MsgManagement*, Octet*);
|
||||
void unpackMMLogMinPdelayReqInterval( Octet* buf, MsgManagement*, PtpClock* );
|
||||
UInteger16 packMMLogMinPdelayReqInterval( MsgManagement*, Octet*);
|
||||
|
||||
|
||||
void unpackPortAddress( Octet* buf, PortAddress*, PtpClock*);
|
||||
void packPortAddress( PortAddress*, Octet*);
|
||||
void freePortAddress( PortAddress*);
|
||||
void unpackPTPText( Octet* buf, PTPText*, PtpClock*);
|
||||
void packPTPText( PTPText*, Octet*);
|
||||
void freePTPText( PTPText*);
|
||||
void unpackPhysicalAddress( Octet* buf, PhysicalAddress*, PtpClock*);
|
||||
void packPhysicalAddress( PhysicalAddress*, Octet*);
|
||||
void freePhysicalAddress( PhysicalAddress*);
|
||||
void unpackClockIdentity( Octet* buf, ClockIdentity *c, PtpClock*);
|
||||
void packClockIdentity( ClockIdentity *c, Octet* buf);
|
||||
void freeClockIdentity( ClockIdentity *c);
|
||||
void unpackClockQuality( Octet* buf, ClockQuality *c, PtpClock*);
|
||||
void packClockQuality( ClockQuality *c, Octet* buf);
|
||||
void freeClockQuality( ClockQuality *c);
|
||||
void unpackTimeInterval( Octet* buf, TimeInterval *t, PtpClock*);
|
||||
void packTimeInterval( TimeInterval *t, Octet* buf);
|
||||
void freeTimeInterval( TimeInterval *t);
|
||||
void unpackPortIdentity( Octet* buf, PortIdentity *p, PtpClock*);
|
||||
void packPortIdentity( PortIdentity *p, Octet* buf);
|
||||
void freePortIdentity( PortIdentity *p);
|
||||
void unpackTimestamp( Octet* buf, Timestamp *t, PtpClock*);
|
||||
void packTimestamp( Timestamp *t, Octet* buf);
|
||||
void freeTimestamp( Timestamp *t);
|
||||
UInteger16 msgPackManagementResponse(Octet * buf,MsgHeader*,MsgManagement*,PtpClock*);
|
||||
/** \}*/
|
||||
|
||||
/** \name net.c (Unix API dependent)
|
||||
* -Init network stuff, send and receive datas*/
|
||||
/**\{*/
|
||||
|
||||
Boolean netInit(NetPath*,RunTimeOpts*,PtpClock*);
|
||||
Boolean netShutdown(RunTimeOpts*,NetPath*);
|
||||
int netSelect(RunTimeOpts *,TimeInternal*,NetPath*,fd_set*);
|
||||
ssize_t netRecvEvent(Octet*,TimeInternal*,NetPath*,int);
|
||||
ssize_t netRecvGeneral(Octet*,NetPath*);
|
||||
ssize_t netSendEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*,Integer32,TimeInternal*);
|
||||
ssize_t netSendGeneral(Octet*,UInteger16,NetPath*,RunTimeOpts*,Integer32 );
|
||||
ssize_t netSendPeerGeneral(Octet*,UInteger16,NetPath*,RunTimeOpts*);
|
||||
ssize_t netSendPeerEvent(Octet*,UInteger16,PtpClock*,RunTimeOpts*,TimeInternal*);
|
||||
Boolean netRefreshIGMP(NetPath *, RunTimeOpts *, PtpClock *);
|
||||
Boolean hostLookup(const char* hostname, Integer32* addr);
|
||||
|
||||
int netSetSysTime (void * ethCookie, struct timespec * ts);
|
||||
int netGetSysTime (void * ethCookie, struct timespec * ts);
|
||||
int netAdjustFreq (void * ethCookie, INT32 adj);
|
||||
int netGetSysIntervalTime (void * ethCookie, IEEE1588_TIMER_SYNC * sync);
|
||||
int netGetSysSyncDelayTime (void * ethCookie, long * delay);
|
||||
int netSetSysIntervalTime (void * ethCookie, IEEE1588_TIMER_SYNC * sync);
|
||||
int netSetSysTimeAdd (void *ethCookie, INT64 * counts);
|
||||
|
||||
int netEnableHwTimeStamp (void * ethCookie, UINT8 enable);
|
||||
Boolean netGetHwTimeStampCap (void * ethCookie);
|
||||
Boolean netGetHwOneStepCap (void * ethCookie);
|
||||
|
||||
|
||||
/** \}*/
|
||||
|
||||
/** \name servo.c
|
||||
* -Clock servo*/
|
||||
/**\{*/
|
||||
|
||||
void initClock(RunTimeOpts*,PtpClock*);
|
||||
void updatePeerDelay (one_way_delay_filter*, RunTimeOpts*,PtpClock*,TimeInternal*,Boolean);
|
||||
void updateDelay (one_way_delay_filter*, RunTimeOpts*, PtpClock*,TimeInternal*);
|
||||
void updateOffset(TimeInternal*,TimeInternal*,
|
||||
offset_from_master_filter*,RunTimeOpts*,PtpClock*,TimeInternal*);
|
||||
void updateClock(RunTimeOpts*,PtpClock*);
|
||||
|
||||
void servo_perform_clock_step(RunTimeOpts * rtOpts, PtpClock * ptpClock);
|
||||
|
||||
PtpClock * ptpdStartup(int slaveMaster, RunTimeOpts * rtOpts);
|
||||
void ptpdShutdown(RunTimeOpts * rtOpts, PtpClock * ptpClock);
|
||||
|
||||
|
||||
void enable_runtime_debug(void );
|
||||
void disable_runtime_debug(void );
|
||||
|
||||
#define D_ON do { enable_runtime_debug(); } while (0);
|
||||
#define D_OFF do { disable_runtime_debug( ); } while (0);
|
||||
|
||||
|
||||
/** \}*/
|
||||
|
||||
/** \name sys.c (Unix API dependent)
|
||||
* -Manage timing system API*/
|
||||
/**\{*/
|
||||
|
||||
/* new debug methods to debug time variables */
|
||||
char *time2st(const TimeInternal * p);
|
||||
void DBG_time(const char *name, const TimeInternal p);
|
||||
|
||||
|
||||
void logStatistics(RunTimeOpts *rtOpts, PtpClock *ptpClock);
|
||||
void ShowStatistics(RunTimeOpts * rtOpts, PtpClock * ptpClock);
|
||||
void displayStatus(const RunTimeOpts *rtOpts,PtpClock *ptpClock, const char *prefixMessage);
|
||||
void displayPortIdentity(PortIdentity *port, const char *prefixMessage);
|
||||
void getTime(RunTimeOpts * ,TimeInternal*);
|
||||
void setTime(RunTimeOpts * ,TimeInternal*);
|
||||
|
||||
double getRand(void);
|
||||
|
||||
|
||||
#ifndef HAVE_SYS_TIMEX_H
|
||||
void adjTime(Integer32);
|
||||
#else
|
||||
|
||||
void adjFreq_wrapper(RunTimeOpts * rtOpts, PtpClock * ptpClock, double adj);
|
||||
Boolean adjFreq(RunTimeOpts *,double);
|
||||
double getAdjFreq(void);
|
||||
void informClockSource(PtpClock* ptpClock);
|
||||
|
||||
/* Observed drift save / recovery functions */
|
||||
void restoreDrift(PtpClock * ptpClock, RunTimeOpts * rtOpts, Boolean quiet);
|
||||
void saveDrift(PtpClock * ptpClock, RunTimeOpts * rtOpts, Boolean quiet);
|
||||
|
||||
/* Helper function to manage ntpadjtime / adjtimex flags */
|
||||
void setTimexFlags(int flags, Boolean quiet);
|
||||
void unsetTimexFlags(int flags, Boolean quiet);
|
||||
int getTimexFlags(void);
|
||||
Boolean checkTimexFlags(int flags);
|
||||
|
||||
#endif /* HAVE_SYS_TIMEX_H */
|
||||
|
||||
#ifndef _WRS_CONFIG_ARCH_i86
|
||||
double trunc(double x);
|
||||
double round(double x);
|
||||
#endif
|
||||
|
||||
/** \}*/
|
||||
|
||||
/** \name timer.c (Unix API dependent)
|
||||
* -Handle with timers*/
|
||||
/**\{*/
|
||||
void initTimer(void);
|
||||
void timerUpdate(IntervalTimer*);
|
||||
void timerStop(UInteger16,IntervalTimer*);
|
||||
|
||||
/* void timerStart(UInteger16,UInteger16,IntervalTimer*); */
|
||||
|
||||
/* R135 patch: we went back to floating point periods (for less than 1s )*/
|
||||
void timerStart(UInteger16 index, float interval, IntervalTimer * itimer);
|
||||
|
||||
/* Version with randomized backoff */
|
||||
void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer);
|
||||
|
||||
Boolean timerExpired(UInteger16,IntervalTimer*);
|
||||
Boolean timerStopped(UInteger16,IntervalTimer*);
|
||||
Boolean timerRunning(UInteger16,IntervalTimer*);
|
||||
/** \}*/
|
||||
|
||||
void
|
||||
reset_operator_messages(RunTimeOpts * rtOpts, PtpClock * ptpClock);
|
||||
|
||||
void setupPIservo(PIservo* servo, const RunTimeOpts* rtOpts);
|
||||
void resetPIservo(PIservo* servo);
|
||||
double runPIservo(RunTimeOpts * rtOpts, PIservo* servo, const Integer32 input);
|
||||
|
||||
#endif /*PTPD_DEP_H_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,732 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 The IMS Company
|
||||
* Vincent Bernat
|
||||
*
|
||||
* 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 snmp.c
|
||||
* @author Vincent Bernat <bernat@luffy.cx>
|
||||
* @date Sat Jun 23 23:08:05 2012
|
||||
*
|
||||
* @brief SNMP related functions
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
|
||||
// snmp_shutdown("example-demon");
|
||||
|
||||
|
||||
/* Hard to get header... */
|
||||
extern int header_generic(struct variable *, oid *, size_t *, int,
|
||||
size_t *, WriteMethod **);
|
||||
|
||||
#define PTPBASE_SYSTEM_PROFILE 1
|
||||
#define PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL 2
|
||||
#define PTPBASE_SYSTEM_DOMAIN_TOTALS 3
|
||||
#define PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED 4
|
||||
#define PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER 5
|
||||
#define PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY 6
|
||||
#define PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID 7
|
||||
#define PTPBASE_CLOCK_PARENT_DS_PARENT_STATS 8
|
||||
#define PTPBASE_CLOCK_PARENT_DS_OFFSET 9
|
||||
#define PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE 10
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY 11
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1 12
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2 13
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS 14
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY 15
|
||||
#define PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET 16
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG 17
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY 18
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_PRIO1 19
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_PRIO2 20
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY 21
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS 22
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY 23
|
||||
#define PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET 24
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID 25
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET 26
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59 27
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61 28
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE 29
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE 30
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE 31
|
||||
#define PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE 32
|
||||
#define PTPBASE_CLOCK_PORT_NAME 33
|
||||
#define PTPBASE_CLOCK_PORT_ROLE 34
|
||||
#define PTPBASE_CLOCK_PORT_SYNC_ONE_STEP 35
|
||||
#define PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE 36
|
||||
#define PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS 37
|
||||
#define PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS 38
|
||||
#define PTPBASE_CLOCK_PORT_DS_PORT_NAME 39
|
||||
#define PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY 40
|
||||
#define PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL 41
|
||||
#define PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT 42
|
||||
#define PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL 43
|
||||
#define PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL 44
|
||||
#define PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL 45
|
||||
#define PTPBASE_CLOCK_PORT_DS_DELAY_MECH 46
|
||||
#define PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY 47
|
||||
#define PTPBASE_CLOCK_PORT_DS_GRANT_DURATION 48
|
||||
#define PTPBASE_CLOCK_PORT_DS_PTP_VERSION 49
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_NAME 50
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_STATE 51
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_ROLE 52
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX 53
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_IPVERSION 54
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE 55
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_TX_MODE 56
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_RX_MODE 57
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED 58
|
||||
#define PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT 59
|
||||
|
||||
#define SNMP_PTP_ORDINARY_CLOCK 1
|
||||
#define SNMP_PTP_CLOCK_INSTANCE 1 /* Only one instance */
|
||||
#define SNMP_PTP_PORT_MASTER 1
|
||||
#define SNMP_PTP_PORT_SLAVE 2
|
||||
#define SNMP_IPv4 1
|
||||
#define SNMP_PTP_TX_UNICAST 1
|
||||
#define SNMP_PTP_TX_MULTICAST 2
|
||||
#define SNMP_PTP_TX_MULTICAST_MIX 3
|
||||
|
||||
static oid ptp_oid[] = {1, 3, 6, 1, 4, 1, 39178, 100, 2};
|
||||
|
||||
static PtpClock *snmpPtpClock;
|
||||
static RunTimeOpts *snmpRtOpts;
|
||||
|
||||
/* Helper functions to build header_*indexed_table() functions. Those
|
||||
functions keep an internal state. They are not reentrant!
|
||||
*/
|
||||
/* {{{ */
|
||||
struct snmpHeaderIndex {
|
||||
struct variable *vp;
|
||||
oid *name; /* Requested/returned OID */
|
||||
size_t *length; /* Length of above OID */
|
||||
int exact;
|
||||
oid best[MAX_OID_LEN]; /* Best OID */
|
||||
size_t best_len; /* Best OID length */
|
||||
void *entity; /* Best entity */
|
||||
};
|
||||
|
||||
static int
|
||||
snmpHeaderInit(struct snmpHeaderIndex *idx,
|
||||
struct variable *vp, oid *name, size_t *length,
|
||||
int exact, size_t *var_len, WriteMethod **write_method)
|
||||
{
|
||||
/* If the requested OID name is less than OID prefix we
|
||||
handle, adjust it to our prefix. */
|
||||
if ((snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
|
||||
memcpy(name, vp->name, sizeof(oid) * vp->namelen);
|
||||
*length = vp->namelen;
|
||||
}
|
||||
/* Now, we can only handle OID matching our prefix. Those two
|
||||
tests are not really necessary since NetSNMP won't give us
|
||||
OID "above" our prefix. But this makes unit tests
|
||||
easier. */
|
||||
if (*length < vp->namelen) return 0;
|
||||
if (memcmp(name, vp->name, vp->namelen * sizeof(oid))) return 0;
|
||||
|
||||
if(write_method != NULL) *write_method = 0;
|
||||
*var_len = sizeof(long);
|
||||
|
||||
/* Initialize our header index structure */
|
||||
idx->vp = vp;
|
||||
idx->name = name;
|
||||
idx->length = length;
|
||||
idx->exact = exact;
|
||||
idx->best_len = 0;
|
||||
idx->entity = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
snmpHeaderIndexAdd(struct snmpHeaderIndex *idx,
|
||||
oid *index, size_t len, void *entity)
|
||||
{
|
||||
int result;
|
||||
oid *target;
|
||||
size_t target_len;
|
||||
|
||||
target = idx->name + idx->vp->namelen;
|
||||
target_len = *idx->length - idx->vp->namelen;
|
||||
if ((result = snmp_oid_compare(index, len, target, target_len)) < 0)
|
||||
return; /* Too small. */
|
||||
if (idx->exact) {
|
||||
if (result == 0) {
|
||||
memcpy(idx->best, index, sizeof(oid) * len);
|
||||
idx->best_len = len;
|
||||
idx->entity = entity;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result == 0)
|
||||
return; /* Too small. */
|
||||
if (idx->best_len == 0 ||
|
||||
(snmp_oid_compare(index, len,
|
||||
idx->best,
|
||||
idx->best_len) < 0)) {
|
||||
memcpy(idx->best, index, sizeof(oid) * len);
|
||||
idx->best_len = len;
|
||||
idx->entity = entity;
|
||||
}
|
||||
}
|
||||
|
||||
static void*
|
||||
snmpHeaderIndexBest(struct snmpHeaderIndex *idx)
|
||||
{
|
||||
if (idx->entity == NULL)
|
||||
return NULL;
|
||||
if (idx->exact) {
|
||||
if (snmp_oid_compare(idx->name + idx->vp->namelen,
|
||||
*idx->length - idx->vp->namelen,
|
||||
idx->best, idx->best_len) == 0)
|
||||
return idx->entity;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(idx->name + idx->vp->namelen,
|
||||
idx->best, sizeof(oid) * idx->best_len);
|
||||
*idx->length = idx->vp->namelen + idx->best_len;
|
||||
return idx->entity;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
#define SNMP_LOCAL_VARIABLES \
|
||||
static unsigned long long_ret; \
|
||||
static U64 counter64_ret; \
|
||||
static uint32_t ipaddr; \
|
||||
Integer64 bigint; \
|
||||
struct snmpHeaderIndex idx; \
|
||||
(void)long_ret; \
|
||||
(void)counter64_ret; \
|
||||
(void)ipaddr; \
|
||||
(void)bigint; \
|
||||
(void)idx
|
||||
#define SNMP_INDEXED_TABLE \
|
||||
if (!snmpHeaderInit(&idx, vp, name, \
|
||||
length, exact, \
|
||||
var_len, \
|
||||
write_method)) \
|
||||
return NULL
|
||||
#define SNMP_ADD_INDEX(index, len, w) \
|
||||
snmpHeaderIndexAdd(&idx, index, len, w)
|
||||
#define SNMP_BEST_MATCH \
|
||||
snmpHeaderIndexBest(&idx)
|
||||
#define SNMP_OCTETSTR(V, L) \
|
||||
( *var_len = L, \
|
||||
(u_char *)V )
|
||||
#define SNMP_COUNTER64(V) \
|
||||
( counter64_ret.low = (V) & 0xffffffff, \
|
||||
counter64_ret.high = (V) >> 32, \
|
||||
*var_len = sizeof (counter64_ret), \
|
||||
(u_char*)&counter64_ret )
|
||||
#define SNMP_TIMEINTERNAL(V) \
|
||||
( *var_len = sizeof(counter64_ret), \
|
||||
internalTime_to_integer64(V, &bigint), \
|
||||
counter64_ret.low = htonl(bigint.lsb), \
|
||||
counter64_ret.high = htonl(bigint.msb), \
|
||||
(u_char *)&counter64_ret )
|
||||
#define SNMP_INTEGER(V) \
|
||||
( long_ret = (V), \
|
||||
*var_len = sizeof (long_ret), \
|
||||
(u_char*)&long_ret )
|
||||
#define SNMP_IPADDR(A) \
|
||||
( ipaddr = A, \
|
||||
*var_len = sizeof (ipaddr), \
|
||||
(u_char*)&ipaddr )
|
||||
#define SNMP_GAUGE SNMP_INTEGER
|
||||
#define SNMP_UNSIGNED SNMP_INTEGER
|
||||
#define SNMP_TRUE SNMP_INTEGER(1)
|
||||
#define SNMP_FALSE SNMP_INTEGER(2)
|
||||
#define SNMP_BOOLEAN(V) \
|
||||
(V == TRUE)?SNMP_TRUE:SNMP_FALSE
|
||||
#define SNMP_SIGNATURE struct variable *vp, \
|
||||
oid *name, \
|
||||
size_t *length, \
|
||||
int exact, \
|
||||
size_t *var_len, \
|
||||
WriteMethod **write_method
|
||||
|
||||
/**
|
||||
* Handle SNMP scalar values.
|
||||
*/
|
||||
static u_char*
|
||||
snmpScalars(SNMP_SIGNATURE) {
|
||||
SNMP_LOCAL_VARIABLES;
|
||||
|
||||
if (header_generic(vp, name, length, exact, var_len, write_method))
|
||||
return NULL;
|
||||
|
||||
switch (vp->magic) {
|
||||
case PTPBASE_SYSTEM_PROFILE:
|
||||
return SNMP_INTEGER(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ptpbaseSystemTable
|
||||
*/
|
||||
static u_char*
|
||||
snmpSystemTable(SNMP_SIGNATURE) {
|
||||
oid index[2];
|
||||
SNMP_LOCAL_VARIABLES;
|
||||
SNMP_INDEXED_TABLE;
|
||||
|
||||
/* We only have one index: one domain, one instance */
|
||||
index[0] = snmpPtpClock->domainNumber;
|
||||
index[1] = SNMP_PTP_CLOCK_INSTANCE;
|
||||
SNMP_ADD_INDEX(index, 2, snmpPtpClock);
|
||||
|
||||
if (!SNMP_BEST_MATCH) return NULL;
|
||||
|
||||
switch (vp->magic) {
|
||||
case PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL:
|
||||
return SNMP_GAUGE(snmpPtpClock->numberPorts);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ptpbaseSystemDomainTable
|
||||
*/
|
||||
static u_char*
|
||||
snmpSystemDomainTable(SNMP_SIGNATURE) {
|
||||
oid index[1];
|
||||
SNMP_LOCAL_VARIABLES;
|
||||
SNMP_INDEXED_TABLE;
|
||||
|
||||
/* We only have one index: ordinary clock */
|
||||
index[0] = SNMP_PTP_ORDINARY_CLOCK;
|
||||
SNMP_ADD_INDEX(index, 1, snmpPtpClock);
|
||||
|
||||
if (!SNMP_BEST_MATCH) return NULL;
|
||||
|
||||
switch (vp->magic) {
|
||||
case PTPBASE_SYSTEM_DOMAIN_TOTALS:
|
||||
/* We only handle one domain... */
|
||||
return SNMP_UNSIGNED(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle various ptpbaseClock*DSTable
|
||||
*/
|
||||
static u_char*
|
||||
snmpClockDSTable(SNMP_SIGNATURE) {
|
||||
oid index[3];
|
||||
SNMP_LOCAL_VARIABLES;
|
||||
SNMP_INDEXED_TABLE;
|
||||
|
||||
/* We only have one valid index */
|
||||
index[0] = snmpPtpClock->domainNumber;
|
||||
index[1] = SNMP_PTP_ORDINARY_CLOCK;
|
||||
index[2] = SNMP_PTP_CLOCK_INSTANCE;
|
||||
SNMP_ADD_INDEX(index, 3, snmpPtpClock);
|
||||
|
||||
if (!SNMP_BEST_MATCH) return NULL;
|
||||
|
||||
switch (vp->magic) {
|
||||
/* ptpbaseClockCurrentDSTable */
|
||||
case PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->stepsRemoved);
|
||||
case PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER:
|
||||
return SNMP_TIMEINTERNAL(snmpPtpClock->offsetFromMaster);
|
||||
case PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY:
|
||||
return SNMP_TIMEINTERNAL(snmpPtpClock->meanPathDelay);
|
||||
/* ptpbaseClockParentDSTable */
|
||||
case PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID:
|
||||
return SNMP_OCTETSTR(&snmpPtpClock->parentPortIdentity,
|
||||
sizeof(PortIdentity));
|
||||
case PTPBASE_CLOCK_PARENT_DS_PARENT_STATS:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->parentStats);
|
||||
case PTPBASE_CLOCK_PARENT_DS_OFFSET:
|
||||
return SNMP_INTEGER(snmpPtpClock->observedParentOffsetScaledLogVariance);
|
||||
case PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE:
|
||||
return SNMP_INTEGER(snmpPtpClock->observedParentClockPhaseChangeRate);
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY:
|
||||
return SNMP_OCTETSTR(&snmpPtpClock->grandmasterIdentity,
|
||||
sizeof(ClockIdentity));
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->grandmasterPriority1);
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->grandmasterPriority2);
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->grandmasterClockQuality.clockClass);
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY:
|
||||
return SNMP_INTEGER(snmpPtpClock->grandmasterClockQuality.clockAccuracy);
|
||||
case PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET:
|
||||
return SNMP_INTEGER(snmpPtpClock->grandmasterClockQuality.offsetScaledLogVariance);
|
||||
/* ptpbaseClockDefaultDSTable */
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->twoStepFlag);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY:
|
||||
return SNMP_OCTETSTR(&snmpPtpClock->clockIdentity,
|
||||
sizeof(ClockIdentity));
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_PRIO1:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->priority1);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_PRIO2:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->priority2);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->slaveOnly);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS:
|
||||
return SNMP_UNSIGNED(snmpPtpClock->clockQuality.clockClass);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY:
|
||||
return SNMP_INTEGER(snmpPtpClock->clockQuality.clockAccuracy);
|
||||
case PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET:
|
||||
return SNMP_INTEGER(snmpPtpClock->clockQuality.offsetScaledLogVariance);
|
||||
/* ptpbaseClockTimePropertiesDSTable */
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.currentUtcOffsetValid);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET:
|
||||
return SNMP_INTEGER(snmpPtpClock->timePropertiesDS.currentUtcOffset);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.leap59);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.leap61);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.timeTraceable);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.frequencyTraceable);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE:
|
||||
return SNMP_BOOLEAN(snmpPtpClock->timePropertiesDS.ptpTimescale);
|
||||
case PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE:
|
||||
return SNMP_INTEGER(snmpPtpClock->timePropertiesDS.timeSource);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ptpbaseClockPort*Table
|
||||
*/
|
||||
static u_char*
|
||||
snmpClockPortTable(SNMP_SIGNATURE) {
|
||||
oid index[4];
|
||||
SNMP_LOCAL_VARIABLES;
|
||||
SNMP_INDEXED_TABLE;
|
||||
|
||||
/* We only have one valid index */
|
||||
index[0] = snmpPtpClock->domainNumber;
|
||||
index[1] = SNMP_PTP_ORDINARY_CLOCK;
|
||||
index[2] = SNMP_PTP_CLOCK_INSTANCE;
|
||||
index[3] = snmpPtpClock->portIdentity.portNumber;
|
||||
SNMP_ADD_INDEX(index, 4, snmpPtpClock);
|
||||
|
||||
if (!SNMP_BEST_MATCH) return NULL;
|
||||
|
||||
switch (vp->magic) {
|
||||
/* ptpbaseClockPortTable */
|
||||
case PTPBASE_CLOCK_PORT_NAME:
|
||||
case PTPBASE_CLOCK_PORT_DS_PORT_NAME:
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_NAME:
|
||||
return SNMP_OCTETSTR(snmpPtpClock->user_description,
|
||||
strlen(snmpPtpClock->user_description));
|
||||
case PTPBASE_CLOCK_PORT_ROLE:
|
||||
return SNMP_INTEGER((snmpPtpClock->portState == PTP_MASTER)?
|
||||
SNMP_PTP_PORT_MASTER:SNMP_PTP_PORT_SLAVE);
|
||||
case PTPBASE_CLOCK_PORT_SYNC_ONE_STEP:
|
||||
return (snmpPtpClock->twoStepFlag == TRUE)?SNMP_FALSE:SNMP_TRUE;
|
||||
case PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE:
|
||||
/* Only supports IPv4 */
|
||||
return SNMP_INTEGER(SNMP_IPv4);
|
||||
case PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS:
|
||||
if (snmpPtpClock->netPath.unicastAddr)
|
||||
return SNMP_IPADDR(snmpPtpClock->netPath.unicastAddr);
|
||||
return SNMP_IPADDR(snmpPtpClock->netPath.multicastAddr);
|
||||
case PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS:
|
||||
/* Either we are master and we use multicast and we
|
||||
* consider we have a session or we are slave and we
|
||||
* have only one master. */
|
||||
return SNMP_INTEGER(1);
|
||||
|
||||
/* ptpbaseClockPortDSTable */
|
||||
case PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY:
|
||||
return SNMP_OCTETSTR(&snmpPtpClock->portIdentity,
|
||||
sizeof(PortIdentity));
|
||||
case PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL:
|
||||
/* TODO: is it really logAnnounceInterval? */
|
||||
return SNMP_INTEGER(snmpPtpClock->logAnnounceInterval);
|
||||
case PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT:
|
||||
return SNMP_INTEGER(snmpPtpClock->announceReceiptTimeout);
|
||||
case PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL:
|
||||
/* TODO: is it really logSyncInterval? */
|
||||
return SNMP_INTEGER(snmpPtpClock->logSyncInterval);
|
||||
case PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL:
|
||||
/* TODO: is it really logMinDelayReqInterval? */
|
||||
return SNMP_INTEGER(snmpPtpClock->logMinDelayReqInterval);
|
||||
case PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL:
|
||||
/* TODO: is it really logMinPdelayReqInterval? */
|
||||
return SNMP_INTEGER(snmpPtpClock->logMinPdelayReqInterval);
|
||||
case PTPBASE_CLOCK_PORT_DS_DELAY_MECH:
|
||||
return SNMP_INTEGER(snmpPtpClock->delayMechanism);
|
||||
case PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY:
|
||||
return SNMP_TIMEINTERNAL(snmpPtpClock->peerMeanPathDelay);
|
||||
case PTPBASE_CLOCK_PORT_DS_GRANT_DURATION:
|
||||
/* TODO: what is it? */
|
||||
return SNMP_UNSIGNED(0);
|
||||
case PTPBASE_CLOCK_PORT_DS_PTP_VERSION:
|
||||
return SNMP_INTEGER(snmpPtpClock->versionNumber);
|
||||
|
||||
/* ptpbaseClockPortRunningTable */
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_STATE:
|
||||
return SNMP_INTEGER(snmpPtpClock->portState);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_ROLE:
|
||||
return SNMP_INTEGER((snmpPtpClock->portState == PTP_MASTER)?
|
||||
SNMP_PTP_PORT_MASTER:SNMP_PTP_PORT_SLAVE);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX:
|
||||
/* TODO: maybe we can have it from the general configuration? */
|
||||
return SNMP_INTEGER(0);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_IPVERSION:
|
||||
/* IPv4 only */
|
||||
/* TODO: shouldn't we return SNMP_IPv4??? */
|
||||
return SNMP_INTEGER(4);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE:
|
||||
/* None. Moreover, the format is not really described in the MIB... */
|
||||
return SNMP_INTEGER(0);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_TX_MODE:
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_RX_MODE:
|
||||
if (snmpRtOpts->ip_mode == IPMODE_UNICAST)
|
||||
return SNMP_INTEGER(SNMP_PTP_TX_UNICAST);
|
||||
if (snmpRtOpts->ip_mode == IPMODE_HYBRID)
|
||||
return SNMP_INTEGER(SNMP_PTP_TX_MULTICAST_MIX);
|
||||
return SNMP_INTEGER(SNMP_PTP_TX_MULTICAST);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED:
|
||||
return SNMP_COUNTER64(snmpPtpClock->netPath.receivedPackets);
|
||||
case PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT:
|
||||
return SNMP_COUNTER64(snmpPtpClock->netPath.sentPackets);
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* MIB definition
|
||||
*/
|
||||
static struct variable7 snmpVariables[] = {
|
||||
/* ptpbaseSystemTable */
|
||||
{ PTPBASE_DOMAIN_CLOCK_PORTS_TOTAL, ASN_GAUGE, HANDLER_CAN_RONLY,
|
||||
snmpSystemTable, 5, {1, 1, 1, 1, 3}},
|
||||
/* ptpbaseSystemDomainTable */
|
||||
{ PTPBASE_SYSTEM_DOMAIN_TOTALS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpSystemDomainTable, 5, {1, 1, 2, 1, 2}},
|
||||
/* Scalars */
|
||||
{ PTPBASE_SYSTEM_PROFILE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpScalars, 3, {1, 1, 3}},
|
||||
/* ptpbaseClockCurrentDSTable */
|
||||
{ PTPBASE_CLOCK_CURRENT_DS_STEPS_REMOVED, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 1, 1, 4}},
|
||||
{ PTPBASE_CLOCK_CURRENT_DS_OFFSET_FROM_MASTER, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 1, 1, 5}},
|
||||
{ PTPBASE_CLOCK_CURRENT_DS_MEAN_PATH_DELAY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 1, 1, 6}},
|
||||
/* ptpbaseClockParentDSTable */
|
||||
{ PTPBASE_CLOCK_PARENT_DS_PARENT_PORT_ID, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 4}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_PARENT_STATS, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 5}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 6}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_CLOCK_PH_CH_RATE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 7}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 8}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO1, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 9}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_PRIO2, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 10}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_CLASS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 11}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_ACCURACY, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 12}},
|
||||
{ PTPBASE_CLOCK_PARENT_DS_GM_CLOCK_QUALITY_OFFSET, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 2, 1, 13}},
|
||||
/* ptpbaseClockDefaultDSTable */
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_TWO_STEP_FLAG, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 4}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_CLOCK_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 5}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_PRIO1, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 6}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_PRIO2, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 7}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_SLAVE_ONLY, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 8}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_CLASS, ASN_UNSIGNED, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 9}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_ACCURACY, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 10}},
|
||||
{ PTPBASE_CLOCK_DEFAULT_DS_QUALITY_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 3, 1, 11}},
|
||||
/* ptpbaseClockRunningTable: no data available for this table? */
|
||||
/* ptpbaseClockTimePropertiesDSTable */
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 4}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 5}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP59, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 6}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_LEAP61, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 7}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_TIME_TRACEABLE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 8}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_FREQ_TRACEABLE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 9}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_PTP_TIMESCALE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 10}},
|
||||
{ PTPBASE_CLOCK_TIME_PROPERTIES_DS_SOURCE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockDSTable, 5, {1, 2, 5, 1, 11}},
|
||||
/* ptpbaseClockPortTable */
|
||||
{ PTPBASE_CLOCK_PORT_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 5}},
|
||||
{ PTPBASE_CLOCK_PORT_ROLE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 6}},
|
||||
{ PTPBASE_CLOCK_PORT_SYNC_ONE_STEP, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 7}},
|
||||
{ PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS_TYPE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 8}},
|
||||
{ PTPBASE_CLOCK_PORT_CURRENT_PEER_ADDRESS, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 9}},
|
||||
{ PTPBASE_CLOCK_PORT_NUM_ASSOCIATED_PORTS, ASN_GAUGE, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 7, 1, 10}},
|
||||
/* ptpbaseClockPortDSTable */
|
||||
{ PTPBASE_CLOCK_PORT_DS_PORT_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 5}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_PORT_IDENTITY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 6}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_ANNOUNCEMENT_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 7}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_ANNOUNCE_RCT_TIMEOUT, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 8}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_SYNC_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 9}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_MIN_DELAY_REQ_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 10}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_PEER_DELAY_REQ_INTERVAL, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 11}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_DELAY_MECH, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 12}},
|
||||
{ PTPBASE_CLOCK_PORT_DS_PEER_MEAN_PATH_DELAY, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 13}},
|
||||
/* { PTPBASE_CLOCK_PORT_DS_GRANT_DURATION, ASN_UNSIGNED, HANDLER_CAN_RONLY, */
|
||||
/* snmpClockPortTable, 5, {1, 2, 8, 1, 14}}, */
|
||||
{ PTPBASE_CLOCK_PORT_DS_PTP_VERSION, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 8, 1, 15}},
|
||||
/* ptpbaseClockPortRunningTable */
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_NAME, ASN_OCTET_STR, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 5}},
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_STATE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 6}},
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_ROLE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 7}},
|
||||
/* { PTPBASE_CLOCK_PORT_RUNNING_INTERFACE_INDEX, ASN_INTEGER, HANDLER_CAN_RONLY, */
|
||||
/* snmpClockPortTable, 5, {1, 2, 9, 1, 8}}, */
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_IPVERSION, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 9}},
|
||||
/* { PTPBASE_CLOCK_PORT_RUNNING_ENCAPSULATION_TYPE, ASN_INTEGER, HANDLER_CAN_RONLY, */
|
||||
/* snmpClockPortTable, 5, {1, 2, 9, 1, 10}}, */
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_TX_MODE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 11}},
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_RX_MODE, ASN_INTEGER, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 12}},
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_PACKETS_RECEIVED, ASN_COUNTER64, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 13}},
|
||||
{ PTPBASE_CLOCK_PORT_RUNNING_PACKETS_SENT, ASN_COUNTER64, HANDLER_CAN_RONLY,
|
||||
snmpClockPortTable, 5, {1, 2, 9, 1, 14}},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Log messages from NetSNMP subsystem.
|
||||
*/
|
||||
static int
|
||||
snmpLogCallback(int major, int minor,
|
||||
void *serverarg, void *clientarg)
|
||||
{
|
||||
struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
|
||||
char *msg = strdup (slm->msg);
|
||||
if (msg) msg[strlen(msg)-1] = '\0';
|
||||
|
||||
switch (slm->priority)
|
||||
{
|
||||
case LOG_EMERG: EMERGENCY("snmp[emerg]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_ALERT: ALERT ("snmp[alert]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_CRIT: CRITICAL ("snmp[crit]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_ERR: ERROR ("snmp[err]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_WARNING: WARNING ("snmp[warning]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_NOTICE: NOTICE ("snmp[notice]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_INFO: INFO ("snmp[info]: %s\n", msg?msg:slm->msg); break;
|
||||
case LOG_DEBUG: DBGV ("snmp[debug]: %s\n", msg?msg:slm->msg); break;
|
||||
}
|
||||
free(msg);
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisation of SNMP subsystem.
|
||||
*/
|
||||
void
|
||||
snmpInit(RunTimeOpts *rtOpts, PtpClock *ptpClock) {
|
||||
|
||||
netsnmp_enable_subagent();
|
||||
snmp_disable_log();
|
||||
snmp_enable_calllog();
|
||||
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
|
||||
SNMP_CALLBACK_LOGGING,
|
||||
snmpLogCallback,
|
||||
NULL);
|
||||
init_agent("ptpAgent");
|
||||
REGISTER_MIB("ptpMib", snmpVariables, variable7, ptp_oid);
|
||||
init_snmp("ptpAgent");
|
||||
|
||||
/* Currently, ptpd only handle one clock. We put it in a
|
||||
* global variable for the need of our subsystem. */
|
||||
snmpPtpClock = ptpClock;
|
||||
snmpRtOpts = rtOpts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and shut down the SNMP subagent
|
||||
*/
|
||||
|
||||
void
|
||||
snmpShutdown() {
|
||||
|
||||
unregister_mib(ptp_oid, sizeof(ptp_oid) / sizeof(oid));
|
||||
snmp_shutdown("ptpMib");
|
||||
SOCK_CLEANUP;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Wind River Systems, Inc,
|
||||
* Copyright (c) 2014 Wojciech Owczarek,
|
||||
* Copyright (c) 2012-2013 George V. Neville-Neil,
|
||||
* Wojciech Owczarek
|
||||
* Copyright (c) 2011-2012 George V. Neville-Neil,
|
||||
* Steven Kreuzer,
|
||||
* Martin Burnicki,
|
||||
* Jan Breuer,
|
||||
* Gael Mace,
|
||||
* Alexandre Van Kempen,
|
||||
* Inaqui Delgado,
|
||||
* Rick Ratzel,
|
||||
* National Instruments.
|
||||
* Copyright (c) 2009-2010 George V. Neville-Neil,
|
||||
* Steven Kreuzer,
|
||||
* Martin Burnicki,
|
||||
* Jan Breuer,
|
||||
* Gael Mace,
|
||||
* Alexandre Van Kempen
|
||||
*
|
||||
* Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
15aug16,xxy Add PTP features.(F6696)
|
||||
02feb16,h_l Init version.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file startup.c
|
||||
* @date Wed Jun 23 09:33:27 2010
|
||||
*
|
||||
* @brief Code to handle daemon startup, including command line args
|
||||
*
|
||||
* The function in this file are called when the daemon starts up
|
||||
* and include the getopt() command line argument parsing.
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
|
||||
void
|
||||
ptpdShutdown(RunTimeOpts *rtOpts, PtpClock *ptpClock)
|
||||
{
|
||||
|
||||
(void)netShutdown(rtOpts, &ptpClock->netPath);
|
||||
free(ptpClock->foreign);
|
||||
|
||||
/* free management messages, they can have dynamic memory allocated */
|
||||
if (ptpClock->msgTmpHeader.messageType == MANAGEMENT)
|
||||
{
|
||||
freeManagementTLV(&ptpClock->msgTmp.manage);
|
||||
}
|
||||
|
||||
freeManagementTLV(&ptpClock->outgoingManageTmp);
|
||||
|
||||
|
||||
|
||||
/* Not running statistics code - write observed drift to driftfile if enabled, inform user */
|
||||
if (ptpClock->slaveOnly && !ptpClock->servo.runningMaxOutput)
|
||||
{
|
||||
saveDrift(ptpClock, rtOpts, FALSE);
|
||||
}
|
||||
|
||||
|
||||
free(ptpClock);
|
||||
ptpClock = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
PtpClock *
|
||||
ptpdStartup(int slaveMaster, RunTimeOpts *rtOpts)
|
||||
{
|
||||
PtpClock *ptpClock;
|
||||
|
||||
if (slaveMaster == PTP_DEVICE_SLAVE)
|
||||
{
|
||||
rtOpts->slaveOnly = 1;
|
||||
rtOpts->selectedPreset = PTP_PRESET_SLAVEONLY;
|
||||
rtOpts->clockQuality.clockClass = SLAVE_ONLY_CLOCK_CLASS;
|
||||
}
|
||||
else if (slaveMaster == PTP_DEVICE_MASTER)
|
||||
{
|
||||
rtOpts->selectedPreset = PTP_PRESET_MASTERONLY;
|
||||
rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS__APPLICATION_SPECIFIC_TIME_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtOpts->selectedPreset = PTP_PRESET_MASTERSLAVE;
|
||||
rtOpts->clockQuality.clockClass = DEFAULT_CLOCK_CLASS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is where the final checking of the candidate settings container happens.
|
||||
* A dictionary is returned with only the known options, explicitly set to defaults
|
||||
* if not present. NULL is returned on any config error - parameters missing, out of range,
|
||||
* etc. The getopt loop in loadCommandLineOptions() only sets keys verified here.
|
||||
*/
|
||||
|
||||
parseConfig(rtOpts);
|
||||
|
||||
|
||||
configcheck:
|
||||
|
||||
|
||||
/* Allocate memory after we're done with other checks but before going into daemon */
|
||||
ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock));
|
||||
|
||||
if (!ptpClock)
|
||||
{
|
||||
PERROR("Error: Failed to allocate memory for protocol engine data");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("allocated %d bytes for protocol engine data\n",
|
||||
(int)sizeof(PtpClock));
|
||||
ptpClock->foreign = (ForeignMasterRecord *)
|
||||
calloc(rtOpts->max_foreign_records,
|
||||
sizeof(ForeignMasterRecord));
|
||||
|
||||
if (!ptpClock->foreign)
|
||||
{
|
||||
PERROR("failed to allocate memory for foreign "
|
||||
"master data");
|
||||
free(ptpClock);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("allocated %d bytes for foreign master data\n",
|
||||
(int)(rtOpts->max_foreign_records *
|
||||
sizeof(ForeignMasterRecord)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Init to 0 net buffer */
|
||||
memset(ptpClock->msgIbuf, 0, PACKET_SIZE);
|
||||
memset(ptpClock->msgObuf, 0, PACKET_SIZE);
|
||||
|
||||
/* Init user_description */
|
||||
memset(ptpClock->user_description, 0, sizeof(ptpClock->user_description));
|
||||
memcpy(ptpClock->user_description, &USER_DESCRIPTION, sizeof(USER_DESCRIPTION));
|
||||
|
||||
/* Init outgoing management message */
|
||||
ptpClock->outgoingManageTmp.tlv = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
NOTICE(USER_DESCRIPTION" started successfully on %s using \"%s\" preset \n",
|
||||
rtOpts->ifaceName,
|
||||
(getPtpPreset(rtOpts->selectedPreset, rtOpts)).presetName
|
||||
);
|
||||
ptpClock->resetStatisticsLog = TRUE;
|
||||
|
||||
|
||||
ptpClock->netPath.generalSock = -1;
|
||||
ptpClock->netPath.eventSock = -1;
|
||||
|
||||
if (rtOpts->transport == IEEE_802_3)
|
||||
{
|
||||
memset (&ptpClock->netPath.layer2addr, 0, sizeof(ptpClock->netPath.layer2addr));
|
||||
|
||||
ptpClock->netPath.layer2addr.sll_family = AF_PACKET;
|
||||
ptpClock->netPath.layer2addr.sll_ifindex = if_nametoindex (rtOpts->primaryIfaceName);
|
||||
ptpClock->netPath.layer2addr.sll_halen = ETHER_ADDR_LEN;
|
||||
|
||||
if (rtOpts->ptp_profile == PTP_802_1AS_PROFILE)
|
||||
{
|
||||
ptpClock->netPath.layer2addr.sll_addr[0] = 0x01;
|
||||
ptpClock->netPath.layer2addr.sll_addr[1] = 0x80;
|
||||
ptpClock->netPath.layer2addr.sll_addr[2] = 0xc2;
|
||||
ptpClock->netPath.layer2addr.sll_addr[3] = 0x00;
|
||||
ptpClock->netPath.layer2addr.sll_addr[4] = 0x00;
|
||||
ptpClock->netPath.layer2addr.sll_addr[5] = 0x0e;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptpClock->netPath.layer2addr.sll_addr[0] = 0x01;
|
||||
ptpClock->netPath.layer2addr.sll_addr[1] = 0x1b;
|
||||
ptpClock->netPath.layer2addr.sll_addr[2] = 0x19;
|
||||
ptpClock->netPath.layer2addr.sll_addr[3] = 0x00;
|
||||
ptpClock->netPath.layer2addr.sll_addr[4] = 0x00;
|
||||
ptpClock->netPath.layer2addr.sll_addr[5] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
return ptpClock;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,702 @@
|
||||
/**
|
||||
* @file statistics.c
|
||||
* @authors Wojciech Owczarek
|
||||
* @date Sun Jul 7 13:28:10 2013
|
||||
* This souece file contains the implementations of functions maintaining and
|
||||
* computing statistical information.
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
|
||||
static int cmpInt32 (const void *vA, const void *vB) {
|
||||
|
||||
int32_t a = *(int32_t*)vA;
|
||||
int32_t b = *(int32_t*)vB;
|
||||
|
||||
return ((a < b) ? -1 : (a > b) ? 1 : 0);
|
||||
}
|
||||
|
||||
static int cmpDouble (const void *vA, const void *vB) {
|
||||
|
||||
double a = *(double*)vA;
|
||||
double b = *(double*)vB;
|
||||
|
||||
return ((a < b) ? -1 : (a > b) ? 1 : 0);
|
||||
}
|
||||
|
||||
void
|
||||
resetIntPermanentMean(IntPermanentMean* container) {
|
||||
|
||||
container->mean = 0;
|
||||
container->count = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t
|
||||
feedIntPermanentMean(IntPermanentMean* container, int32_t sample)
|
||||
{
|
||||
|
||||
container->mean += ( sample - container-> mean ) / ++container->count;
|
||||
return container->mean;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetIntPermanentStdDev(IntPermanentStdDev* container) {
|
||||
|
||||
resetIntPermanentMean(&container->meanContainer);
|
||||
container->squareSum = 0;
|
||||
container->stdDev = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t
|
||||
feedIntPermanentStdDev(IntPermanentStdDev* container, int32_t sample)
|
||||
{
|
||||
|
||||
container->squareSum += ( sample - container->meanContainer.mean) *
|
||||
( sample - feedIntPermanentMean(&container->meanContainer, sample ));
|
||||
|
||||
if(container->meanContainer.count > 1) {
|
||||
container->stdDev = sqrt( container->squareSum /
|
||||
(container->meanContainer.count - 1) );
|
||||
} else {
|
||||
container->stdDev = 0;
|
||||
}
|
||||
|
||||
return container->stdDev;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetDoublePermanentMean(DoublePermanentMean* container)
|
||||
{
|
||||
if(container == NULL)
|
||||
return;
|
||||
container->mean = 0.0;
|
||||
container->count = 0;
|
||||
|
||||
}
|
||||
|
||||
double
|
||||
feedDoublePermanentMean(DoublePermanentMean* container, double sample)
|
||||
{
|
||||
|
||||
container->mean += ( sample - container-> mean ) / ++container->count;
|
||||
return container->mean;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetDoublePermanentStdDev(DoublePermanentStdDev* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
resetDoublePermanentMean(&container->meanContainer);
|
||||
container->squareSum = 0.0;
|
||||
container->stdDev = 0.0;
|
||||
|
||||
}
|
||||
|
||||
double
|
||||
feedDoublePermanentStdDev(DoublePermanentStdDev* container, double sample)
|
||||
{
|
||||
|
||||
container->squareSum += ( sample - container->meanContainer.mean) *
|
||||
( sample - feedDoublePermanentMean(&container->meanContainer, sample )) ;
|
||||
|
||||
if(container->meanContainer.count > 1) {
|
||||
container->stdDev = sqrt(container->squareSum /
|
||||
((container->meanContainer.count+0.0) - 1.0)) ;
|
||||
} else {
|
||||
container->stdDev = 0;
|
||||
}
|
||||
|
||||
return container->stdDev;
|
||||
|
||||
}
|
||||
|
||||
/* Moving statistics - up to last n samples */
|
||||
|
||||
IntMovingMean*
|
||||
createIntMovingMean(int capacity)
|
||||
{
|
||||
|
||||
IntMovingMean* container;
|
||||
if ( !(container = calloc (1, sizeof(IntMovingMean))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
container->capacity = (capacity > STATCONTAINER_MAX_SAMPLES ) ?
|
||||
STATCONTAINER_MAX_SAMPLES : capacity;
|
||||
|
||||
if ( !(container->samples = calloc (container->capacity, sizeof(int32_t))) ) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeIntMovingMean(IntMovingMean** container)
|
||||
{
|
||||
|
||||
free((*container)->samples);
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetIntMovingMean(IntMovingMean* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
container->sum = 0;
|
||||
container->mean = 0;
|
||||
container->count = 0;
|
||||
memset(container->samples, 0, sizeof(&container->samples));
|
||||
|
||||
}
|
||||
|
||||
int32_t
|
||||
feedIntMovingMean(IntMovingMean* container, int32_t sample)
|
||||
{
|
||||
|
||||
if(container == NULL) return 0;
|
||||
|
||||
/* sample buffer is full */
|
||||
if ( container->count == container->capacity ) {
|
||||
/* keep the sum current - drop the oldest value */
|
||||
container->sum -= container->samples[0];
|
||||
/* shift the sample buffer left, dropping the oldest sample */
|
||||
memcpy(container->samples, container->samples + 1,
|
||||
sizeof(int32_t) * (container->capacity - 1) );
|
||||
/* counter will be incremented further, so we decrement it here */
|
||||
container->count--;
|
||||
container->full = TRUE;
|
||||
}
|
||||
|
||||
container->samples[container->count++] = sample;
|
||||
container->sum += sample;
|
||||
container->mean = container->sum / container->count;
|
||||
|
||||
return container->mean;
|
||||
|
||||
}
|
||||
|
||||
IntMovingStdDev* createIntMovingStdDev(int capacity)
|
||||
{
|
||||
|
||||
IntMovingStdDev* container;
|
||||
if ( !(container = calloc (1, sizeof(IntMovingStdDev))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((container->meanContainer = createIntMovingMean(capacity))
|
||||
== NULL) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeIntMovingStdDev(IntMovingStdDev** container)
|
||||
{
|
||||
|
||||
freeIntMovingMean(&((*container)->meanContainer));
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetIntMovingStdDev(IntMovingStdDev* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
resetIntMovingMean(container->meanContainer);
|
||||
container->squareSum = 0;
|
||||
container->stdDev = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t
|
||||
feedIntMovingStdDev(IntMovingStdDev* container, int32_t sample)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
|
||||
if(container == NULL)
|
||||
return 0;
|
||||
|
||||
feedIntMovingMean(container->meanContainer, sample);
|
||||
|
||||
if (container->meanContainer->count < 2) {
|
||||
container->stdDev = 0;
|
||||
} else {
|
||||
|
||||
container->squareSum = 0;
|
||||
for(i = 0; i < container->meanContainer->count; i++) {
|
||||
container->squareSum += ( container->meanContainer->samples[i] - container->meanContainer->mean ) *
|
||||
( container->meanContainer->samples[i] - container->meanContainer->mean );
|
||||
}
|
||||
|
||||
container->stdDev = sqrt ( container->squareSum /
|
||||
(container->meanContainer->count - 1 ));
|
||||
|
||||
}
|
||||
|
||||
return container->stdDev;
|
||||
|
||||
}
|
||||
|
||||
DoubleMovingMean*
|
||||
createDoubleMovingMean(int capacity)
|
||||
{
|
||||
|
||||
DoubleMovingMean* container;
|
||||
if ( !(container = calloc (1, sizeof(DoubleMovingMean))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
container->capacity = (capacity > STATCONTAINER_MAX_SAMPLES ) ?
|
||||
STATCONTAINER_MAX_SAMPLES : capacity;
|
||||
if ( !(container->samples = calloc(container->capacity, sizeof(double))) ) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeDoubleMovingMean(DoubleMovingMean** container)
|
||||
{
|
||||
|
||||
if(*container == NULL) {
|
||||
return;
|
||||
}
|
||||
free((*container)->samples);
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetDoubleMovingMean(DoubleMovingMean* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
container->sum = 0;
|
||||
container->mean = 0;
|
||||
container->count = 0;
|
||||
memset(container->samples, 0, sizeof(&container->samples));
|
||||
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
feedDoubleMovingMean(DoubleMovingMean* container, double sample)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return 0;
|
||||
/* sample buffer is full */
|
||||
if ( container->count == container->capacity ) {
|
||||
/* keep the sum current - drop the oldest value */
|
||||
container->sum -= container->samples[0];
|
||||
/* shift the sample buffer left, dropping the oldest sample */
|
||||
memcpy(container->samples, container->samples + 1,
|
||||
sizeof(double) * (container->capacity - 1) );
|
||||
/* counter will be incremented further, so we decrement it here */
|
||||
container->count--;
|
||||
container->full = TRUE;
|
||||
}
|
||||
container->samples[container->count++] = sample;
|
||||
container->sum += sample;
|
||||
container->mean = container->sum / container->count;
|
||||
|
||||
return container->mean;
|
||||
|
||||
}
|
||||
|
||||
DoubleMovingStdDev* createDoubleMovingStdDev(int capacity)
|
||||
{
|
||||
|
||||
DoubleMovingStdDev* container;
|
||||
if ( !(container = calloc (1, sizeof(DoubleMovingStdDev))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((container->meanContainer = createDoubleMovingMean(capacity))
|
||||
== NULL) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeDoubleMovingStdDev(DoubleMovingStdDev** container)
|
||||
{
|
||||
|
||||
freeDoubleMovingMean(&((*container)->meanContainer));
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetDoubleMovingStdDev(DoubleMovingStdDev* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
resetDoubleMovingMean(container->meanContainer);
|
||||
container->squareSum = 0.0;
|
||||
container->stdDev = 0.0;
|
||||
|
||||
}
|
||||
double
|
||||
feedDoubleMovingStdDev(DoubleMovingStdDev* container, double sample)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
|
||||
if(container == NULL)
|
||||
return 0.0;
|
||||
|
||||
feedDoubleMovingMean(container->meanContainer, sample);
|
||||
|
||||
if (container->meanContainer->count < 2) {
|
||||
container->stdDev = 0.0;
|
||||
} else {
|
||||
|
||||
container->squareSum = 0.0;
|
||||
for(i = 0; i < container->meanContainer->count; i++) {
|
||||
container->squareSum += ( container->meanContainer->samples[i] - container->meanContainer->mean ) *
|
||||
( container->meanContainer->samples[i] - container->meanContainer->mean );
|
||||
}
|
||||
|
||||
container->stdDev = sqrt ( container->squareSum /
|
||||
(container->meanContainer->count - 1));
|
||||
|
||||
}
|
||||
|
||||
return container->stdDev;
|
||||
|
||||
}
|
||||
|
||||
IntMovingMedian* createIntMovingMedian(int capacity)
|
||||
{
|
||||
|
||||
IntMovingMedian* container;
|
||||
if ( !(container = calloc (1, sizeof(IntMovingMedian))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((container->meanContainer = createIntMovingMean(capacity))
|
||||
== NULL) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeIntMovingMedian(IntMovingMedian** container)
|
||||
{
|
||||
|
||||
freeIntMovingMean(&((*container)->meanContainer));
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetIntMovingMedian(IntMovingMedian* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
resetIntMovingMean(container->meanContainer);
|
||||
container->median = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t
|
||||
feedIntMovingMedian(IntMovingMedian* container, int32_t sample)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return 0;
|
||||
|
||||
feedIntMovingMean(container->meanContainer, sample);
|
||||
|
||||
int count = container->meanContainer->count;
|
||||
|
||||
int32_t sortedSamples[count];
|
||||
|
||||
Boolean odd = ((count %2 ) == 1);
|
||||
|
||||
memcpy(sortedSamples, container->meanContainer->samples, count * sizeof(sample));
|
||||
|
||||
qsort(sortedSamples, count, sizeof(sample), cmpInt32);
|
||||
|
||||
if(odd) {
|
||||
|
||||
container->median = sortedSamples[(count / 2)];
|
||||
|
||||
} else {
|
||||
|
||||
container->median = (sortedSamples[(count / 2) - 1] + sortedSamples[(count / 2)]) / 2;
|
||||
|
||||
}
|
||||
|
||||
return container->median;
|
||||
|
||||
}
|
||||
|
||||
DoubleMovingMedian* createDoubleMovingMedian(int capacity)
|
||||
{
|
||||
|
||||
DoubleMovingMedian* container;
|
||||
if ( !(container = calloc (1, sizeof(DoubleMovingMedian))) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((container->meanContainer = createDoubleMovingMean(capacity))
|
||||
== NULL) {
|
||||
free(container);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
freeDoubleMovingMedian(DoubleMovingMedian** container)
|
||||
{
|
||||
|
||||
freeDoubleMovingMean(&((*container)->meanContainer));
|
||||
free(*container);
|
||||
*container = NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
resetDoubleMovingMedian(DoubleMovingMedian* container)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return;
|
||||
resetDoubleMovingMean(container->meanContainer);
|
||||
container->median = 0;
|
||||
|
||||
}
|
||||
|
||||
double
|
||||
feedDoubleMovingMedian(DoubleMovingMedian* container, double sample)
|
||||
{
|
||||
|
||||
if(container == NULL)
|
||||
return 0;
|
||||
|
||||
feedDoubleMovingMean(container->meanContainer, sample);
|
||||
|
||||
int count = container->meanContainer->count;
|
||||
|
||||
double sortedSamples[count];
|
||||
|
||||
Boolean odd = ((count %2 ) == 1);
|
||||
|
||||
memcpy(sortedSamples, container->meanContainer->samples, count * sizeof(sample));
|
||||
|
||||
qsort(sortedSamples, count, sizeof(sample), cmpDouble);
|
||||
|
||||
if(odd) {
|
||||
|
||||
container->median = sortedSamples[(count / 2)];
|
||||
|
||||
} else {
|
||||
|
||||
container->median = (sortedSamples[(count / 2) -1] + sortedSamples[(count / 2)]) / 2;
|
||||
|
||||
}
|
||||
|
||||
DBGV("Median sample %.09f median %.09f\n", sample, container->median);
|
||||
|
||||
return container->median;
|
||||
|
||||
}
|
||||
|
||||
double getpeircesCriterion(int numObservations, int numDoubtful) {
|
||||
|
||||
static const double peircesTable[60][9] = {
|
||||
/* 1 - 10 samples */
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
{1.196, -1, -1, -1, -1, -1, -1, -1, -1},
|
||||
{1.383, 1.078, -1, -1, -1, -1, -1, -1, -1},
|
||||
{1.509, 1.2, -1, -1, -1, -1, -1, -1, -1},
|
||||
{1.61, 1.299, 1.099, -1, -1, -1, -1, -1, -1},
|
||||
{1.693, 1.382, 1.187, 1.022, -1, -1, -1, -1, -1},
|
||||
{1.763, 1.453, 1.261, 1.109, -1, -1, -1, -1, -1},
|
||||
{1.824, 1.515, 1.324, 1.178, 1.045, -1, -1, -1, -1},
|
||||
{1.878, 1.57, 1.38, 1.237, 1.114, -1, -1, -1, -1},
|
||||
/* 11 - 20 samples */
|
||||
{1.925, 1.619, 1.43, 1.289, 1.172, 1.059, -1, -1, -1},
|
||||
{1.969, 1.663, 1.475, 1.336, 1.221, 1.118, 1.009, -1, -1},
|
||||
{2.007, 1.704, 1.516, 1.379, 1.266, 1.167, 1.07, -1, -1},
|
||||
{2.043, 1.741, 1.554, 1.417, 1.307, 1.21, 1.12, 1.026, -1},
|
||||
{2.076, 1.775, 1.589, 1.453, 1.344, 1.249, 1.164, 1.078, -1},
|
||||
{2.106, 1.807, 1.622, 1.486, 1.378, 1.285, 1.202, 1.122, 1.039},
|
||||
{2.134, 1.836, 1.652, 1.517, 1.409, 1.318, 1.237, 1.161, 1.084},
|
||||
{2.161, 1.864, 1.68, 1.546, 1.438, 1.348, 1.268, 1.195, 1.123},
|
||||
{2.185, 1.89, 1.707, 1.573, 1.466, 1.377, 1.298, 1.226, 1.158},
|
||||
{2.209, 1.914, 1.732, 1.599, 1.492, 1.404, 1.326, 1.255, 1.19},
|
||||
/* 21 - 30 samples */
|
||||
{2.23, 1.938, 1.756, 1.623, 1.517, 1.429, 1.352, 1.282, 1.218},
|
||||
{2.251, 1.96, 1.779, 1.646, 1.54, 1.452, 1.376, 1.308, 1.245},
|
||||
{2.271, 1.981, 1.8, 1.668, 1.563, 1.475, 1.399, 1.332, 1.27},
|
||||
{2.29, 2, 1.821, 1.689, 1.584, 1.497, 1.421, 1.354, 1.293},
|
||||
{2.307, 2.019, 1.84, 1.709, 1.604, 1.517, 1.442, 1.375, 1.315},
|
||||
{2.324, 2.037, 1.859, 1.728, 1.624, 1.537, 1.462, 1.396, 1.336},
|
||||
{2.341, 2.055, 1.877, 1.746, 1.642, 1.556, 1.481, 1.415, 1.356},
|
||||
{2.356, 2.071, 1.894, 1.764, 1.66, 1.574, 1.5, 1.434, 1.375},
|
||||
{2.371, 2.088, 1.911, 1.781, 1.677, 1.591, 1.517, 1.452, 1.393},
|
||||
/* 31 - 40 samples */
|
||||
{2.385, 2.103, 1.927, 1.797, 1.694, 1.608, 1.534, 1.469, 1.411},
|
||||
{2.399, 2.118, 1.942, 1.812, 1.71, 1.624, 1.55, 1.486, 1.428},
|
||||
{2.412, 2.132, 1.957, 1.828, 1.725, 1.64, 1.567, 1.502, 1.444},
|
||||
{2.425, 2.146, 1.971, 1.842, 1.74, 1.655, 1.582, 1.517, 1.459},
|
||||
{2.438, 2.159, 1.985, 1.856, 1.754, 1.669, 1.597, 1.532, 1.475},
|
||||
{2.45, 2.172, 1.998, 1.87, 1.768, 1.683, 1.611, 1.547, 1.489},
|
||||
{2.461, 2.184, 2.011, 1.883, 1.782, 1.697, 1.624, 1.561, 1.504},
|
||||
{2.472, 2.196, 2.024, 1.896, 1.795, 1.711, 1.638, 1.574, 1.517},
|
||||
{2.483, 2.208, 2.036, 1.909, 1.807, 1.723, 1.651, 1.587, 1.531},
|
||||
/* 41 - 50 samples */
|
||||
{2.494, 2.219, 2.047, 1.921, 1.82, 1.736, 1.664, 1.6, 1.544},
|
||||
{2.504, 2.23, 2.059, 1.932, 1.832, 1.748, 1.676, 1.613, 1.556},
|
||||
{2.514, 2.241, 2.07, 1.944, 1.843, 1.76, 1.688, 1.625, 1.568},
|
||||
{2.524, 2.251, 2.081, 1.955, 1.855, 1.771, 1.699, 1.636, 1.58},
|
||||
{2.533, 2.261, 2.092, 1.966, 1.866, 1.783, 1.711, 1.648, 1.592},
|
||||
{2.542, 2.271, 2.102, 1.976, 1.876, 1.794, 1.722, 1.659, 1.603},
|
||||
{2.551, 2.281, 2.112, 1.987, 1.887, 1.804, 1.733, 1.67, 1.614},
|
||||
{2.56, 2.29, 2.122, 1.997, 1.897, 1.815, 1.743, 1.681, 1.625},
|
||||
{2.568, 2.299, 2.131, 2.006, 1.907, 1.825, 1.754, 1.691, 1.636},
|
||||
{2.577, 2.308, 2.14, 2.016, 1.917, 1.835, 1.764, 1.701, 1.646},
|
||||
/* 51 - 60 * samples */
|
||||
{2.585, 2.317, 2.149, 2.026, 1.927, 1.844, 1.773, 1.711, 1.656},
|
||||
{2.592, 2.326, 2.158, 2.035, 1.936, 1.854, 1.783, 1.721, 1.666},
|
||||
{2.6, 2.334, 2.167, 2.044, 1.945, 1.863, 1.792, 1.73, 1.675},
|
||||
{2.608, 2.342, 2.175, 2.052, 1.954, 1.872, 1.802, 1.74, 1.685},
|
||||
{2.615, 2.35, 2.184, 2.061, 1.963, 1.881, 1.811, 1.749, 1.694},
|
||||
{2.622, 2.358, 2.192, 2.069, 1.972, 1.89, 1.82, 1.758, 1.703},
|
||||
{2.629, 2.365, 2.2, 2.077, 1.98, 1.898, 1.828, 1.767, 1.711},
|
||||
{2.636, 2.373, 2.207, 2.085, 1.988, 1.907, 1.837, 1.775, 1.72},
|
||||
{2.643, 2.38, 2.215, 2.093, 1.996, 1.915, 1.845, 1.784, 1.729},
|
||||
{2.65, 2.387, 2.223, 2.101, 2.004, 1.923, 1.853, 1.792, 1.737},
|
||||
{2.656, 2.394, 2.23, 2.109, 2.012, 1.931, 1.861, 1.8, 1.745},
|
||||
{2.663, 2.401, 2.237, 2.116, 2.019, 1.939, 1.869, 1.808, 1.753},
|
||||
};
|
||||
|
||||
if ( numObservations < 1 || numObservations > 60)
|
||||
return -1.0;
|
||||
if ( numDoubtful < 1 || numDoubtful > 9)
|
||||
return -1.0;
|
||||
|
||||
return(peircesTable[numObservations - 1][numDoubtful - 1]);
|
||||
|
||||
}
|
||||
|
||||
Boolean isIntPeircesOutlier(IntMovingStdDev *container, int32_t sample, double threshold) {
|
||||
|
||||
double maxDev;
|
||||
|
||||
/* Sanity check - race condition was seen when enabling and disabling filters repeatedly */
|
||||
if(container == NULL || container->meanContainer == NULL)
|
||||
return FALSE;
|
||||
|
||||
maxDev = container->stdDev * getpeircesCriterion(container->meanContainer->count, 1) * threshold;
|
||||
|
||||
/*
|
||||
* Two cases:
|
||||
* - Too early - we got a -1 from Peirce's table,
|
||||
* - safeguard: std dev is zero and filter is blocking
|
||||
* everything, hus, we let the sample through
|
||||
*/
|
||||
if (maxDev <= 0.0 ) return FALSE;
|
||||
|
||||
if(fabs((double)(sample - container->meanContainer->mean)) > maxDev) {
|
||||
DBGV("Peirce %s outlier: val: %d, cnt: %d, mxd: %.09f (%.03f * dev * %.03f), dev: %.09f, mea: %.09f, dif: %.09f\n", container->identifier,
|
||||
sample, container->meanContainer->count, maxDev, getpeircesCriterion(container->meanContainer->count, 1), threshold,
|
||||
container->stdDev,
|
||||
container->meanContainer->mean, fabs(sample - container->meanContainer->mean));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
Boolean isDoublePeircesOutlier(DoubleMovingStdDev *container, double sample, double threshold) {
|
||||
|
||||
double maxDev;
|
||||
|
||||
/* Sanity check - race condition was seen when enabling and disabling filters repeatedly */
|
||||
if(container == NULL || container->meanContainer == NULL)
|
||||
return FALSE;
|
||||
|
||||
maxDev = container->stdDev * getpeircesCriterion(container->meanContainer->count, 1) * threshold;
|
||||
|
||||
/*
|
||||
* Two cases:
|
||||
* - Too early - we got a -1 from Peirce's table,
|
||||
* - safeguard: std dev is zero and filter is blocking
|
||||
* everything, hus, we let the sample through
|
||||
*/
|
||||
if (maxDev <= 0.0 ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(fabs((double)(sample - container->meanContainer->mean)) > maxDev) {
|
||||
DBGV("Peirce %s outlier: val: %.09f, cnt: %d, mxd: %.09f (%.03f * dev * %.03f), dev: %.09f, mea: %.09f, dif: %.09f\n", container->identifier,
|
||||
sample, container->meanContainer->count, maxDev, getpeircesCriterion(container->meanContainer->count, 1), threshold,
|
||||
container->stdDev,
|
||||
container->meanContainer->mean, fabs(sample - container->meanContainer->mean));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
clearPtpEngineSlaveStats(PtpEngineSlaveStats* stats)
|
||||
{
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
}
|
||||
|
||||
void
|
||||
resetPtpEngineSlaveStats(PtpEngineSlaveStats* stats) {
|
||||
|
||||
resetDoublePermanentStdDev(&stats->ofmStats);
|
||||
resetDoublePermanentStdDev(&stats->owdStats);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file statistics.h
|
||||
* @authors Wojciech Owczarek
|
||||
* @date Sun Jul 7 13:28:10 2013
|
||||
*
|
||||
* This header file contains the definitions of structures and functions
|
||||
* implementing standard statistical measures - means and standard deviations,
|
||||
* both complete (from t0 to tnow) and moving (from t0+n*windowsize to t0+(n+1)*windowsize)
|
||||
*/
|
||||
|
||||
#ifndef STATISTICS_H_
|
||||
#define STATISTICS_H_
|
||||
|
||||
#define STATCONTAINER_MAX_SAMPLES 60
|
||||
|
||||
/* "Permanent" i.e. non-moving statistics containers - useful for long term measurement */
|
||||
|
||||
typedef struct {
|
||||
|
||||
int32_t mean;
|
||||
int32_t count;
|
||||
|
||||
} IntPermanentMean;
|
||||
|
||||
typedef struct {
|
||||
|
||||
double mean;
|
||||
double count;
|
||||
|
||||
} DoublePermanentMean;
|
||||
|
||||
typedef struct {
|
||||
|
||||
IntPermanentMean meanContainer;
|
||||
int32_t squareSum;
|
||||
int32_t stdDev;
|
||||
|
||||
} IntPermanentStdDev;
|
||||
|
||||
typedef struct {
|
||||
|
||||
DoublePermanentMean meanContainer;
|
||||
double squareSum;
|
||||
double stdDev;
|
||||
|
||||
} DoublePermanentStdDev;
|
||||
|
||||
void resetIntPermanentMean(IntPermanentMean* container);
|
||||
int32_t feedIntPermanentMean(IntPermanentMean* container, int32_t sample);
|
||||
void resetIntPermanentStdDev(IntPermanentStdDev* container);
|
||||
int32_t feedIntPermanentStdDev(IntPermanentStdDev* container, int32_t sample);
|
||||
|
||||
void resetDoublePermanentMean(DoublePermanentMean* container);
|
||||
double feedDoublePermanentMean(DoublePermanentMean* container, double sample);
|
||||
void resetDoublePermanentStdDev(DoublePermanentStdDev* container);
|
||||
double feedDoublePermanentStdDev(DoublePermanentStdDev* container, double sample);
|
||||
|
||||
/* Moving statistics - up to last n samples */
|
||||
|
||||
typedef struct {
|
||||
|
||||
int32_t mean;
|
||||
int32_t sum;
|
||||
int32_t* samples;
|
||||
Boolean full;
|
||||
int count;
|
||||
int capacity;
|
||||
|
||||
} IntMovingMean;
|
||||
|
||||
typedef struct {
|
||||
|
||||
double mean;
|
||||
double sum;
|
||||
double* samples;
|
||||
Boolean full;
|
||||
int count;
|
||||
int capacity;
|
||||
|
||||
} DoubleMovingMean;
|
||||
|
||||
typedef struct {
|
||||
|
||||
IntMovingMean* meanContainer;
|
||||
int32_t squareSum;
|
||||
int32_t stdDev;
|
||||
char* identifier[10];
|
||||
|
||||
} IntMovingStdDev;
|
||||
|
||||
typedef struct {
|
||||
|
||||
DoubleMovingMean* meanContainer;
|
||||
double squareSum;
|
||||
double stdDev;
|
||||
char identifier[10];
|
||||
|
||||
} DoubleMovingStdDev;
|
||||
|
||||
typedef struct {
|
||||
|
||||
IntMovingMean* meanContainer;
|
||||
int32_t median;
|
||||
int32_t* sortedSamples;
|
||||
char* identifier[10];
|
||||
|
||||
} IntMovingMedian;
|
||||
|
||||
typedef struct {
|
||||
|
||||
DoubleMovingMean* meanContainer;
|
||||
double median;
|
||||
double* sortedSamples;
|
||||
char* identifier[10];
|
||||
|
||||
} DoubleMovingMedian;
|
||||
|
||||
IntMovingMean* createIntMovingMean(int capacity);
|
||||
void freeIntMovingMean(IntMovingMean** container);
|
||||
void resetIntMovingMean(IntMovingMean* container);
|
||||
int32_t feedIntMovingMean(IntMovingMean* container, int32_t sample);
|
||||
|
||||
IntMovingStdDev* createIntMovingStdDev(int capacity);
|
||||
void freeIntMovingStdDev(IntMovingStdDev** container);
|
||||
void resetIntMovingStdDev(IntMovingStdDev* container);
|
||||
int32_t feedIntMovingStdDev(IntMovingStdDev* container, int32_t sample);
|
||||
|
||||
DoubleMovingMean* createDoubleMovingMean(int capacity);
|
||||
void freeDoubleMovingMean(DoubleMovingMean** container);
|
||||
void resetDoubleMovingMean(DoubleMovingMean* container);
|
||||
double feedDoubleMovingMean(DoubleMovingMean* container, double sample);
|
||||
|
||||
DoubleMovingStdDev* createDoubleMovingStdDev(int capacity);
|
||||
void freeDoubleMovingStdDev(DoubleMovingStdDev** container);
|
||||
void resetDoubleMovingStdDev(DoubleMovingStdDev* container);
|
||||
double feedDoubleMovingStdDev(DoubleMovingStdDev* container, double sample);
|
||||
|
||||
IntMovingMedian* createIntMovingMedian(int capacity);
|
||||
void freeIntMovingMedian(IntMovingMedian** container);
|
||||
void resetIntMovingMedian(IntMovingMedian* container);
|
||||
int32_t feedIntMovingMedian(IntMovingMedian* container, int32_t sample);
|
||||
|
||||
DoubleMovingMedian* createDoubleMovingMedian(int capacity);
|
||||
void freeDoubleMovingMedian(DoubleMovingMedian** container);
|
||||
void resetDoubleMovingMedian(DoubleMovingMedian* container);
|
||||
double feedDoubleMovingMedian(DoubleMovingMedian* container, double sample);
|
||||
|
||||
void intStatsTest(int32_t sample);
|
||||
void doubleStatsTest(double sample);
|
||||
|
||||
double getPeircesCriterion(int numObservations, int numDoubtful);
|
||||
|
||||
Boolean isIntPeircesOutlier(IntMovingStdDev *container, int32_t sample, double threshold);
|
||||
Boolean isDoublePeircesOutlier(DoubleMovingStdDev *container, double sample, double threshold);
|
||||
|
||||
/**
|
||||
* \struct PtpEngineSlaveStats
|
||||
* \brief Ptpd clock statistics per port
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Boolean statsCalculated;
|
||||
double ofmMean;
|
||||
double ofmStdDev;
|
||||
double owdMean;
|
||||
double owdStdDev;
|
||||
Boolean owdIsStable;
|
||||
double owdStabilityThreshold;
|
||||
int owdStabilityPeriod;
|
||||
DoublePermanentStdDev ofmStats;
|
||||
DoublePermanentStdDev owdStats;
|
||||
} PtpEngineSlaveStats;
|
||||
|
||||
void clearPtpEngineSlaveStats(PtpEngineSlaveStats* stats);
|
||||
void resetPtpEngineSlaveStats(PtpEngineSlaveStats* stats);
|
||||
|
||||
#endif /*STATISTICS_H_*/
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,291 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Wind River Systems, Inc,
|
||||
* Copyright (c) 2011-2012 George V. Neville-Neil,
|
||||
* Steven Kreuzer,
|
||||
* Martin Burnicki,
|
||||
* Jan Breuer,
|
||||
* Gael Mace,
|
||||
* Alexandre Van Kempen,
|
||||
* Inaqui Delgado,
|
||||
* Rick Ratzel,
|
||||
* National Instruments.
|
||||
* Copyright (c) 2009-2010 George V. Neville-Neil,
|
||||
* Steven Kreuzer,
|
||||
* Martin Burnicki,
|
||||
* Jan Breuer,
|
||||
* Gael Mace,
|
||||
* Alexandre Van Kempen
|
||||
*
|
||||
* Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02feb16,h_l Init version.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file timer.c
|
||||
* @date Wed Jun 23 09:41:26 2010
|
||||
*
|
||||
* @brief The timers which run the state machine.
|
||||
*
|
||||
* Timers in the PTP daemon are run off of the signal system.
|
||||
*/
|
||||
|
||||
#include "../ptpd.h"
|
||||
|
||||
#define US_TIMER_INTERVAL (62500)
|
||||
volatile unsigned int elapsed;
|
||||
|
||||
static timer_t ptpd_timerid;
|
||||
|
||||
/*
|
||||
* original code calls sigalarm every fixed 1ms. This highly pollutes the debug_log, and causes more interrupted instructions
|
||||
* This was later modified to have a fixed granularity of 1s.
|
||||
*
|
||||
* Currently this has a configured granularity, and timerStart() guarantees that clocks expire ASAP when the granularity is too small.
|
||||
* Timers must now be explicitelly canceled with timerStop (instead of timerStart(0.0))
|
||||
*/
|
||||
|
||||
void
|
||||
catch_alarm(int sig)
|
||||
{
|
||||
elapsed++;
|
||||
/* be sure to NOT call DBG in asynchronous handlers! */
|
||||
}
|
||||
|
||||
void
|
||||
initTimer(void)
|
||||
{
|
||||
struct itimerval itimer;
|
||||
|
||||
DBG("initTimer\n");
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
|
||||
elapsed = 0;
|
||||
itimer.it_value.tv_sec = itimer.it_interval.tv_sec = 0;
|
||||
itimer.it_value.tv_usec = itimer.it_interval.tv_usec = US_TIMER_INTERVAL;
|
||||
|
||||
signal(SIGALRM, catch_alarm);
|
||||
#ifdef VXWORKS_OS
|
||||
/*timer_create (CLOCK_REALTIME, NULL, &ptpd_timerid);
|
||||
timer_settime(ptpd_timerid, 0, &itimer, NULL);*/
|
||||
#else
|
||||
setitimer(ITIMER_REAL, &itimer, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
timerUpdate(IntervalTimer * itimer)
|
||||
{
|
||||
|
||||
int i, delta;
|
||||
|
||||
/*
|
||||
* latch how many ticks we got since we were last called
|
||||
* remember that catch_alarm() is totally asynchronous to this timerUpdate()
|
||||
*/
|
||||
#if 0
|
||||
delta = elapsed;
|
||||
elapsed = 0;
|
||||
|
||||
if (delta <= 0)
|
||||
return;
|
||||
|
||||
#endif
|
||||
/*
|
||||
* if time actually passed, then decrease every timer left
|
||||
* the one(s) that went to zero or negative are:
|
||||
* a) rearmed at the original time (ignoring the time that may have passed ahead)
|
||||
* b) have their expiration latched until timerExpired() is called
|
||||
*/
|
||||
for (i = 0; i < TIMER_ARRAY_SIZE; ++i) {
|
||||
if ((itimer[i].interval) > 0 && ((itimer[i].left) <= tickGet()) ) {
|
||||
#ifdef VXWORKS_OS
|
||||
itimer[i].left = itimer[i].interval + tickGet();
|
||||
#else
|
||||
itimer[i].left = itimer[i].interval;
|
||||
#endif
|
||||
itimer[i].expire = TRUE;
|
||||
DBG2("TimerUpdate: Timer %u has now expired. (Re-armed again with interval %d, left %d)\n", i, itimer[i].interval, itimer[i].left );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
timerStop(UInteger16 index, IntervalTimer * itimer)
|
||||
{
|
||||
if (index >= TIMER_ARRAY_SIZE)
|
||||
return;
|
||||
|
||||
itimer[index].interval = 0;
|
||||
DBG2("timerStop: Stopping timer %d. (New interval: %d; New left: %d)\n", index, itimer[index].left , itimer[index].interval);
|
||||
}
|
||||
|
||||
void
|
||||
timerStart(UInteger16 index, float interval, IntervalTimer * itimer)
|
||||
{
|
||||
if (index >= TIMER_ARRAY_SIZE)
|
||||
return;
|
||||
|
||||
itimer[index].expire = FALSE;
|
||||
|
||||
|
||||
/*
|
||||
* US_TIMER_INTERVAL defines the minimum interval between sigalarms.
|
||||
* timerStart has a float parameter for the interval, which is casted to integer.
|
||||
* very small amounts are forced to expire ASAP by setting the interval to 1
|
||||
*/
|
||||
#ifdef VXWORKS_OS
|
||||
itimer[index].left = tickGet() + (UInteger32)(interval * sysClkRateGet()) ;
|
||||
#else
|
||||
itimer[index].left = (int)((interval * 1E6) / US_TIMER_INTERVAL);
|
||||
#endif
|
||||
if(itimer[index].left == 0){
|
||||
/*
|
||||
* the interval is too small, raise it to 1 to make sure it expires ASAP
|
||||
* Timer cancelation is done explicitelly with stopTimer()
|
||||
*/
|
||||
itimer[index].left = 1;
|
||||
|
||||
static int operator_warned_interval_too_small = 0;
|
||||
if(!operator_warned_interval_too_small){
|
||||
operator_warned_interval_too_small = 1;
|
||||
/*
|
||||
* using random uniform timers it is pratically guarantted that we hit the possible minimum timer.
|
||||
* This is because of the current timer model based on periodic sigalarm, irrespective if the next
|
||||
* event is close or far away in time.
|
||||
*
|
||||
* A solution would be to recode this whole module with a calendar queue, while keeping the same API:
|
||||
* E.g.: http://www.isi.edu/nsnam/ns/doc/node35.html
|
||||
*
|
||||
* Having events that expire immediatly (ie, delayreq invocations using random timers) can lead to
|
||||
* messages appearing in unexpected ordering, so the protocol implementation must check more conditions
|
||||
* and not assume a certain ususal ordering
|
||||
*/
|
||||
DBG("Timer would be issued immediatly. Please raise dep/timer.c:US_TIMER_INTERVAL to hold %.2fs\n",
|
||||
interval
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
#ifdef VXWORKS_OS
|
||||
itimer[index].interval = (UInteger32)(interval * sysClkRateGet());
|
||||
if(itimer[index].interval == 0)
|
||||
{
|
||||
itimer[index].interval = 1;
|
||||
}
|
||||
#else
|
||||
itimer[index].interval = itimer[index].left;
|
||||
#endif
|
||||
#if 0
|
||||
printf("timerStart: Set timer index %d to internal %f New left: %d; new interval: %d\n", index, interval, itimer[index].left , itimer[index].interval);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function arms the timer with a uniform range, as requested by page 105 of the standard (for sending delayReqs.)
|
||||
* actual time will be U(0, interval * 2.0);
|
||||
*
|
||||
* PTPv1 algorithm was:
|
||||
* ptpClock->R = getRand(&ptpClock->random_seed) % (PTP_DELAY_REQ_INTERVAL - 2) + 2;
|
||||
* R is the number of Syncs to be received, before sending a new request
|
||||
*
|
||||
*/
|
||||
void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer)
|
||||
{
|
||||
float new_value;
|
||||
|
||||
new_value = getRand() * interval ;
|
||||
DBG2(" timerStart_random: requested %.2f, got %.2f\n", interval, new_value);
|
||||
|
||||
timerStart(index, new_value, itimer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Boolean
|
||||
timerExpired(UInteger16 index, IntervalTimer * itimer)
|
||||
{
|
||||
timerUpdate(itimer);
|
||||
|
||||
if (index >= TIMER_ARRAY_SIZE)
|
||||
return FALSE;
|
||||
|
||||
if (!itimer[index].expire)
|
||||
return FALSE;
|
||||
|
||||
itimer[index].expire = FALSE;
|
||||
|
||||
#if 0
|
||||
DBG2("timerExpired: Timer %d expired, taking actions. current interval: %d; current left: %d\n", index, itimer[index].left , itimer[index].interval);
|
||||
#else
|
||||
/*
|
||||
logMsg("timerExpired: Timer %d expired, taking actions. current left: %d; current interval: %d\n", index, itimer[index].left , itimer[index].interval,0,0,0);
|
||||
*/
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Boolean
|
||||
timerStopped(UInteger16 index, IntervalTimer * itimer)
|
||||
{
|
||||
timerUpdate(itimer);
|
||||
|
||||
if (index >= TIMER_ARRAY_SIZE)
|
||||
return FALSE;
|
||||
|
||||
if (itimer[index].interval == 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
Boolean
|
||||
timerRunning(UInteger16 index, IntervalTimer * itimer)
|
||||
{
|
||||
timerUpdate(itimer);
|
||||
|
||||
if (index >= TIMER_ARRAY_SIZE)
|
||||
return FALSE;
|
||||
|
||||
if ((itimer[index].interval != 0) &&
|
||||
(itimer[index].expire == FALSE)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user