linuxptp-devel Mailing List for linuxptp (Page 2)
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
You can subscribe to this list here.
2012 |
Jan
|
Feb
|
Mar
(2) |
Apr
|
May
(18) |
Jun
|
Jul
(96) |
Aug
(129) |
Sep
(67) |
Oct
(30) |
Nov
(56) |
Dec
(65) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2013 |
Jan
(72) |
Feb
(136) |
Mar
(75) |
Apr
(107) |
May
(183) |
Jun
(110) |
Jul
(158) |
Aug
(76) |
Sep
(108) |
Oct
(125) |
Nov
(47) |
Dec
(56) |
2014 |
Jan
(47) |
Feb
(73) |
Mar
(87) |
Apr
(74) |
May
(88) |
Jun
(151) |
Jul
(41) |
Aug
(8) |
Sep
(13) |
Oct
(19) |
Nov
(55) |
Dec
(45) |
2015 |
Jan
(15) |
Feb
(104) |
Mar
(79) |
Apr
(8) |
May
(20) |
Jun
(22) |
Jul
(19) |
Aug
(379) |
Sep
(17) |
Oct
(8) |
Nov
(35) |
Dec
(5) |
2016 |
Jan
(7) |
Feb
|
Mar
(9) |
Apr
(15) |
May
|
Jun
|
Jul
(70) |
Aug
(31) |
Sep
(26) |
Oct
(53) |
Nov
(14) |
Dec
(24) |
2017 |
Jan
(12) |
Feb
(29) |
Mar
(28) |
Apr
(34) |
May
(56) |
Jun
(67) |
Jul
(77) |
Aug
(97) |
Sep
(45) |
Oct
(40) |
Nov
(2) |
Dec
(24) |
2018 |
Jan
(56) |
Feb
(41) |
Mar
(233) |
Apr
(187) |
May
(51) |
Jun
(99) |
Jul
(100) |
Aug
(76) |
Sep
(74) |
Oct
(60) |
Nov
(92) |
Dec
(20) |
2019 |
Jan
(61) |
Feb
(51) |
Mar
(97) |
Apr
(13) |
May
(16) |
Jun
(34) |
Jul
(10) |
Aug
(7) |
Sep
(66) |
Oct
(56) |
Nov
(3) |
Dec
(20) |
2020 |
Jan
(6) |
Feb
(84) |
Mar
(81) |
Apr
(24) |
May
(90) |
Jun
(78) |
Jul
(21) |
Aug
(118) |
Sep
(16) |
Oct
(29) |
Nov
(115) |
Dec
(45) |
2021 |
Jan
(110) |
Feb
(77) |
Mar
(114) |
Apr
(74) |
May
(116) |
Jun
(25) |
Jul
(62) |
Aug
(36) |
Sep
(25) |
Oct
(58) |
Nov
(118) |
Dec
(9) |
2022 |
Jan
(66) |
Feb
(45) |
Mar
(115) |
Apr
(24) |
May
(105) |
Jun
(94) |
Jul
(80) |
Aug
(67) |
Sep
(69) |
Oct
(109) |
Nov
(77) |
Dec
(71) |
2023 |
Jan
(24) |
Feb
(108) |
Mar
(119) |
Apr
(81) |
May
(74) |
Jun
(112) |
Jul
(82) |
Aug
(23) |
Sep
(53) |
Oct
(33) |
Nov
(171) |
Dec
(42) |
From: Richard C. <ric...@gm...> - 2023-12-02 23:38:34
|
Because of the implementation of the UDS module, it is not possible for a process to act as both a PTP management client (PMC) and server. Going forward, one ptp4l instance will need to subscribe to another using the PMC methods. Pave the way by allowing the interface to include an optional remote UDS address. Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 4 ++-- config.c | 2 +- interface.c | 12 ++++++++++-- interface.h | 10 +++++++++- pmc_common.c | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/clock.c b/clock.c index b66dda5..6f7722c 100644 --- a/clock.c +++ b/clock.c @@ -1242,7 +1242,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, /* Configure the UDS. */ uds_ifname = config_get_string(config, NULL, "uds_address"); - c->uds_rw_if = interface_create(uds_ifname); + c->uds_rw_if = interface_create(uds_ifname, NULL); if (config_set_section_int(config, interface_name(c->uds_rw_if), "announceReceiptTimeout", 0)) { return NULL; @@ -1261,7 +1261,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, } uds_ifname = config_get_string(config, NULL, "uds_ro_address"); - c->uds_ro_if = interface_create(uds_ifname); + c->uds_ro_if = interface_create(uds_ifname, NULL); if (config_set_section_int(config, interface_name(c->uds_ro_if), "announceReceiptTimeout", 0)) { return NULL; diff --git a/config.c b/config.c index ad675c8..fe65b76 100644 --- a/config.c +++ b/config.c @@ -896,7 +896,7 @@ struct interface *config_create_interface(const char *name, struct config *cfg) return iface; } - iface = interface_create(name); + iface = interface_create(name, NULL); if (!iface) { fprintf(stderr, "cannot allocate memory for a port\n"); return NULL; diff --git a/interface.c b/interface.c index 9a83c36..e088e07 100644 --- a/interface.c +++ b/interface.c @@ -12,12 +12,13 @@ struct interface { STAILQ_ENTRY(interface) list; char name[MAX_IFNAME_SIZE + 1]; char ts_label[MAX_IFNAME_SIZE + 1]; + char remote[MAX_IFNAME_SIZE + 1]; struct sk_ts_info ts_info; struct sk_if_info if_info; int vclock; }; -struct interface *interface_create(const char *name) +struct interface *interface_create(const char *name, const char *remote) { struct interface *iface; @@ -27,6 +28,9 @@ struct interface *interface_create(const char *name) } strncpy(iface->name, name, MAX_IFNAME_SIZE); strncpy(iface->ts_label, name, MAX_IFNAME_SIZE); + if (remote) { + strncpy(iface->remote, remote, MAX_IFNAME_SIZE); + } iface->vclock = -1; return iface; @@ -57,7 +61,6 @@ bool interface_ifinfo_valid(struct interface *iface) return iface->if_info.valid ? true : false; } - const char *interface_name(struct interface *iface) { return iface->name; @@ -68,6 +71,11 @@ int interface_phc_index(struct interface *iface) return iface->ts_info.phc_index; } +const char *interface_remote(struct interface *iface) +{ + return iface->remote; +} + void interface_set_label(struct interface *iface, const char *label) { strncpy(iface->ts_label, label, MAX_IFNAME_SIZE); diff --git a/interface.h b/interface.h index 0873bba..b56adc5 100644 --- a/interface.h +++ b/interface.h @@ -23,9 +23,10 @@ struct interface; /** * Creates an instance of an interface. * @param name The device which indentifies this interface. + * @param remote For UDS interfaces, the address of the remote server, possibly NULL. * @return A pointer to an interface instance on success, NULL otherwise. */ -struct interface *interface_create(const char *name); +struct interface *interface_create(const char *name, const char *remote); /** * Destroys an instance of an interface. @@ -70,6 +71,13 @@ const char *interface_name(struct interface *iface); */ int interface_phc_index(struct interface *iface); +/** + * Obtains the remote address from a UDS interface. + * @param iface The interface of interest. + * @return The device name of the network interface. + */ +const char *interface_remote(struct interface *iface); + /** * Set the time stamping label of a given interface. * @param iface The interface of interest. diff --git a/pmc_common.c b/pmc_common.c index 62e34a6..5092c09 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -524,7 +524,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, goto failed; } - pmc->iface = interface_create(iface_name); + pmc->iface = interface_create(iface_name, NULL); if (!pmc->iface) { pr_err("failed to create interface"); goto failed; -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 23:38:32
|
The CMLDS lets one peer-to-peer delay measurement be shared among multiple PTP stack instances running on the same host. To try it, connect the Ethernet ports of two hosts directly: On one host run CMLDS setup: ptp4l -mqf CMLDS_server.cfg ptp4l -mqf CMLDS_client.cfg and on the other host run a normal P2P stack: ptp4l -mqi eth1 -P --ignore_transport_specific=1 (The ignore_transport_specific is needed because of the extremely silly way the majorSdoId aka transportSpecific field is specified in 1588.) Changes in v3 ~~~~~~~~~~~~~ - Make delay timer a) actually fire, and b) do the right thing. - Add COMMOM_P2P to the list of delay mechanisms in the man page. Changes in v2 ~~~~~~~~~~~~~ - Added timer to renew push subscription and detect missing server. - Addressed Andrew and Kishen's review comments. - Added example configuration files. Richard Cochran (6): interface: Add an optional remote address for use by the UDS transport. pmc/uds: Configure the remote server address using the interface API. Introduce the Common Mean Link Delay Information TLV. Add a push notification for the CMLDS TLV. Implement the COMMON_P2P delay mechanism. Add example Common Mean Link Delay Service configuration files. clock.c | 5 +- config.c | 8 +- configs/CMLDS_client.cfg | 10 ++ configs/CMLDS_server.cfg | 16 ++++ configs/default.cfg | 5 + dm.h | 3 + fd.h | 1 + interface.c | 12 ++- interface.h | 10 +- makefile | 4 +- notification.h | 1 + pmc.c | 23 ++++- pmc_agent.c | 3 +- pmc_common.c | 23 +++-- pmc_common.h | 6 +- port.c | 197 +++++++++++++++++++++++++++++++++++++-- port.h | 2 + port_private.h | 7 ++ ptp4l.8 | 39 +++++++- tlv.c | 16 ++++ tlv.h | 7 ++ tz2alt.c | 3 +- uds.c | 6 +- 23 files changed, 368 insertions(+), 39 deletions(-) create mode 100644 configs/CMLDS_client.cfg create mode 100644 configs/CMLDS_server.cfg -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:29:02
|
On Sat, Dec 02, 2023 at 02:24:52PM -0800, Richard Cochran wrote: > Changes in v2 > ~~~~~~~~~~~~~ > - Added timer to renew push subscription and detect missing server. > - Addressed Andrew and Kishen's review comments. > - Added example configuration files. I also updated the man page with the new config options. Still need to add COMMON_P2P into man page. Thanks, Richard |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:21
|
If a given port selects the COMMON_P2P delay mechanism, let it open a local PTP Management channel to the Common Mean Link Delay Service over a UNIX domain socket. Signed-off-by: Richard Cochran <ric...@gm...> --- config.c | 6 ++ configs/default.cfg | 5 ++ dm.h | 3 + fd.h | 1 + makefile | 4 +- port.c | 180 +++++++++++++++++++++++++++++++++++++++++--- port_private.h | 7 ++ ptp4l.8 | 35 +++++++++ 8 files changed, 228 insertions(+), 13 deletions(-) diff --git a/config.c b/config.c index fe65b76..8cf1620 100644 --- a/config.c +++ b/config.c @@ -171,6 +171,7 @@ static struct config_enum delay_filter_enu[] = { static struct config_enum delay_mech_enu[] = { { "Auto", DM_AUTO }, + { "COMMON_P2P", DM_COMMON_P2P }, { "E2E", DM_E2E }, { "P2P", DM_P2P }, { "NONE", DM_NO_MECHANISM }, @@ -249,6 +250,11 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("clock_class_threshold", CLOCK_CLASS_THRESHOLD_DEFAULT, 6, CLOCK_CLASS_THRESHOLD_DEFAULT), GLOB_ITEM_ENU("clock_servo", CLOCK_SERVO_PI, clock_servo_enu), GLOB_ITEM_ENU("clock_type", CLOCK_TYPE_ORDINARY, clock_type_enu), + PORT_ITEM_STR("cmlds.client_address", "/var/run/cmlds_cleint"), + PORT_ITEM_INT("cmlds.domainNumber", 0, 0, 255), + PORT_ITEM_INT("cmlds.majorSdoId", 2, 0, 0x0F), + PORT_ITEM_INT("cmlds.port", 0, 0, UINT16_MAX), + PORT_ITEM_STR("cmlds.server_address", "/var/run/cmlds_server"), GLOB_ITEM_ENU("dataset_comparison", DS_CMP_IEEE1588, dataset_comp_enu), PORT_ITEM_INT("delayAsymmetry", 0, INT_MIN, INT_MAX), PORT_ITEM_ENU("delay_filter", FILTER_MOVING_MEDIAN, delay_filter_enu), diff --git a/configs/default.cfg b/configs/default.cfg index 0c7661c..29a34fd 100644 --- a/configs/default.cfg +++ b/configs/default.cfg @@ -93,6 +93,11 @@ write_phase_mode 0 # # Transport options # +cmlds.client_address /var/run/cmlds_cleint +cmlds.domainNumber 0 +cmlds.majorSdoId 2 +cmlds.port 0 +cmlds.server_address /var/run/cmlds_server transportSpecific 0x0 ptp_dst_mac 01:1B:19:00:00:00 p2p_dst_mac 01:80:C2:00:00:0E diff --git a/dm.h b/dm.h index 47bd847..80d1ce5 100644 --- a/dm.h +++ b/dm.h @@ -34,6 +34,9 @@ enum delay_mechanism { /** Peer delay mechanism. */ DM_P2P, + /** Peer delay as measured by CMLDS. */ + DM_COMMON_P2P, + /** No Delay Mechanism. */ DM_NO_MECHANISM = 0xFE, }; diff --git a/fd.h b/fd.h index 16420d7..9a072ab 100644 --- a/fd.h +++ b/fd.h @@ -39,6 +39,7 @@ enum { FD_SYNC_TX_TIMER, FD_UNICAST_REQ_TIMER, FD_UNICAST_SRV_TIMER, + FD_CMLDS, FD_RTNL, N_POLLFD, }; diff --git a/makefile b/makefile index 7fc5f6f..e9c1ccc 100644 --- a/makefile +++ b/makefile @@ -30,8 +30,8 @@ TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_pps_source.o \ ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o ts2phc_pps_source.o OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \ e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \ - port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \ - sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ + pmc_common.o port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o \ + $(SERVOS) sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ unicast_fsm.o unicast_service.o util.o version.o OBJECTS = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o pmc_agent.o \ diff --git a/port.c b/port.c index 23f021c..88d794e 100644 --- a/port.c +++ b/port.c @@ -46,6 +46,8 @@ #include "util.h" #define ANNOUNCE_SPAN 1 +#define CMLDS_SUBSCRIPTION_INTERVAL 60 /*seconds*/ +#define CMLDS_UPDATE_INTERVAL (CMLDS_SUBSCRIPTION_INTERVAL / 2) enum syfu_event { SYNC_MISMATCH, @@ -965,7 +967,8 @@ static int port_management_fill_response(struct port *target, ptp_text_copy(cd->userDescription, &desc->userDescription); buf += sizeof(struct PTPText) + cd->userDescription->length; - if (target->delayMechanism == DM_P2P) { + if (target->delayMechanism == DM_P2P || + target->delayMechanism == DM_COMMON_P2P) { memcpy(buf, profile_id_p2p, PROFILE_ID_LEN); } else { struct config *cfg = clock_config(target->clock); @@ -1275,14 +1278,16 @@ int port_set_delay_tmo(struct port *p) if (p->inhibit_delay_req) { return 0; } - - if (p->delayMechanism == DM_P2P) { + switch (p->delayMechanism) { + case DM_COMMON_P2P: + case DM_P2P: return set_tmo_log(p->fda.fd[FD_DELAY_TIMER], 1, - p->logPdelayReqInterval); - } else { - return set_tmo_random(p->fda.fd[FD_DELAY_TIMER], 0, 2, - p->logMinDelayReqInterval); + p->logPdelayReqInterval); + default: + break; } + return set_tmo_random(p->fda.fd[FD_DELAY_TIMER], 0, 2, + p->logMinDelayReqInterval); } static int port_set_manno_tmo(struct port *p) @@ -1528,6 +1533,45 @@ static void port_syfufsm(struct port *p, enum syfu_event event, } } +static int port_cmlds_renew(struct port *p, time_t now) +{ + struct subscribe_events_np sen = { + .duration = CMLDS_SUBSCRIPTION_INTERVAL, + }; + int err; + + event_bitmask_set(sen.bitmask, NOTIFY_CMLDS, TRUE); + err = pmc_send_set_action(p->cmlds.pmc, MID_SUBSCRIBE_EVENTS_NP, + &sen, sizeof(sen)); + if (err) { + return err; + } + p->cmlds.last_renewal = now; + return 0; +} + +static enum fsm_event port_cmlds_timeout(struct port *p) +{ + struct timespec now; + int err; + + if (!p->cmlds.pmc) { + return EV_NONE; + } + clock_gettime(CLOCK_MONOTONIC, &now); + if (now.tv_sec - p->cmlds.last_renewal > CMLDS_UPDATE_INTERVAL) { + err = port_cmlds_renew(p, now.tv_sec); + if (err) { + return EV_FAULT_DETECTED; + } + } + p->cmlds.timer_count++; + if (p->cmlds.timer_count > p->allowedLostResponses) { + return EV_FAULT_DETECTED; + } + return EV_NONE; +} + static int port_pdelay_request(struct port *p) { struct ptp_message *msg; @@ -1871,6 +1915,33 @@ static void port_clear_fda(struct port *p, int count) p->fda.fd[i] = -1; } +static int port_cmlds_initialize(struct port *p) +{ + struct config *cfg = clock_config(p->clock); + const int zero_datalen = 1; + const UInteger8 hops = 0; + struct timespec now; + + p->cmlds.port = config_get_int(cfg, p->name, "cmlds.port"); + if (!p->cmlds.port) { + p->cmlds.port = portnum(p); + } + p->cmlds.pmc = pmc_create(cfg, TRANS_UDS, + config_get_string(cfg, p->name, "cmlds.client_address"), + config_get_string(cfg, p->name, "cmlds.server_address"), + hops, + config_get_int(cfg, p->name, "cmlds.domainNumber"), + config_get_int(cfg, p->name, "cmlds.majorSdoId") << 4, + zero_datalen); + if (!p->cmlds.pmc) { + return -1; + } + p->cmlds.timer_count = 0; + p->fda.fd[FD_CMLDS] = pmc_get_transport_fd(p->cmlds.pmc); + clock_gettime(CLOCK_MONOTONIC, &now); + return port_cmlds_renew(p, now.tv_sec); +} + void port_disable(struct port *p) { int i; @@ -1888,6 +1959,12 @@ void port_disable(struct port *p) close(p->fda.fd[FD_FIRST_TIMER + i]); } + if (p->cmlds.pmc) { + pmc_destroy(p->cmlds.pmc); + p->fda.fd[FD_CMLDS] = -1; + p->cmlds.pmc = NULL; + } + /* Keep rtnl socket to get link status info. */ port_clear_fda(p, FD_RTNL); clock_fda_changed(p->clock); @@ -1935,7 +2012,8 @@ int port_initialize(struct port *p) pr_err("inhibit_delay_req can only be set when asCapable == 'true'."); return -1; } - if (port_delay_mechanism(p) == DM_NO_MECHANISM) { + if (port_delay_mechanism(p) == DM_COMMON_P2P || + port_delay_mechanism(p) == DM_NO_MECHANISM) { p->inhibit_delay_req = 1; } @@ -1963,6 +2041,10 @@ int port_initialize(struct port *p) goto no_tmo; } + if (port_delay_mechanism(p) == DM_COMMON_P2P && port_cmlds_initialize(p)) { + goto no_tmo; + } + /* No need to open rtnl socket on UDS port. */ if (!port_is_uds(p)) { /* @@ -2104,6 +2186,65 @@ int process_announce(struct port *p, struct ptp_message *m) return result; } +static int process_cmlds(struct port *p) +{ + struct cmlds_info_np *cmlds; + struct management_tlv *mgt; + struct ptp_message *msg; + struct TLV *tlv; + int err = 0; + + msg = pmc_recv(p->cmlds.pmc); + if (!msg) { + pr_err("%s: pmc_recv failed", p->log_name); + return -1; + } + if (msg_type(msg) != MANAGEMENT) { + pr_err("%s: pmc_recv bad message", p->log_name); + err = -1; + goto out; + } + tlv = (struct TLV *) msg->management.suffix; + if (tlv->type != TLV_MANAGEMENT) { + pr_err("%s: pmc_recv bad message", p->log_name); + err = -1; + goto out; + } + mgt = (struct management_tlv *) msg->management.suffix; + if (mgt->length == 2 && mgt->id != MID_NULL_MANAGEMENT) { + pr_err("%s: pmc_recv bad length", p->log_name); + goto out; + } + + switch (mgt->id) { + case MID_CMLDS_INFO_NP: + if (msg->header.sourcePortIdentity.portNumber != p->cmlds.port) { + break; + } + cmlds = (struct cmlds_info_np *) mgt->data; + p->peer_delay = nanoseconds_to_tmv(cmlds->meanLinkDelay >> 16); + p->peerMeanPathDelay = cmlds->meanLinkDelay; + p->nrate.ratio = 1.0 + (double) cmlds->scaledNeighborRateRatio / POW2_41; + p->asCapable = cmlds->as_capable; + p->cmlds.timer_count = 0; + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { + const tmv_t tx = tmv_zero(); + clock_peer_delay(p->clock, p->peer_delay, tx, tx, p->nrate.ratio); + } + break; + case MID_SUBSCRIBE_EVENTS_NP: + break; + default: + pr_err("%s: pmc_recv bad mgt id 0x%x", p->log_name, mgt->id); + err = -1; + break; + } + +out: + msg_put(msg); + return err; +} + static int process_delay_req(struct port *p, struct ptp_message *m) { struct ptp_message *msg; @@ -2115,7 +2256,7 @@ static int process_delay_req(struct port *p, struct ptp_message *m) return 0; } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || p->delayMechanism == DM_COMMON_P2P) { pr_warning("%s: delay request on P2P port", p->log_name); return 0; } @@ -2280,6 +2421,9 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) return -1; } + if (p->delayMechanism == DM_COMMON_P2P) { + return 0; + } if (p->delayMechanism == DM_E2E) { pr_warning("%s: pdelay_req on E2E port", p->log_name); return 0; @@ -2475,6 +2619,9 @@ calc: int process_pdelay_resp(struct port *p, struct ptp_message *m) { + if (p->delayMechanism == DM_COMMON_P2P) { + return 0; + } if (p->peer_delay_resp) { if (!p->multiple_pdr_detected) { pr_err("%s: multiple peer responses", p->log_name); @@ -2750,10 +2897,14 @@ static void bc_dispatch(struct port *p, enum fsm_event event, int mdiff) return; } - if (p->delayMechanism == DM_P2P) { + switch (p->delayMechanism) { + case DM_COMMON_P2P: + case DM_P2P: port_p2p_transition(p, p->state); - } else { + break; + default: port_e2e_transition(p, p->state); + break; } if (p->jbod && p->state == PS_UNCALIBRATED && p->phc_index >= 0 ) { @@ -2901,6 +3052,9 @@ static enum fsm_event bc_event(struct port *p, int fd_index) case FD_DELAY_TIMER: pr_debug("%s: delay timeout", p->log_name); port_set_delay_tmo(p); + if (p->delayMechanism == DM_COMMON_P2P) { + return port_cmlds_timeout(p); + } delay_req_prune(p); p->service_stats.delay_timeout++; if (port_delay_request(p)) { @@ -2947,6 +3101,10 @@ static enum fsm_event bc_event(struct port *p, int fd_index) p->service_stats.unicast_request_timeout++; return unicast_client_timer(p) ? EV_FAULT_DETECTED : EV_NONE; + case FD_CMLDS: + pr_debug("%s: CMLDS push notification", p->log_name); + return process_cmlds(p) ? EV_FAULT_DETECTED : EV_NONE; + case FD_RTNL: pr_debug("%s: received link status notification", p->log_name); rtnl_link_status(fd, p->name, port_link_status, p); diff --git a/port_private.h b/port_private.h index 1072ad6..4f158cd 100644 --- a/port_private.h +++ b/port_private.h @@ -26,6 +26,7 @@ #include "fsm.h" #include "monitor.h" #include "msg.h" +#include "pmc_common.h" #include "power_profile.h" #include "tmv.h" #include "util.h" @@ -164,6 +165,12 @@ struct port { /* slave event monitoring */ struct monitor *slave_event_monitor; bool unicast_state_dirty; + struct { + unsigned int timer_count; + time_t last_renewal; + struct pmc *pmc; + int port; + } cmlds; }; #define portnum(p) (p->portIdentity.portNumber) diff --git a/ptp4l.8 b/ptp4l.8 index 4cb9adb..c53e769 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -159,6 +159,41 @@ collection of clocks must be synchronized by an external program, for example phc2sys(8) in "automatic" mode. The default is 0 (disabled). +.TP +.B cmlds.client_address +Specifies the source address for the UNIX domain socket that receives +peer delay measurement when using the "COMMON_P2P" delay mechanism. +The default is /var/run/cmlds_cleint. + +.TP +.B cmlds.domainNumber +Specifies the domainNumber message field for communications with the +local Common Mean Link Delay Service, used with the "COMMON_P2P" delay +mechanism. +The default is 0. + +.TP +.B cmlds.majorSdoId +Specifies the transportSpecific message field for communications with +the local Common Mean Link Delay Service, used with the "COMMON_P2P" +delay mechanism. +The default is 2. + +.TP +.B cmlds.port +Specifies the port number of local Common Mean Link Delay Service from +which to accept delay measurements. The range of valid port numbers +is one to 65535, but the special value zero configures the port number +of the port requesting the measurements. +The default is 0, meaning the requesting port number. + +.TP +.B +cmlds.server_address +Specifies the UNIX domain socket address of the local Common Mean Link +Delay Service, for use with the "COMMON_P2P" delay mechanism. +The default is /var/run/cmlds_server. + .TP .B delayAsymmetry The time difference in nanoseconds of the transmit and receive -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:19
|
Signed-off-by: Richard Cochran <ric...@gm...> --- configs/CMLDS_client.cfg | 10 ++++++++++ configs/CMLDS_server.cfg | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 configs/CMLDS_client.cfg create mode 100644 configs/CMLDS_server.cfg diff --git a/configs/CMLDS_client.cfg b/configs/CMLDS_client.cfg new file mode 100644 index 0000000..ef10fef --- /dev/null +++ b/configs/CMLDS_client.cfg @@ -0,0 +1,10 @@ +# +# Common Mean Link Delay Service (CMLDS) example configuration for a +# CMLDS client, containing those attributes which differ from the +# defaults. See the file, default.cfg, for the complete list of +# available options. +# +[global] + +[eth1] +delay_mechanism COMMON_P2P diff --git a/configs/CMLDS_server.cfg b/configs/CMLDS_server.cfg new file mode 100644 index 0000000..36f118c --- /dev/null +++ b/configs/CMLDS_server.cfg @@ -0,0 +1,16 @@ +# +# Common Mean Link Delay Service (CMLDS) example configuration for a +# CMLDS Link Port, containing those attributes which differ from the +# defaults. See the file, default.cfg, for the complete list of +# available options. +# +[global] +clientOnly 1 +clockIdentity C37D50.0000.000000 +free_running 1 +ignore_transport_specific 1 +transportSpecific 2 +uds_address /var/run/cmlds_server + +[eth1] +delay_mechanism P2P -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:19
|
Add a new TLV to convey link delay measurements by the Common Mean Link Delay Service (CMLDS) (as specified in IEEE 1588/16.6.3) over the management interface. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 1 - pmc.c | 11 +++++++++++ pmc_common.c | 1 + port.c | 9 +++++++++ port.h | 2 ++ tlv.c | 16 ++++++++++++++++ tlv.h | 7 +++++++ 7 files changed, 46 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 6f7722c..c999c83 100644 --- a/clock.c +++ b/clock.c @@ -47,7 +47,6 @@ #include "util.h" #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ -#define POW2_41 ((double)(1ULL << 41)) struct interface { STAILQ_ENTRY(interface) list; diff --git a/pmc.c b/pmc.c index d18fea0..12a6109 100644 --- a/pmc.c +++ b/pmc.c @@ -169,6 +169,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) struct subscribe_events_np *sen; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct timePropertiesDS *tp; struct management_tlv *mgt; struct time_status_np *tsn; @@ -623,6 +624,16 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) pwr->networkTimeInaccuracy, pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *) mgt->data; + fprintf(fp, "CMLDS_INFO_NP " + IFMT "meanLinkDelay %" PRId64 + IFMT "scaledNeighborRateRatio %" PRId32 + IFMT "as_capable %" PRIu32, + cmlds->meanLinkDelay >> 16, + cmlds->scaledNeighborRateRatio, + cmlds->as_capable); + break; case MID_LOG_ANNOUNCE_INTERVAL: mtd = (struct management_tlv_datum *) mgt->data; fprintf(fp, "LOG_ANNOUNCE_INTERVAL " diff --git a/pmc_common.c b/pmc_common.c index fca16c6..1d537f2 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -156,6 +156,7 @@ struct management_id idtab[] = { { "UNICAST_MASTER_TABLE_NP", MID_UNICAST_MASTER_TABLE_NP, do_get_action }, { "PORT_HWCLOCK_NP", MID_PORT_HWCLOCK_NP, do_get_action }, { "POWER_PROFILE_SETTINGS_NP", MID_POWER_PROFILE_SETTINGS_NP, do_set_action }, + { "CMLDS_INFO_NP", MID_CMLDS_INFO_NP, do_get_action }, }; static void do_get_action(struct pmc *pmc, int action, int index, char *str) diff --git a/port.c b/port.c index b7fbfb1..2eca876 100644 --- a/port.c +++ b/port.c @@ -883,6 +883,7 @@ static int port_management_fill_response(struct port *target, struct clock_description *desc; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct management_tlv *tlv; struct port_stats_np *psn; struct foreign_clock *fc; @@ -1125,6 +1126,14 @@ static int port_management_fill_response(struct port *target, memcpy(pwr, &target->pwr, sizeof(*pwr)); datalen = sizeof(*pwr); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *)tlv->data; + cmlds->meanLinkDelay = target->peerMeanPathDelay; + cmlds->scaledNeighborRateRatio = + (Integer32) (target->nrate.ratio * POW2_41 - POW2_41); + cmlds->as_capable = target->asCapable; + datalen = sizeof(*cmlds); + break; default: /* The caller should *not* respond to this message. */ tlv_extra_recycle(extra); diff --git a/port.h b/port.h index 57c8c2f..cc03859 100644 --- a/port.h +++ b/port.h @@ -26,6 +26,8 @@ #include "notification.h" #include "transport.h" +#define POW2_41 ((double)(1ULL << 41)) + /* forward declarations */ struct interface; struct clock; diff --git a/tlv.c b/tlv.c index 9b82bd9..7cbd84d 100644 --- a/tlv.c +++ b/tlv.c @@ -176,6 +176,7 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, struct port_properties_np *ppn; struct port_hwclock_np *phn; struct timePropertiesDS *tp; + struct cmlds_info_np *cmlds; struct time_status_np *tsn; struct port_stats_np *psn; int extra_len = 0, i, len; @@ -481,6 +482,14 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, NTOHL(pwr->networkTimeInaccuracy); NTOHL(pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + if (data_len < sizeof(struct cmlds_info_np)) + goto bad_length; + cmlds = (struct cmlds_info_np *)m->data; + net2host64_unaligned(&cmlds->meanLinkDelay); + NTOHL(cmlds->scaledNeighborRateRatio); + NTOHL(cmlds->as_capable); + break; case MID_SAVE_IN_NON_VOLATILE_STORAGE: case MID_RESET_NON_VOLATILE_STORAGE: case MID_INITIALIZE: @@ -514,6 +523,7 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) struct subscribe_events_np *sen; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct timePropertiesDS *tp; struct time_status_np *tsn; struct port_stats_np *psn; @@ -672,6 +682,12 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) HTONL(pwr->networkTimeInaccuracy); HTONL(pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *)m->data; + host2net64_unaligned(&cmlds->meanLinkDelay); + HTONL(cmlds->scaledNeighborRateRatio); + HTONL(cmlds->as_capable); + break; } } diff --git a/tlv.h b/tlv.h index 8b51ffd..d8875b3 100644 --- a/tlv.h +++ b/tlv.h @@ -129,6 +129,7 @@ enum management_action { #define MID_UNICAST_MASTER_TABLE_NP 0xC008 #define MID_PORT_HWCLOCK_NP 0xC009 #define MID_POWER_PROFILE_SETTINGS_NP 0xC00A +#define MID_CMLDS_INFO_NP 0xC00B /* Management error ID values */ #define MID_RESPONSE_TOO_BIG 0x0001 @@ -323,6 +324,12 @@ typedef struct Integer96 { uint16_t fractional_nanoseconds; } PACKED ScaledNs; +struct cmlds_info_np { + TimeInterval meanLinkDelay; + Integer32 scaledNeighborRateRatio; + uint32_t as_capable; +} PACKED; + struct follow_up_info_tlv { Enumeration16 type; UInteger16 length; -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:16
|
Because of the implementation of the UDS module, it is not possible for a process to act as both a PTP management client (PMC) and server. Going forward, one ptp4l instance will need to subscribe to another using the PMC methods. Pave the way by allowing the interface to include an optional remote UDS address. Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 4 ++-- config.c | 2 +- interface.c | 12 ++++++++++-- interface.h | 10 +++++++++- pmc_common.c | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/clock.c b/clock.c index b66dda5..6f7722c 100644 --- a/clock.c +++ b/clock.c @@ -1242,7 +1242,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, /* Configure the UDS. */ uds_ifname = config_get_string(config, NULL, "uds_address"); - c->uds_rw_if = interface_create(uds_ifname); + c->uds_rw_if = interface_create(uds_ifname, NULL); if (config_set_section_int(config, interface_name(c->uds_rw_if), "announceReceiptTimeout", 0)) { return NULL; @@ -1261,7 +1261,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, } uds_ifname = config_get_string(config, NULL, "uds_ro_address"); - c->uds_ro_if = interface_create(uds_ifname); + c->uds_ro_if = interface_create(uds_ifname, NULL); if (config_set_section_int(config, interface_name(c->uds_ro_if), "announceReceiptTimeout", 0)) { return NULL; diff --git a/config.c b/config.c index ad675c8..fe65b76 100644 --- a/config.c +++ b/config.c @@ -896,7 +896,7 @@ struct interface *config_create_interface(const char *name, struct config *cfg) return iface; } - iface = interface_create(name); + iface = interface_create(name, NULL); if (!iface) { fprintf(stderr, "cannot allocate memory for a port\n"); return NULL; diff --git a/interface.c b/interface.c index 9a83c36..e088e07 100644 --- a/interface.c +++ b/interface.c @@ -12,12 +12,13 @@ struct interface { STAILQ_ENTRY(interface) list; char name[MAX_IFNAME_SIZE + 1]; char ts_label[MAX_IFNAME_SIZE + 1]; + char remote[MAX_IFNAME_SIZE + 1]; struct sk_ts_info ts_info; struct sk_if_info if_info; int vclock; }; -struct interface *interface_create(const char *name) +struct interface *interface_create(const char *name, const char *remote) { struct interface *iface; @@ -27,6 +28,9 @@ struct interface *interface_create(const char *name) } strncpy(iface->name, name, MAX_IFNAME_SIZE); strncpy(iface->ts_label, name, MAX_IFNAME_SIZE); + if (remote) { + strncpy(iface->remote, remote, MAX_IFNAME_SIZE); + } iface->vclock = -1; return iface; @@ -57,7 +61,6 @@ bool interface_ifinfo_valid(struct interface *iface) return iface->if_info.valid ? true : false; } - const char *interface_name(struct interface *iface) { return iface->name; @@ -68,6 +71,11 @@ int interface_phc_index(struct interface *iface) return iface->ts_info.phc_index; } +const char *interface_remote(struct interface *iface) +{ + return iface->remote; +} + void interface_set_label(struct interface *iface, const char *label) { strncpy(iface->ts_label, label, MAX_IFNAME_SIZE); diff --git a/interface.h b/interface.h index 0873bba..b56adc5 100644 --- a/interface.h +++ b/interface.h @@ -23,9 +23,10 @@ struct interface; /** * Creates an instance of an interface. * @param name The device which indentifies this interface. + * @param remote For UDS interfaces, the address of the remote server, possibly NULL. * @return A pointer to an interface instance on success, NULL otherwise. */ -struct interface *interface_create(const char *name); +struct interface *interface_create(const char *name, const char *remote); /** * Destroys an instance of an interface. @@ -70,6 +71,13 @@ const char *interface_name(struct interface *iface); */ int interface_phc_index(struct interface *iface); +/** + * Obtains the remote address from a UDS interface. + * @param iface The interface of interest. + * @return The device name of the network interface. + */ +const char *interface_remote(struct interface *iface); + /** * Set the time stamping label of a given interface. * @param iface The interface of interest. diff --git a/pmc_common.c b/pmc_common.c index 62e34a6..5092c09 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -524,7 +524,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, goto failed; } - pmc->iface = interface_create(iface_name); + pmc->iface = interface_create(iface_name, NULL); if (!pmc->iface) { pr_err("failed to create interface"); goto failed; -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:15
|
Signed-off-by: Richard Cochran <ric...@gm...> --- notification.h | 1 + pmc.c | 6 ++++-- pmc_common.c | 14 ++++++++++---- port.c | 7 +++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/notification.h b/notification.h index c1a6395..7a8f641 100644 --- a/notification.h +++ b/notification.h @@ -45,6 +45,7 @@ enum notification { NOTIFY_PORT_STATE, NOTIFY_TIME_SYNC, NOTIFY_PARENT_DATA_SET, + NOTIFY_CMLDS, }; #endif diff --git a/pmc.c b/pmc.c index 12a6109..6cdd7b0 100644 --- a/pmc.c +++ b/pmc.c @@ -453,11 +453,13 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) IFMT "duration %hu" IFMT "NOTIFY_PORT_STATE %s" IFMT "NOTIFY_TIME_SYNC %s" - IFMT "NOTIFY_PARENT_DATA_SET %s", + IFMT "NOTIFY_PARENT_DATA_SET %s" + IFMT "NOTIFY_CMLDS %s", sen->duration, event_bitmask_get(sen->bitmask, NOTIFY_PORT_STATE) ? "on" : "off", event_bitmask_get(sen->bitmask, NOTIFY_TIME_SYNC) ? "on" : "off", - event_bitmask_get(sen->bitmask, NOTIFY_PARENT_DATA_SET) ? "on" : "off"); + event_bitmask_get(sen->bitmask, NOTIFY_PARENT_DATA_SET) ? "on" : "off", + event_bitmask_get(sen->bitmask, NOTIFY_CMLDS) ? "on" : "off"); break; case MID_SYNCHRONIZATION_UNCERTAIN_NP: mtd = (struct management_tlv_datum *) mgt->data; diff --git a/pmc_common.c b/pmc_common.c index 1d537f2..a549af5 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -180,6 +180,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) char onoff_port_state[4] = "off"; char onoff_time_status[4] = "off"; char onoff_parent_data_set[4] = "off"; + char onoff_cmlds[4] = "off"; char display_name[11] = {0}; uint64_t jump; uint8_t key; @@ -306,13 +307,15 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) "duration %hu " "NOTIFY_PORT_STATE %3s " "NOTIFY_TIME_SYNC %3s " - "NOTIFY_PARENT_DATA_SET %3s ", + "NOTIFY_PARENT_DATA_SET %3s " + "NOTIFY_CMLDS %3s ", &sen.duration, onoff_port_state, onoff_time_status, - onoff_parent_data_set); - if (cnt != 4) { - fprintf(stderr, "%s SET needs 4 values\n", + onoff_parent_data_set, + onoff_cmlds); + if (cnt != 5) { + fprintf(stderr, "%s SET needs 5 values\n", idtab[index].name); break; } @@ -326,6 +329,9 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) event_bitmask_set(sen.bitmask, NOTIFY_PARENT_DATA_SET, TRUE); } + if (!strcasecmp(onoff_cmlds, "on")) { + event_bitmask_set(sen.bitmask, NOTIFY_CMLDS, TRUE); + } pmc_send_set_action(pmc, code, &sen, sizeof(sen)); break; case MID_SYNCHRONIZATION_UNCERTAIN_NP: diff --git a/port.c b/port.c index 2eca876..23f021c 100644 --- a/port.c +++ b/port.c @@ -748,6 +748,7 @@ capable: if (p->asCapable == NOT_CAPABLE) { pr_debug("%s: setting asCapable", p->log_name); p->asCapable = AS_CAPABLE; + port_notify_event(p, NOTIFY_CMLDS); } return 1; @@ -755,6 +756,7 @@ not_capable: if (p->asCapable) port_nrate_initialize(p); p->asCapable = NOT_CAPABLE; + port_notify_event(p, NOTIFY_CMLDS); return 0; } @@ -2467,6 +2469,8 @@ calc: msg_put(p->peer_delay_req); p->peer_delay_req = NULL; + + port_notify_event(p, NOTIFY_CMLDS); } int process_pdelay_resp(struct port *p, struct ptp_message *m) @@ -3264,6 +3268,9 @@ void port_notify_event(struct port *p, enum notification event) case NOTIFY_PORT_STATE: id = MID_PORT_DATA_SET; break; + case NOTIFY_CMLDS: + id = MID_CMLDS_INFO_NP; + break; default: return; } -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:14
|
The UDS uses a global setting from the configuration to set the remote server address. As a result, a program cannot act as both a UDS client and server, because the source and destination addresses would be identical. Fix the issue by allowing the remote address to be configurable. Signed-off-by: Richard Cochran <ric...@gm...> --- pmc.c | 6 ++++-- pmc_agent.c | 3 ++- pmc_common.c | 8 ++++---- pmc_common.h | 6 +++--- tz2alt.c | 3 ++- uds.c | 6 ++++-- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/pmc.c b/pmc.c index 9faf790..d18fea0 100644 --- a/pmc.c +++ b/pmc.c @@ -823,8 +823,10 @@ int main(int argc, char *argv[]) print_set_syslog(1); print_set_verbose(1); - pmc = pmc_create(cfg, transport_type, iface_name, boundary_hops, - domain_number, transport_specific, zero_datalen); + pmc = pmc_create(cfg, transport_type, iface_name, + config_get_string(cfg, NULL, "uds_address"), + boundary_hops, domain_number, transport_specific, + zero_datalen); if (!pmc) { fprintf(stderr, "failed to create pmc\n"); config_destroy(cfg); diff --git a/pmc_agent.c b/pmc_agent.c index 494c174..fec6dea 100644 --- a/pmc_agent.c +++ b/pmc_agent.c @@ -232,7 +232,8 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout) int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds, pmc_node_recv_subscribed_t *recv_subscribed, void *context) { - node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0, + node->pmc = pmc_create(cfg, TRANS_UDS, uds, + config_get_string(cfg, NULL, "uds_address"), 0, config_get_int(cfg, NULL, "domainNumber"), config_get_int(cfg, NULL, "transportSpecific") << 4, 1); if (!node->pmc) { diff --git a/pmc_common.c b/pmc_common.c index 5092c09..fca16c6 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -488,9 +488,9 @@ struct pmc { }; struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, - const char *iface_name, UInteger8 boundary_hops, - UInteger8 domain_number, UInteger8 transport_specific, - int zero_datalen) + const char *iface_name, const char *remote_address, + UInteger8 boundary_hops, UInteger8 domain_number, + UInteger8 transport_specific, int zero_datalen) { struct pmc *pmc; UInteger32 proc_id; @@ -524,7 +524,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, goto failed; } - pmc->iface = interface_create(iface_name, NULL); + pmc->iface = interface_create(iface_name, remote_address); if (!pmc->iface) { pr_err("failed to create interface"); goto failed; diff --git a/pmc_common.h b/pmc_common.h index 6fb2fae..355b2c0 100644 --- a/pmc_common.h +++ b/pmc_common.h @@ -29,9 +29,9 @@ struct pmc; struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, - const char *iface_name, UInteger8 boundary_hops, - UInteger8 domain_number, UInteger8 transport_specific, - int zero_datalen); + const char *iface_name, const char *remote_address, + UInteger8 boundary_hops, UInteger8 domain_number, + UInteger8 transport_specific, int zero_datalen); void pmc_destroy(struct pmc *pmc); diff --git a/tz2alt.c b/tz2alt.c index feb77a5..65b5835 100644 --- a/tz2alt.c +++ b/tz2alt.c @@ -181,7 +181,8 @@ static int update_ptp_serivce(struct tzinfo *tz, struct tzinfo *next) struct pmc *pmc; int err; - pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0, + pmc = pmc_create(cfg, TRANS_UDS, uds_local, + config_get_string(cfg, NULL, "uds_address"), 0, config_get_int(cfg, NULL, "domainNumber"), config_get_int(cfg, NULL, "transportSpecific") << 4, 1); if (!pmc) { diff --git a/uds.c b/uds.c index 6d39dc8..fafb100 100644 --- a/uds.c +++ b/uds.c @@ -54,7 +54,7 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray enum timestamp_type tt) { char *uds_ro_path = config_get_string(t->cfg, NULL, "uds_ro_address"); - char *uds_path = config_get_string(t->cfg, NULL, "uds_address"); + const char *uds_path = interface_remote(iface); struct uds *uds = container_of(t, struct uds, t); const char *name = interface_name(iface); const char* file_mode_cfg; @@ -89,7 +89,9 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray /* For client use, pre load the server path. */ memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path, uds_path, sizeof(sa.sun_path) - 1); + if (uds_path) { + strncpy(sa.sun_path, uds_path, sizeof(sa.sun_path) - 1); + } uds->address.sun = sa; uds->address.len = sizeof(sa); -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 22:25:08
|
The CMLDS lets one peer-to-peer delay measurement be shared among multiple PTP stack instances running on the same host. To try it, connect the Ethernet ports of two hosts directly: On one host run CMLDS setup: ptp4l -mqf CMLDS_server.cfg ptp4l -mqf CMLDS_client.cfg and on the other host run a normal P2P stack: ptp4l -mqi eth1 -P --ignore_transport_specific=1 (The ignore_transport_specific is needed because of the extremely silly way the majorSdoId aka transportSpecific field is specified in 1588.) Changes in v2 ~~~~~~~~~~~~~ - Added timer to renew push subscription and detect missing server. - Addressed Andrew and Kishen's review comments. - Added example configuration files. Richard Cochran (6): interface: Add an optional remote address for use by the UDS transport. pmc/uds: Configure the remote server address using the interface API. Introduce the Common Mean Link Delay Information TLV. Add a push notification for the CMLDS TLV. Implement the COMMON_P2P delay mechanism. Add example Common Mean Link Delay Service configuration files. clock.c | 5 +- config.c | 8 +- configs/CMLDS_client.cfg | 10 ++ configs/CMLDS_server.cfg | 16 ++++ configs/default.cfg | 5 + dm.h | 3 + fd.h | 1 + interface.c | 12 ++- interface.h | 10 +- makefile | 4 +- notification.h | 1 + pmc.c | 23 ++++- pmc_agent.c | 3 +- pmc_common.c | 23 +++-- pmc_common.h | 6 +- port.c | 196 ++++++++++++++++++++++++++++++++++++--- port.h | 2 + port_private.h | 7 ++ ptp4l.8 | 35 +++++++ tlv.c | 16 ++++ tlv.h | 7 ++ tz2alt.c | 3 +- uds.c | 6 +- 23 files changed, 363 insertions(+), 39 deletions(-) create mode 100644 configs/CMLDS_client.cfg create mode 100644 configs/CMLDS_server.cfg -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-12-02 21:57:03
|
On Wed, Nov 22, 2023 at 09:36:36AM -0800, Rahul Rameshbabu via Linuxptp-devel wrote: > Use the common NSEC_PER_SEC macro in phc_ctl. > > Signed-off-by: Rahul Rameshbabu <rra...@nv...> Series applied, but I fixed up one more NSEC2SEC that was added into phc_ctl.c since this series was posted. Thanks, Richard |
From: Richard C. <ric...@gm...> - 2023-12-02 06:07:47
|
On Thu, Nov 30, 2023 at 04:52:44PM -0800, Kishen Maloor wrote: > CMLDS ptp4l process would be configured with > transportSpecific/domain=0x2/0. Question about the spec: How on earth is this going to work? I mean, if the link partner is not also using CMLDS, then it won't reply because of the majorSdoId mismatch. Does the standard require that either ALL the nodes in a network use CMLDS, or none do at all? This is messed up, IMO. Thanks, Richard |
From: Richard C. <ric...@gm...> - 2023-12-01 15:06:50
|
On Thu, Nov 30, 2023 at 04:52:44PM -0800, Kishen Maloor wrote: > If serviceMeasurementValid=true, then we set both peer_portid_valid and > p->nrate.ratio_valid to true so that port_capable() could evaluate to true. Even simpler: include asCapable from the CMLDS Link Port in the TLV, and just assign asCapable directly in the cleint. Thanks, Richard |
From: Luigi 'C. M. <lui...@gm...> - 2023-12-01 08:23:03
|
I vote to fix also pmc (that is just a tool) output. Also adding a new PUSH we break the pmc tools... ciao luigi Il giorno ven 1 dic 2023 alle ore 09:03 Chwee-Lin Choong < chw...@in...> ha scritto: > Add the computation for scaledLastGmFreqChange, as specified in > IEEE 802.1AS-2020, clause 11.4.4.3.9. This incorporates the > necessary logic to calculate scaledLastGmFreqChange and > appends the result to the follow-up TLV. > > In addition, a naming error has been rectified from > scaledLastGmPhaseChange to scaledLastGmFreqChange. > > v2: Maintain existing printed name 'scaledLastGmPhaseChange' > in pmc.c to avoid potential disruptions to users' setups. > > Signed-off-by: Tan Tee Min <tee...@li...> > Signed-off-by: Chwee-Lin Choong <chw...@in...> > --- > clock.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- > clock.h | 7 +++++++ > pmc.c | 2 +- > port.c | 5 +++-- > tlv.c | 8 ++++---- > tlv.h | 4 ++-- > 6 files changed, 72 insertions(+), 13 deletions(-) > > diff --git a/clock.c b/clock.c > index b66dda5..c24d496 100644 > --- a/clock.c > +++ b/clock.c > @@ -148,6 +148,7 @@ struct clock { > int step_window_counter; > int step_window; > struct time_zone tz[MAX_TIME_ZONES]; > + struct follow_up_info_tlv clksrc_fup_info; > }; > > struct clock the_clock; > @@ -544,13 +545,15 @@ static int clock_management_fill_response(struct > clock *c, struct port *p, > tsn->cumulativeScaledRateOffset = > (Integer32) (c->status.cumulativeScaledRateOffset + > c->nrr * POW2_41 - POW2_41); > - tsn->scaledLastGmPhaseChange = > c->status.scaledLastGmPhaseChange; > tsn->gmTimeBaseIndicator = c->status.gmTimeBaseIndicator; > tsn->lastGmPhaseChange = c->status.lastGmPhaseChange; > - if (cid_eq(&c->dad.pds.grandmasterIdentity, > &c->dds.clockIdentity)) > + if (cid_eq(&c->dad.pds.grandmasterIdentity, > &c->dds.clockIdentity)) { > tsn->gmPresent = 0; > - else > + tsn->scaledLastGmFreqChange = > c->clksrc_fup_info.scaledLastGmFreqChange; > + } else { > tsn->gmPresent = 1; > + tsn->scaledLastGmFreqChange = > c->status.scaledLastGmFreqChange; > + } > tsn->gmIdentity = c->dad.pds.grandmasterIdentity; > datalen = sizeof(*tsn); > break; > @@ -1289,6 +1292,7 @@ struct clock *clock_create(enum clock_type type, > struct config *config, > c->utc_offset = config_get_int(config, NULL, "utc_offset"); > c->time_source = config_get_int(config, NULL, "timeSource"); > c->step_window = config_get_int(config, NULL, "step_window"); > + memset(&c->clksrc_fup_info, 0 , sizeof(c->clksrc_fup_info)); > > if (c->free_running) { > c->clkid = CLOCK_INVALID; > @@ -1482,12 +1486,21 @@ struct port *clock_first_port(struct clock *c) > void clock_follow_up_info(struct clock *c, struct follow_up_info_tlv *f) > { > c->status.cumulativeScaledRateOffset = > f->cumulativeScaledRateOffset; > - c->status.scaledLastGmPhaseChange = f->scaledLastGmPhaseChange; > + c->status.scaledLastGmFreqChange = f->scaledLastGmFreqChange; > c->status.gmTimeBaseIndicator = f->gmTimeBaseIndicator; > memcpy(&c->status.lastGmPhaseChange, &f->lastGmPhaseChange, > sizeof(c->status.lastGmPhaseChange)); > } > > +void clock_set_follow_up_info(struct clock *c, struct follow_up_info_tlv > *f) > +{ > + if (cid_eq(&c->dad.pds.grandmasterIdentity, > &c->dds.clockIdentity)) { > + f->scaledLastGmFreqChange = > c->clksrc_fup_info.scaledLastGmFreqChange; > + } else { > + f->scaledLastGmFreqChange = > c->status.scaledLastGmFreqChange; > + } > +} > + > int clock_free_running(struct clock *c) > { > return c->free_running ? 1 : 0; > @@ -1991,6 +2004,42 @@ static int clock_synchronize_locked(struct clock > *c, double adj) > return 0; > } > > +void calculate_freq_change(struct clock *c, tmv_t ingress, tmv_t origin) > +{ > + struct freq_estimator *f = &c->fest; > + double ratio; > + > + /* > + * The ratio of the local clock freqency to the master clock > + * is estimated by: > + * > + * (origin_2 - origin_1) / (ingress_2 - ingress_1) > + * > + * Both of the origin time estimates include the path delay, > + * but we assume that the path delay is in fact constant. > + * By leaving out the path delay altogther, we can avoid the > + * error caused by our imperfect path delay measurement. > + */ > + if (tmv_is_zero(f->ingress1)) { > + f->ingress1 = ingress; > + f->origin1 = origin; > + return; > + } > + > + if (tmv_cmp(ingress, f->ingress1) == 0) { > + pr_warning("bad timestamps in rate ratio calculation"); > + return; > + } > + > + ratio = tmv_dbl(tmv_sub(origin, f->origin1)) / > + tmv_dbl(tmv_sub(ingress, f->ingress1)); > + > + c->clksrc_fup_info.scaledLastGmFreqChange = (Integer32)((ratio - > 1.0) * POW2_41); > + > + f->ingress1 = ingress; > + f->origin1 = origin; > +} > + > enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t > origin) > { > enum servo_state state = SERVO_UNLOCKED; > @@ -2023,6 +2072,8 @@ enum servo_state clock_synchronize(struct clock *c, > tmv_t ingress, tmv_t origin) > > c->cur.offsetFromMaster = tmv_to_TimeInterval(c->master_offset); > > + calculate_freq_change(c, ingress, origin); > + > if (c->free_running) { > state = clock_no_adjust(c, ingress, origin); > clock_notify_event(c, NOTIFY_TIME_SYNC); > diff --git a/clock.h b/clock.h > index ce9ae91..f17bea9 100644 > --- a/clock.h > +++ b/clock.h > @@ -150,6 +150,13 @@ struct port *clock_first_port(struct clock *c); > */ > void clock_follow_up_info(struct clock *c, struct follow_up_info_tlv *f); > > +/** > + * Set the follow_up info TLV for a slave port. > + * @param c The clock instance. > + * @param f Pointer to the TLV. > + */ > +void clock_set_follow_up_info(struct clock *c, struct follow_up_info_tlv > *f); > + > /** > * Determine if a clock is free running or not. > * @param c The clock instance. > diff --git a/pmc.c b/pmc.c > index 9faf790..b4b146f 100644 > --- a/pmc.c > +++ b/pmc.c > @@ -412,7 +412,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) > tsn->master_offset, > tsn->ingress_time, > (tsn->cumulativeScaledRateOffset + 0.0) / P41, > - tsn->scaledLastGmPhaseChange, > + tsn->scaledLastGmFreqChange, > tsn->gmTimeBaseIndicator, > tsn->lastGmPhaseChange.nanoseconds_msb, > tsn->lastGmPhaseChange.nanoseconds_lsb, > diff --git a/port.c b/port.c > index 136d036..f94789b 100644 > --- a/port.c > +++ b/port.c > @@ -431,7 +431,7 @@ static int add_foreign_master(struct port *p, struct > ptp_message *m) > return broke_threshold || diff; > } > > -static int follow_up_info_append(struct ptp_message *m) > +static int follow_up_info_append(struct port *p, struct ptp_message *m) > { > struct follow_up_info_tlv *fui; > struct tlv_extra *extra; > @@ -445,6 +445,7 @@ static int follow_up_info_append(struct ptp_message *m) > fui->length = sizeof(*fui) - sizeof(fui->type) - > sizeof(fui->length); > memcpy(fui->id, ieee8021_id, sizeof(ieee8021_id)); > fui->subtype[2] = 1; > + clock_set_follow_up_info(p->clock, fui); > > return 0; > } > @@ -1781,7 +1782,7 @@ int port_tx_sync(struct port *p, struct address > *dst, uint16_t sequence_id) > fup->address = *dst; > fup->header.flagField[0] |= UNICAST; > } > - if (p->follow_up_info && follow_up_info_append(fup)) { > + if (p->follow_up_info && follow_up_info_append(p, fup)) { > pr_err("%s: append fup info failed", p->log_name); > err = -1; > goto out; > diff --git a/tlv.c b/tlv.c > index 9b82bd9..71619f0 100644 > --- a/tlv.c > +++ b/tlv.c > @@ -362,7 +362,7 @@ static int mgt_post_recv(struct management_tlv *m, > uint16_t data_len, > tsn->master_offset = net2host64(tsn->master_offset); > tsn->ingress_time = net2host64(tsn->ingress_time); > tsn->cumulativeScaledRateOffset = > ntohl(tsn->cumulativeScaledRateOffset); > - tsn->scaledLastGmPhaseChange = > ntohl(tsn->scaledLastGmPhaseChange); > + tsn->scaledLastGmFreqChange = > ntohl(tsn->scaledLastGmFreqChange); > tsn->gmTimeBaseIndicator = ntohs(tsn->gmTimeBaseIndicator); > scaled_ns_n2h(&tsn->lastGmPhaseChange); > tsn->gmPresent = ntohl(tsn->gmPresent); > @@ -582,7 +582,7 @@ static void mgt_pre_send(struct management_tlv *m, > struct tlv_extra *extra) > tsn->master_offset = host2net64(tsn->master_offset); > tsn->ingress_time = host2net64(tsn->ingress_time); > tsn->cumulativeScaledRateOffset = > htonl(tsn->cumulativeScaledRateOffset); > - tsn->scaledLastGmPhaseChange = > htonl(tsn->scaledLastGmPhaseChange); > + tsn->scaledLastGmFreqChange = > htonl(tsn->scaledLastGmFreqChange); > tsn->gmTimeBaseIndicator = htons(tsn->gmTimeBaseIndicator); > scaled_ns_h2n(&tsn->lastGmPhaseChange); > tsn->gmPresent = htonl(tsn->gmPresent); > @@ -798,7 +798,7 @@ static int org_post_recv(struct organization_tlv *org) > f->cumulativeScaledRateOffset = > ntohl(f->cumulativeScaledRateOffset); > f->gmTimeBaseIndicator = > ntohs(f->gmTimeBaseIndicator); > scaled_ns_n2h(&f->lastGmPhaseChange); > - f->scaledLastGmPhaseChange = > ntohl(f->scaledLastGmPhaseChange); > + f->scaledLastGmFreqChange = > ntohl(f->scaledLastGmFreqChange); > break; > > case 2: > @@ -860,7 +860,7 @@ static void org_pre_send(struct organization_tlv *org) > f->cumulativeScaledRateOffset = > htonl(f->cumulativeScaledRateOffset); > f->gmTimeBaseIndicator = > htons(f->gmTimeBaseIndicator); > scaled_ns_h2n(&f->lastGmPhaseChange); > - f->scaledLastGmPhaseChange = > htonl(f->scaledLastGmPhaseChange); > + f->scaledLastGmFreqChange = > htonl(f->scaledLastGmFreqChange); > break; > } > } else if (0 == memcmp(org->id, itu_t_id, sizeof(itu_t_id))) { > diff --git a/tlv.h b/tlv.h > index 8b51ffd..ce87c72 100644 > --- a/tlv.h > +++ b/tlv.h > @@ -331,7 +331,7 @@ struct follow_up_info_tlv { > Integer32 cumulativeScaledRateOffset; > UInteger16 gmTimeBaseIndicator; > ScaledNs lastGmPhaseChange; > - Integer32 scaledLastGmPhaseChange; > + Integer32 scaledLastGmFreqChange; > } PACKED; > > struct ieee_c37_238_2011_tlv { > @@ -380,7 +380,7 @@ struct time_status_np { > int64_t master_offset; /*nanoseconds*/ > int64_t ingress_time; /*nanoseconds*/ > Integer32 cumulativeScaledRateOffset; > - Integer32 scaledLastGmPhaseChange; > + Integer32 scaledLastGmFreqChange; > UInteger16 gmTimeBaseIndicator; > ScaledNs lastGmPhaseChange; > Integer32 gmPresent; > -- > 2.42.0 > > > > _______________________________________________ > Linuxptp-devel mailing list > Lin...@li... > https://lists.sourceforge.net/lists/listinfo/linuxptp-devel > -- *Luigi 'Comio' Mantellini* My Professional Profile <http://www.linkedin.com/in/comio> *"UNIX is very simple, it just needs a genius to understand its simplicity." [cit.]* |
From: Chwee-Lin C. <chw...@in...> - 2023-12-01 08:02:08
|
Add the computation for scaledLastGmFreqChange, as specified in IEEE 802.1AS-2020, clause 11.4.4.3.9. This incorporates the necessary logic to calculate scaledLastGmFreqChange and appends the result to the follow-up TLV. In addition, a naming error has been rectified from scaledLastGmPhaseChange to scaledLastGmFreqChange. v2: Maintain existing printed name 'scaledLastGmPhaseChange' in pmc.c to avoid potential disruptions to users' setups. Signed-off-by: Tan Tee Min <tee...@li...> Signed-off-by: Chwee-Lin Choong <chw...@in...> --- clock.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- clock.h | 7 +++++++ pmc.c | 2 +- port.c | 5 +++-- tlv.c | 8 ++++---- tlv.h | 4 ++-- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/clock.c b/clock.c index b66dda5..c24d496 100644 --- a/clock.c +++ b/clock.c @@ -148,6 +148,7 @@ struct clock { int step_window_counter; int step_window; struct time_zone tz[MAX_TIME_ZONES]; + struct follow_up_info_tlv clksrc_fup_info; }; struct clock the_clock; @@ -544,13 +545,15 @@ static int clock_management_fill_response(struct clock *c, struct port *p, tsn->cumulativeScaledRateOffset = (Integer32) (c->status.cumulativeScaledRateOffset + c->nrr * POW2_41 - POW2_41); - tsn->scaledLastGmPhaseChange = c->status.scaledLastGmPhaseChange; tsn->gmTimeBaseIndicator = c->status.gmTimeBaseIndicator; tsn->lastGmPhaseChange = c->status.lastGmPhaseChange; - if (cid_eq(&c->dad.pds.grandmasterIdentity, &c->dds.clockIdentity)) + if (cid_eq(&c->dad.pds.grandmasterIdentity, &c->dds.clockIdentity)) { tsn->gmPresent = 0; - else + tsn->scaledLastGmFreqChange = c->clksrc_fup_info.scaledLastGmFreqChange; + } else { tsn->gmPresent = 1; + tsn->scaledLastGmFreqChange = c->status.scaledLastGmFreqChange; + } tsn->gmIdentity = c->dad.pds.grandmasterIdentity; datalen = sizeof(*tsn); break; @@ -1289,6 +1292,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, c->utc_offset = config_get_int(config, NULL, "utc_offset"); c->time_source = config_get_int(config, NULL, "timeSource"); c->step_window = config_get_int(config, NULL, "step_window"); + memset(&c->clksrc_fup_info, 0 , sizeof(c->clksrc_fup_info)); if (c->free_running) { c->clkid = CLOCK_INVALID; @@ -1482,12 +1486,21 @@ struct port *clock_first_port(struct clock *c) void clock_follow_up_info(struct clock *c, struct follow_up_info_tlv *f) { c->status.cumulativeScaledRateOffset = f->cumulativeScaledRateOffset; - c->status.scaledLastGmPhaseChange = f->scaledLastGmPhaseChange; + c->status.scaledLastGmFreqChange = f->scaledLastGmFreqChange; c->status.gmTimeBaseIndicator = f->gmTimeBaseIndicator; memcpy(&c->status.lastGmPhaseChange, &f->lastGmPhaseChange, sizeof(c->status.lastGmPhaseChange)); } +void clock_set_follow_up_info(struct clock *c, struct follow_up_info_tlv *f) +{ + if (cid_eq(&c->dad.pds.grandmasterIdentity, &c->dds.clockIdentity)) { + f->scaledLastGmFreqChange = c->clksrc_fup_info.scaledLastGmFreqChange; + } else { + f->scaledLastGmFreqChange = c->status.scaledLastGmFreqChange; + } +} + int clock_free_running(struct clock *c) { return c->free_running ? 1 : 0; @@ -1991,6 +2004,42 @@ static int clock_synchronize_locked(struct clock *c, double adj) return 0; } +void calculate_freq_change(struct clock *c, tmv_t ingress, tmv_t origin) +{ + struct freq_estimator *f = &c->fest; + double ratio; + + /* + * The ratio of the local clock freqency to the master clock + * is estimated by: + * + * (origin_2 - origin_1) / (ingress_2 - ingress_1) + * + * Both of the origin time estimates include the path delay, + * but we assume that the path delay is in fact constant. + * By leaving out the path delay altogther, we can avoid the + * error caused by our imperfect path delay measurement. + */ + if (tmv_is_zero(f->ingress1)) { + f->ingress1 = ingress; + f->origin1 = origin; + return; + } + + if (tmv_cmp(ingress, f->ingress1) == 0) { + pr_warning("bad timestamps in rate ratio calculation"); + return; + } + + ratio = tmv_dbl(tmv_sub(origin, f->origin1)) / + tmv_dbl(tmv_sub(ingress, f->ingress1)); + + c->clksrc_fup_info.scaledLastGmFreqChange = (Integer32)((ratio - 1.0) * POW2_41); + + f->ingress1 = ingress; + f->origin1 = origin; +} + enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin) { enum servo_state state = SERVO_UNLOCKED; @@ -2023,6 +2072,8 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin) c->cur.offsetFromMaster = tmv_to_TimeInterval(c->master_offset); + calculate_freq_change(c, ingress, origin); + if (c->free_running) { state = clock_no_adjust(c, ingress, origin); clock_notify_event(c, NOTIFY_TIME_SYNC); diff --git a/clock.h b/clock.h index ce9ae91..f17bea9 100644 --- a/clock.h +++ b/clock.h @@ -150,6 +150,13 @@ struct port *clock_first_port(struct clock *c); */ void clock_follow_up_info(struct clock *c, struct follow_up_info_tlv *f); +/** + * Set the follow_up info TLV for a slave port. + * @param c The clock instance. + * @param f Pointer to the TLV. + */ +void clock_set_follow_up_info(struct clock *c, struct follow_up_info_tlv *f); + /** * Determine if a clock is free running or not. * @param c The clock instance. diff --git a/pmc.c b/pmc.c index 9faf790..b4b146f 100644 --- a/pmc.c +++ b/pmc.c @@ -412,7 +412,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) tsn->master_offset, tsn->ingress_time, (tsn->cumulativeScaledRateOffset + 0.0) / P41, - tsn->scaledLastGmPhaseChange, + tsn->scaledLastGmFreqChange, tsn->gmTimeBaseIndicator, tsn->lastGmPhaseChange.nanoseconds_msb, tsn->lastGmPhaseChange.nanoseconds_lsb, diff --git a/port.c b/port.c index 136d036..f94789b 100644 --- a/port.c +++ b/port.c @@ -431,7 +431,7 @@ static int add_foreign_master(struct port *p, struct ptp_message *m) return broke_threshold || diff; } -static int follow_up_info_append(struct ptp_message *m) +static int follow_up_info_append(struct port *p, struct ptp_message *m) { struct follow_up_info_tlv *fui; struct tlv_extra *extra; @@ -445,6 +445,7 @@ static int follow_up_info_append(struct ptp_message *m) fui->length = sizeof(*fui) - sizeof(fui->type) - sizeof(fui->length); memcpy(fui->id, ieee8021_id, sizeof(ieee8021_id)); fui->subtype[2] = 1; + clock_set_follow_up_info(p->clock, fui); return 0; } @@ -1781,7 +1782,7 @@ int port_tx_sync(struct port *p, struct address *dst, uint16_t sequence_id) fup->address = *dst; fup->header.flagField[0] |= UNICAST; } - if (p->follow_up_info && follow_up_info_append(fup)) { + if (p->follow_up_info && follow_up_info_append(p, fup)) { pr_err("%s: append fup info failed", p->log_name); err = -1; goto out; diff --git a/tlv.c b/tlv.c index 9b82bd9..71619f0 100644 --- a/tlv.c +++ b/tlv.c @@ -362,7 +362,7 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, tsn->master_offset = net2host64(tsn->master_offset); tsn->ingress_time = net2host64(tsn->ingress_time); tsn->cumulativeScaledRateOffset = ntohl(tsn->cumulativeScaledRateOffset); - tsn->scaledLastGmPhaseChange = ntohl(tsn->scaledLastGmPhaseChange); + tsn->scaledLastGmFreqChange = ntohl(tsn->scaledLastGmFreqChange); tsn->gmTimeBaseIndicator = ntohs(tsn->gmTimeBaseIndicator); scaled_ns_n2h(&tsn->lastGmPhaseChange); tsn->gmPresent = ntohl(tsn->gmPresent); @@ -582,7 +582,7 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) tsn->master_offset = host2net64(tsn->master_offset); tsn->ingress_time = host2net64(tsn->ingress_time); tsn->cumulativeScaledRateOffset = htonl(tsn->cumulativeScaledRateOffset); - tsn->scaledLastGmPhaseChange = htonl(tsn->scaledLastGmPhaseChange); + tsn->scaledLastGmFreqChange = htonl(tsn->scaledLastGmFreqChange); tsn->gmTimeBaseIndicator = htons(tsn->gmTimeBaseIndicator); scaled_ns_h2n(&tsn->lastGmPhaseChange); tsn->gmPresent = htonl(tsn->gmPresent); @@ -798,7 +798,7 @@ static int org_post_recv(struct organization_tlv *org) f->cumulativeScaledRateOffset = ntohl(f->cumulativeScaledRateOffset); f->gmTimeBaseIndicator = ntohs(f->gmTimeBaseIndicator); scaled_ns_n2h(&f->lastGmPhaseChange); - f->scaledLastGmPhaseChange = ntohl(f->scaledLastGmPhaseChange); + f->scaledLastGmFreqChange = ntohl(f->scaledLastGmFreqChange); break; case 2: @@ -860,7 +860,7 @@ static void org_pre_send(struct organization_tlv *org) f->cumulativeScaledRateOffset = htonl(f->cumulativeScaledRateOffset); f->gmTimeBaseIndicator = htons(f->gmTimeBaseIndicator); scaled_ns_h2n(&f->lastGmPhaseChange); - f->scaledLastGmPhaseChange = htonl(f->scaledLastGmPhaseChange); + f->scaledLastGmFreqChange = htonl(f->scaledLastGmFreqChange); break; } } else if (0 == memcmp(org->id, itu_t_id, sizeof(itu_t_id))) { diff --git a/tlv.h b/tlv.h index 8b51ffd..ce87c72 100644 --- a/tlv.h +++ b/tlv.h @@ -331,7 +331,7 @@ struct follow_up_info_tlv { Integer32 cumulativeScaledRateOffset; UInteger16 gmTimeBaseIndicator; ScaledNs lastGmPhaseChange; - Integer32 scaledLastGmPhaseChange; + Integer32 scaledLastGmFreqChange; } PACKED; struct ieee_c37_238_2011_tlv { @@ -380,7 +380,7 @@ struct time_status_np { int64_t master_offset; /*nanoseconds*/ int64_t ingress_time; /*nanoseconds*/ Integer32 cumulativeScaledRateOffset; - Integer32 scaledLastGmPhaseChange; + Integer32 scaledLastGmFreqChange; UInteger16 gmTimeBaseIndicator; ScaledNs lastGmPhaseChange; Integer32 gmPresent; -- 2.42.0 |
From: Richard C. <ric...@gm...> - 2023-12-01 04:28:14
|
On Thu, Nov 30, 2023 at 04:52:44PM -0800, Kishen Maloor wrote: > > + p->cmlds_pmc = pmc_create(cfg, TRANS_UDS, > > + config_get_string(cfg, p->name, "cmlds_client_address"), > > + config_get_string(cfg, p->name, "cmlds_server_address"), > > + hops, > > + config_get_int(cfg, NULL, "domainNumber"), > > + config_get_int(cfg, p->name, "transportSpecific") << 4, > > I haven't studied the flow here, but using the P2P_COMMON instance's > transportSpecific and domainNumber above might cause the CMLDS server's > port_ignore() to drop this message as the > CMLDS ptp4l process would be configured with > transportSpecific/domain=0x2/0. > > Perhaps just passing 0x2/0 above will fix things? This is assuming that > there are no transportSpecific/domainNumber checks on the receive path > for CMLDS events (which seemed to be the case looking at the code). Right, those two fields must match. So I think: - we'll need options for those two, and - this is another reason to use a separate pmc instance for cmlds rather than reusing the uds port. > > Right, so the next TODO is to enable FD_DELAY_TIMER for P2P_COMMON > > mode and let it 1) renew the push subscription and 2) catch the case > > when the push notification does not arrive on time. > > > > Yes, in our series CMLDS queries were performed synchronously at the Pdelay > request cadence. If serviceMeasurementValid=false then port->pdr_missing was > incremented and immediately followed by a call to port_capable(). This was > necessary as I recollect there was a related Avnu test case. > > If serviceMeasurementValid=true, then we set both peer_portid_valid and > p->nrate.ratio_valid to true so that port_capable() could evaluate to true. I think that logic can be implemented without any service Measurement Valid field in the TLV. Thanks, Richard |
From: Kishen M. <kis...@in...> - 2023-12-01 00:53:06
|
Hi Richard, Firstly, thanks so much for your reviews and efforts to get this done. I'll just rehash a couple of points also raised by Andrew. On this change below: > +static int port_cmlds_initialize(struct port *p) > +{ > + struct config *cfg = clock_config(p->clock); > + struct subscribe_events_np sen = {0}; > + const int zero_datalen = 1; > + const UInteger8 hops = 0; > + > + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); > + p->cmlds_pmc = pmc_create(cfg, TRANS_UDS, > + config_get_string(cfg, p->name, "cmlds_client_address"), > + config_get_string(cfg, p->name, "cmlds_server_address"), > + hops, > + config_get_int(cfg, NULL, "domainNumber"), > + config_get_int(cfg, p->name, "transportSpecific") << 4, I haven't studied the flow here, but using the P2P_COMMON instance's transportSpecific and domainNumber above might cause the CMLDS server's port_ignore() to drop this message as the CMLDS ptp4l process would be configured with transportSpecific/domain=0x2/0. Perhaps just passing 0x2/0 above will fix things? This is assuming that there are no transportSpecific/domainNumber checks on the receive path for CMLDS events (which seemed to be the case looking at the code). On 11/30/23 11:28 AM, Richard Cochran wrote: ... >>> serviceMeasurementValid is implicit, because if you get a PUSH >>> notification, it is valid. >> >> Right, serviceMeasurementValid == true is implicit but >> serviceMeasurementValid == false is useful for the .port_id_valid / >> .pdr_missing logic to work. The timeout logic is disabled with >> P2P_COMMON. > > Right, so the next TODO is to enable FD_DELAY_TIMER for P2P_COMMON > mode and let it 1) renew the push subscription and 2) catch the case > when the push notification does not arrive on time. > Yes, in our series CMLDS queries were performed synchronously at the Pdelay request cadence. If serviceMeasurementValid=false then port->pdr_missing was incremented and immediately followed by a call to port_capable(). This was necessary as I recollect there was a related Avnu test case. If serviceMeasurementValid=true, then we set both peer_portid_valid and p->nrate.ratio_valid to true so that port_capable() could evaluate to true. |
From: Richard C. <ric...@gm...> - 2023-11-30 19:28:54
|
On Thu, Nov 30, 2023 at 07:12:54PM +0100, Andrew Zaborowski wrote: > On Thu, 30 Nov 2023 at 17:44, Richard Cochran <ric...@gm...> wrote: > > On Thu, Nov 30, 2023 at 04:32:20PM +0100, Andrew Zaborowski wrote: > > > > + PORT_ITEM_STR("cmlds_client_address", "/var/run/cmlds_cleint"), > > > > > > I assume the use of this is simply to set unique names for per-port > > > sockets. Maybe something like tempnam() could be used instead. > > > > No, it has to be under user control, because the path might be under a > > security policy. > > Do you mean that the user might want it to be under a security policy? Yes. > Otherwise it could be in /tmp. The top down path has to be the user's choice, /tmp/... or /var/run/... or /whatever/... and so there must be a configuration option in any case. It seems silly to restrict the option to the leading path and not include the socket file name. > > > > @@ -1868,6 +1869,33 @@ static void port_clear_fda(struct port *p, int count) > > > > p->fda.fd[i] = -1; > > > > } > > > > > > > > +static int port_cmlds_initialize(struct port *p) > > > > +{ > > > > + struct config *cfg = clock_config(p->clock); > > > > + struct subscribe_events_np sen = {0}; > > > > + const int zero_datalen = 1; > > > > + const UInteger8 hops = 0; > > > > + > > > > + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); > > > > > > Should this fall back to port_number(p)? > > > > I don't see how, since there is always a default for each > > configuration option. > > Right, it'd need to default to, say, -1 which would be checked here. Okay, sure. That will reduce configuration burden for normal setups. > > Also, I understood from you guys that the port > > number _has_ to be different to pass compliance tests. For that, I > > thought adding a "starting port number" option would do the trick > > The port identity (clock identity + port number) has to be unique. As > long as the clock identity is unique, which it has to be, I don't > think the port number *has* to be different. Got it. > > serviceMeasurementValid is implicit, because if you get a PUSH > > notification, it is valid. > > Right, serviceMeasurementValid == true is implicit but > serviceMeasurementValid == false is useful for the .port_id_valid / > .pdr_missing logic to work. The timeout logic is disabled with > P2P_COMMON. Right, so the next TODO is to enable FD_DELAY_TIMER for P2P_COMMON mode and let it 1) renew the push subscription and 2) catch the case when the push notification does not arrive on time. Thoughts? Thanks, Richard |
From: Andrew Z. <and...@in...> - 2023-11-30 19:18:05
|
On Thu, 30 Nov 2023 at 17:44, Richard Cochran <ric...@gm...> wrote: > On Thu, Nov 30, 2023 at 04:32:20PM +0100, Andrew Zaborowski wrote: > > > + PORT_ITEM_STR("cmlds_client_address", "/var/run/cmlds_cleint"), > > > > I assume the use of this is simply to set unique names for per-port > > sockets. Maybe something like tempnam() could be used instead. > > No, it has to be under user control, because the path might be under a > security policy. Do you mean that the user might want it to be under a security policy? Otherwise it could be in /tmp. > > > > @@ -1868,6 +1869,33 @@ static void port_clear_fda(struct port *p, int count) > > > p->fda.fd[i] = -1; > > > } > > > > > > +static int port_cmlds_initialize(struct port *p) > > > +{ > > > + struct config *cfg = clock_config(p->clock); > > > + struct subscribe_events_np sen = {0}; > > > + const int zero_datalen = 1; > > > + const UInteger8 hops = 0; > > > + > > > + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); > > > > Should this fall back to port_number(p)? > > I don't see how, since there is always a default for each > configuration option. Right, it'd need to default to, say, -1 which would be checked here. > Also, I understood from you guys that the port > number _has_ to be different to pass compliance tests. For that, I > thought adding a "starting port number" option would do the trick The port identity (clock identity + port number) has to be unique. As long as the clock identity is unique, which it has to be, I don't think the port number *has* to be different. > > > In Kishen's patch series struct cmlds_info_np also had a > > .serviceMeasurementValid which enabled the port_capable() logic to > > work and IIRC that is important at least for 802.1AS compliance. If > > that was to be re-added, the event would need to be emitted in an > > extra place in the CMLDS, perhaps where pdr_missing is incremented. > > serviceMeasurementValid is implicit, because if you get a PUSH > notification, it is valid. Right, serviceMeasurementValid == true is implicit but serviceMeasurementValid == false is useful for the .port_id_valid / .pdr_missing logic to work. The timeout logic is disabled with P2P_COMMON. Best regards |
From: Richard C. <ric...@gm...> - 2023-11-30 16:44:07
|
On Thu, Nov 30, 2023 at 04:32:20PM +0100, Andrew Zaborowski wrote: > > @@ -249,6 +250,9 @@ struct config_item config_tab[] = { > > GLOB_ITEM_INT("clock_class_threshold", CLOCK_CLASS_THRESHOLD_DEFAULT, 6, CLOCK_CLASS_THRESHOLD_DEFAULT), > > GLOB_ITEM_ENU("clock_servo", CLOCK_SERVO_PI, clock_servo_enu), > > GLOB_ITEM_ENU("clock_type", CLOCK_TYPE_ORDINARY, clock_type_enu), > > + PORT_ITEM_STR("cmlds_client_address", "/var/run/cmlds_cleint"), > > I assume the use of this is simply to set unique names for per-port > sockets. Maybe something like tempnam() could be used instead. No, it has to be under user control, because the path might be under a security policy. > > @@ -1868,6 +1869,33 @@ static void port_clear_fda(struct port *p, int count) > > p->fda.fd[i] = -1; > > } > > > > +static int port_cmlds_initialize(struct port *p) > > +{ > > + struct config *cfg = clock_config(p->clock); > > + struct subscribe_events_np sen = {0}; > > + const int zero_datalen = 1; > > + const UInteger8 hops = 0; > > + > > + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); > > Should this fall back to port_number(p)? I don't see how, since there is always a default for each configuration option. Also, I understood from you guys that the port number _has_ to be different to pass compliance tests. For that, I thought adding a "starting port number" option would do the trick. > > + p->cmlds_pmc = pmc_create(cfg, TRANS_UDS, > > + config_get_string(cfg, p->name, "cmlds_client_address"), > > + config_get_string(cfg, p->name, "cmlds_server_address"), > > + hops, > > + config_get_int(cfg, NULL, "domainNumber"), > > + config_get_int(cfg, p->name, "transportSpecific") << 4, > > The sdoId is (by either IEEE 1588 or 802.1AS) different for the CMLDS > than for a P2P_COMMON port, I think a check in port_ignore will > discard the messages as a result. Maybe hardcode TS_CMLDS here? (with > TS_CMLDS defined in msg.h next to TS_IEEE_8021AS) > > Using pmc here surely works but I wonder if it's not actually more > work than reusing c->uds_port. I considered that, but I invite you to try implementing that to see which one is simpler. > > + switch (mgt->id) { > > + case MID_CMLDS_INFO_NP: > > + if (msg->header.sourcePortIdentity.portNumber != p->cmlds_port) { > > + break; > > + } > > + cmlds = (struct cmlds_info_np *) mgt->data; > > + p->peer_delay = nanoseconds_to_tmv(cmlds->meanLinkDelay >> 16); > > + p->peerMeanPathDelay = tmv_to_TimeInterval(p->peer_delay); > > cmlds->meanLinkDelay is already a TimeInterval in case you want to use that. good point > > + > > + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { > > + const struct timestamp dummy = {0}; > > + const tmv_t tx = timestamp_to_tmv(dummy); > > tmv_zero() could also be used. yeah > > + clock_peer_delay(p->clock, p->peer_delay, tx, tx, > > + p->nrate.ratio); > > p->nrate.ratio hasn't been set yet, I think a line similar to this is missing: > > p->nrate.ratio = 1.0 + (double) cmlds->scaledNeighborRateRatio / POW2_41; Right > The CMLDS port will also need to ensure that the NRR is calculated > because now it's done conditionally. Huh, I didn't change that part? > In Kishen's patch series struct cmlds_info_np also had a > .serviceMeasurementValid which enabled the port_capable() logic to > work and IIRC that is important at least for 802.1AS compliance. If > that was to be re-added, the event would need to be emitted in an > extra place in the CMLDS, perhaps where pdr_missing is incremented. serviceMeasurementValid is implicit, because if you get a PUSH notification, it is valid. Thanks, Richard |
From: Andrew Z. <and...@in...> - 2023-11-30 15:32:53
|
Hi Richard, I haven't tested this but here are some comments. On Thu, 30 Nov 2023 at 08:58, Richard Cochran <ric...@gm...> wrote: > From: Kishen Maloor <kis...@in...> > > Signed-off-by: Richard Cochran <ric...@gm...> > --- > config.c | 4 ++ > dm.h | 3 + > fd.h | 1 + > makefile | 4 +- > port.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++-- > port_private.h | 3 + > 6 files changed, 174 insertions(+), 7 deletions(-) > > diff --git a/config.c b/config.c > index fe65b76..05ffd3c 100644 > --- a/config.c > +++ b/config.c > @@ -171,6 +171,7 @@ static struct config_enum delay_filter_enu[] = { > > static struct config_enum delay_mech_enu[] = { > { "Auto", DM_AUTO }, > + { "COMMON_P2P", DM_COMMON_P2P }, > { "E2E", DM_E2E }, > { "P2P", DM_P2P }, > { "NONE", DM_NO_MECHANISM }, > @@ -249,6 +250,9 @@ struct config_item config_tab[] = { > GLOB_ITEM_INT("clock_class_threshold", CLOCK_CLASS_THRESHOLD_DEFAULT, 6, CLOCK_CLASS_THRESHOLD_DEFAULT), > GLOB_ITEM_ENU("clock_servo", CLOCK_SERVO_PI, clock_servo_enu), > GLOB_ITEM_ENU("clock_type", CLOCK_TYPE_ORDINARY, clock_type_enu), > + PORT_ITEM_STR("cmlds_client_address", "/var/run/cmlds_cleint"), I assume the use of this is simply to set unique names for per-port sockets. Maybe something like tempnam() could be used instead. > + PORT_ITEM_INT("cmlds_port", 1, 1, UINT16_MAX), > + PORT_ITEM_STR("cmlds_server_address", "/var/run/cmlds_server"), > GLOB_ITEM_ENU("dataset_comparison", DS_CMP_IEEE1588, dataset_comp_enu), > PORT_ITEM_INT("delayAsymmetry", 0, INT_MIN, INT_MAX), > PORT_ITEM_ENU("delay_filter", FILTER_MOVING_MEDIAN, delay_filter_enu), > diff --git a/dm.h b/dm.h > index 47bd847..80d1ce5 100644 > --- a/dm.h > +++ b/dm.h > @@ -34,6 +34,9 @@ enum delay_mechanism { > /** Peer delay mechanism. */ > DM_P2P, > > + /** Peer delay as measured by CMLDS. */ > + DM_COMMON_P2P, > + > /** No Delay Mechanism. */ > DM_NO_MECHANISM = 0xFE, > }; > diff --git a/fd.h b/fd.h > index 16420d7..9a072ab 100644 > --- a/fd.h > +++ b/fd.h > @@ -39,6 +39,7 @@ enum { > FD_SYNC_TX_TIMER, > FD_UNICAST_REQ_TIMER, > FD_UNICAST_SRV_TIMER, > + FD_CMLDS, > FD_RTNL, > N_POLLFD, > }; > diff --git a/makefile b/makefile > index 7fc5f6f..e9c1ccc 100644 > --- a/makefile > +++ b/makefile > @@ -30,8 +30,8 @@ TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_pps_source.o \ > ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o ts2phc_pps_source.o > OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \ > e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \ > - port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \ > - sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ > + pmc_common.o port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o \ > + $(SERVOS) sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ > unicast_fsm.o unicast_service.o util.o version.o > > OBJECTS = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o pmc_agent.o \ > diff --git a/port.c b/port.c > index 8afe1b2..75b4dd8 100644 > --- a/port.c > +++ b/port.c > @@ -963,7 +963,8 @@ static int port_management_fill_response(struct port *target, > ptp_text_copy(cd->userDescription, &desc->userDescription); > buf += sizeof(struct PTPText) + cd->userDescription->length; > > - if (target->delayMechanism == DM_P2P) { > + if (target->delayMechanism == DM_P2P || > + target->delayMechanism == DM_COMMON_P2P) { > memcpy(buf, profile_id_p2p, PROFILE_ID_LEN); > } else { > struct config *cfg = clock_config(target->clock); > @@ -1868,6 +1869,33 @@ static void port_clear_fda(struct port *p, int count) > p->fda.fd[i] = -1; > } > > +static int port_cmlds_initialize(struct port *p) > +{ > + struct config *cfg = clock_config(p->clock); > + struct subscribe_events_np sen = {0}; > + const int zero_datalen = 1; > + const UInteger8 hops = 0; > + > + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); Should this fall back to port_number(p)? > + p->cmlds_pmc = pmc_create(cfg, TRANS_UDS, > + config_get_string(cfg, p->name, "cmlds_client_address"), > + config_get_string(cfg, p->name, "cmlds_server_address"), > + hops, > + config_get_int(cfg, NULL, "domainNumber"), > + config_get_int(cfg, p->name, "transportSpecific") << 4, The sdoId is (by either IEEE 1588 or 802.1AS) different for the CMLDS than for a P2P_COMMON port, I think a check in port_ignore will discard the messages as a result. Maybe hardcode TS_CMLDS here? (with TS_CMLDS defined in msg.h next to TS_IEEE_8021AS) Using pmc here surely works but I wonder if it's not actually more work than reusing c->uds_port. > + zero_datalen); > + if (!p->cmlds_pmc) { > + return -1; > + } > + > + event_bitmask_set(sen.bitmask, NOTIFY_CMLDS, TRUE); > + sen.duration = 3600; > + p->fda.fd[FD_CMLDS] = pmc_get_transport_fd(p->cmlds_pmc); > + pmc_send_set_action(p->cmlds_pmc, MID_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen)); > + > + return 0; > +} > + > void port_disable(struct port *p) > { > int i; > @@ -1885,6 +1913,12 @@ void port_disable(struct port *p) > close(p->fda.fd[FD_FIRST_TIMER + i]); > } > > + if (p->cmlds_pmc) { > + pmc_destroy(p->cmlds_pmc); > + p->fda.fd[FD_CMLDS] = -1; > + p->cmlds_pmc = NULL; > + } > + > /* Keep rtnl socket to get link status info. */ > port_clear_fda(p, FD_RTNL); > clock_fda_changed(p->clock); > @@ -1932,7 +1966,8 @@ int port_initialize(struct port *p) > pr_err("inhibit_delay_req can only be set when asCapable == 'true'."); > return -1; > } > - if (port_delay_mechanism(p) == DM_NO_MECHANISM) { > + if (port_delay_mechanism(p) == DM_COMMON_P2P || > + port_delay_mechanism(p) == DM_NO_MECHANISM) { > p->inhibit_delay_req = 1; > } > > @@ -1960,6 +1995,10 @@ int port_initialize(struct port *p) > goto no_tmo; > } > > + if (port_delay_mechanism(p) == DM_COMMON_P2P && port_cmlds_initialize(p)) { > + goto no_tmo; > + } > + > /* No need to open rtnl socket on UDS port. */ > if (!port_is_uds(p)) { > /* > @@ -2101,6 +2140,65 @@ int process_announce(struct port *p, struct ptp_message *m) > return result; > } > > +static int process_cmlds(struct port *p) > +{ > + struct cmlds_info_np *cmlds; > + struct management_tlv *mgt; > + struct ptp_message *msg; > + struct TLV *tlv; > + int err = 0; > + > + msg = pmc_recv(p->cmlds_pmc); > + if (!msg) { > + pr_err("%s: pmc_recv failed", p->log_name); > + return -1; > + } > + if (msg_type(msg) != MANAGEMENT) { > + pr_err("%s: pmc_recv bad message", p->log_name); > + err = -1; > + goto out; > + } > + tlv = (struct TLV *) msg->management.suffix; > + if (tlv->type != TLV_MANAGEMENT) { > + pr_err("%s: pmc_recv bad message", p->log_name); > + err = -1; > + goto out; > + } > + mgt = (struct management_tlv *) msg->management.suffix; > + if (mgt->length == 2 && mgt->id != MID_NULL_MANAGEMENT) { > + pr_err("%s: pmc_recv bad length", p->log_name); > + goto out; > + } > + > + switch (mgt->id) { > + case MID_CMLDS_INFO_NP: > + if (msg->header.sourcePortIdentity.portNumber != p->cmlds_port) { > + break; > + } > + cmlds = (struct cmlds_info_np *) mgt->data; > + p->peer_delay = nanoseconds_to_tmv(cmlds->meanLinkDelay >> 16); > + p->peerMeanPathDelay = tmv_to_TimeInterval(p->peer_delay); cmlds->meanLinkDelay is already a TimeInterval in case you want to use that. > + > + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { > + const struct timestamp dummy = {0}; > + const tmv_t tx = timestamp_to_tmv(dummy); tmv_zero() could also be used. > + clock_peer_delay(p->clock, p->peer_delay, tx, tx, > + p->nrate.ratio); p->nrate.ratio hasn't been set yet, I think a line similar to this is missing: p->nrate.ratio = 1.0 + (double) cmlds->scaledNeighborRateRatio / POW2_41; The CMLDS port will also need to ensure that the NRR is calculated because now it's done conditionally. In Kishen's patch series struct cmlds_info_np also had a .serviceMeasurementValid which enabled the port_capable() logic to work and IIRC that is important at least for 802.1AS compliance. If that was to be re-added, the event would need to be emitted in an extra place in the CMLDS, perhaps where pdr_missing is incremented. Best regards |
From: Richard C. <ric...@gm...> - 2023-11-30 08:02:14
|
On Wed, Nov 29, 2023 at 11:57:16PM -0800, Richard Cochran wrote: > This is how CMLD should be done, IMHO. Sample configs... ~~~~~~~~~~~~~~~~ CMLDS_server.cfg ~~~~~~~~~~~~~~~~ [global] clientOnly 1 free_running 1 uds_address /var/run/cmlds_server use_syslog 0 verbose 1 [eth2] delay_mechanism P2P [eth1] delay_mechanism P2P ~~~~~~~~~~~~~~~~ CMLDS_client.cfg ~~~~~~~~~~~~~~~~ [global] use_syslog 0 verbose 1 [eth1] delay_mechanism COMMON_P2P cmlds_port 2 |
From: Richard C. <ric...@gm...> - 2023-11-30 07:57:47
|
From: Kishen Maloor <kis...@in...> Signed-off-by: Richard Cochran <ric...@gm...> --- config.c | 4 ++ dm.h | 3 + fd.h | 1 + makefile | 4 +- port.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++-- port_private.h | 3 + 6 files changed, 174 insertions(+), 7 deletions(-) diff --git a/config.c b/config.c index fe65b76..05ffd3c 100644 --- a/config.c +++ b/config.c @@ -171,6 +171,7 @@ static struct config_enum delay_filter_enu[] = { static struct config_enum delay_mech_enu[] = { { "Auto", DM_AUTO }, + { "COMMON_P2P", DM_COMMON_P2P }, { "E2E", DM_E2E }, { "P2P", DM_P2P }, { "NONE", DM_NO_MECHANISM }, @@ -249,6 +250,9 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("clock_class_threshold", CLOCK_CLASS_THRESHOLD_DEFAULT, 6, CLOCK_CLASS_THRESHOLD_DEFAULT), GLOB_ITEM_ENU("clock_servo", CLOCK_SERVO_PI, clock_servo_enu), GLOB_ITEM_ENU("clock_type", CLOCK_TYPE_ORDINARY, clock_type_enu), + PORT_ITEM_STR("cmlds_client_address", "/var/run/cmlds_cleint"), + PORT_ITEM_INT("cmlds_port", 1, 1, UINT16_MAX), + PORT_ITEM_STR("cmlds_server_address", "/var/run/cmlds_server"), GLOB_ITEM_ENU("dataset_comparison", DS_CMP_IEEE1588, dataset_comp_enu), PORT_ITEM_INT("delayAsymmetry", 0, INT_MIN, INT_MAX), PORT_ITEM_ENU("delay_filter", FILTER_MOVING_MEDIAN, delay_filter_enu), diff --git a/dm.h b/dm.h index 47bd847..80d1ce5 100644 --- a/dm.h +++ b/dm.h @@ -34,6 +34,9 @@ enum delay_mechanism { /** Peer delay mechanism. */ DM_P2P, + /** Peer delay as measured by CMLDS. */ + DM_COMMON_P2P, + /** No Delay Mechanism. */ DM_NO_MECHANISM = 0xFE, }; diff --git a/fd.h b/fd.h index 16420d7..9a072ab 100644 --- a/fd.h +++ b/fd.h @@ -39,6 +39,7 @@ enum { FD_SYNC_TX_TIMER, FD_UNICAST_REQ_TIMER, FD_UNICAST_SRV_TIMER, + FD_CMLDS, FD_RTNL, N_POLLFD, }; diff --git a/makefile b/makefile index 7fc5f6f..e9c1ccc 100644 --- a/makefile +++ b/makefile @@ -30,8 +30,8 @@ TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_pps_source.o \ ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o ts2phc_pps_source.o OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \ e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \ - port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \ - sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ + pmc_common.o port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o \ + $(SERVOS) sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \ unicast_fsm.o unicast_service.o util.o version.o OBJECTS = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o pmc_agent.o \ diff --git a/port.c b/port.c index 8afe1b2..75b4dd8 100644 --- a/port.c +++ b/port.c @@ -963,7 +963,8 @@ static int port_management_fill_response(struct port *target, ptp_text_copy(cd->userDescription, &desc->userDescription); buf += sizeof(struct PTPText) + cd->userDescription->length; - if (target->delayMechanism == DM_P2P) { + if (target->delayMechanism == DM_P2P || + target->delayMechanism == DM_COMMON_P2P) { memcpy(buf, profile_id_p2p, PROFILE_ID_LEN); } else { struct config *cfg = clock_config(target->clock); @@ -1868,6 +1869,33 @@ static void port_clear_fda(struct port *p, int count) p->fda.fd[i] = -1; } +static int port_cmlds_initialize(struct port *p) +{ + struct config *cfg = clock_config(p->clock); + struct subscribe_events_np sen = {0}; + const int zero_datalen = 1; + const UInteger8 hops = 0; + + p->cmlds_port = config_get_int(cfg, p->name, "cmlds_port"); + p->cmlds_pmc = pmc_create(cfg, TRANS_UDS, + config_get_string(cfg, p->name, "cmlds_client_address"), + config_get_string(cfg, p->name, "cmlds_server_address"), + hops, + config_get_int(cfg, NULL, "domainNumber"), + config_get_int(cfg, p->name, "transportSpecific") << 4, + zero_datalen); + if (!p->cmlds_pmc) { + return -1; + } + + event_bitmask_set(sen.bitmask, NOTIFY_CMLDS, TRUE); + sen.duration = 3600; + p->fda.fd[FD_CMLDS] = pmc_get_transport_fd(p->cmlds_pmc); + pmc_send_set_action(p->cmlds_pmc, MID_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen)); + + return 0; +} + void port_disable(struct port *p) { int i; @@ -1885,6 +1913,12 @@ void port_disable(struct port *p) close(p->fda.fd[FD_FIRST_TIMER + i]); } + if (p->cmlds_pmc) { + pmc_destroy(p->cmlds_pmc); + p->fda.fd[FD_CMLDS] = -1; + p->cmlds_pmc = NULL; + } + /* Keep rtnl socket to get link status info. */ port_clear_fda(p, FD_RTNL); clock_fda_changed(p->clock); @@ -1932,7 +1966,8 @@ int port_initialize(struct port *p) pr_err("inhibit_delay_req can only be set when asCapable == 'true'."); return -1; } - if (port_delay_mechanism(p) == DM_NO_MECHANISM) { + if (port_delay_mechanism(p) == DM_COMMON_P2P || + port_delay_mechanism(p) == DM_NO_MECHANISM) { p->inhibit_delay_req = 1; } @@ -1960,6 +1995,10 @@ int port_initialize(struct port *p) goto no_tmo; } + if (port_delay_mechanism(p) == DM_COMMON_P2P && port_cmlds_initialize(p)) { + goto no_tmo; + } + /* No need to open rtnl socket on UDS port. */ if (!port_is_uds(p)) { /* @@ -2101,6 +2140,65 @@ int process_announce(struct port *p, struct ptp_message *m) return result; } +static int process_cmlds(struct port *p) +{ + struct cmlds_info_np *cmlds; + struct management_tlv *mgt; + struct ptp_message *msg; + struct TLV *tlv; + int err = 0; + + msg = pmc_recv(p->cmlds_pmc); + if (!msg) { + pr_err("%s: pmc_recv failed", p->log_name); + return -1; + } + if (msg_type(msg) != MANAGEMENT) { + pr_err("%s: pmc_recv bad message", p->log_name); + err = -1; + goto out; + } + tlv = (struct TLV *) msg->management.suffix; + if (tlv->type != TLV_MANAGEMENT) { + pr_err("%s: pmc_recv bad message", p->log_name); + err = -1; + goto out; + } + mgt = (struct management_tlv *) msg->management.suffix; + if (mgt->length == 2 && mgt->id != MID_NULL_MANAGEMENT) { + pr_err("%s: pmc_recv bad length", p->log_name); + goto out; + } + + switch (mgt->id) { + case MID_CMLDS_INFO_NP: + if (msg->header.sourcePortIdentity.portNumber != p->cmlds_port) { + break; + } + cmlds = (struct cmlds_info_np *) mgt->data; + p->peer_delay = nanoseconds_to_tmv(cmlds->meanLinkDelay >> 16); + p->peerMeanPathDelay = tmv_to_TimeInterval(p->peer_delay); + + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { + const struct timestamp dummy = {0}; + const tmv_t tx = timestamp_to_tmv(dummy); + clock_peer_delay(p->clock, p->peer_delay, tx, tx, + p->nrate.ratio); + } + break; + case MID_SUBSCRIBE_EVENTS_NP: + break; + default: + pr_err("%s: pmc_recv bad mgt id 0x%x", p->log_name, mgt->id); + err = -1; + break; + } + +out: + msg_put(msg); + return err; +} + static int process_delay_req(struct port *p, struct ptp_message *m) { struct ptp_message *msg; @@ -2112,7 +2210,7 @@ static int process_delay_req(struct port *p, struct ptp_message *m) return 0; } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || p->delayMechanism == DM_COMMON_P2P) { pr_warning("%s: delay request on P2P port", p->log_name); return 0; } @@ -2277,6 +2375,9 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) return -1; } + if (p->delayMechanism == DM_COMMON_P2P) { + return 0; + } if (p->delayMechanism == DM_E2E) { pr_warning("%s: pdelay_req on E2E port", p->log_name); return 0; @@ -2472,6 +2573,9 @@ calc: int process_pdelay_resp(struct port *p, struct ptp_message *m) { + if (p->delayMechanism == DM_COMMON_P2P) { + return 0; + } if (p->peer_delay_resp) { if (!p->multiple_pdr_detected) { pr_err("%s: multiple peer responses", p->log_name); @@ -2642,6 +2746,48 @@ struct foreign_clock *port_compute_best(struct port *p) return p->best; } +static void port_cmlds_transition(struct port *p, enum port_state next) +{ + port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]); + port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]); + port_clr_tmo(p->fda.fd[FD_DELAY_TIMER]); + port_clr_tmo(p->fda.fd[FD_QUALIFICATION_TIMER]); + port_clr_tmo(p->fda.fd[FD_MANNO_TIMER]); + port_clr_tmo(p->fda.fd[FD_SYNC_TX_TIMER]); + /* Leave FD_UNICAST_REQ_TIMER running. */ + + switch (next) { + case PS_INITIALIZING: + break; + case PS_FAULTY: + case PS_DISABLED: + port_disable(p); + break; + case PS_LISTENING: + port_set_announce_tmo(p); + break; + case PS_PRE_MASTER: + port_set_qualification_tmo(p); + break; + case PS_MASTER: + case PS_GRAND_MASTER: + if (!p->inhibit_announce) { + set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ + } + port_set_sync_tx_tmo(p); + break; + case PS_PASSIVE: + port_set_announce_tmo(p); + break; + case PS_UNCALIBRATED: + flush_last_sync(p); + /* fall through */ + case PS_SLAVE: + port_set_announce_tmo(p); + break; + }; +} + static void port_e2e_transition(struct port *p, enum port_state next) { port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]); @@ -2747,10 +2893,16 @@ static void bc_dispatch(struct port *p, enum fsm_event event, int mdiff) return; } - if (p->delayMechanism == DM_P2P) { + switch (p->delayMechanism) { + case DM_P2P: port_p2p_transition(p, p->state); - } else { + break; + case DM_COMMON_P2P: + port_cmlds_transition(p, p->state); + break; + default: port_e2e_transition(p, p->state); + break; } if (p->jbod && p->state == PS_UNCALIBRATED && p->phc_index >= 0 ) { @@ -2944,6 +3096,10 @@ static enum fsm_event bc_event(struct port *p, int fd_index) p->service_stats.unicast_request_timeout++; return unicast_client_timer(p) ? EV_FAULT_DETECTED : EV_NONE; + case FD_CMLDS: + pr_debug("%s: CMLDS push notification", p->log_name); + return process_cmlds(p) ? EV_FAULT_DETECTED : EV_NONE; + case FD_RTNL: pr_debug("%s: received link status notification", p->log_name); rtnl_link_status(fd, p->name, port_link_status, p); diff --git a/port_private.h b/port_private.h index 1ef816a..7c8fcd9 100644 --- a/port_private.h +++ b/port_private.h @@ -26,6 +26,7 @@ #include "fsm.h" #include "monitor.h" #include "msg.h" +#include "pmc_common.h" #include "power_profile.h" #include "tmv.h" @@ -165,6 +166,8 @@ struct port { /* slave event monitoring */ struct monitor *slave_event_monitor; bool unicast_state_dirty; + struct pmc *cmlds_pmc; + int cmlds_port; }; #define portnum(p) (p->portIdentity.portNumber) -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-11-30 07:57:46
|
Add a new TLV to convey link delay measurements by the Common Mean Link Delay Service (CMLDS) (as specified in IEEE 1588/16.6.3) over the management interface. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 1 - pmc.c | 9 +++++++++ pmc_common.c | 1 + port.c | 8 ++++++++ port.h | 2 ++ tlv.c | 14 ++++++++++++++ tlv.h | 6 ++++++ 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 6f7722c..c999c83 100644 --- a/clock.c +++ b/clock.c @@ -47,7 +47,6 @@ #include "util.h" #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ -#define POW2_41 ((double)(1ULL << 41)) struct interface { STAILQ_ENTRY(interface) list; diff --git a/pmc.c b/pmc.c index d18fea0..c29e3b7 100644 --- a/pmc.c +++ b/pmc.c @@ -169,6 +169,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) struct subscribe_events_np *sen; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct timePropertiesDS *tp; struct management_tlv *mgt; struct time_status_np *tsn; @@ -623,6 +624,14 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) pwr->networkTimeInaccuracy, pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *) mgt->data; + fprintf(fp, "CMLDS_INFO_NP " + IFMT "meanLinkDelay %" PRId64 + IFMT "scaledNeighborRateRatio %" PRId32, + cmlds->meanLinkDelay >> 16, + cmlds->scaledNeighborRateRatio); + break; case MID_LOG_ANNOUNCE_INTERVAL: mtd = (struct management_tlv_datum *) mgt->data; fprintf(fp, "LOG_ANNOUNCE_INTERVAL " diff --git a/pmc_common.c b/pmc_common.c index fca16c6..1d537f2 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -156,6 +156,7 @@ struct management_id idtab[] = { { "UNICAST_MASTER_TABLE_NP", MID_UNICAST_MASTER_TABLE_NP, do_get_action }, { "PORT_HWCLOCK_NP", MID_PORT_HWCLOCK_NP, do_get_action }, { "POWER_PROFILE_SETTINGS_NP", MID_POWER_PROFILE_SETTINGS_NP, do_set_action }, + { "CMLDS_INFO_NP", MID_CMLDS_INFO_NP, do_get_action }, }; static void do_get_action(struct pmc *pmc, int action, int index, char *str) diff --git a/port.c b/port.c index 136d036..aab9d3f 100644 --- a/port.c +++ b/port.c @@ -883,6 +883,7 @@ static int port_management_fill_response(struct port *target, struct clock_description *desc; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct management_tlv *tlv; struct port_stats_np *psn; struct foreign_clock *fc; @@ -1125,6 +1126,13 @@ static int port_management_fill_response(struct port *target, memcpy(pwr, &target->pwr, sizeof(*pwr)); datalen = sizeof(*pwr); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *)tlv->data; + cmlds->meanLinkDelay = target->peerMeanPathDelay; + cmlds->scaledNeighborRateRatio = + (Integer32) (target->nrate.ratio * POW2_41 - POW2_41); + datalen = sizeof(*cmlds); + break; default: /* The caller should *not* respond to this message. */ tlv_extra_recycle(extra); diff --git a/port.h b/port.h index 57c8c2f..cc03859 100644 --- a/port.h +++ b/port.h @@ -26,6 +26,8 @@ #include "notification.h" #include "transport.h" +#define POW2_41 ((double)(1ULL << 41)) + /* forward declarations */ struct interface; struct clock; diff --git a/tlv.c b/tlv.c index 9b82bd9..8fbeb1a 100644 --- a/tlv.c +++ b/tlv.c @@ -176,6 +176,7 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, struct port_properties_np *ppn; struct port_hwclock_np *phn; struct timePropertiesDS *tp; + struct cmlds_info_np *cmlds; struct time_status_np *tsn; struct port_stats_np *psn; int extra_len = 0, i, len; @@ -481,6 +482,13 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, NTOHL(pwr->networkTimeInaccuracy); NTOHL(pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + if (data_len < sizeof(struct cmlds_info_np)) + goto bad_length; + cmlds = (struct cmlds_info_np *)m->data; + net2host64_unaligned(&cmlds->meanLinkDelay); + NTOHL(cmlds->scaledNeighborRateRatio); + break; case MID_SAVE_IN_NON_VOLATILE_STORAGE: case MID_RESET_NON_VOLATILE_STORAGE: case MID_INITIALIZE: @@ -514,6 +522,7 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) struct subscribe_events_np *sen; struct port_properties_np *ppn; struct port_hwclock_np *phn; + struct cmlds_info_np *cmlds; struct timePropertiesDS *tp; struct time_status_np *tsn; struct port_stats_np *psn; @@ -672,6 +681,11 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) HTONL(pwr->networkTimeInaccuracy); HTONL(pwr->totalTimeInaccuracy); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *)m->data; + host2net64_unaligned(&cmlds->meanLinkDelay); + HTONL(cmlds->scaledNeighborRateRatio); + break; } } diff --git a/tlv.h b/tlv.h index 8b51ffd..6287333 100644 --- a/tlv.h +++ b/tlv.h @@ -129,6 +129,7 @@ enum management_action { #define MID_UNICAST_MASTER_TABLE_NP 0xC008 #define MID_PORT_HWCLOCK_NP 0xC009 #define MID_POWER_PROFILE_SETTINGS_NP 0xC00A +#define MID_CMLDS_INFO_NP 0xC00B /* Management error ID values */ #define MID_RESPONSE_TOO_BIG 0x0001 @@ -323,6 +324,11 @@ typedef struct Integer96 { uint16_t fractional_nanoseconds; } PACKED ScaledNs; +struct cmlds_info_np { + TimeInterval meanLinkDelay; + Integer32 scaledNeighborRateRatio; +} PACKED; + struct follow_up_info_tlv { Enumeration16 type; UInteger16 length; -- 2.39.2 |
From: Richard C. <ric...@gm...> - 2023-11-30 07:57:46
|
Signed-off-by: Richard Cochran <ric...@gm...> --- notification.h | 1 + pmc.c | 6 ++++-- pmc_common.c | 14 ++++++++++---- port.c | 5 +++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/notification.h b/notification.h index c1a6395..7a8f641 100644 --- a/notification.h +++ b/notification.h @@ -45,6 +45,7 @@ enum notification { NOTIFY_PORT_STATE, NOTIFY_TIME_SYNC, NOTIFY_PARENT_DATA_SET, + NOTIFY_CMLDS, }; #endif diff --git a/pmc.c b/pmc.c index c29e3b7..e733cf0 100644 --- a/pmc.c +++ b/pmc.c @@ -453,11 +453,13 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) IFMT "duration %hu" IFMT "NOTIFY_PORT_STATE %s" IFMT "NOTIFY_TIME_SYNC %s" - IFMT "NOTIFY_PARENT_DATA_SET %s", + IFMT "NOTIFY_PARENT_DATA_SET %s" + IFMT "NOTIFY_CMLDS %s", sen->duration, event_bitmask_get(sen->bitmask, NOTIFY_PORT_STATE) ? "on" : "off", event_bitmask_get(sen->bitmask, NOTIFY_TIME_SYNC) ? "on" : "off", - event_bitmask_get(sen->bitmask, NOTIFY_PARENT_DATA_SET) ? "on" : "off"); + event_bitmask_get(sen->bitmask, NOTIFY_PARENT_DATA_SET) ? "on" : "off", + event_bitmask_get(sen->bitmask, NOTIFY_CMLDS) ? "on" : "off"); break; case MID_SYNCHRONIZATION_UNCERTAIN_NP: mtd = (struct management_tlv_datum *) mgt->data; diff --git a/pmc_common.c b/pmc_common.c index 1d537f2..a549af5 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -180,6 +180,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) char onoff_port_state[4] = "off"; char onoff_time_status[4] = "off"; char onoff_parent_data_set[4] = "off"; + char onoff_cmlds[4] = "off"; char display_name[11] = {0}; uint64_t jump; uint8_t key; @@ -306,13 +307,15 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) "duration %hu " "NOTIFY_PORT_STATE %3s " "NOTIFY_TIME_SYNC %3s " - "NOTIFY_PARENT_DATA_SET %3s ", + "NOTIFY_PARENT_DATA_SET %3s " + "NOTIFY_CMLDS %3s ", &sen.duration, onoff_port_state, onoff_time_status, - onoff_parent_data_set); - if (cnt != 4) { - fprintf(stderr, "%s SET needs 4 values\n", + onoff_parent_data_set, + onoff_cmlds); + if (cnt != 5) { + fprintf(stderr, "%s SET needs 5 values\n", idtab[index].name); break; } @@ -326,6 +329,9 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) event_bitmask_set(sen.bitmask, NOTIFY_PARENT_DATA_SET, TRUE); } + if (!strcasecmp(onoff_cmlds, "on")) { + event_bitmask_set(sen.bitmask, NOTIFY_CMLDS, TRUE); + } pmc_send_set_action(pmc, code, &sen, sizeof(sen)); break; case MID_SYNCHRONIZATION_UNCERTAIN_NP: diff --git a/port.c b/port.c index aab9d3f..8afe1b2 100644 --- a/port.c +++ b/port.c @@ -2466,6 +2466,8 @@ calc: msg_put(p->peer_delay_req); p->peer_delay_req = NULL; + + port_notify_event(p, NOTIFY_CMLDS); } int process_pdelay_resp(struct port *p, struct ptp_message *m) @@ -3263,6 +3265,9 @@ void port_notify_event(struct port *p, enum notification event) case NOTIFY_PORT_STATE: id = MID_PORT_DATA_SET; break; + case NOTIFY_CMLDS: + id = MID_CMLDS_INFO_NP; + break; default: return; } -- 2.39.2 |