mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-01 13:23:01 +02:00
confd: add gps support to ietf-hardware and ietf-ntp
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -150,6 +150,12 @@ static int hardware_cand_infer_class(json_t *root, sr_session_ctx_t *session, co
|
||||
inferred.data.string_val = "infix-hardware:wifi";
|
||||
err = srx_set_item(session, &inferred, 0, "%s/class", xpath);
|
||||
}
|
||||
|
||||
if (!fnmatch("gps+([0-9])", name, FNM_EXTMATCH)) {
|
||||
inferred.data.string_val = "infix-hardware:gps";
|
||||
err = srx_set_item(session, &inferred, 0, "%s/class", xpath);
|
||||
}
|
||||
|
||||
out_free_name:
|
||||
free(name);
|
||||
out_free_xpath:
|
||||
|
||||
+75
-2
@@ -134,12 +134,85 @@ static int change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Reference clock (local stratum) - fallback time source */
|
||||
/* Reference clock configuration */
|
||||
refclock = lydx_get_child(ntp, "refclock-master");
|
||||
if (refclock) {
|
||||
struct lyd_node *source;
|
||||
int stratum = atoi(lydx_get_cattr(refclock, "master-stratum"));
|
||||
bool has_gps_sources = false;
|
||||
|
||||
/* Only configure local clock if stratum is valid (1-15) */
|
||||
/*
|
||||
* GPS/GNSS reference clock sources via gpsd SHM
|
||||
*
|
||||
* Each GPS hardware component (gps0, gps1, ...) maps to:
|
||||
* - SHM unit 2*N for GPS time (coarse, ~100ms)
|
||||
* - SHM unit 2*N+1 for PPS time (precise, ~1us) if enabled
|
||||
*
|
||||
* The mapping is based on gpsd's convention.
|
||||
*/
|
||||
LYX_LIST_FOR_EACH(lyd_child(refclock), source, "source") {
|
||||
const char *receiver, *refid, *poll_str, *precision_str;
|
||||
const char *offset_str, *delay_str;
|
||||
bool prefer, pps;
|
||||
int unit;
|
||||
|
||||
receiver = lydx_get_cattr(source, "receiver");
|
||||
if (!receiver)
|
||||
continue;
|
||||
|
||||
/* Extract unit number from receiver name (gps0 -> 0, gps1 -> 1, ...) */
|
||||
if (sscanf(receiver, "gps%d", &unit) != 1) {
|
||||
ERROR("Invalid GPS receiver name: %s (expected gpsN)", receiver);
|
||||
continue;
|
||||
}
|
||||
|
||||
refid = lydx_get_cattr(source, "refid");
|
||||
poll_str = lydx_get_cattr(source, "poll");
|
||||
precision_str = lydx_get_cattr(source, "precision");
|
||||
offset_str = lydx_get_cattr(source, "offset");
|
||||
delay_str = lydx_get_cattr(source, "delay");
|
||||
prefer = lydx_get_bool(source, "prefer");
|
||||
pps = lydx_get_bool(source, "pps");
|
||||
|
||||
if (!has_gps_sources) {
|
||||
fprintf(fp, "# GPS/GNSS reference clock sources (via gpsd SHM)\n");
|
||||
has_gps_sources = true;
|
||||
}
|
||||
|
||||
/* GPS time source: SHM unit 2*N */
|
||||
fprintf(fp, "refclock SHM %d", unit * 2);
|
||||
if (poll_str)
|
||||
fprintf(fp, " poll %s", poll_str);
|
||||
if (refid)
|
||||
fprintf(fp, " refid %s", refid);
|
||||
if (precision_str)
|
||||
fprintf(fp, " precision %s", precision_str);
|
||||
if (offset_str && atof(offset_str) != 0.0)
|
||||
fprintf(fp, " offset %s", offset_str);
|
||||
if (delay_str && atof(delay_str) != 0.0)
|
||||
fprintf(fp, " delay %s", delay_str);
|
||||
if (prefer)
|
||||
fprintf(fp, " prefer");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* PPS time source: SHM unit 2*N+1 (if enabled) */
|
||||
if (pps) {
|
||||
fprintf(fp, "refclock SHM %d", unit * 2 + 1);
|
||||
fprintf(fp, " poll %s", poll_str ? poll_str : "-6");
|
||||
fprintf(fp, " refid PPS");
|
||||
fprintf(fp, " precision 0.000001");
|
||||
if (prefer)
|
||||
fprintf(fp, " prefer");
|
||||
/* PPS needs a time source for initial lock */
|
||||
fprintf(fp, " lock %s", refid ? refid : "GPS");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (has_gps_sources)
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Local clock fallback - only if stratum is valid (1-15) */
|
||||
if (stratum >= 1 && stratum <= 15) {
|
||||
fprintf(fp, "# Local reference clock - fallback stratum %d source\n", stratum);
|
||||
fprintf(fp, "local stratum %d orphan\n\n", stratum);
|
||||
|
||||
@@ -27,7 +27,7 @@ MODULES=(
|
||||
"infix-syslog@2025-11-17.yang"
|
||||
"iana-hardware@2018-03-13.yang"
|
||||
"ietf-hardware@2018-03-13.yang -e hardware-state -e hardware-sensor"
|
||||
"infix-hardware@2026-01-19.yang"
|
||||
"infix-hardware@2026-02-08.yang"
|
||||
"ieee802-dot1q-types@2022-10-29.yang"
|
||||
"infix-ip@2025-11-02.yang"
|
||||
"infix-if-type@2026-01-07.yang"
|
||||
@@ -51,6 +51,6 @@ MODULES=(
|
||||
"ietf-crypto-types -e cleartext-symmetric-keys"
|
||||
"infix-crypto-types@2025-11-09.yang"
|
||||
"ietf-keystore -e symmetric-keys"
|
||||
"infix-ntp@2025-12-03.yang"
|
||||
"infix-ntp@2026-02-08.yang"
|
||||
"infix-keystore@2025-12-17.yang"
|
||||
)
|
||||
|
||||
@@ -21,6 +21,10 @@ module infix-hardware {
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Vital Product Data augmentation of ieee-hardware and deviations.";
|
||||
|
||||
revision 2026-02-08 {
|
||||
description "Add GPS/GNSS receiver hardware class and container for time sync.";
|
||||
reference "internal";
|
||||
}
|
||||
revision 2026-01-19 {
|
||||
description "Add probe-timeout for slow USB WiFi dongles.";
|
||||
reference "internal";
|
||||
@@ -63,6 +67,15 @@ module infix-hardware {
|
||||
WiFi radios are hardware components with class 'ih:wifi'.";
|
||||
}
|
||||
|
||||
typedef gps-receiver-ref {
|
||||
type leafref {
|
||||
path "/iehw:hardware/iehw:component/iehw:name";
|
||||
}
|
||||
description
|
||||
"Reference to a GPS/GNSS receiver hardware component.
|
||||
GPS receivers are hardware components with class 'ih:gps'.";
|
||||
}
|
||||
|
||||
typedef wifi-band {
|
||||
type enumeration {
|
||||
enum "2.4GHz" {
|
||||
@@ -95,6 +108,11 @@ module infix-hardware {
|
||||
description "This identity is used to describe a WiFi radio/PHY";
|
||||
}
|
||||
|
||||
identity gps {
|
||||
base iahw:hardware-class;
|
||||
description "GPS/GNSS receiver for time synchronization";
|
||||
}
|
||||
|
||||
deviation "/iehw:hardware/iehw:component/iehw:state/iehw:admin-state" {
|
||||
deviate add {
|
||||
must ". = 'locked' or . = 'unlocked'" {
|
||||
@@ -510,5 +528,126 @@ module infix-hardware {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GPS/GNSS Receiver configuration (when class = 'ih:gps')
|
||||
*/
|
||||
|
||||
container gps-receiver {
|
||||
when "derived-from-or-self(../iehw:class, 'ih:gps')";
|
||||
presence "GPS receiver configuration";
|
||||
description
|
||||
"GPS/GNSS receiver configuration and operational data.
|
||||
|
||||
This container is present when the hardware component represents
|
||||
a GPS/GNSS receiver (class 'ih:gps'). GPS receivers provide
|
||||
precision time via gpsd, which chronyd can use as a reference
|
||||
clock through shared memory (SHM).
|
||||
|
||||
The hardware component name (e.g., 'gps0') determines:
|
||||
- Device path: /dev/gps0 (symlink managed by udev)
|
||||
- SHM unit: 0 for GPS time, 1 for PPS (derived from gpsN index)
|
||||
|
||||
Supported GNSS constellations depend on the hardware:
|
||||
- GPS (US)
|
||||
- GLONASS (Russia)
|
||||
- Galileo (EU)
|
||||
- BeiDou (China)";
|
||||
|
||||
/*
|
||||
* Operational state from gpsd
|
||||
*/
|
||||
|
||||
leaf device {
|
||||
config false;
|
||||
type string;
|
||||
description
|
||||
"Actual device path being used (e.g., /dev/ttyUSB0, /dev/ttyACM0).
|
||||
This is the physical device that /dev/gpsN symlinks to.";
|
||||
}
|
||||
|
||||
leaf driver {
|
||||
config false;
|
||||
type string;
|
||||
description
|
||||
"GPS driver/protocol in use (e.g., 'u-blox', 'NMEA', 'SiRF').";
|
||||
}
|
||||
|
||||
leaf activated {
|
||||
config false;
|
||||
type boolean;
|
||||
description
|
||||
"Whether gpsd has successfully activated this GPS device.";
|
||||
}
|
||||
|
||||
leaf satellites-visible {
|
||||
config false;
|
||||
type uint8;
|
||||
description
|
||||
"Number of satellites currently visible to the receiver.";
|
||||
}
|
||||
|
||||
leaf satellites-used {
|
||||
config false;
|
||||
type uint8;
|
||||
description
|
||||
"Number of satellites being used for the fix.";
|
||||
}
|
||||
|
||||
leaf fix-mode {
|
||||
config false;
|
||||
type enumeration {
|
||||
enum "none" {
|
||||
description "No fix available";
|
||||
}
|
||||
enum "2d" {
|
||||
description "2D fix (latitude/longitude only)";
|
||||
}
|
||||
enum "3d" {
|
||||
description "3D fix (latitude/longitude/altitude)";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Current GPS fix mode. A 3D fix is required for accurate time.";
|
||||
}
|
||||
|
||||
leaf latitude {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
units "degrees";
|
||||
description
|
||||
"Current latitude in decimal degrees. Negative values are south.";
|
||||
}
|
||||
|
||||
leaf longitude {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
units "degrees";
|
||||
description
|
||||
"Current longitude in decimal degrees. Negative values are west.";
|
||||
}
|
||||
|
||||
leaf altitude {
|
||||
config false;
|
||||
type decimal64 {
|
||||
fraction-digits 1;
|
||||
}
|
||||
units "meters";
|
||||
description
|
||||
"Current altitude above mean sea level in meters.";
|
||||
}
|
||||
|
||||
leaf pps-available {
|
||||
config false;
|
||||
type boolean;
|
||||
description
|
||||
"Whether this GPS device provides a PPS (Pulse Per Second) signal.
|
||||
PPS provides microsecond-level timing accuracy.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,30 @@ module infix-ntp {
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
import ietf-hardware {
|
||||
prefix iehw;
|
||||
reference
|
||||
"RFC 8348: A YANG Data Model for Hardware Management";
|
||||
}
|
||||
|
||||
import infix-hardware {
|
||||
prefix ih;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix deviations and augments to ietf-ntp.";
|
||||
|
||||
revision 2026-02-08 {
|
||||
description
|
||||
"Add GPS/GNSS reference clock support.
|
||||
|
||||
Augments refclock-master with a list of hardware GPS sources that
|
||||
chronyd can use via gpsd's shared memory (SHM) interface. Supports
|
||||
multiple GNSS receivers for redundancy (GPS, GLONASS, Galileo, BeiDou).";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2025-12-03 {
|
||||
description
|
||||
"Initial release - NTP server support.
|
||||
@@ -70,6 +90,150 @@ module infix-ntp {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GPS/GNSS reference clock sources
|
||||
*
|
||||
* Augments refclock-master with hardware GPS sources that chronyd
|
||||
* can use via gpsd's shared memory (SHM) interface.
|
||||
*/
|
||||
augment "/ntp:ntp/ntp:refclock-master" {
|
||||
list source {
|
||||
key "receiver";
|
||||
max-elements 2;
|
||||
description
|
||||
"GPS/GNSS hardware reference clock sources.
|
||||
|
||||
Each source references a GPS receiver hardware component and
|
||||
configures how chronyd should use it. The hardware component
|
||||
name (e.g., 'gps0') determines the SHM unit number:
|
||||
- gps0 -> SHM 0 (GPS time), SHM 1 (PPS if available)
|
||||
- gps1 -> SHM 2 (GPS time), SHM 3 (PPS if available)
|
||||
|
||||
Two sources can be configured for redundancy against jamming
|
||||
or hardware failure. The NTP server will evaluate all sources
|
||||
and select the best one.";
|
||||
|
||||
leaf receiver {
|
||||
type leafref {
|
||||
path "/iehw:hardware/iehw:component/iehw:name";
|
||||
}
|
||||
must "derived-from-or-self(/iehw:hardware/iehw:component[iehw:name=current()]/iehw:class, 'ih:gps')" {
|
||||
error-message "Referenced hardware component must be a GPS receiver (class 'ih:gps')";
|
||||
}
|
||||
description
|
||||
"Reference to a GPS receiver hardware component.
|
||||
|
||||
The component name determines the device path (/dev/gpsN)
|
||||
and the SHM unit number for chronyd.";
|
||||
}
|
||||
|
||||
leaf poll {
|
||||
type int8 {
|
||||
range "-6..10";
|
||||
}
|
||||
default "2";
|
||||
description
|
||||
"Polling interval in log2 seconds.
|
||||
|
||||
Common values:
|
||||
- -6 = 1/64 second (for hardware with PPS)
|
||||
- 0 = 1 second
|
||||
- 2 = 4 seconds (default, good for GPS without PPS)
|
||||
- 4 = 16 seconds
|
||||
|
||||
Lower values provide faster response but higher CPU usage.";
|
||||
}
|
||||
|
||||
leaf precision {
|
||||
type decimal64 {
|
||||
fraction-digits 9;
|
||||
range "0.000000001..1.0";
|
||||
}
|
||||
default "0.1";
|
||||
units "seconds";
|
||||
description
|
||||
"Assumed precision of the reference clock in seconds.
|
||||
|
||||
Typical values:
|
||||
- 0.1 (100ms) - GPS without PPS, default
|
||||
- 0.001 (1ms) - GPS with software PPS processing
|
||||
- 0.000001 (1us) - GPS with hardware PPS";
|
||||
}
|
||||
|
||||
leaf offset {
|
||||
type decimal64 {
|
||||
fraction-digits 9;
|
||||
}
|
||||
default "0.0";
|
||||
units "seconds";
|
||||
description
|
||||
"Constant offset correction in seconds.
|
||||
|
||||
Used to compensate for known systematic delays in the
|
||||
GPS receiver or signal path. Positive values mean the
|
||||
GPS time is ahead of true time.";
|
||||
}
|
||||
|
||||
leaf delay {
|
||||
type decimal64 {
|
||||
fraction-digits 9;
|
||||
range "0.0..1.0";
|
||||
}
|
||||
default "0.0";
|
||||
units "seconds";
|
||||
description
|
||||
"Assumed maximum delay from the GPS receiver in seconds.
|
||||
|
||||
This accounts for processing delays in gpsd and the
|
||||
GPS receiver. Default is 0 (let chronyd estimate).";
|
||||
}
|
||||
|
||||
leaf refid {
|
||||
type string {
|
||||
length "1..4";
|
||||
pattern "[A-Z0-9]+";
|
||||
}
|
||||
default "GPS";
|
||||
description
|
||||
"Reference identifier (refid) shown in chronyc tracking.
|
||||
|
||||
Common values:
|
||||
- GPS - Generic GPS
|
||||
- GLO - GLONASS
|
||||
- GAL - Galileo
|
||||
- BDS - BeiDou
|
||||
- PPS - Pulse Per Second (for PPS-only sources)
|
||||
- GNSS - Multi-constellation receiver";
|
||||
}
|
||||
|
||||
leaf prefer {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Prefer this source over others when multiple are available.
|
||||
|
||||
When multiple reference clocks have similar quality, the
|
||||
preferred source will be selected. Useful for designating
|
||||
a primary GPS receiver.";
|
||||
}
|
||||
|
||||
leaf pps {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Use PPS (Pulse Per Second) signal from this source.
|
||||
|
||||
When enabled, chronyd will also configure the PPS SHM
|
||||
unit (2*N+1) for microsecond-level accuracy. The GPS
|
||||
receiver must provide PPS and gpsd must be configured
|
||||
to expose it.
|
||||
|
||||
Note: PPS requires the GPS source for initial time lock,
|
||||
then provides precise time edges.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Additional operational state fields from chronyd
|
||||
* that are not part of the standard ietf-ntp model
|
||||
|
||||
Reference in New Issue
Block a user