Beispiel #1
0
/*Local clock is synchronized to Ebest Table 16 (9.3.5) of the spec*/
void s1(MsgHeader *header,MsgAnnounce *announce,PtpClock *ptpClock, RunTimeOpts *rtOpts)
{

	Boolean previousLeap59 = FALSE, previousLeap61 = FALSE;
	Integer16 previousUtcOffset = 0;

	if (ptpClock->portState == PTP_SLAVE) {
		previousLeap59 = ptpClock->leap59;
		previousLeap61 = ptpClock->leap61;
		previousUtcOffset = ptpClock->currentUtcOffset;
	}

	/* Current DS */
	ptpClock->stepsRemoved = announce->stepsRemoved + 1;

	/* Parent DS */
	copyClockIdentity(ptpClock->parentPortIdentity.clockIdentity,
	       header->sourcePortIdentity.clockIdentity);
	ptpClock->parentPortIdentity.portNumber = 
		header->sourcePortIdentity.portNumber;
	copyClockIdentity(ptpClock->grandmasterIdentity,
			announce->grandmasterIdentity);
	ptpClock->grandmasterClockQuality.clockAccuracy = 
		announce->grandmasterClockQuality.clockAccuracy;
	ptpClock->grandmasterClockQuality.clockClass = 
		announce->grandmasterClockQuality.clockClass;
	ptpClock->grandmasterClockQuality.offsetScaledLogVariance = 
		announce->grandmasterClockQuality.offsetScaledLogVariance;
	ptpClock->grandmasterPriority1 = announce->grandmasterPriority1;
	ptpClock->grandmasterPriority2 = announce->grandmasterPriority2;

	/* Timeproperties DS */
	ptpClock->currentUtcOffset = announce->currentUtcOffset;

        /* "Valid" is bit 2 in second octet of flagfield */
        ptpClock->currentUtcOffsetValid = IS_SET(header->flagField1, UTCV);

	/* set PTP_PASSIVE-specific state */
	p1(ptpClock, rtOpts);

	/* only set leap state in slave mode */
	if (ptpClock->portState == PTP_SLAVE) {
		ptpClock->leap59 = IS_SET(header->flagField1, LI59);
		ptpClock->leap61 = IS_SET(header->flagField1, LI61);
	}

        ptpClock->timeTraceable = IS_SET(header->flagField1, TTRA);
        ptpClock->frequencyTraceable = IS_SET(header->flagField1, FTRA);
        ptpClock->ptpTimescale = IS_SET(header->flagField1, PTPT);
        ptpClock->timeSource = announce->timeSource;

#if defined(MOD_TAI) &&  NTP_API == 4
	/*
	 * update kernel TAI offset, but only if timescale is
	 * PTP not ARB - spec section 7.2
	 */
        if (ptpClock->ptpTimescale &&
            (ptpClock->currentUtcOffset != previousUtcOffset)) {
		setKernelUtcOffset(ptpClock->currentUtcOffset);
        }
#endif /* MOD_TAI */

	/* Leap second handling */

        if (ptpClock->portState == PTP_SLAVE) {
		if(ptpClock->leap59 && ptpClock->leap61) {
			ERROR("Both Leap59 and Leap61 flags set!\n");
			toState(PTP_FAULTY, rtOpts, ptpClock);
			return;
		}

		/* one of the leap second flags has suddenly been unset */
		if(ptpClock->leapSecondPending && 
		    !ptpClock->leapSecondInProgress &&
		    ((previousLeap59 != ptpClock->leap59) || 
		     (previousLeap61 != ptpClock->leap61))) {
			WARNING("=== Leap second event aborted by GM!");
			ptpClock->leapSecondPending = FALSE;
			ptpClock->leapSecondInProgress = FALSE;
			timerStop(LEAP_SECOND_PAUSE_TIMER, ptpClock->itimer);
      /** FIXME dumblob */
#if !defined(__APPLE__) && !defined(__QNXNTO__)
			unsetTimexFlags(STA_INS | STA_DEL,TRUE);
#endif /* apple */
		}

		/*
		 * one of the leap second flags has been set
		 * or flags are lit but we have no event pending
		 */
		if( (ptpClock->leap59 || ptpClock->leap61) && (
		    (!ptpClock->leapSecondPending && 
		    !ptpClock->leapSecondInProgress ) ||
		    ((!previousLeap59 && ptpClock->leap59) ||
		    (!previousLeap61 && ptpClock->leap61)))) {
#if !defined(__APPLE__) && !defined(__QNXNTO__)
			WARNING("=== Leap second pending! Setting kernel to %s "
				"one second at midnight\n",
				ptpClock->leap61 ? "add" : "delete");
		    if (!checkTimexFlags(ptpClock->leap61 ? STA_INS : STA_DEL)) {
			    unsetTimexFlags(ptpClock->leap61 ? STA_DEL : STA_INS,
					    TRUE);
			    setTimexFlags(ptpClock->leap61 ? STA_INS : STA_DEL,
					  FALSE);
		    }
#else
			WARNING("=== Leap second pending! No kernel leap second "
				"API support - expect a clock jump at "
				"midnight!\n");
#endif /* apple */
			/* only set the flag, the rest happens in doState() */
			ptpClock->leapSecondPending = TRUE;
		}

		if((previousUtcOffset != ptpClock->currentUtcOffset) && 
		   !ptpClock->leapSecondPending && 
		   !ptpClock->leapSecondInProgress ) {
			WARNING("=== UTC offset changed from %d to %d with "
				"no leap second pending!\n",
				previousUtcOffset, ptpClock->currentUtcOffset);
		} else if( previousUtcOffset != ptpClock->currentUtcOffset) {
			WARNING("=== UTC offset changed from %d to %d\n",
				previousUtcOffset,ptpClock->currentUtcOffset);
		}
	}
}
Beispiel #2
0
void
updateClock(RunTimeOpts * rtOpts, PtpClock * ptpClock)
{

	/* updates paused, leap second pending - do nothing */
        if(ptpClock->leapSecondInProgress)
            return;
	DBGV("==> updateClock\n");

	if(ptpClock->panicMode) {
	    DBG("Panic mode - skipping updateClock");
	}



/*
if(rtOpts->delayMSOutlierFilterEnabled && rtOpts->delayMSOutlierFilterDiscard && ptpClock->delayMSoutlier)
	    goto display;
*/
	if (rtOpts->maxReset) { /* If maxReset is 0 then it's OFF */
		if (ptpClock->offsetFromMaster.seconds && rtOpts->maxReset) {
			INFO("updateClock aborted, offset greater than 1"
			     " second.");
			if (rtOpts->displayPackets)
				msgDump(ptpClock);
			goto display;
		}

		if (ptpClock->offsetFromMaster.nanoseconds > rtOpts->maxReset) {
			INFO("updateClock aborted, offset %d greater than "
			     "administratively set maximum %d\n",
			     ptpClock->offsetFromMaster.nanoseconds, 
			     rtOpts->maxReset);
			if (rtOpts->displayPackets)
				msgDump(ptpClock);
			goto display;
		}
	}

	if (ptpClock->offsetFromMaster.seconds) {
		/* if secs, reset clock or set freq adjustment to max */
		
		/* 
		  if offset from master seconds is non-zero, then this is a "big jump:
		  in time.  Check Run Time options to see if we will reset the clock or
		  set frequency adjustment to max to adjust the time
		*/

		/*
		 * noAdjust     = cannot do any change to clock
		 * noResetClock = if can change the clock, can we also step it?
		 */
		if (!rtOpts->noAdjust) {


	if(rtOpts->enablePanicMode && !ptpClock->panicOver) {

		if(ptpClock->panicMode)
		    goto display;

		if(ptpClock->panicOver) {
		    ptpClock->panicMode = FALSE;
		    ptpClock->panicOver = FALSE;
#ifdef PTPD_STATISTICS
		    ptpClock->isCalibrated = FALSE;
#endif /* PTPD_STATISTICS */
		    goto display;
		}

		CRITICAL("Offset above 1 second - entering panic mode\n");

		ptpClock->panicMode = TRUE;
		ptpClock->panicModeTimeLeft = 2 * rtOpts->panicModeDuration;
		timerStart(PANIC_MODE_TIMER, 30, ptpClock->itimer);

#ifdef PTPD_NTPDC

/* Trigger NTP failover as part of panic mode */

if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {

				/* Make sure we log ntp control errors now */
				ptpClock->ntpControl.requestFailed = FALSE;
                                /* We have a timeout defined */
                                if(rtOpts->ntpOptions.failoverTimeout) {
                                        DBG("NTP failover timer started - panic mode\n");
                                        timerStart(NTPD_FAILOVER_TIMER,
                                                    rtOpts->ntpOptions.failoverTimeout,
                                                    ptpClock->itimer);
                                /* Fail over to NTP straight away */
                                } else {
                                        DBG("Initiating NTP failover\n");
                                        ptpClock->ntpControl.isRequired = TRUE;
                                        ptpClock->ntpControl.isFailOver = TRUE;
                                        if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                                DBG("PANIC MODE instant NTP failover - could not fail over\n");
                                }

}

#endif /* PTPD_NTPDC */
		goto display;

	}

			if(rtOpts->enablePanicMode) {
				if(ptpClock->panicOver)
					CRITICAL("Panic mode timeout - accepting current offset. Clock will jump\n");
				ptpClock->panicOver = FALSE;
				timerStop(PANIC_MODE_TIMER, ptpClock->itimer);

#ifdef PTPD_NTPDC
/* Exiting ntp failover - getting out of panic mode */
	if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {
                            timerStop(NTPD_FAILOVER_TIMER, ptpClock->itimer);
			    ptpClock->ntpControl.isRequired = FALSE;
			    ptpClock->ntpControl.isFailOver = FALSE;
                            if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                DBG("NTPdcontrol - could not return from NTP panic mode\n");
	}
#endif /* PTPD_NTPDC */

			}
			if (!rtOpts->noResetClock) {
				servo_perform_clock_step(rtOpts, ptpClock);
			} else {
#ifdef HAVE_SYS_TIMEX_H
				if(ptpClock->offsetFromMaster.nanoseconds > 0)
				    ptpClock->servo.observedDrift = rtOpts->servoMaxPpb;
				else
				    ptpClock->servo.observedDrift = -rtOpts->servoMaxPpb;
				warn_operator_slow_slewing(rtOpts, ptpClock);
				adjFreq_wrapper(rtOpts, ptpClock, -ptpClock->servo.observedDrift);
				/* its not clear how the APPLE case works for large jumps */
#endif /* HAVE_SYS_TIMEX_H */
			}
		}
	} else {

	    /* If we're in panic mode, either exit if no threshold configured, or exit if we're outside the exit threshold */
	    if(rtOpts->enablePanicMode && 
		((ptpClock->panicMode && ( rtOpts->panicModeExitThreshold == 0 || ((rtOpts->panicModeExitThreshold > 0) &&  ((ptpClock->offsetFromMaster.seconds == 0) && (ptpClock->offsetFromMaster.nanoseconds < rtOpts->panicModeExitThreshold))))   ) || ptpClock->panicOver)) {
		    ptpClock->panicMode = FALSE;
		    ptpClock->panicOver = FALSE;
		    timerStop(PANIC_MODE_TIMER, ptpClock->itimer);
		    NOTICE("Offset below 1 second again: exiting panic mode\n");
#ifdef PTPD_NTPDC
/* exiting ntp failover - panic mode over */
	if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {
                            timerStop(NTPD_FAILOVER_TIMER, ptpClock->itimer);
			    ptpClock->ntpControl.isRequired = FALSE;
			    ptpClock->ntpControl.isFailOver = FALSE;
                            if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                DBG("NTPdcontrol - could not return from NTP panic mode\n");
	}
#endif /* PTPD_NTPDC */

	    }

	/* Servo dT is the log sync interval */
	/* TODO: if logsyincinterval is 127 [unicast], switch to measured */
	if(rtOpts->servoDtMethod == DT_CONSTANT)
		ptpClock->servo.logdT = ptpClock->logSyncInterval;

/* If the last delayMS was an outlier and filter action is discard, skip servo run */
#ifdef PTPD_STATISTICS
	if(rtOpts->delayMSOutlierFilterEnabled && rtOpts->delayMSOutlierFilterDiscard && ptpClock->delayMSoutlier)
		goto statistics;
#endif /* PTPD_STATISTICS */

#ifndef HAVE_SYS_TIMEX_H
			adjTime(ptpClock->offsetFromMaster.nanoseconds);
#else

#ifdef PTPD_STATISTICS
	/* if statistics are enabled, only run the servo if we are calibrted - if calibration delay configured */
	if(!rtOpts->calibrationDelay || ptpClock->isCalibrated)
#endif /*PTPD_STATISTICS */
		/* Adjust the clock first -> the PI controller runs here */
		adjFreq_wrapper(rtOpts, ptpClock, runPIservo(&ptpClock->servo, ptpClock->offsetFromMaster.nanoseconds));
		/* Unset STA_UNSYNC */
		unsetTimexFlags(STA_UNSYNC, TRUE);
		/* "Tell" the clock about maxerror, esterror etc. */
		informClockSource(ptpClock);
#endif /* HAVE_SYS_TIMEX_H */
	}

/* Update relevant statistics containers, feed outlier filter thresholds etc. */
#ifdef PTPD_STATISTICS
statistics:
                        if (rtOpts->delayMSOutlierFilterEnabled) {
                        	double dDelayMS = timeInternalToDouble(&ptpClock->rawDelayMS);
                        	if(ptpClock->delayMSoutlier) {
				/* Allow [weight] * [deviation from mean] to influence std dev in the next outlier checks */
                        		DBG("DelayMS Outlier: %.09f\n", dDelayMS);
                        		dDelayMS = ptpClock->delayMSRawStats->meanContainer->mean + 
						    rtOpts->delayMSOutlierWeight * ( dDelayMS - ptpClock->delayMSRawStats->meanContainer->mean);
                        	}
                                feedDoubleMovingStdDev(ptpClock->delayMSRawStats, dDelayMS);
                                feedDoubleMovingMean(ptpClock->delayMSFiltered, timeInternalToDouble(&ptpClock->delayMS));
                        }
                        feedDoublePermanentStdDev(&ptpClock->slaveStats.ofmStats, timeInternalToDouble(&ptpClock->offsetFromMaster));
                        feedDoublePermanentStdDev(&ptpClock->servo.driftStats, ptpClock->servo.observedDrift);
#endif /* PTPD_STATISTICS */

display:
		logStatistics(rtOpts, ptpClock);

	DBGV("\n--Offset Correction-- \n");
	DBGV("Raw offset from master:  %10ds %11dns\n",
	    ptpClock->delayMS.seconds,
	    ptpClock->delayMS.nanoseconds);

	DBGV("\n--Offset and Delay filtered-- \n");

	if (ptpClock->delayMechanism == P2P) {
		DBGV("one-way delay averaged (P2P):  %10ds %11dns\n",
		    ptpClock->peerMeanPathDelay.seconds, 
		    ptpClock->peerMeanPathDelay.nanoseconds);
	} else if (ptpClock->delayMechanism == E2E) {
		DBGV("one-way delay averaged (E2E):  %10ds %11dns\n",
		    ptpClock->meanPathDelay.seconds, 
		    ptpClock->meanPathDelay.nanoseconds);
	}

	DBGV("offset from master:      %10ds %11dns\n",
	    ptpClock->offsetFromMaster.seconds, 
	    ptpClock->offsetFromMaster.nanoseconds);
	DBGV("observed drift:          %10d\n", ptpClock->servo.observedDrift);
}