Thread: Re: [Linuxptp-devel] [PATCH v3 6/6] Add example Common Mean Link Delay Service configuration files. (Page 4)
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
From: Andrew Z. <and...@in...> - 2023-12-05 01:44:45
|
I tested a basic 802.1AS type scenario with this v3 patchset on both ends, and it worked! We may have more test results in a few days if my colleague runs a real test suite. The only caveats were: * if I stop a CMLDS client and rerun it, it will receive the CMLDS notifications twice until the old subscription expires. If I restart it again quickly enough it'll receive each notification 3 times. This is because pmc_recv doesn't filter by .targetPortIdentity. It could but it wouldn't be bullet proof anyway because the PMC port's identity is based on the pid, which is not unique, so I'm not sure if it's worth doing. * inhibit_delay_req / logMinPdelayReqInterval / operLogPdelayReqInterval should not be used in the CMLDS client config (which wouldn't be useful anyway) because they'll affect the subscription renewals. * I had two extra changes, one to always calculate the NRR in the CMLDS port, and one to handle an exception specified in 802.1AS-2020 section 11.2.17.1 above NOTE 3 -- this can be added later separately from this CMLDS patchset Best regards configs/802.1as-2020-master-cmlds.cfg | 19 ++++++++++ configs/802.1as-2020-master-domain-0.cfg | 43 ++++++++++++++++++++++ configs/802.1as-2020-slave-cmlds.cfg | 19 ++++++++++ configs/802.1as-2020-slave-domain-0.cfg | 45 ++++++++++++++++++++++++ msg.h | 3 +- port.c | 7 ++-- 6 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 configs/802.1as-2020-master-cmlds.cfg create mode 100644 configs/802.1as-2020-master-domain-0.cfg create mode 100644 configs/802.1as-2020-slave-cmlds.cfg create mode 100644 configs/802.1as-2020-slave-domain-0.cfg diff --git a/configs/802.1as-2020-master-cmlds.cfg b/configs/802.1as-2020-master-cmlds.cfg new file mode 100644 index 0000000..2e09c6d --- /dev/null +++ b/configs/802.1as-2020-master-cmlds.cfg @@ -0,0 +1,19 @@ +# +# Common Mean Link Delay Service (CMLDS) example configuration, +# containing those attributes which differ from the defaults. +# See the file default.cfg for the complete list of available options. +# +[global] +# Set this for CMLDS regardless of actual port roles on this node +clientOnly 1 +free_running 1 +assume_two_step 1 +follow_up_info 1 +asCapable true +network_transport L2 +uds_address /var/run/master-cmlds + +transportSpecific 2 +clockIdentity 000001.0000.800000 + +delay_mechanism P2P diff --git a/configs/802.1as-2020-master-domain-0.cfg b/configs/802.1as-2020-master-domain-0.cfg new file mode 100644 index 0000000..0e69565 --- /dev/null +++ b/configs/802.1as-2020-master-domain-0.cfg @@ -0,0 +1,43 @@ +# +# 802.1AS configuration example for a single domain out of many (or not +# so many) on a multidomain-capable node. Uses a local CMLDS instance, +# see configs/802.1as-2020-master-cmlds.cfg. +# +[global] +gmCapable 1 +priority1 248 +priority2 248 +logAnnounceInterval 0 +logSyncInterval -3 +syncReceiptTimeout 3 +neighborPropDelayThresh 800 +min_neighbor_prop_delay -20000000 +assume_two_step 1 +path_trace_enabled 1 +follow_up_info 1 +asCapable true +network_transport L2 +BMCA noop +# Required to quickly correct Time Jumps in master +step_threshold 1 +inhibit_announce 1 +operLogSyncInterval 0 +operLogPdelayReqInterval 2 +msg_interval_request 1 +servo_offset_threshold 30 +servo_num_offset_values 10 + +# Master only bits +serverOnly 1 +inhibit_announce 1 + +uds_address /var/run/master-domain-0 +cmlds.server_address /var/run/master-cmlds +# FIXME: must set client_address per port +cmlds.client_address /var/run/master-client-0 + +domainNumber 0 +transportSpecific 1 +clockIdentity 000001.0000.000000 + +delay_mechanism COMMON_P2P diff --git a/configs/802.1as-2020-slave-cmlds.cfg b/configs/802.1as-2020-slave-cmlds.cfg new file mode 100644 index 0000000..e78e468 --- /dev/null +++ b/configs/802.1as-2020-slave-cmlds.cfg @@ -0,0 +1,19 @@ +# +# Common Mean Link Delay Service (CMLDS) example configuration, +# containing those attributes which differ from the defaults. +# See the file default.cfg for the complete list of available options. +# +[global] +# Set this for CMLDS regardless of actual port roles on this node +clientOnly 1 +free_running 1 +assume_two_step 1 +follow_up_info 1 +asCapable true +network_transport L2 +uds_address /var/run/slave-cmlds + +transportSpecific 2 +clockIdentity 000002.0000.800000 + +delay_mechanism P2P diff --git a/configs/802.1as-2020-slave-domain-0.cfg b/configs/802.1as-2020-slave-domain-0.cfg new file mode 100644 index 0000000..8656e60 --- /dev/null +++ b/configs/802.1as-2020-slave-domain-0.cfg @@ -0,0 +1,45 @@ +# +# 802.1AS configuration example for a single domain out of many (or not +# so many) on a multidomain-capable node. Uses a local CMLDS instance, +# see configs/802.1as-2020-slave-cmlds.cfg. +# +[global] +gmCapable 1 +priority1 248 +priority2 248 +logAnnounceInterval 0 +logSyncInterval -3 +syncReceiptTimeout 3 +neighborPropDelayThresh 800 +min_neighbor_prop_delay -20000000 +assume_two_step 1 +path_trace_enabled 1 +follow_up_info 1 +asCapable true +network_transport L2 +BMCA noop +# Required to quickly correct Time Jumps in master +step_threshold 1 +inhibit_announce 1 +operLogSyncInterval 0 +operLogPdelayReqInterval 2 +msg_interval_request 1 +servo_offset_threshold 30 +servo_num_offset_values 10 + +# Slave only bits +clientOnly 1 +ignore_source_id 1 +servo_offset_threshold 30 +servo_num_offset_values 10 + +uds_address /var/run/slave-domain-0 +cmlds.server_address /var/run/slave-cmlds +# FIXME: must set client_address per port +cmlds.client_address /var/run/slave-client-0 + +domainNumber 0 +transportSpecific 1 +clockIdentity 000002.0000.000000 + +delay_mechanism COMMON_P2P diff --git a/msg.h b/msg.h index 9c80f45..d4294ae 100644 --- a/msg.h +++ b/msg.h @@ -38,7 +38,8 @@ #define MAJOR_VERSION_MASK 0x0f /* Values for the transportSpecific field */ -#define TS_IEEE_8021AS (1<<4) +#define TS_IEEE_8021AS (1<<4) +#define TS_CMLDS (2<<4) /* Values for the messageType field */ #define SYNC 0x0 diff --git a/port.c b/port.c index e2ebaeb..c5c31d8 100644 --- a/port.c +++ b/port.c @@ -2424,9 +2424,6 @@ 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; @@ -2445,7 +2442,7 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) p->peer_portid_valid = 0; port_capable(p); } - } else { + } else if (p->delayMechanism != DM_COMMON_P2P) { p->peer_portid_valid = 1; p->peer_portid = m->header.sourcePortIdentity; pr_debug("%s: peer port id set to %s", p->log_name, @@ -2597,7 +2594,7 @@ calc: t3c = tmv_add(t3, tmv_add(c1, c2)); } - if (p->follow_up_info) + if (p->follow_up_info || p->transportSpecific == TS_CMLDS) /* FIXME */ port_nrate_calculate(p, t3c, t4); tsproc_set_clock_rate_ratio(p->tsproc, p->nrate.ratio * -- 2.42.0 On Mon, 4 Dec 2023 at 22:51, Andrew Zaborowski <and...@in...> wrote: > > On Sun, 3 Dec 2023 at 00:39, Richard Cochran <ric...@gm...> wrote: > > +# Common Mean Link Delay Service (CMLDS) example configuration for a > > +# CMLDS Link Port, containing those attributes which differ from the > > While there's only one Link Port here I wouldn't mention this because > the CMLDS config basically has to cover all of the ports. > > > +# 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 > > I assume ignore_transport_specific can be dropped in this version. > > > +transportSpecific 2 > > +uds_address /var/run/cmlds_server > > + > > +[eth1] > > +delay_mechanism P2P > > This line has to be the same for all interfaces in use by the CMLDS so > I'd move this to [global] to avoid repetition. > > This way you basically have nothing port-specific to configure and can > pass the interface names on the command line instead of listing here. > On the client side cmlds.client_address will not allow this because I > believe the source address has to be different for each port's socket. > I thought (even before this came up) it would be nice for uds_address > to default to something that includes the domainNumber, and now for > cmlds.client_address to include the domainNumber and port number. > > I'm going to try test this patchset in an 802.1AS configuration and report back. > > Best regards |
From: Richard C. <ric...@gm...> - 2023-12-05 13:13:44
|
On Tue, Dec 05, 2023 at 02:44:18AM +0100, Andrew Zaborowski wrote: > * if I stop a CMLDS client and rerun it, it will receive the CMLDS > notifications twice until the old subscription expires. If I restart > it again quickly enough it'll receive each notification 3 times. This > is because pmc_recv doesn't filter by .targetPortIdentity. It could > but it wouldn't be bullet proof anyway because the PMC port's identity > is based on the pid, which is not unique, so I'm not sure if it's > worth doing. Yeah, super annoying. Maybe the cure is to first cancel push notifications unconditionally? > * inhibit_delay_req / logMinPdelayReqInterval / > operLogPdelayReqInterval should not be used in the CMLDS client config > (which wouldn't be useful anyway) because they'll affect the > subscription renewals. Right, a check should be added to avoid this combination. > * I had two extra changes, one to always calculate the NRR in the > CMLDS port, Can't this be taken from the Link Port? Thanks, Richard |
From: Miroslav L. <mli...@re...> - 2023-12-05 07:57:58
|
On Mon, Dec 04, 2023 at 11:25:00PM +0100, Andrew Zaborowski wrote: > On Sun, 3 Dec 2023 at 00:39, Richard Cochran <ric...@gm...> wrote: > > @@ -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", > > Doing cnt != 4 && cnt != 5 should just work as sscanf() should stop > parsing when it doesn't find NOTIFY_CMLDS and leave onoff_cmlds as > "off". Obviously this won't scale as more events are added but it'd > keep syntax backwards-compatible for scripts. Good idea. The PARENT_DATA_SET notification is new too (added after 4.1) and I guess there is no reason to require even the original two notifications, so change that to "cnt < 1" with "%s SET needs at least 1 value", requiring only the duration, which would effectively reset all existing notifications? -- Miroslav Lichvar |
From: Richard C. <ric...@gm...> - 2023-12-05 13:06:01
|
On Tue, Dec 05, 2023 at 08:57:36AM +0100, Miroslav Lichvar wrote: > On Mon, Dec 04, 2023 at 11:25:00PM +0100, Andrew Zaborowski wrote: > > Doing cnt != 4 && cnt != 5 should just work as sscanf() should stop > > parsing when it doesn't find NOTIFY_CMLDS and leave onoff_cmlds as > > "off". Obviously this won't scale as more events are added but it'd > > keep syntax backwards-compatible for scripts. > > Good idea. The PARENT_DATA_SET notification is new too (added after > 4.1) and I guess there is no reason to require even the original two > notifications, so change that to "cnt < 1" with "%s SET needs at least > 1 value", requiring only the duration, which would effectively reset > all existing notifications? Makes sense to me. Thanks, Richard |
From: Erez <ere...@gm...> - 2023-12-06 14:43:11
|
On Tue, 5 Dec 2023 at 08:59, Miroslav Lichvar <mli...@re...> wrote: > On Mon, Dec 04, 2023 at 11:25:00PM +0100, Andrew Zaborowski wrote: > > On Sun, 3 Dec 2023 at 00:39, Richard Cochran <ric...@gm...> > wrote: > > > @@ -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", > > > > Doing cnt != 4 && cnt != 5 should just work as sscanf() should stop > > parsing when it doesn't find NOTIFY_CMLDS and leave onoff_cmlds as > > "off". Obviously this won't scale as more events are added but it'd > > keep syntax backwards-compatible for scripts. > > Good idea. The PARENT_DATA_SET notification is new too (added after > 4.1) and I guess there is no reason to require even the original two > notifications, so change that to "cnt < 1" with "%s SET needs at least > 1 value", requiring only the duration, which would effectively reset > all existing notifications? > + > > -- > Miroslav Lichvar > > > > _______________________________________________ > Linuxptp-devel mailing list > Lin...@li... > https://lists.sourceforge.net/lists/listinfo/linuxptp-devel > |
From: Andrew Z. <and...@in...> - 2023-12-06 14:43:41
|
On Tue, 5 Dec 2023 at 02:44, Andrew Zaborowski <and...@in...> wrote: > * if I stop a CMLDS client and rerun it, it will receive the CMLDS > notifications twice until the old subscription expires. If I restart > it again quickly enough it'll receive each notification 3 times. This > is because pmc_recv doesn't filter by .targetPortIdentity. It could > but it wouldn't be bullet proof anyway because the PMC port's identity > is based on the pid, which is not unique, so I'm not sure if it's > worth doing. On a second thought, if the pid ends up being reused, when the client re-subscribes to the CMLDS notifications, the server will update the existing subscription so duplicate notifications wouldn't be sent. So at least this specific use case would be covered. Additionally we found we needed to exit early from port_capable() so as not to overwrite the p->asCapable value set by process_cmlds(). Again feel free to include it or leave it for us to send separately. @@ -700,6 +700,11 @@ int port_capable(struct port *p) goto capable; } + if (p->delayMechanism == DM_COMMON_P2P) { + /* asCapable is calculated by the CMLDS. */ + return p->asCapable != NOT_CAPABLE ? 1 : 0; + } + if (tmv_to_nanoseconds(p->peer_delay) > p->neighborPropDelayThresh) { if (p->asCapable) pr_debug("%s: peer_delay (%" PRId64 ") > neighborPropDelayThresh " Best regards |
From: Richard C. <ric...@gm...> - 2023-12-06 15:15:24
|
On Wed, Dec 06, 2023 at 03:43:15PM +0100, Andrew Zaborowski wrote: > Again feel free to include it or leave it for us to send separately. I prefer to roll your fixes into this series. Thanks, Richard |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:19
|
This change adds cofig file parameters to configure CMLDS support and access in PTP instances. 'cmlds_clockIdentity': This global setting assigns a CMLDS clockIdentity to be used by a PTP instance on a PTP node that exposes CMLDS over one or more links. 'run_cmlds': This per-port setting (0/1) declares that a port will perform the role of a CMLDS Link Port (IEEE 1588, clause 16.6.1) and execute CMLDS Pdelay transactions to conduct link delay measurements and further convey those measurements to other PTP instances on its node via MID_CMLDS_INFO_NP. Said another way, this port will expose CMLDS. 'cmlds_portNumber': This per-port setting in a PTP instance specifies the CMLDS Link Port portNumber. Note that this is distinct from and independent of the portNumber associated with the PTP Port. In a PTP instance that exposes the CMLDS via a CMLDS Link Port, this setting assigns the CMLDS Link Port portNumber. In PTP instances that consume the CMLDS (using the COMMON_P2P delay mechanism), this setting is used to target MID_CMLDS_INFO_NP queries to a specific CMLDS Link Port. 'cmlds_uds_address': This per-port setting in ptp4l instances specifies the 'uds_address' of a ptp4l instance on the PTP node that exposes the CMLDS. A port which employs the COMMON_P2P delay mechanism would communicate with the CMLDS over the UDS. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> --- config.c | 4 ++++ port.c | 28 ++++++++++++++++++++++++++++ port.h | 8 ++++++++ port_private.h | 4 ++++ 4 files changed, 44 insertions(+) diff --git a/config.c b/config.c index cb4421f572c7..fdbcf3932485 100644 --- a/config.c +++ b/config.c @@ -245,6 +245,10 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("clockAccuracy", 0xfe, 0, UINT8_MAX), GLOB_ITEM_INT("clockClass", 248, 0, UINT8_MAX), GLOB_ITEM_STR("clockIdentity", "000000.0000.000000"), + GLOB_ITEM_STR("cmlds_clockIdentity", "000000.0000.000000"), + PORT_ITEM_INT("run_cmlds", 0, 0, 1), + PORT_ITEM_INT("cmlds_portNumber", 0, 0, UINT16_MAX), + PORT_ITEM_STR("cmlds_uds_address", "/var/run/ptp4l"), 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), diff --git a/port.c b/port.c index d61e9b67e422..64c31aec5823 100644 --- a/port.c +++ b/port.c @@ -3299,6 +3299,8 @@ struct port *port_open(const char *phc_device, enum clock_type type = clock_type(clock); struct config *cfg = clock_config(clock); struct port *p = malloc(sizeof(*p)); + char *cmlds_uds_address; + const char *cmlds_cid; int i; if (!p) { @@ -3479,6 +3481,27 @@ struct port *port_open(const char *phc_device, goto err_tsproc; } } + + /* Store CMLDS parameters */ + p->cmlds_enabled = config_get_int(cfg, p->name, "run_cmlds"); + + p->cmlds_portIdentity.portNumber = config_get_int(cfg, p->name, "cmlds_portNumber"); + + cmlds_uds_address = config_get_string(cfg, p->name, "cmlds_uds_address"); + memset(&p->cmlds_uds_address, 0, sizeof(struct address)); + p->cmlds_uds_address.sun.sun_family = AF_LOCAL; + strncpy(p->cmlds_uds_address.sun.sun_path, cmlds_uds_address, + sizeof(p->cmlds_uds_address.sun.sun_path) - 1); + p->cmlds_uds_address.len = sizeof(struct sockaddr_un); + + cmlds_cid = config_get_string(cfg, NULL, "cmlds_clockIdentity"); + if (strcmp(cmlds_cid, "000000.0000.000000") != 0) { + if (str2cid(cmlds_cid, &p->cmlds_portIdentity.clockIdentity)) { + pr_err("failed to parse CMLDS clock identity"); + return NULL; + } + } + return p; err_tsproc: @@ -3506,6 +3529,11 @@ enum delay_mechanism port_delay_mechanism(struct port *port) return port->delayMechanism; } +int port_cmlds_enabled(struct port *port) +{ + return port->cmlds_enabled; +} + int port_state_update(struct port *p, enum fsm_event event, int mdiff) { enum port_state next = p->state_machine(p->state, event, mdiff); diff --git a/port.h b/port.h index 57c8c2ffeb9e..96e0cf8aa970 100644 --- a/port.h +++ b/port.h @@ -364,4 +364,12 @@ void tc_cleanup(void); */ void port_update_unicast_state(struct port *p); +/** + * Query if a port exposes CMLDS. + * + * @param port A port instance. + * @return One if CMLDS is exposed, zero otherwise. + */ +int port_cmlds_enabled(struct port *port); + #endif diff --git a/port_private.h b/port_private.h index 3b02d2fe45c4..7d36a8200896 100644 --- a/port_private.h +++ b/port_private.h @@ -164,6 +164,10 @@ struct port { /* slave event monitoring */ struct monitor *slave_event_monitor; bool unicast_state_dirty; + /* CMLDS parameters */ + int cmlds_enabled; + struct PortIdentity cmlds_portIdentity; + struct address cmlds_uds_address; }; #define portnum(p) (p->portIdentity.portNumber) -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:21
|
For ports that are configured with "run_cmlds=1", i.e. CMLDS Link Ports, this change updates port_pdelay_request(), process_pdelay_req() and port_peer_delay() to utilize the CMLDS sdoid/domainNumber/portId along code paths where necessary. It also ensures that neighborRateRatio is calculated on CMLDS Link Ports and is available to users of MID_CMLDS_INFO_NP. Further, process_pdelay_request() enforces two-step Pdelay when responding as CMLDS. These changes are in accordance to the requirements outlined in IEEE 1588, clause 16.6.3. In addition, CMLDS Link Ports respond with instance-specific peer delay messages to PdelayReqs with an sdoid/domainNumber that match their ptp4l instance configuration. This aims to address the requirement outlined above NOTE 3 in IEEE 802.1AS-2020, clause 11.2.17.1. Note that all these changes take effect only in ports with a "run_cmlds=1" setting. Default behavior applies otherwise. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> --- port.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/port.c b/port.c index e31e697310c2..e632316aa492 100644 --- a/port.c +++ b/port.c @@ -47,6 +47,8 @@ #define ALLOWED_LOST_RESPONSES 3 #define ANNOUNCE_SPAN 1 +#define CMLDS_TRANSPORTSPECIFIC 0x20 +#define CMLDS_DOMAINNUMBER 0 enum syfu_event { SYNC_MISMATCH, @@ -1534,6 +1536,9 @@ static void port_syfufsm(struct port *p, enum syfu_event event, static int port_pdelay_request(struct port *p) { + struct PortIdentity sourcePortIdentity = p->portIdentity; + UInteger8 domainNumber = clock_domain_number(p->clock); + UInteger8 transportSpecific = p->transportSpecific; struct ptp_message *msg; int err; @@ -1548,14 +1553,23 @@ static int port_pdelay_request(struct port *p) return -1; } + /* If this port exposes CMLDS, advertise the CMLDS sdoid, + * domainNumber and portId + */ + if (port_cmlds_enabled(p)) { + transportSpecific = CMLDS_TRANSPORTSPECIFIC; + domainNumber = CMLDS_DOMAINNUMBER; + sourcePortIdentity = p->cmlds_portIdentity; + } + msg->hwts.type = p->timestamping; - msg->header.tsmt = PDELAY_REQ | p->transportSpecific; + msg->header.tsmt = PDELAY_REQ | transportSpecific; msg->header.ver = PTP_VERSION; msg->header.messageLength = sizeof(struct pdelay_req_msg); - msg->header.domainNumber = clock_domain_number(p->clock); + msg->header.domainNumber = domainNumber; msg->header.correction = -p->asymmetry; - msg->header.sourcePortIdentity = p->portIdentity; + msg->header.sourcePortIdentity = sourcePortIdentity; msg->header.sequenceId = p->seqnum.delayreq++; msg->header.control = CTL_OTHER; msg->header.logMessageInterval = port_is_ieee8021as(p) ? @@ -2300,7 +2314,16 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) port_set_delay_tmo(p); } if (p->peer_portid_valid) { - if (!pid_eq(&p->peer_portid, &m->header.sourcePortIdentity)) { + /* The first subexpression bypasses port ID matching + * and the ensuing block in the specific case when + * a CMLDS Link Port receives a PdelayReq with the PTP + * instance's sdoid/domainNumber in order to + * issue PDELAY_RESP/RESP_FOLLOW_UP messages + * back to the requesting port. + */ + if ((!port_cmlds_enabled(p) || + msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) && + !pid_eq(&p->peer_portid, &m->header.sourcePortIdentity)) { pr_err("%s: received pdelay_req msg with " "unexpected peer port id %s", p->log_name, @@ -2337,11 +2360,22 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) rsp->header.control = CTL_OTHER; rsp->header.logMessageInterval = 0x7f; + /* If this is a CMLDS PdelayReq, then respond with the CMLDS + * sdoid/domainNumber/port id. + */ + if (msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) { + rsp->header.tsmt = PDELAY_RESP | CMLDS_TRANSPORTSPECIFIC; + rsp->header.domainNumber = CMLDS_DOMAINNUMBER; + rsp->header.sourcePortIdentity = p->cmlds_portIdentity; + } + /* * NB - We do not have any fraction nanoseconds for the correction * fields, neither in the response or the follow up. */ - if (p->timestamping == TS_P2P1STEP) { + if (p->timestamping == TS_P2P1STEP && + /* Enforce two-step Pdelay when responding as CMLDS */ + msg_transport_specific(m) != CMLDS_TRANSPORTSPECIFIC) { rsp->header.correction = m->header.correction; rsp->header.correction += p->tx_timestamp_offset; rsp->header.correction += p->rx_timestamp_offset; @@ -2390,6 +2424,15 @@ int process_pdelay_req(struct port *p, struct ptp_message *m) fup->pdelay_resp_fup.responseOriginTimestamp = tmv_to_Timestamp(rsp->hwts.ts); + /* If this is a CMLDS PdelayReq, then respond with the CMLDS + * sdoid/domainNumber/port id. + */ + if (msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) { + fup->header.tsmt = PDELAY_RESP_FOLLOW_UP | CMLDS_TRANSPORTSPECIFIC; + fup->header.domainNumber = CMLDS_DOMAINNUMBER; + fup->header.sourcePortIdentity = p->cmlds_portIdentity; + } + if (msg_unicast(m)) { fup->address = m->address; fup->header.flagField[0] |= UNICAST; @@ -2407,17 +2450,25 @@ out: static void port_peer_delay(struct port *p) { + struct PortIdentity portIdentity = p->portIdentity; tmv_t c1, c2, t1, t2, t3, t3c, t4; struct ptp_message *req = p->peer_delay_req; struct ptp_message *rsp = p->peer_delay_resp; struct ptp_message *fup = p->peer_delay_fup; + /* Following a CMLDS PDELAY transaction, use the CMLDS port id + * for comparisons below with the 'requestingPortIdentity'. + */ + if (msg_transport_specific(req) == CMLDS_TRANSPORTSPECIFIC) { + portIdentity = p->cmlds_portIdentity; + } + /* Check for response, validate port and sequence number. */ if (!rsp) return; - if (!pid_eq(&rsp->pdelay_resp.requestingPortIdentity, &p->portIdentity)) + if (!pid_eq(&rsp->pdelay_resp.requestingPortIdentity, &portIdentity)) return; if (rsp->header.sequenceId != ntohs(req->header.sequenceId)) @@ -2440,7 +2491,7 @@ static void port_peer_delay(struct port *p) if (!fup) return; - if (!pid_eq(&fup->pdelay_resp_fup.requestingPortIdentity, &p->portIdentity)) + if (!pid_eq(&fup->pdelay_resp_fup.requestingPortIdentity, &portIdentity)) return; if (fup->header.sequenceId != rsp->header.sequenceId) @@ -2456,7 +2507,8 @@ static void port_peer_delay(struct port *p) calc: t3c = tmv_add(t3, tmv_add(c1, c2)); - if (p->follow_up_info) + /* Always calculate the NRR when the port exposes CMLDS */ + if (p->follow_up_info || port_cmlds_enabled(p)) port_nrate_calculate(p, t3c, t4); tsproc_set_clock_rate_ratio(p->tsproc, p->nrate.ratio * -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:21
|
port_cmlds_ignore() assesses incoming messages per the following policy: * All messages that bear the CMLDS sdoid/domainNumber are directed to a CMLDS Link Port context and processed by this function. All other messages go through the regular flow (i.e. port_ignore() and beyond) based on the the ptp4l instance configuration. * PDELAY_REQ, PDELAY_RESP, PDELAY_RESP_FOLLOW_UP and management messages for MID_CMLDS_INFO_NP are the only expected message types at a CMLDS Link Port. All other received messages at a CMLDS Link Port (i.e., bearing the CMLDS sdoid/domainNumber) are ignored. Signed-off-by: Kishen Maloor <kis...@in...> --- port.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/port.c b/port.c index e632316aa492..9040453fb2dc 100644 --- a/port.c +++ b/port.c @@ -772,9 +772,62 @@ int port_clr_tmo(int fd) return timerfd_settime(fd, 0, &tmo, NULL); } +static int port_cmlds_ignore(struct port *p, struct ptp_message *m) +{ + struct management_tlv *mgt = (struct management_tlv *) + m->management.suffix; + + /* Messages that do not bear the CMLDS sdoid/domainNumber + * are unrelated to CMLDS. + */ + if (msg_transport_specific(m) != CMLDS_TRANSPORTSPECIFIC || + m->header.domainNumber != CMLDS_DOMAINNUMBER) { + /* MID_CMLDS_INFO_NP may only be accessed using the CMLDS + * sdoid/domainNumber. + */ + if (msg_type(m) == MANAGEMENT && + mgt->id == MID_CMLDS_INFO_NP) { + return -1; + } + return 0; + } + + /* CMLDS messages */ + if (msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) { + /* Only MID_CMLDS_INFO_NP may be accessed using the CMLDS + * sdoid/domainNumber. Ignore anything else. + */ + if (msg_type(m) == MANAGEMENT && + mgt->id != MID_CMLDS_INFO_NP) + return -1; + + /* Ignore CMLDS messages received at a port that does + * not expose CMLDS. + * Note: Messages across ptp4l instacnes to/from + * MID_CMLDS_INFO_NP currently propagate over the UDS. + */ + if (!port_is_uds(p) && !port_cmlds_enabled(p)) { + return -1; + } + + /* Only the following message types are permitted to/from + * the CMLDS. Ignore anything else. + */ + if (msg_type(m) != MANAGEMENT && + msg_type(m) != PDELAY_REQ && + msg_type(m) != PDELAY_RESP && + msg_type(m) != PDELAY_RESP_FOLLOW_UP) { + return -1; + } + } + /* This is a permitted CMLDS PDELAY or MANAGEMENT message */ + return 1; +} + static int port_ignore(struct port *p, struct ptp_message *m) { struct ClockIdentity c1, c2; + int cmlds = 0; if (port_is_uds(p) && msg_type(m) != MANAGEMENT) { return 1; @@ -785,14 +838,24 @@ static int port_ignore(struct port *p, struct ptp_message *m) if (path_trace_ignore(p, m)) { return 1; } - if (p->match_transport_specific && + + /* Ignore non-permitted CMLDS messages */ + if ((cmlds = port_cmlds_ignore(p, m)) == -1) + return 1; + + /* Suppress transportSpecific/domainNumber matching below for + * mesaages to/from the CMLDS as the requisite checks have + * already been performed by port_cmlds_ignore() + */ + if (!cmlds && p->match_transport_specific && msg_transport_specific(m) != p->transportSpecific) { return 1; } if (pid_eq(&m->header.sourcePortIdentity, &p->portIdentity)) { return 1; } - if (m->header.domainNumber != clock_domain_number(p->clock)) { + if (!cmlds && + m->header.domainNumber != clock_domain_number(p->clock)) { return 1; } -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:23
|
From: Andrew Zaborowski <and...@in...> This change implements the COMMON_P2P DM by issuing a request to the CMLDS for CommonMeanLinkDelayInformation upon expiry of the delay timer and handles the response to assimilate the received meanPathDelay and NRR. Signed-off-by: Andrew Zaborowski <and...@in...> --- pmc.c | 7 +++++-- port.c | 57 +++++++++++++++++++++++++++++++++++++++++++++----- port_private.h | 2 ++ tlv.c | 4 ++++ tlv.h | 2 ++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/pmc.c b/pmc.c index fbf312cb6c53..cac06fb5b41d 100644 --- a/pmc.c +++ b/pmc.c @@ -657,9 +657,12 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) fprintf(fp, "CMLDS INFO " IFMT "serviceMeasurementValid %i" IFMT "meanLinkDelay %" PRId64 - IFMT "scaledNeighborRateRatio %" PRId32, + IFMT "scaledNeighborRateRatio %" PRId32 + IFMT "egress_ts %" PRId64 + IFMT "rx_ts %" PRId64, cmlds->serviceMeasurementValid, cmlds->meanLinkDelay, - cmlds->scaledNeighborRateRatio); + cmlds->scaledNeighborRateRatio, + cmlds->egress_ts, cmlds->rx_ts); break; } out: diff --git a/port.c b/port.c index 14d2b71d0d73..072ddffd9049 100644 --- a/port.c +++ b/port.c @@ -1198,13 +1198,23 @@ static int port_management_fill_response(struct port *target, break; case MID_CMLDS_INFO_NP: cmlds = (struct cmlds_info_np *)tlv->data; + /* IEEE1588-2019 16.6.3.2 h) 1) && nrate.ratio_valid because + * we have no extra field to convey that separately. + */ cmlds->serviceMeasurementValid = - /* IEEE1588-2019 16.6.3.2 h) 1) */ target->peer_portid_valid && !target->pdr_missing && - !target->multiple_pdr_detected; + !target->multiple_pdr_detected && + target->nrate.ratio_valid; cmlds->meanLinkDelay = target->peerMeanPathDelay; cmlds->scaledNeighborRateRatio = (Integer32) (target->nrate.ratio * POW2_41 - POW2_41); + /* 16.6.3.2: "Upon receipt of a request for information, the + * Common Mean Link Delay Service may in addition return the + * raw measurement data gathered by the service for use in + * estimating the <meanLinkDelay> and <neighborRateRatio>." + */ + cmlds->egress_ts = tmv_to_nanoseconds(target->peer_delay_t1); + cmlds->rx_ts = tmv_to_nanoseconds(target->peer_delay_t2); datalen = sizeof(*cmlds); /* Reflect the CMLDS sdoid/domainNumber/port id in * MID_CMLDS_INFO_NP responses @@ -1676,6 +1686,10 @@ int port_delay_request(struct port *p) { struct ptp_message *msg; + if (p->delayMechanism == DM_COMMON_P2P) { + return port_request_cmlds_info(p); + } + /* Time to send a new request, forget current pdelay resp and fup */ if (p->peer_delay_resp) { msg_put(p->peer_delay_resp); @@ -2594,6 +2608,9 @@ calc: p->nrate.ratio); } + p->peer_delay_t1 = t1; + p->peer_delay_t2 = t2; + msg_put(p->peer_delay_req); p->peer_delay_req = NULL; } @@ -3757,11 +3774,41 @@ int process_cmlds_response(struct port *p, pr_debug("CMLDS INFO\n" "\tserviceMeasurementValid %i\n" "\tmeanLinkDelay %" PRId64 "\n" - "\tscaledNeighborRateRatio %" PRId32, + "\tscaledNeighborRateRatio %" PRId32 "\n" + "\tegress_ts %" PRId64 "\n" + "\trx_ts %" PRId64, cmlds->serviceMeasurementValid, cmlds->meanLinkDelay, - cmlds->scaledNeighborRateRatio); + cmlds->scaledNeighborRateRatio, cmlds->egress_ts, + cmlds->rx_ts); - /* COMMON_P2P DM implementation goes here */ + if (!cmlds->serviceMeasurementValid) { + p->pdr_missing++; + p->peer_portid_valid = false; + p->nrate.ratio_valid = false; + return 0; + } + + /* Note: the CMLDS may be using a different local clock. Do not track + * the CMLDS-clock-to-local-clock rate ratio at this time as the + * difference should be small, or nul with vclocks. + */ + p->pdr_missing = 0; + p->peerMeanPathDelay = cmlds->meanLinkDelay; + p->peer_delay = nanoseconds_to_tmv(p->peerMeanPathDelay >> 16); + p->nrate.ratio = 1.0 + (double) cmlds->scaledNeighborRateRatio / POW2_41; + + /* Note: this determines the value of port_capable(p), however + * p->peer_portid itself is not actually used outside of the Pdelay FSM. + */ + p->peer_portid_valid = true; + p->nrate.ratio_valid = true; + + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { + clock_peer_delay(p->clock, p->peer_delay, + nanoseconds_to_tmv(cmlds->egress_ts), + nanoseconds_to_tmv(cmlds->rx_ts), + p->nrate.ratio); + } return 0; } diff --git a/port_private.h b/port_private.h index 10ce05f3a895..664d14944919 100644 --- a/port_private.h +++ b/port_private.h @@ -99,6 +99,8 @@ struct port { unsigned int pdr_missing; unsigned int multiple_seq_pdr_count; unsigned int multiple_pdr_detected; + tmv_t peer_delay_t1; + tmv_t peer_delay_t2; enum port_state (*state_machine)(enum port_state state, enum fsm_event event, int mdiff); int bmca; diff --git a/tlv.c b/tlv.c index aefbcb9f744e..8b97d2cfc9f5 100644 --- a/tlv.c +++ b/tlv.c @@ -497,6 +497,8 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, cmlds = (struct cmlds_info_np *)m->data; net2host64_unaligned(&cmlds->meanLinkDelay); NTOHL(cmlds->scaledNeighborRateRatio); + net2host64_unaligned(&cmlds->egress_ts); + net2host64_unaligned(&cmlds->rx_ts); break; } if (extra_len) { @@ -685,6 +687,8 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) cmlds = (struct cmlds_info_np *)m->data; host2net64_unaligned(&cmlds->meanLinkDelay); HTONL(cmlds->scaledNeighborRateRatio); + host2net64_unaligned(&cmlds->egress_ts); + host2net64_unaligned(&cmlds->rx_ts); break; } } diff --git a/tlv.h b/tlv.h index 73b6078e2efd..6446fc068488 100644 --- a/tlv.h +++ b/tlv.h @@ -480,6 +480,8 @@ struct cmlds_info_np { Integer8 serviceMeasurementValid; TimeInterval meanLinkDelay; Integer32 scaledNeighborRateRatio; + Integer64 egress_ts; + Integer64 rx_ts; } PACKED; /** -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:18
|
This change introduces 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. Also updated 'pmc' to support the new MID, MID_CMLDS_INFO_NP. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> --- clock.c | 1 - msg.h | 2 ++ pmc.c | 10 ++++++++++ pmc_common.c | 1 + port.c | 12 ++++++++++++ tlv.c | 14 ++++++++++++++ tlv.h | 9 +++++++++ 7 files changed, 48 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 75d7c4008977..85f2a04867e5 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/msg.h b/msg.h index b7423eec8778..0feb6c4b18fa 100644 --- a/msg.h +++ b/msg.h @@ -69,6 +69,8 @@ #define SIGNAL_NO_CHANGE -128 #define SIGNAL_SET_INITIAL 126 +#define POW2_41 ((double)(1ULL << 41)) + enum timestamp_type { TS_SOFTWARE, TS_HARDWARE, diff --git a/pmc.c b/pmc.c index 00e691f0c244..fbf312cb6c53 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; @@ -651,6 +652,15 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) fprintf(fp, "LOG_MIN_PDELAY_REQ_INTERVAL " IFMT "logMinPdelayReqInterval %hhd", mtd->val); break; + case MID_CMLDS_INFO_NP: + cmlds = (struct cmlds_info_np *) mgt->data; + fprintf(fp, "CMLDS INFO " + IFMT "serviceMeasurementValid %i" + IFMT "meanLinkDelay %" PRId64 + IFMT "scaledNeighborRateRatio %" PRId32, + cmlds->serviceMeasurementValid, cmlds->meanLinkDelay, + cmlds->scaledNeighborRateRatio); + break; } out: fprintf(fp, "\n"); diff --git a/pmc_common.c b/pmc_common.c index a03f191e8dc6..50d9db46aa92 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 3453716f6020..d61e9b67e422 100644 --- a/port.c +++ b/port.c @@ -887,6 +887,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; @@ -1129,6 +1130,17 @@ 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->serviceMeasurementValid = + /* IEEE1588-2019 16.6.3.2 h) 1) */ + target->peer_portid_valid && !target->pdr_missing && + !target->multiple_pdr_detected; + 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/tlv.c b/tlv.c index 79400126cbc4..aefbcb9f744e 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; @@ -490,6 +491,13 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, if (data_len != 0) goto bad_length; 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; } if (extra_len) { if (extra_len % 2) @@ -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 8b51ffd88816..73b6078e2efd 100644 --- a/tlv.h +++ b/tlv.h @@ -130,6 +130,9 @@ enum management_action { #define MID_PORT_HWCLOCK_NP 0xC009 #define MID_POWER_PROFILE_SETTINGS_NP 0xC00A +/* CMLDS management ID values */ +#define MID_CMLDS_INFO_NP 0xC00B + /* Management error ID values */ #define MID_RESPONSE_TOO_BIG 0x0001 #define MID_NO_SUCH_ID 0x0002 @@ -473,6 +476,12 @@ struct msg_interface_rate_tlv { UInteger16 numberOfBitsAfterTimestamp; } PACKED; +struct cmlds_info_np { + Integer8 serviceMeasurementValid; + TimeInterval meanLinkDelay; + Integer32 scaledNeighborRateRatio; +} PACKED; + /** * Allocates a new tlv_extra structure. * @return Pointer to a new structure on success or NULL otherwise. -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:19
|
This change adds COMMON_P2P (IEEE 802.1AS-2020, clause 14.8.5) to the enumeration of delay mechanisms and incorporates it into existing code paths pertaining to DM_P2P to (where appropriate) maintain parity with DM_P2P. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> --- config.c | 1 + dm.h | 3 +++ port.c | 10 ++++++---- unicast_client.c | 10 +++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/config.c b/config.c index fdbcf3932485..ea82ebb44fbf 100644 --- a/config.c +++ b/config.c @@ -173,6 +173,7 @@ static struct config_enum delay_mech_enu[] = { { "Auto", DM_AUTO }, { "E2E", DM_E2E }, { "P2P", DM_P2P }, + { "COMMON_P2P", DM_COMMON_P2P }, { "NONE", DM_NO_MECHANISM }, { NULL, 0 }, }; diff --git a/dm.h b/dm.h index 47bd8474ca0d..80d1ce551166 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/port.c b/port.c index 64c31aec5823..e31e697310c2 100644 --- a/port.c +++ b/port.c @@ -967,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); @@ -1281,7 +1282,7 @@ int port_set_delay_tmo(struct port *p) return 0; } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || p->delayMechanism == DM_COMMON_P2P) { return set_tmo_log(p->fda.fd[FD_DELAY_TIMER], 1, p->logPdelayReqInterval); } else { @@ -2123,7 +2124,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; } @@ -2754,7 +2755,7 @@ static void bc_dispatch(struct port *p, enum fsm_event event, int mdiff) return; } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || p->delayMechanism == DM_COMMON_P2P) { port_p2p_transition(p, p->state); } else { port_e2e_transition(p, p->state); @@ -2892,6 +2893,7 @@ static enum fsm_event bc_event(struct port *p, int fd_index) delay_req_prune(p); if (clock_slave_only(p->clock) && p->delayMechanism != DM_P2P && + p->delayMechanism != DM_COMMON_P2P && port_renew_transport(p)) { return EV_FAULT_DETECTED; } diff --git a/unicast_client.c b/unicast_client.c index 0843554e355a..9053acc0b599 100644 --- a/unicast_client.c +++ b/unicast_client.c @@ -202,6 +202,7 @@ static int unicast_client_renew(struct port *p, goto out; } if (p->delayMechanism != DM_P2P && + p->delayMechanism != DM_COMMON_P2P && p->delayMechanism != DM_NO_MECHANISM) { err = attach_request(msg, p->logMinDelayReqInterval, DELAY_RESP, @@ -256,6 +257,7 @@ static int unicast_client_sydy(struct port *p, goto out; } if (p->delayMechanism != DM_P2P && + p->delayMechanism != DM_COMMON_P2P && p->delayMechanism != DM_NO_MECHANISM) { err = attach_request(msg, p->logMinDelayReqInterval, DELAY_RESP, p->unicast_req_duration); @@ -404,7 +406,8 @@ int unicast_client_initialize(struct port *p) pr_warning("%s: unicast master transport mismatch", p->log_name); } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || + p->delayMechanism == DM_COMMON_P2P) { master->sydymsk = P2P_SYDY_MASK; } else if (p->delayMechanism == DM_NO_MECHANISM) { master->sydymsk = E2E_SY_MASK; @@ -463,7 +466,7 @@ void unicast_client_grant(struct port *p, struct ptp_message *m, pr_debug("%s: unicast %s granted for %u sec", p->log_name, msg_type_string(mtype), g->durationField); - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || p->delayMechanism == DM_COMMON_P2P) { switch (mtype) { case DELAY_RESP: return; @@ -579,7 +582,8 @@ int unicast_client_timer(struct port *p) err = unicast_client_renew(p, master); break; } - if (p->delayMechanism == DM_P2P) { + if (p->delayMechanism == DM_P2P || + p->delayMechanism == DM_COMMON_P2P) { unicast_client_peer_renew(p); } } -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:23
|
This change furnishes the plumbing for interacting with CMLDS Link Ports (i.e. ports with "run_cmlds=1"). It adds internal functions for PTP Ports which employ the COMMON_P2P delay mechanism to issue requests to a CMLDS Link Port at MID_CMLDS_INFO_NP and handle the response. port_request_cmlds_info() encodes the CMLDS Link Port portNumber associated with its physical port as read from its config file. The request is sent to the configured cmlds_uds_address, i.e. the uds_address of a ptp4l instance that hosts the CMLDS Link Port. Upon receiving a request for MID_CMLDS_INFO_NP, the receiving ptp4l instance matches the target portNumber against the CMLDS Link Port portNumber that was assigned in its own config file and invokes process_cmlds_response(). Ports that do not expose the CMLDS ('run_cmlds' set to 0) will not respond to MID_CMLDS_INFO_NP queries. Co-authored-by: Andrew Zaborowski <and...@in...> Signed-off-by: Kishen Maloor <kis...@in...> --- clock.c | 10 ++++ clock.h | 6 +++ port.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++- port_private.h | 2 + 4 files changed, 147 insertions(+), 2 deletions(-) diff --git a/clock.c b/clock.c index 85f2a04867e5..626063849f2b 100644 --- a/clock.c +++ b/clock.c @@ -1650,6 +1650,11 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg) return changed; } break; + case RESPONSE: + /* Let the destined Port handle a response from CMLDS */ + if (mgt->id == MID_CMLDS_INFO_NP) + break; + return changed; default: return changed; } @@ -2280,3 +2285,8 @@ enum servo_state clock_servo_state(struct clock *c) { return c->servo_state; } + +struct port *clock_uds_rw_port(struct clock *c) +{ + return c->uds_rw_port; +} diff --git a/clock.h b/clock.h index ce9ae913eaaf..deb827f0afad 100644 --- a/clock.h +++ b/clock.h @@ -396,4 +396,10 @@ void clock_check_ts(struct clock *c, uint64_t ts); */ double clock_rate_ratio(struct clock *c); +/** + * Return a handle to the UDS RW port. + * @param c The clock instance. + */ +struct port *clock_uds_rw_port(struct clock *c); + #endif diff --git a/port.c b/port.c index 9040453fb2dc..14d2b71d0d73 100644 --- a/port.c +++ b/port.c @@ -1206,6 +1206,12 @@ static int port_management_fill_response(struct port *target, cmlds->scaledNeighborRateRatio = (Integer32) (target->nrate.ratio * POW2_41 - POW2_41); datalen = sizeof(*cmlds); + /* Reflect the CMLDS sdoid/domainNumber/port id in + * MID_CMLDS_INFO_NP responses + */ + rsp->header.tsmt = MANAGEMENT | CMLDS_TRANSPORTSPECIFIC; + rsp->header.domainNumber = CMLDS_DOMAINNUMBER; + rsp->header.sourcePortIdentity = target->cmlds_portIdentity; break; default: /* The caller should *not* respond to this message. */ @@ -3240,10 +3246,26 @@ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) struct management_tlv *mgt; UInteger16 target = msg->management.targetPortIdentity.portNumber; - if (target != portnum(p) && target != 0xffff) { + mgt = (struct management_tlv *) msg->management.suffix; + + /* Given a query to CMLDS and this port exposes CMLDS, try to match + * the target portNumber with the CMLDS Link Port PortNumber. + */ + if (mgt->id == MID_CMLDS_INFO_NP && + management_action(msg) == GET) { + if (port_cmlds_enabled(p)) { + if (target != 0xffff && + target != p->cmlds_portIdentity.portNumber) + return 0; + } else { + /* Do not respond to MID_CMLDS_INFO_NP if this port + * does not expose CMLDS + */ + return 0; + } + } else if (target != portnum(p) && target != 0xffff) { return 0; } - mgt = (struct management_tlv *) msg->management.suffix; switch (management_action(msg)) { case GET: @@ -3256,6 +3278,12 @@ int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) break; case COMMAND: break; + case RESPONSE: + /* Handle a response from CMLDS */ + if (mgt->id == MID_CMLDS_INFO_NP) { + return process_cmlds_response(p, msg); + } + break; default: return -1; } @@ -3707,3 +3735,102 @@ void port_update_unicast_state(struct port *p) p->unicast_state_dirty = false; } } + +int process_cmlds_response(struct port *p, + struct ptp_message *msg) +{ + struct management_tlv *mgt = (struct management_tlv *) + msg->management.suffix; + struct cmlds_info_np *cmlds; + + if (port_delay_mechanism(p) != DM_COMMON_P2P || + msg_tlv_count(msg) != 1) { + return -1; + } + + pr_debug("Response\t%s seq %hu ", + pid2str(&msg->header.sourcePortIdentity), + msg->header.sequenceId); + + cmlds = (struct cmlds_info_np *) mgt->data; + + pr_debug("CMLDS INFO\n" + "\tserviceMeasurementValid %i\n" + "\tmeanLinkDelay %" PRId64 "\n" + "\tscaledNeighborRateRatio %" PRId32, + cmlds->serviceMeasurementValid, cmlds->meanLinkDelay, + cmlds->scaledNeighborRateRatio); + + /* COMMON_P2P DM implementation goes here */ + + return 0; +} + +int port_request_cmlds_info(struct port *p) +{ + struct port *uds = clock_uds_rw_port(p->clock); + struct management_tlv *mgt; + struct tlv_extra *extra; + struct ptp_message *msg; + int err; + + if (port_delay_mechanism(p) != DM_COMMON_P2P) { + return -1; + } + + msg = msg_allocate(); + if (!msg) + return -ENOMEM; + + msg->hwts.type = p->timestamping; + + msg->header.tsmt = MANAGEMENT | CMLDS_TRANSPORTSPECIFIC; + msg->header.ver = PTP_VERSION; + msg->header.domainNumber = CMLDS_DOMAINNUMBER; + msg->header.sourcePortIdentity = p->portIdentity; + msg->header.sequenceId = p->seqnum.delayreq++; + msg->header.control = CTL_MANAGEMENT; + msg->header.logMessageInterval = 0x7f; + + /* Set the target cid to the wildcard as this request is being + * sent to the specific ptp4l instance that exposes the CMLDS + */ + msg->management.targetPortIdentity.clockIdentity = + (struct ClockIdentity){ + .id = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }; + /* Set the target CMLDS Link Port portNumber */ + msg->management.targetPortIdentity.portNumber = p->cmlds_portIdentity.portNumber; + + msg->management.flags = GET; + + mgt = (struct management_tlv *) msg->management.suffix; + mgt->type = TLV_MANAGEMENT; + mgt->length = sizeof(mgt->id); + mgt->id = MID_CMLDS_INFO_NP; + msg->header.messageLength = sizeof(struct management_msg) + sizeof(*mgt); + + extra = tlv_extra_alloc(); + if (!extra) { + pr_err("failed to allocate TLV descriptor"); + msg_put(msg); + return -ENOMEM; + } + extra->tlv = (struct TLV *) msg->management.suffix; + msg_tlv_attach(msg, extra); + + err = msg_pre_send(msg); + if (err) { + pr_err("msg_pre_send failed"); + return -1; + } + + /* Set the target CMLDS UDS address */ + msg->address = p->cmlds_uds_address; + err = port_forward_to(uds, msg); + + pr_debug("CMLDS request sent: %s", strerror(err < 0 ? -err : 0)); + + msg_put(msg); + return err; +} diff --git a/port_private.h b/port_private.h index 7d36a8200896..10ce05f3a895 100644 --- a/port_private.h +++ b/port_private.h @@ -205,6 +205,8 @@ int port_tx_interval_request(struct port *p, Integer8 timeSyncInterval, Integer8 linkDelayInterval); int port_tx_sync(struct port *p, struct address *dst, uint16_t sequence_id); +int port_request_cmlds_info(struct port *p); +int process_cmlds_response(struct port *p, struct ptp_message *msg); int process_announce(struct port *p, struct ptp_message *m); void process_delay_resp(struct port *p, struct ptp_message *m); void process_follow_up(struct port *p, struct ptp_message *m); -- 2.31.1 |
From: Kishen M. <kis...@in...> - 2023-03-20 02:37:24
|
This adds two example config files to instantate a gPTP domain 0 instance that hosts a CMLDS Link Port (run_cmlds=1) and a gPTP domain 1 instance that invokes the CMLDS using the COMMON_P2P delay mechanism. Signed-off-by: Kishen Maloor <kis...@in...> --- configs/gPTP-cmlds.cfg | 34 ++++++++++++++++++++++++++++++++++ configs/gPTP-common-p2p.cfg | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 configs/gPTP-cmlds.cfg create mode 100644 configs/gPTP-common-p2p.cfg diff --git a/configs/gPTP-cmlds.cfg b/configs/gPTP-cmlds.cfg new file mode 100644 index 000000000000..d682e5b6c2cd --- /dev/null +++ b/configs/gPTP-cmlds.cfg @@ -0,0 +1,34 @@ +# +# 802.1AS example configuration containing those attributes which +# differ from the defaults. See the file, default.cfg, for the +# complete list of available options. +# +[global] +gmCapable 1 +priority1 248 +priority2 248 +logAnnounceInterval 0 +logSyncInterval -3 +syncReceiptTimeout 3 +neighborPropDelayThresh 800 +min_neighbor_prop_delay -20000000 +assume_two_step 1 +path_trace_enabled 1 +follow_up_info 1 +transportSpecific 0x1 +ptp_dst_mac 01:80:C2:00:00:0E +network_transport L2 +delay_mechanism P2P +phc_index 11 + +# Configure a distinct UDS for this PTP instance +uds_address /var/run/ptp4l.dom0 + +# Assign a CMLDS clock identity +cmlds_clockIdentity 123456.7890.abcdef + +[enp4s0] +# Declare that this port will expose the CMLDS +run_cmlds 1 +# Configure a CMLDS Link Port PortNumber for this link +cmlds_portNumber 20 \ No newline at end of file diff --git a/configs/gPTP-common-p2p.cfg b/configs/gPTP-common-p2p.cfg new file mode 100644 index 000000000000..e6a252648b76 --- /dev/null +++ b/configs/gPTP-common-p2p.cfg @@ -0,0 +1,35 @@ +# +# 802.1AS example configuration containing those attributes which +# differ from the defaults. See the file, default.cfg, for the +# complete list of available options. +# +[global] +gmCapable 1 +priority1 248 +priority2 248 +logAnnounceInterval 0 +logSyncInterval -3 +syncReceiptTimeout 3 +neighborPropDelayThresh 800 +min_neighbor_prop_delay -20000000 +assume_two_step 1 +path_trace_enabled 1 +follow_up_info 1 +transportSpecific 0x1 +ptp_dst_mac 01:80:C2:00:00:0E +network_transport L2 +phc_index 12 + +# Configure a distinct UDS for this PTP instance +uds_address /var/run/ptp4l.dom1 + +# Configure a clockIdentity for this PTP instance that is +# unique across the PTP network +clockIdentity 000001.0001.000001 +domainNumber 1 + +[enp4s0] +# Configure the CMLDS Link Port parameters for this link +cmlds_portNumber 20 +cmlds_uds_address /var/run/ptp4l.dom0 +delay_mechanism COMMON_P2P -- 2.31.1 |
From: Richard C. <ric...@gm...> - 2023-03-20 19:31:54
|
On Sun, Mar 19, 2023 at 10:36:48PM -0400, Kishen Maloor wrote: > 'run_cmlds': This per-port setting (0/1) declares that a port > will perform the role of a CMLDS Link Port (IEEE 1588, clause 16.6.1) > and execute CMLDS Pdelay transactions How many ports may have run_cmlds == 1 ? Thanks, Richard |
From: Kishen M. <kis...@in...> - 2023-03-20 21:40:54
|
On 3/20/23 12:31 PM, Richard Cochran wrote: > On Sun, Mar 19, 2023 at 10:36:48PM -0400, Kishen Maloor wrote: > >> 'run_cmlds': This per-port setting (0/1) declares that a port >> will perform the role of a CMLDS Link Port (IEEE 1588, clause 16.6.1) >> and execute CMLDS Pdelay transactions > > How many ports may have run_cmlds == 1 ? We may configure 'run_cmlds=1' on as many (links) ports as we need. > > Thanks, > Richard > > |
From: Richard C. <ric...@gm...> - 2023-03-21 03:10:21
|
On Mon, Mar 20, 2023 at 02:40:30PM -0700, Kishen Maloor wrote: > On 3/20/23 12:31 PM, Richard Cochran wrote: > > On Sun, Mar 19, 2023 at 10:36:48PM -0400, Kishen Maloor wrote: > > > >> 'run_cmlds': This per-port setting (0/1) declares that a port > >> will perform the role of a CMLDS Link Port (IEEE 1588, clause 16.6.1) > >> and execute CMLDS Pdelay transactions > > > > How many ports may have run_cmlds == 1 ? > > We may configure 'run_cmlds=1' on as many (links) ports as we need. But there should be at most one cmlds on a given physical port, right? Thanks, Richard |
From: Kishen M. <kis...@in...> - 2023-03-21 04:05:16
|
On 3/20/23 8:10 PM, Richard Cochran wrote: > On Mon, Mar 20, 2023 at 02:40:30PM -0700, Kishen Maloor wrote: >> On 3/20/23 12:31 PM, Richard Cochran wrote: >>> On Sun, Mar 19, 2023 at 10:36:48PM -0400, Kishen Maloor wrote: >>> >>>> 'run_cmlds': This per-port setting (0/1) declares that a port >>>> will perform the role of a CMLDS Link Port (IEEE 1588, clause 16.6.1) >>>> and execute CMLDS Pdelay transactions >>> >>> How many ports may have run_cmlds == 1 ? >> >> We may configure 'run_cmlds=1' on as many (links) ports as we need. > > But there should be at most one cmlds on a given physical port, right? Yes, we would configure CMLDS just once per physical port on a PTP node. > > Thanks, > Richard |
From: Richard C. <ric...@gm...> - 2023-03-22 04:14:51
|
On Mon, Mar 20, 2023 at 09:04:59PM -0700, Kishen Maloor wrote: > Yes, we would configure CMLDS just once per physical port on a PTP node. Okay, so the code should check this. (Haven't reviewed yet, maybe you handle that already?) Thanks, Richard |
From: Andrew Z. <and...@in...> - 2023-03-22 09:00:28
|
On Wed, 22 Mar 2023 at 05:17, Richard Cochran <ric...@gm...> wrote: > On Mon, Mar 20, 2023 at 09:04:59PM -0700, Kishen Maloor wrote: > > Yes, we would configure CMLDS just once per physical port on a PTP node. > > Okay, so the code should check this. > > (Haven't reviewed yet, maybe you handle that already?) We do not because that would require IPC and largely depend on the user to provide correct configuration. Let me explain. In a typical setup, you'd have one ptp4l instance per domain, each with a different domainNumber, clockIdentity and uds_address. You'd configure one of these ptp4l instances to run the CMLDS for all of the physical ports the machine has using run_cmlds=1. The cmlds_uds_address is option is how other instances know how to talk to that one instance. If your cmlds_uds_address values are wrong you can't detect a run_cmlds misconfiguration, not with UDS at least. Note: Since config.c falls back to searching [global] when no per-port option is found, you would probably set run_cmlds=1 directly under [global] for that one ptp4l session. The reason this option is per-port is that there's no requirement that all of the PTP Instances (domains) use the same subset of links on the PTP Node so you may have no single ptp4l instance that uses all of your ports and may need to split the responsibility of prviding CMLDS between more than one instance. Best regards |