From: Richard C. <ric...@gm...> - 2018-01-02 04:05:59
|
This series adds support for Meinberg Funkuhren's NetSync Monitor (NSM) protocol. NSM allows a node with a local time reference (like a GM using GPS) to measure the offset of a given clock. In a nutshell, NSM works by having the node to be measured act like a unicast master clock on demand. 1. The monitoring node sends a unicast delay request with a special TLV attached. 2. The node to be measured replies with a unicast delay response, followed by unicast Sync and FollowUp messages. 3. Once the monitoring node receives the three responses, it calculates the measured node's offset. One the nice features of NSM is that, when used from the GM, it allows one to empirically determine the end to end asymmetry in the network. The details of the protocol are described in a brief PDF published by Meinberg. If anyone would like a copy, please contact me off list. Patches 1-3 fix trivial issues found along the way. Patches 4-9 add various background support bits. Patches 10-13 implement NSM in the ptp4l program. Patches 14-18 implement monitor support in the pmc program. Comments and review are most welcome! Thanks, Richard @Miroslav: The last patch breaks linuxptp-testsuite test 20-pmc. The pmc program exits immediately with no output at all. When I test pmc outside of the clknetsim it behaves as expected, but I didn't look into why clknetsim case fails. Maybe you have an idea? Richard Cochran (18): pmc: Fix white space errors. port: Fix coding style. tlv: Fix coding style. msg: Allow zero length TLVs. msg: Share a static global more globally. msg: Allow tacking a TLV onto a delay request message. clock: Introduce a method to get the current dataset. clock: Introduce a method to obtain the last synchronization time. tmv: Add a method to convert to a struct Timestamp. tlv: Introduce the NetSync Monitor TLVs. port: Introduce unicast sync messages. port: Implement the NetSync Monitor protocol. Add a configuration file option to enable the NetSync Monitor protocol. util: Relocate utility functions from pmc.c. pmc: Add command line options for specifying the time stamping mode. pmc: Add an accessory function for the event message socket. pmc: Introduce a time stamp processor. pmc: Implement the NetSync Monitor query. clock.c | 10 ++ clock.h | 14 +++ config.c | 1 + default.cfg | 1 + gPTP.cfg | 1 + makefile | 11 +- msg.c | 6 +- msg.h | 1 + pmc.c | 101 ++++++++---------- pmc_common.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- pmc_common.h | 21 ++++ port.c | 144 +++++++++++++++++++++++-- ptp4l.8 | 12 ++- ptp4l.c | 2 - tlv.c | 147 +++++++++++++++++++++++++- tlv.h | 17 +++ tmv.h | 15 +++ util.c | 39 +++++++ util.h | 15 +++ 19 files changed, 816 insertions(+), 81 deletions(-) -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:02:00
|
This series adds support for Meinberg Funkuhren's NetSync Monitor (NSM) protocol. NSM allows a node with a local time reference (like a GM using GPS) to measure the offset of a given clock. In a nutshell, NSM works by having the node to be measured act like a unicast master clock on demand. 1. The monitoring node sends a unicast delay request with a special TLV attached. 2. The node to be measured replies with a unicast delay response, followed by unicast Sync and FollowUp messages. 3. Once the monitoring node receives the three responses, it calculates the measured node's offset. The details of the protocol are described in a brief PDF published by Meinberg. If anyone would like a copy, please contact me off list. * Changes in V2: - rebased to use the multiple TLV API - the NSM client is now its own program, not a part of pmc Richard Cochran (11): msg: Allow zero length TLVs. msg: Allow tacking a TLV onto a delay request message. clock: Introduce a method to get the current dataset. clock: Introduce a method to obtain the last synchronization time. tmv: Add a method to convert to a struct Timestamp. tlv: Introduce the NetSync Monitor TLVs. port: Introduce unicast sync messages. port: Implement the NetSync Monitor protocol. Add a configuration file option to enable the NetSync Monitor protocol. util: Relocate utility functions from pmc.c. nsm: Implement the NetSync Monitor query. .gitignore | 1 + clock.c | 10 + clock.h | 14 ++ config.c | 1 + default.cfg | 1 + gPTP.cfg | 1 + makefile | 7 +- msg.c | 5 +- msg.h | 1 + nsm.c | 627 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pmc.c | 48 ----- port.c | 145 +++++++++++++- ptp4l.8 | 12 +- tlv.c | 138 +++++++++++++ tlv.h | 18 ++ tmv.h | 15 ++ util.c | 39 ++++ util.h | 15 ++ 18 files changed, 1039 insertions(+), 59 deletions(-) create mode 100644 nsm.c -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:06:48
|
The file, pmc.c, contains utility functions for printing out a port address structure. We will want to call these functions from pmc_common.c, and so this patch moves the utility functions where they belong. Signed-off-by: Richard Cochran <ric...@gm...> --- pmc.c | 48 ------------------------------------------------ util.c | 39 +++++++++++++++++++++++++++++++++++++++ util.h | 15 +++++++++++++++ 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/pmc.c b/pmc.c index fde2449..7c96a4d 100644 --- a/pmc.c +++ b/pmc.c @@ -127,60 +127,12 @@ static char *text2str(struct PTPText *text) return (char*)(s.text); } -#define MAX_PRINT_BYTES 16 -#define BIN_BUF_SIZE (MAX_PRINT_BYTES * 3 + 1) - -static char *bin2str_impl(Octet *data, int len, char *buf, int buf_len) -{ - int i, offset = 0; - if (len > MAX_PRINT_BYTES) - len = MAX_PRINT_BYTES; - buf[0] = '\0'; - if (!data) - return buf; - if (len) - offset += snprintf(buf, buf_len, "%02hhx", data[0]); - for (i = 1; i < len; i++) { - if (offset >= buf_len) - /* truncated output */ - break; - offset += snprintf(buf + offset, buf_len - offset, ":%02hhx", data[i]); - } - return buf; -} - static char *bin2str(Octet *data, int len) { static char buf[BIN_BUF_SIZE]; return bin2str_impl(data, len, buf, sizeof(buf)); } -static uint16_t align16(uint16_t *p) -{ - uint16_t v; - memcpy(&v, p, sizeof(v)); - return v; -} - -static char *portaddr2str(struct PortAddress *addr) -{ - static char buf[BIN_BUF_SIZE]; - switch(align16(&addr->networkProtocol)) { - case TRANS_UDP_IPV4: - if (align16(&addr->addressLength) == 4 - && inet_ntop(AF_INET, addr->address, buf, sizeof(buf))) - return buf; - break; - case TRANS_UDP_IPV6: - if (align16(&addr->addressLength) == 16 - && inet_ntop(AF_INET6, addr->address, buf, sizeof(buf))) - return buf; - break; - } - bin2str_impl(addr->address, align16(&addr->addressLength), buf, sizeof(buf)); - return buf; -} - static void pmc_show(struct ptp_message *msg, FILE *fp) { int action; diff --git a/util.c b/util.c index 62f2638..2eacafc 100644 --- a/util.c +++ b/util.c @@ -16,6 +16,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <arpa/inet.h> #include <errno.h> #include <signal.h> #include <stdarg.h> @@ -68,6 +69,25 @@ const char *ev_str[] = { "RS_PASSIVE", }; +char *bin2str_impl(Octet *data, int len, char *buf, int buf_len) +{ + int i, offset = 0; + if (len > MAX_PRINT_BYTES) + len = MAX_PRINT_BYTES; + buf[0] = '\0'; + if (!data) + return buf; + if (len) + offset += snprintf(buf, buf_len, "%02hhx", data[0]); + for (i = 1; i < len; i++) { + if (offset >= buf_len) + /* truncated output */ + break; + offset += snprintf(buf + offset, buf_len - offset, ":%02hhx", data[i]); + } + return buf; +} + char *cid2str(struct ClockIdentity *id) { static char buf[64]; @@ -100,6 +120,25 @@ char *pid2str(struct PortIdentity *id) return buf; } +char *portaddr2str(struct PortAddress *addr) +{ + static char buf[BIN_BUF_SIZE]; + switch (align16(&addr->networkProtocol)) { + case TRANS_UDP_IPV4: + if (align16(&addr->addressLength) == 4 + && inet_ntop(AF_INET, addr->address, buf, sizeof(buf))) + return buf; + break; + case TRANS_UDP_IPV6: + if (align16(&addr->addressLength) == 16 + && inet_ntop(AF_INET6, addr->address, buf, sizeof(buf))) + return buf; + break; + } + bin2str_impl(addr->address, align16(&addr->addressLength), buf, sizeof(buf)); + return buf; +} + int str2mac(const char *s, unsigned char mac[MAC_LEN]) { unsigned char buf[MAC_LEN]; diff --git a/util.h b/util.h index 0c1a357..41fbdb2 100644 --- a/util.h +++ b/util.h @@ -20,11 +20,15 @@ #ifndef HAVE_UTIL_H #define HAVE_UTIL_H +#include <string.h> #include <time.h> #include "ddt.h" #include "ether.h" +#define MAX_PRINT_BYTES 16 +#define BIN_BUF_SIZE (MAX_PRINT_BYTES * 3 + 1) + /** * Table of human readable strings, one for each port state. */ @@ -35,6 +39,15 @@ extern const char *ps_str[]; */ extern const char *ev_str[]; +static inline uint16_t align16(uint16_t *p) +{ + uint16_t v; + memcpy(&v, p, sizeof(v)); + return v; +} + +char *bin2str_impl(Octet *data, int len, char *buf, int buf_len); + /** * Convert a clock identity into a human readable string. * @@ -65,6 +78,8 @@ int count_char(const char *str, char c); */ char *pid2str(struct PortIdentity *id); +char *portaddr2str(struct PortAddress *addr); + /** * Scan a string containing a MAC address and convert it into binary form. * -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:07:07
|
The port will need to send unicast Sync messages in order to support the NSM protocol. Besides that, we will need this ability anyhow if we ever want to implement unicast operation. Signed-off-by: Richard Cochran <ric...@gm...> --- port.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/port.c b/port.c index 606f471..cc5a09e 100644 --- a/port.c +++ b/port.c @@ -1331,7 +1331,7 @@ static int port_tx_announce(struct port *p) return err; } -static int port_tx_sync(struct port *p) +static int port_tx_sync(struct port *p, struct address *dst) { struct ptp_message *msg, *fup; int err, event; @@ -1367,6 +1367,10 @@ static int port_tx_sync(struct port *p) if (p->timestamping != TS_ONESTEP) msg->header.flagField[0] |= TWO_STEP; + if (dst) { + msg->address = *dst; + msg->header.flagField[0] |= UNICAST; + } err = port_prepare_and_send(p, msg, event); if (err) { pr_err("port %hu: send sync failed", portnum(p)); @@ -1396,6 +1400,10 @@ static int port_tx_sync(struct port *p) ts_to_timestamp(&msg->hwts.ts, &fup->follow_up.preciseOriginTimestamp); + if (dst) { + fup->address = *dst; + fup->header.flagField[0] |= UNICAST; + } if (p->follow_up_info && follow_up_info_append(p, fup)) { pr_err("port %hu: append fup info failed", portnum(p)); err = -1; @@ -2342,7 +2350,7 @@ enum fsm_event port_event(struct port *p, int fd_index) case FD_SYNC_TX_TIMER: pr_debug("port %hu: master sync timeout", portnum(p)); port_set_sync_tx_tmo(p); - return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE; + return port_tx_sync(p, NULL) ? EV_FAULT_DETECTED : EV_NONE; case FD_RTNL: pr_debug("port %hu: received link status notification", portnum(p)); -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:13:02
|
This will be needed in order to support the NetSync Monitor protocol. Signed-off-by: Richard Cochran <ric...@gm...> --- msg.c | 3 ++- msg.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/msg.c b/msg.c index 9038616..a36d4d0 100644 --- a/msg.c +++ b/msg.c @@ -116,7 +116,7 @@ static uint8_t *msg_suffix(struct ptp_message *m) case SYNC: return NULL; case DELAY_REQ: - return NULL; + return m->delay_req.suffix; case PDELAY_REQ: return NULL; case PDELAY_RESP: @@ -354,6 +354,7 @@ int msg_post_recv(struct ptp_message *m, int cnt) timestamp_post_recv(m, &m->sync.originTimestamp); break; case DELAY_REQ: + suffix = m->delay_req.suffix; break; case PDELAY_REQ: break; diff --git a/msg.h b/msg.h index dd8c069..985b78f 100644 --- a/msg.h +++ b/msg.h @@ -114,6 +114,7 @@ struct sync_msg { struct delay_req_msg { struct ptp_header hdr; struct Timestamp originTimestamp; + uint8_t suffix[0]; } PACKED; struct follow_up_msg { -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:13:51
|
This will be needed in order to generate a TLV for the NSM protocol. Signed-off-by: Richard Cochran <ric...@gm...> --- tmv.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tmv.h b/tmv.h index 30b41ee..5d1e12b 100644 --- a/tmv.h +++ b/tmv.h @@ -96,6 +96,21 @@ static inline TimeInterval tmv_to_TimeInterval(tmv_t x) return x << 16; } +static inline struct Timestamp tmv_to_Timestamp(tmv_t x) +{ + struct Timestamp result; + uint64_t sec, nsec; + + sec = x / 1000000000ULL; + nsec = x % 1000000000ULL; + + result.seconds_lsb = sec & 0xFFFFFFFF; + result.seconds_msb = (sec >> 32) & 0xFFFF; + result.nanoseconds = nsec; + + return result; +} + static inline tmv_t timespec_to_tmv(struct timespec ts) { return ts.tv_sec * NS_PER_SEC + ts.tv_nsec; -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:13:58
|
When NSM is enabled on a given port, that port always replies to a NSM delay request with a delay response, sync, and follow up, regardless of the current state of the port. Signed-off-by: Richard Cochran <ric...@gm...> --- port.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/port.c b/port.c index cc5a09e..52b9282 100644 --- a/port.c +++ b/port.c @@ -126,6 +126,7 @@ struct port { int freq_est_interval; int hybrid_e2e; int min_neighbor_prop_delay; + int net_sync_monitor; int path_trace_enabled; int rx_timestamp_offset; int tx_timestamp_offset; @@ -184,6 +185,29 @@ static int clear_fault_asap(struct fault_interval *faint) return 0; } +static void extract_address(struct ptp_message *m, struct PortAddress *paddr) +{ + int len = 0; + + switch (paddr->networkProtocol) { + case TRANS_UDP_IPV4: + len = sizeof(m->address.sin.sin_addr.s_addr); + memcpy(paddr->address, &m->address.sin.sin_addr.s_addr, len); + break; + case TRANS_UDP_IPV6: + len = sizeof(m->address.sin6.sin6_addr.s6_addr); + memcpy(paddr->address, &m->address.sin6.sin6_addr.s6_addr, len); + break; + case TRANS_IEEE_802_3: + len = MAC_LEN; + memcpy(paddr->address, &m->address.sll.sll_addr, len); + break; + default: + return; + } + paddr->addressLength = len; +} + static int msg_current(struct ptp_message *m, struct timespec now) { int64_t t1, t2, tmo; @@ -449,6 +473,67 @@ static int follow_up_info_append(struct port *p, struct ptp_message *m) return 0; } +static int net_sync_resp_append(struct port *p, struct ptp_message *m) +{ + struct timePropertiesDS *tp = clock_time_properties(p->clock); + struct ClockIdentity cid = clock_identity(p->clock), pid; + struct currentDS *cds = clock_current_dataset(p->clock); + struct parent_ds *dad = clock_parent_ds(p->clock); + struct port *best = clock_best_port(p->clock); + struct nsm_resp_tlv_head *head; + struct Timestamp last_sync; + struct PortAddress paddr; + struct ptp_message *tmp; + struct tlv_extra *extra; + unsigned char *ptr; + int tlv_len; + + last_sync = tmv_to_Timestamp(clock_ingress_time(p->clock)); + pid = dad->pds.parentPortIdentity.clockIdentity; + + if (best && memcmp(&cid, &pid, sizeof(cid))) { + /* Extract the parent's protocol address. */ + paddr.networkProtocol = transport_type(best->trp); + paddr.addressLength = + transport_protocol_addr(best->trp, paddr.address); + if (best->best) { + tmp = TAILQ_FIRST(&best->best->messages); + extract_address(tmp, &paddr); + } + } else { + /* We are our own parent. */ + paddr.networkProtocol = transport_type(p->trp); + paddr.addressLength = + transport_protocol_addr(p->trp, paddr.address); + } + + tlv_len = sizeof(*head) + sizeof(*extra->foot) + paddr.addressLength; + + extra = msg_tlv_append(m, tlv_len); + if (!extra) { + return -1; + } + + head = (struct nsm_resp_tlv_head *) extra->tlv; + head->type = TLV_PTPMON_RESP; + head->length = tlv_len - sizeof(head->type) - sizeof(head->length); + head->port_state = p->state == PS_GRAND_MASTER ? PS_MASTER : p->state; + head->parent_addr.networkProtocol = paddr.networkProtocol; + head->parent_addr.addressLength = paddr.addressLength; + memcpy(head->parent_addr.address, paddr.address, paddr.addressLength); + + ptr = (unsigned char *) head; + ptr += sizeof(*head) + paddr.addressLength; + extra->foot = (struct nsm_resp_tlv_foot *) ptr; + + memcpy(&extra->foot->parent, &dad->pds, sizeof(extra->foot->parent)); + memcpy(&extra->foot->current, cds, sizeof(extra->foot->current)); + memcpy(&extra->foot->timeprop, tp, sizeof(extra->foot->timeprop)); + memcpy(&extra->foot->lastsync, &last_sync, sizeof(extra->foot->lastsync)); + + return 0; +} + static struct follow_up_info_tlv *follow_up_info_extract(struct ptp_message *m) { struct follow_up_info_tlv *f; @@ -677,6 +762,27 @@ static int port_ignore(struct port *p, struct ptp_message *m) return 0; } +static int port_nsm_reply(struct port *p, struct ptp_message *m) +{ + struct tlv_extra *extra; + + if (!p->net_sync_monitor) { + return 0; + } + if (!p->hybrid_e2e) { + return 0; + } + if (!(m->header.flagField[0] & UNICAST)) { + return 0; + } + TAILQ_FOREACH(extra, &m->tlv_list, list) { + if (extra->tlv->type == TLV_PTPMON_REQ) { + return 1; + } + } + return 0; +} + /* * Test whether a 802.1AS port may transmit a sync message. */ @@ -1662,10 +1768,12 @@ static int process_announce(struct port *p, struct ptp_message *m) static int process_delay_req(struct port *p, struct ptp_message *m) { + int err, nsm, saved_seqnum_sync; struct ptp_message *msg; - int err; - if (p->state != PS_MASTER && p->state != PS_GRAND_MASTER) + nsm = port_nsm_reply(p, m); + + if (!nsm && p->state != PS_MASTER && p->state != PS_GRAND_MASTER) return 0; if (p->delayMechanism == DM_P2P) { @@ -1698,10 +1806,23 @@ static int process_delay_req(struct port *p, struct ptp_message *m) msg->header.flagField[0] |= UNICAST; msg->header.logMessageInterval = 0x7f; } - + if (nsm && net_sync_resp_append(p, msg)) { + pr_err("port %hu: append NSM failed", portnum(p)); + err = -1; + goto out; + } err = port_prepare_and_send(p, msg, 0); - if (err) + if (err) { pr_err("port %hu: send delay response failed", portnum(p)); + goto out; + } + if (nsm) { + saved_seqnum_sync = p->seqnum.sync; + p->seqnum.sync = m->header.sequenceId; + err = port_tx_sync(p, &m->address); + p->seqnum.sync = saved_seqnum_sync; + } +out: msg_put(msg); return err; } @@ -2728,6 +2849,9 @@ struct port *port_open(int phc_index, if (p->hybrid_e2e && p->delayMechanism != DM_E2E) { pr_warning("port %d: hybrid_e2e only works with E2E", number); } + if (p->net_sync_monitor && !p->hybrid_e2e) { + pr_warning("port %d: net_sync_monitor needs hybrid_e2e", number); + } /* Set fault timeouts to a default value */ for (i = 0; i < FT_CNT; i++) { -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 22:57:35
|
The NetSync Monitor protocol will require us to report the time stamp of the last synchronization. This patch adds new the method. Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 5 +++++ clock.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/clock.c b/clock.c index 28a1406..30e5a0e 100644 --- a/clock.c +++ b/clock.c @@ -1288,6 +1288,11 @@ static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_m } } +tmv_t clock_ingress_time(struct clock *c) +{ + return c->ingress_ts; +} + int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg) { int changed = 0, res, answers; diff --git a/clock.h b/clock.h index 64c5131..94d4ad0 100644 --- a/clock.h +++ b/clock.h @@ -157,6 +157,13 @@ struct ClockIdentity clock_identity(struct clock *c); void clock_fda_changed(struct clock *c); /** + * Obtains the time of the latest synchronization. + * @param c The clock instance. + * @return The local time stamp of the last received Sync message. + */ +tmv_t clock_ingress_time(struct clock *c); + +/** * Manage the clock according to a given message. * @param c The clock instance. * @param p The port on which the message arrived. -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:05:19
|
Signed-off-by: Richard Cochran <ric...@gm...> --- config.c | 1 + default.cfg | 1 + gPTP.cfg | 1 + port.c | 1 + ptp4l.8 | 12 +++++++++++- 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index 56d1556..ba035ac 100644 --- a/config.c +++ b/config.c @@ -205,6 +205,7 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("max_frequency", 900000000, 0, INT_MAX), PORT_ITEM_INT("min_neighbor_prop_delay", -20000000, INT_MIN, -1), PORT_ITEM_INT("neighborPropDelayThresh", 20000000, 0, INT_MAX), + PORT_ITEM_INT("net_sync_monitor", 0, 0, 1), PORT_ITEM_ENU("network_transport", TRANS_UDP_IPV4, nw_trans_enu), GLOB_ITEM_INT("ntpshm_segment", 0, INT_MIN, INT_MAX), GLOB_ITEM_INT("offsetScaledLogVariance", 0xffff, 0, UINT16_MAX), diff --git a/default.cfg b/default.cfg index ebb263a..e76aeae 100644 --- a/default.cfg +++ b/default.cfg @@ -35,6 +35,7 @@ logging_level 6 path_trace_enabled 0 follow_up_info 0 hybrid_e2e 0 +net_sync_monitor 0 tx_timestamp_timeout 1 use_syslog 1 verbose 0 diff --git a/gPTP.cfg b/gPTP.cfg index 142996a..1e7a33e 100644 --- a/gPTP.cfg +++ b/gPTP.cfg @@ -33,6 +33,7 @@ logging_level 6 path_trace_enabled 1 follow_up_info 1 hybrid_e2e 0 +net_sync_monitor 0 tx_timestamp_timeout 1 use_syslog 1 verbose 0 diff --git a/port.c b/port.c index 52b9282..9b88b70 100644 --- a/port.c +++ b/port.c @@ -2831,6 +2831,7 @@ struct port *port_open(int phc_index, p->follow_up_info = config_get_int(cfg, p->name, "follow_up_info"); p->freq_est_interval = config_get_int(cfg, p->name, "freq_est_interval"); p->hybrid_e2e = config_get_int(cfg, p->name, "hybrid_e2e"); + p->net_sync_monitor = config_get_int(cfg, p->name, "net_sync_monitor"); p->path_trace_enabled = config_get_int(cfg, p->name, "path_trace_enabled"); p->rx_timestamp_offset = config_get_int(cfg, p->name, "ingressLatency"); p->tx_timestamp_offset = config_get_int(cfg, p->name, "egressLatency"); diff --git a/ptp4l.8 b/ptp4l.8 index 4cf0b0c..194c8b1 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -1,4 +1,4 @@ -.TH PTP4l 8 "December 2016" "linuxptp" +.TH PTP4l 8 "Novemver 2017" "linuxptp" .SH NAME ptp4l - PTP Boundary/Ordinary Clock @@ -211,6 +211,16 @@ delay requests using unicast delay responses. This option has no effect if the delay_mechanism is set to P2P. The default is 0 (disabled). .TP +.B net_sync_monitor +Enables the NetSync Monitor (NSM) protocol. The NSM protocol allows a +station to measure how well another node is synchronized. The monitor +sends a unicast delay request to the node, which replies +unconditionally with unicast delay response, sync, and follow up +messages. If the monitor is synchronized to the GM, it can use the +time stamps in the message to estimate the node's offset. This option +requires that the 'hybrid_e2e' option be enabled as well. +The default is 0 (disabled). +.TP .B ptp_dst_mac The MAC address to which PTP messages should be sent. Relevant only with L2 transport. The default is 01:1B:19:00:00:00. -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:05:52
|
The NetSync Monitor protocol features a TLV with a length of zero. Our input message parsing assumes that every TLV will have some sort of payload, and up until now this was true. This patch adjusts the parsing code to accept TLVs of length zero. Signed-off-by: Richard Cochran <ric...@gm...> --- msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msg.c b/msg.c index 8bc14f8..9038616 100644 --- a/msg.c +++ b/msg.c @@ -190,7 +190,7 @@ static int suffix_post_recv(struct ptp_message *msg, uint8_t *ptr, int len) if (!ptr) return 0; - while (len > sizeof(struct TLV)) { + while (len >= sizeof(struct TLV)) { extra = tlv_extra_alloc(); if (!extra) { pr_err("failed to allocate TLV descriptor"); -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:09:52
|
As part of the NetSync Monitor protocol, the port will need to have access to the current data set. This patch adds the appropriate function. Signed-off-by: Richard Cochran <ric...@gm...> --- clock.c | 5 +++++ clock.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/clock.c b/clock.c index 201c8e1..28a1406 100644 --- a/clock.c +++ b/clock.c @@ -761,6 +761,11 @@ struct config *clock_config(struct clock *c) return c->config; } +struct currentDS *clock_current_dataset(struct clock *c) +{ + return &c->cur; +} + static int clock_add_port(struct clock *c, int phc_index, enum timestamp_type timestamping, struct interface *iface) diff --git a/clock.h b/clock.h index 986d363..64c5131 100644 --- a/clock.h +++ b/clock.h @@ -73,6 +73,13 @@ UInteger8 clock_class(struct clock *c); struct config *clock_config(struct clock *c); /** + * Obtains a reference to the current dataset. + * @param c The clock instance. + * @return A pointer to the current dataset, without fail. + */ +struct currentDS *clock_current_dataset(struct clock *c); + +/** * Obtains the required time stamping mode. * @param c The clock instance. * @return The value of required time stamping mode, which is a bit mask -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:10:00
|
This patch adds support for packing and unpacking the NSM TLVs. In addition, it introduces macros to make the ntoh/htoh boilerplate easier to read. The idea is to reduce the number of monstrous muti-line assignments like: pds->grandmasterClockQuality.offsetScaledLogVariance = htons(pds->grandmasterClockQuality.offsetScaledLogVariance); Signed-off-by: Richard Cochran <ric...@gm...> --- tlv.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tlv.h | 18 +++++++++ 2 files changed, 156 insertions(+) diff --git a/tlv.c b/tlv.c index 4811f19..7285af7 100644 --- a/tlv.c +++ b/tlv.c @@ -25,6 +25,11 @@ #include "tlv.h" #include "msg.h" +#define HTONS(x) (x) = htons(x) +#define HTONL(x) (x) = htonl(x) +#define NTOHS(x) (x) = ntohs(x) +#define NTOHL(x) (x) = ntohl(x) + #define TLV_LENGTH_INVALID(tlv, type) \ (tlv->length < sizeof(struct type) - sizeof(struct TLV)) @@ -56,6 +61,24 @@ static uint16_t flip16(uint16_t *p) return v; } +static int64_t host2net64_unaligned(int64_t *p) +{ + int64_t v; + memcpy(&v, p, sizeof(v)); + v = host2net64(v); + memcpy(p, &v, sizeof(v)); + return v; +} + +static int64_t net2host64_unaligned(int64_t *p) +{ + int64_t v; + memcpy(&v, p, sizeof(v)); + v = net2host64(v); + memcpy(p, &v, sizeof(v)); + return v; +} + static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, struct tlv_extra *extra) { @@ -371,6 +394,111 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) } } +static int nsm_resp_post_recv(struct tlv_extra *extra) +{ + struct nsm_resp_tlv_head *head; + struct TLV *tlv = extra->tlv; + struct timePropertiesDS *tp; + struct PortAddress *paddr; + struct currentDS *cds; + struct parentDS *pds; + unsigned char *ptr; + uint16_t expected; + + if (tlv->length < sizeof(*head) + sizeof(*extra->foot) + - sizeof(head->type) - sizeof(head->length)) { + return -EBADMSG; + } + head = (struct nsm_resp_tlv_head *) tlv; + paddr = &head->parent_addr; + NTOHS(paddr->networkProtocol); + NTOHS(paddr->addressLength); + + switch (paddr->networkProtocol) { + case TRANS_UDP_IPV4: + expected = 4; + break; + case TRANS_UDP_IPV6: + expected = 16; + break; + case TRANS_IEEE_802_3: + expected = 6; + break; + default: + return -EBADMSG; + } + if (paddr->addressLength != expected) { + return -EBADMSG; + } + if (tlv->length != sizeof(*head) + sizeof(*extra->foot) + + paddr->addressLength - sizeof(head->type) - sizeof(head->length)) { + return -EBADMSG; + } + + ptr = (unsigned char *) tlv; + ptr += sizeof(*head) + paddr->addressLength; + extra->foot = (struct nsm_resp_tlv_foot *) ptr; + + pds = &extra->foot->parent; + cds = &extra->foot->current; + tp = &extra->foot->timeprop; + + /* + * At this point the alignment only 2 bytes worst case. + * So we need to be careful with the 64 bit words. + */ + NTOHS(pds->parentPortIdentity.portNumber); + NTOHS(pds->observedParentOffsetScaledLogVariance); + NTOHL(pds->observedParentClockPhaseChangeRate); + NTOHS(pds->grandmasterClockQuality.offsetScaledLogVariance); + + NTOHS(cds->stepsRemoved); + net2host64_unaligned(&cds->offsetFromMaster); + net2host64_unaligned(&cds->meanPathDelay); + + NTOHS(tp->currentUtcOffset); + + NTOHL(extra->foot->lastsync.seconds_lsb); + NTOHS(extra->foot->lastsync.seconds_msb); + NTOHL(extra->foot->lastsync.nanoseconds); + + return 0; +} + +static void nsm_resp_pre_send(struct tlv_extra *extra) +{ + struct nsm_resp_tlv_head *head; + struct timePropertiesDS *tp; + struct PortAddress *paddr; + struct currentDS *cds; + struct parentDS *pds; + + head = (struct nsm_resp_tlv_head *) extra->tlv; + paddr = &head->parent_addr; + + pds = &extra->foot->parent; + cds = &extra->foot->current; + tp = &extra->foot->timeprop; + + NTOHS(paddr->networkProtocol); + NTOHS(paddr->addressLength); + + HTONS(pds->parentPortIdentity.portNumber); + HTONS(pds->observedParentOffsetScaledLogVariance); + HTONL(pds->observedParentClockPhaseChangeRate); + HTONS(pds->grandmasterClockQuality.offsetScaledLogVariance); + + HTONS(cds->stepsRemoved); + host2net64_unaligned(&cds->offsetFromMaster); + host2net64_unaligned(&cds->meanPathDelay); + + HTONS(tp->currentUtcOffset); + + HTONL(extra->foot->lastsync.seconds_lsb); + HTONS(extra->foot->lastsync.seconds_msb); + HTONL(extra->foot->lastsync.nanoseconds); +} + static int org_post_recv(struct organization_tlv *org) { struct follow_up_info_tlv *f; @@ -489,6 +617,11 @@ int tlv_post_recv(struct tlv_extra *extra) case TLV_AUTHENTICATION_CHALLENGE: case TLV_SECURITY_ASSOCIATION_UPDATE: case TLV_CUM_FREQ_SCALE_FACTOR_OFFSET: + case TLV_PTPMON_REQ: + break; + case TLV_PTPMON_RESP: + result = nsm_resp_post_recv(extra); + break; default: break; } @@ -527,6 +660,11 @@ void tlv_pre_send(struct TLV *tlv, struct tlv_extra *extra) case TLV_AUTHENTICATION_CHALLENGE: case TLV_SECURITY_ASSOCIATION_UPDATE: case TLV_CUM_FREQ_SCALE_FACTOR_OFFSET: + case TLV_PTPMON_REQ: + break; + case TLV_PTPMON_RESP: + nsm_resp_pre_send(extra); + break; default: break; } diff --git a/tlv.h b/tlv.h index 5a919fb..4ec9173 100644 --- a/tlv.h +++ b/tlv.h @@ -39,6 +39,8 @@ #define TLV_AUTHENTICATION_CHALLENGE 0x2001 #define TLV_SECURITY_ASSOCIATION_UPDATE 0x2002 #define TLV_CUM_FREQ_SCALE_FACTOR_OFFSET 0x2003 +#define TLV_PTPMON_REQ 0x21FE +#define TLV_PTPMON_RESP 0x21FF enum management_action { GET, @@ -134,6 +136,21 @@ struct management_error_status { Octet data[0]; } PACKED; +struct nsm_resp_tlv_head { + Enumeration16 type; + UInteger16 length; + uint8_t port_state; + uint8_t reserved; + struct PortAddress parent_addr; +} PACKED; + +struct nsm_resp_tlv_foot { + struct parentDS parent; + struct currentDS current; + struct timePropertiesDS timeprop; + struct Timestamp lastsync; +} PACKED; + /* Organizationally Unique Identifiers */ #define IEEE_802_1_COMMITTEE 0x00, 0x80, 0xC2 extern uint8_t ieee8021_id[3]; @@ -234,6 +251,7 @@ struct tlv_extra { struct TLV *tlv; union { struct mgmt_clock_description cd; + struct nsm_resp_tlv_foot *foot; }; }; -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-03-01 23:20:09
|
This patch adds a new "NSM" program. The new code handles only one outstanding NSM command at a time. If and when all four event time stamps have arrived, the code prints the instantaneous estimated offset without any averaging or smoothing. Signed-off-by: Richard Cochran <ric...@gm...> --- .gitignore | 1 + makefile | 7 +- nsm.c | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 633 insertions(+), 2 deletions(-) create mode 100644 nsm.c diff --git a/.gitignore b/.gitignore index 68a4c3e..6d288ae 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /*.o /.version /hwstamp_ctl +/nsm /phc2sys /pmc /ptp4l diff --git a/makefile b/makefile index f898336..796235b 100644 --- a/makefile +++ b/makefile @@ -22,13 +22,13 @@ CC = $(CROSS_COMPILE)gcc VER = -DVER=$(version) CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS) LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) -PRG = ptp4l pmc phc2sys hwstamp_ctl phc_ctl timemaster +PRG = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \ filter.o fsm.o hash.o linreg.o mave.o mmedian.o msg.o ntpshm.o nullf.o phc.o \ pi.o port.o print.o ptp4l.o raw.o rtnl.o servo.o sk.o stats.o tlv.o \ transport.o tsproc.o udp.o udp6.o uds.o util.o version.o -OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o phc_ctl.o pmc.o pmc_common.o \ +OBJECTS = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o pmc_common.o \ sysoff.o timemaster.o SRC = $(OBJECTS:.o=.c) DEPEND = $(OBJECTS:.o=.d) @@ -46,6 +46,9 @@ all: $(PRG) ptp4l: $(OBJ) +nsm: config.o filter.o hash.o mave.o mmedian.o msg.o nsm.o print.o raw.o \ + rtnl.o sk.o transport.o tlv.o tsproc.o udp.o udp6.o uds.o util.o version.o + pmc: config.o hash.o msg.o pmc.o pmc_common.o print.o raw.o sk.o tlv.o \ transport.o udp.o udp6.o uds.o util.o version.o diff --git a/nsm.c b/nsm.c new file mode 100644 index 0000000..972a4ae --- /dev/null +++ b/nsm.c @@ -0,0 +1,627 @@ +/** + * @file nsm.c + * @brief NSM client program + * @note Copyright (C) 2018 Richard Cochran <ric...@gm...> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <errno.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +#include <arpa/inet.h> + +#include "config.h" +#include "print.h" +#include "rtnl.h" +#include "util.h" +#include "version.h" + +#define IFMT "\n\t\t" +#define NSM_NFD 3 + +struct nsm { + struct config *cfg; + struct fdarray fda; + struct transport *trp; + struct tsproc *tsproc; + struct ptp_message *nsm_delay_req; + struct ptp_message *nsm_delay_resp; + struct ptp_message *nsm_sync; + struct ptp_message *nsm_fup; + struct PortIdentity port_identity; + UInteger16 sequence_id; + const char *name; +} the_nsm; + +static void nsm_help(FILE *fp); +static int nsm_request(struct nsm *nsm, char *target); +static void nsm_reset(struct nsm *nsm); + +static int nsm_command(struct nsm *nsm, const char *cmd) +{ + char action_str[10+1] = {0}, id_str[64+1] = {0}; + + if (0 == strncasecmp(cmd, "HELP", strlen(cmd))) { + nsm_help(stdout); + return 0; + } + if (2 != sscanf(cmd, " %10s %64s", action_str, id_str)) { + pr_err("bad command: %s", cmd); + return -1; + } + if (0 == strncasecmp(action_str, "NSM", strlen(action_str))) { + return nsm_request(nsm, id_str); + } + pr_err("bad command: %s", cmd); + return -1; +} + +static int nsm_complete(struct nsm *nsm) +{ + if (!nsm->nsm_sync) { + return 0; + } + if (one_step(nsm->nsm_sync)) { + return nsm->nsm_delay_resp ? 1 : 0; + } + return (nsm->nsm_delay_resp && nsm->nsm_fup) ? 1 : 0; +} + +static int64_t nsm_compute_offset(struct tsproc *tsp, + struct ptp_message *syn, + struct ptp_message *fup, + struct ptp_message *req, + struct ptp_message *resp) +{ + tmv_t c1, c2, c3, t1, t1c, t2, t3, t4, t4c, offset; + + c1 = correction_to_tmv(syn->header.correction); + c2 = correction_to_tmv(fup->header.correction); + c3 = correction_to_tmv(resp->header.correction); + + t1 = timestamp_to_tmv(fup->ts.pdu); + t2 = timespec_to_tmv(syn->hwts.ts); + t3 = timespec_to_tmv(req->hwts.ts); + t4 = timestamp_to_tmv(resp->ts.pdu); + + t1c = tmv_add(t1, tmv_add(c1, c2)); + t4c = tmv_sub(t4, c3); + + tsproc_reset(tsp, 1); + tsproc_down_ts(tsp, t1c, t2); + tsproc_up_ts(tsp, t3, t4c); + tsproc_update_offset(tsp, &offset, NULL); + + return tmv_to_nanoseconds(offset); +} + +static void nsm_close(struct nsm *nsm) +{ + nsm_reset(nsm); + transport_close(nsm->trp, &nsm->fda); + transport_destroy(nsm->trp); + tsproc_destroy(nsm->tsproc); +} + +static void nsm_handle_msg(struct nsm *nsm, struct ptp_message *msg, FILE *fp) +{ + struct nsm_resp_tlv_head *head; + struct nsm_resp_tlv_foot *foot; + struct timePropertiesDS *tp; + struct PortAddress *paddr; + struct currentDS cds; + struct parentDS *pds; + struct Timestamp ts; + unsigned char *ptr; + int64_t offset; + + if (!nsm->nsm_delay_req) { + return; + } + if (msg->header.sequenceId != + ntohs(nsm->nsm_delay_req->header.sequenceId)) { + return; + } + if (!(msg->header.flagField[0] & UNICAST)) { + return; + } + + switch (msg_type(msg)) { + case SYNC: + if (!nsm->nsm_sync) { + nsm->nsm_sync = msg; + msg_get(msg); + } + break; + case FOLLOW_UP: + if (!nsm->nsm_fup) { + nsm->nsm_fup = msg; + msg_get(msg); + } + break; + case DELAY_RESP: + if (!nsm->nsm_delay_resp) { + nsm->nsm_delay_resp = msg; + msg_get(msg); + } + break; + case DELAY_REQ: + case PDELAY_REQ: + case PDELAY_RESP: + case PDELAY_RESP_FOLLOW_UP: + case ANNOUNCE: + case SIGNALING: + case MANAGEMENT: + return; + } + + if (!nsm_complete(nsm)) { + return; + } + + head = (struct nsm_resp_tlv_head *) nsm->nsm_delay_resp->delay_resp.suffix; + paddr = &head->parent_addr; + + ptr = (unsigned char *) head; + ptr += sizeof(*head) + paddr->addressLength; + foot = (struct nsm_resp_tlv_foot *) ptr; + + pds = &foot->parent; + memcpy(&cds, &foot->current, sizeof(cds)); + tp = &foot->timeprop; + memcpy(&ts, &foot->lastsync, sizeof(ts)); + + offset = nsm_compute_offset(nsm->tsproc, nsm->nsm_sync, nsm->nsm_fup, + nsm->nsm_delay_req, nsm->nsm_delay_resp); + + fprintf(fp, "NSM MEASUREMENT COMPLETE" + IFMT "offset %" PRId64 + IFMT "portState %s" + IFMT "parentPortAddress %hu %s\n", + offset, + ps_str[head->port_state], + head->parent_addr.networkProtocol, + portaddr2str(&head->parent_addr)); + fprintf(fp, "\tparentDataset" + IFMT "parentPortIdentity %s" + IFMT "parentStats %hhu" + IFMT "observedParentOffsetScaledLogVariance 0x%04hx" + IFMT "observedParentClockPhaseChangeRate 0x%08x" + IFMT "grandmasterPriority1 %hhu" + IFMT "gm.ClockClass %hhu" + IFMT "gm.ClockAccuracy 0x%02hhx" + IFMT "gm.OffsetScaledLogVariance 0x%04hx" + IFMT "grandmasterPriority2 %hhu" + IFMT "grandmasterIdentity %s\n", + pid2str(&pds->parentPortIdentity), + pds->parentStats, + pds->observedParentOffsetScaledLogVariance, + pds->observedParentClockPhaseChangeRate, + pds->grandmasterPriority1, + pds->grandmasterClockQuality.clockClass, + pds->grandmasterClockQuality.clockAccuracy, + pds->grandmasterClockQuality.offsetScaledLogVariance, + pds->grandmasterPriority2, + cid2str(&pds->grandmasterIdentity)); + fprintf(fp, "\tcurrentDataset" + IFMT "stepsRemoved %hd" + IFMT "offsetFromMaster %.1f" + IFMT "meanPathDelay %.1f\n", + cds.stepsRemoved, cds.offsetFromMaster / 65536.0, + cds.meanPathDelay / 65536.0); + fprintf(fp, "\ttimePropertiesDataset" + IFMT "currentUtcOffset %hd" + IFMT "leap61 %d" + IFMT "leap59 %d" + IFMT "currentUtcOffsetValid %d" + IFMT "ptpTimescale %d" + IFMT "timeTraceable %d" + IFMT "frequencyTraceable %d" + IFMT "timeSource 0x%02hhx\n", + tp->currentUtcOffset, + tp->flags & LEAP_61 ? 1 : 0, + tp->flags & LEAP_59 ? 1 : 0, + tp->flags & UTC_OFF_VALID ? 1 : 0, + tp->flags & PTP_TIMESCALE ? 1 : 0, + tp->flags & TIME_TRACEABLE ? 1 : 0, + tp->flags & FREQ_TRACEABLE ? 1 : 0, + tp->timeSource); + fprintf(fp, "\tlastSyncTimestamp %" PRId64 ".%09u\n", + ((uint64_t)ts.seconds_lsb) | (((uint64_t)ts.seconds_msb) << 32), + ts.nanoseconds); + + fflush(fp); + nsm_reset(nsm); +} + +static void nsm_help(FILE *fp) +{ + fprintf(fp, "\tSend a NetSync Monitor request to a specific port address:\n"); + fprintf(fp, "\n"); + fprintf(fp, "\tNSM 111.222.333.444\n"); + fprintf(fp, "\tNSM aa:bb:cc:dd:ee:ff\n"); + fprintf(fp, "\n"); +} + +static int nsm_open(struct nsm *nsm, struct config *cfg) +{ + enum transport_type transport; + struct interface *iface; + const char *name; + int count = 0; + + STAILQ_FOREACH(iface, &cfg->interfaces, list) { + rtnl_get_ts_label(iface); + if (iface->ts_label[0] == '\0') { + strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE); + } + count++; + } + if (count != 1) { + pr_err("need exactly one interface"); + return -1; + } + iface = STAILQ_FIRST(&cfg->interfaces); + nsm->name = name = iface->name; + nsm->cfg = cfg; + + transport = config_get_int(cfg, name, "network_transport"); + + if (generate_clock_identity(&nsm->port_identity.clockIdentity, name)) { + pr_err("failed to generate a clock identity"); + return -1; + } + nsm->port_identity.portNumber = 1; + + nsm->tsproc = tsproc_create(TSPROC_RAW, FILTER_MOVING_AVERAGE, 10); + if (!nsm->tsproc) { + pr_err("failed to create time stamp processor"); + goto no_tsproc; + } + nsm->trp = transport_create(cfg, transport); + if (!nsm->trp) { + pr_err("failed to create transport"); + goto no_trans; + } + if (transport_open(nsm->trp, iface, &nsm->fda, + config_get_int(cfg, NULL, "time_stamping"))) { + pr_err("failed to open transport"); + goto open_failed; + } + return 0; + +open_failed: + transport_destroy(nsm->trp); +no_trans: + tsproc_destroy(nsm->tsproc); +no_tsproc: + return -1; +} + +static struct ptp_message *nsm_recv(struct nsm *nsm, int fd) +{ + struct ptp_message *msg; + int cnt, err; + + msg = msg_allocate(); + if (!msg) { + pr_err("low memory"); + return NULL; + } + msg->hwts.type = config_get_int(nsm->cfg, NULL, "time_stamping"); + + cnt = transport_recv(nsm->trp, fd, msg); + if (cnt <= 0) { + pr_err("recv message failed"); + goto failed; + } + err = msg_post_recv(msg, cnt); + if (err) { + switch (err) { + case -EBADMSG: + pr_err("bad message"); + break; + case -ETIME: + pr_err("received %s without timestamp", + msg_type_string(msg_type(msg))); + break; + case -EPROTO: + pr_debug("ignoring message"); + break; + } + goto failed; + } + + return msg; +failed: + msg_put(msg); + return NULL; +} + +static int nsm_request(struct nsm *nsm, char *target) +{ + enum transport_type type = transport_type(nsm->trp); + UInteger8 transportSpecific; + unsigned char mac[MAC_LEN]; + struct in_addr ipv4_addr; + struct ptp_message *msg; + struct tlv_extra *extra; + Integer64 asymmetry; + struct address dst; + int cnt, err; + + memset(&dst, 0, sizeof(dst)); + + switch (type) { + case TRANS_UDS: + case TRANS_UDP_IPV6: + case TRANS_DEVICENET: + case TRANS_CONTROLNET: + case TRANS_PROFINET: + pr_err("sorry, NSM not support with this transport"); + return -1; + case TRANS_UDP_IPV4: + if (!inet_aton(target, &ipv4_addr)) { + pr_err("bad IPv4 address"); + return -1; + } + dst.sin.sin_family = AF_INET; + dst.sin.sin_addr = ipv4_addr; + dst.len = sizeof(dst.sin); + break; + case TRANS_IEEE_802_3: + if (str2mac(target, mac)) { + pr_err("bad Layer-2 address"); + return -1; + } + dst.sll.sll_family = AF_PACKET; + dst.sll.sll_halen = MAC_LEN; + memcpy(&dst.sll.sll_addr, mac, MAC_LEN); + dst.len = sizeof(dst.sll); + break; + } + + msg = msg_allocate(); + if (!msg) { + return -1; + } + + transportSpecific = config_get_int(nsm->cfg, nsm->name, "transportSpecific"); + transportSpecific <<= 4; + + asymmetry = config_get_int(nsm->cfg, nsm->name, "delayAsymmetry"); + asymmetry <<= 16; + + msg->hwts.type = config_get_int(nsm->cfg, NULL, "time_stamping"); + + msg->header.tsmt = DELAY_REQ | transportSpecific; + msg->header.ver = PTP_VERSION; + msg->header.messageLength = sizeof(struct delay_req_msg); + msg->header.domainNumber = config_get_int(nsm->cfg, NULL, "domainNumber"); + msg->header.correction = -asymmetry; + msg->header.sourcePortIdentity = nsm->port_identity; + msg->header.sequenceId = nsm->sequence_id++; + msg->header.control = CTL_DELAY_REQ; + msg->header.logMessageInterval = 0x7f; + + msg->address = dst; + msg->header.flagField[0] |= UNICAST; + + extra = msg_tlv_append(msg, sizeof(struct TLV)); + if (!extra) { + msg_put(msg); + return -ENOMEM; + } + extra->tlv->type = TLV_PTPMON_REQ; + extra->tlv->length = 0; + + err = msg_pre_send(msg); + if (err) { + pr_err("msg_pre_send failed"); + goto out; + } + cnt = transport_sendto(nsm->trp, &nsm->fda, 1, msg); + if (cnt <= 0) { + pr_err("transport_sendto failed"); + err = -1; + goto out; + } + if (msg_sots_missing(msg)) { + pr_err("missing timestamp on transmitted delay request"); + err = -1; + goto out; + } + nsm_reset(nsm); + nsm->nsm_delay_req = msg; + return 0; +out: + msg_put(msg); + return err; +} + +static void nsm_reset(struct nsm *nsm) +{ + if (nsm->nsm_delay_req) { + msg_put(nsm->nsm_delay_req); + } + if (nsm->nsm_delay_resp) { + msg_put(nsm->nsm_delay_resp); + } + if (nsm->nsm_sync) { + msg_put(nsm->nsm_sync); + } + if (nsm->nsm_fup) { + msg_put(nsm->nsm_fup); + } + nsm->nsm_delay_req = NULL; + nsm->nsm_delay_resp = NULL; + nsm->nsm_sync = NULL; + nsm->nsm_fup = NULL; +} + +static void usage(char *progname) +{ + fprintf(stderr, + "\nusage: %s [options]\n\n" + " -f [file] read configuration from 'file'\n" + " -h prints this message and exits\n" + " -i [dev] interface device to use\n" + " -v prints the software version and exits\n" + "\n", + progname); +} + +int main(int argc, char *argv[]) +{ + char *cmd = NULL, *config = NULL, line[1024], *progname; + int c, cnt, err = 0, index, length, tmo = -1; + struct pollfd pollfd[NSM_NFD]; + struct nsm *nsm = &the_nsm; + struct ptp_message *msg; + struct option *opts; + struct config *cfg; + + if (handle_term_signals()) { + return -1; + } + cfg = config_create(); + if (!cfg) { + return -1; + } + opts = config_long_options(cfg); + print_set_verbose(1); + print_set_syslog(0); + + /* Process the command line arguments. */ + progname = strrchr(argv[0], '/'); + progname = progname ? 1+progname : argv[0]; + while (EOF != (c = getopt_long(argc, argv, "f:hi:v", opts, &index))) { + switch (c) { + case 0: + if (config_parse_option(cfg, opts[index].name, optarg)) { + config_destroy(cfg); + return -1; + } + break; + case 'f': + config = optarg; + break; + case 'i': + if (!config_create_interface(optarg, cfg)) { + config_destroy(cfg); + return -1; + } + break; + case 'v': + version_show(stdout); + config_destroy(cfg); + return 0; + case 'h': + usage(progname); + config_destroy(cfg); + return 0; + case '?': + default: + usage(progname); + config_destroy(cfg); + return -1; + } + } + + print_set_syslog(0); + print_set_verbose(1); + + if (config && (err = config_read(config, cfg))) { + goto out; + } + + print_set_progname(progname); + print_set_tag(config_get_string(cfg, NULL, "message_tag")); + print_set_level(config_get_int(cfg, NULL, "logging_level")); + + err = nsm_open(nsm, cfg); + if (err) { + goto out; + } + pollfd[0].fd = nsm->fda.fd[0]; + pollfd[1].fd = nsm->fda.fd[1]; + pollfd[2].fd = STDIN_FILENO; + pollfd[0].events = POLLIN | POLLPRI; + pollfd[1].events = POLLIN | POLLPRI; + pollfd[2].events = POLLIN | POLLPRI; + + while (is_running()) { + cnt = poll(pollfd, NSM_NFD, tmo); + if (cnt < 0) { + if (EINTR == errno) { + continue; + } else { + pr_emerg("poll failed"); + err = -1; + break; + } + } else if (!cnt) { + break; + } + if (pollfd[2].revents & POLLHUP) { + if (tmo == -1) { + /* Wait a bit longer for outstanding replies. */ + tmo = 100; + pollfd[2].fd = -1; + pollfd[2].events = 0; + } else { + break; + } + } + if (pollfd[2].revents & (POLLIN|POLLPRI)) { + if (!fgets(line, sizeof(line), stdin)) { + break; + } + length = strlen(line); + if (length < 2) { + continue; + } + line[length - 1] = 0; + cmd = line; + if (nsm_command(nsm, cmd)) { + pr_err("command failed"); + } + } + if (pollfd[0].revents & (POLLIN|POLLPRI)) { + msg = nsm_recv(nsm, pollfd[0].fd); + if (msg) { + nsm_handle_msg(nsm, msg, stdout); + msg_put(msg); + } + } + if (pollfd[1].revents & (POLLIN|POLLPRI)) { + msg = nsm_recv(nsm, pollfd[1].fd); + if (msg) { + nsm_handle_msg(nsm, msg, stdout); + msg_put(msg); + } + } + } + + nsm_close(nsm); +out: + msg_cleanup(); + config_destroy(cfg); + return err; +} -- 2.11.0 |
From: Anders S. <and...@es...> - 2018-03-05 12:42:10
|
We are programming C, not Java, and so opening braces of a function belong on a line all by themselves. 😉 +static void extract_address(struct ptp_message *m, struct PortAddress *paddr) { static int msg_current(struct ptp_message *m, struct timespec now) { static struct follow_up_info_tlv *follow_up_info_extract(struct ptp_message *m) { +static int port_nsm_reply(struct port *p, struct ptp_message *m) { static int process_delay_req(struct port *p, struct ptp_message *m) { no line break on this: + memcpy(&extra->foot->lastsync, &last_sync, +sizeof(extra->foot->lastsync)); -----Ursprungligt meddelande----- Från: Richard Cochran [mailto:ric...@gm...] Skickat: den 1 mars 2018 20:41 Till: lin...@li... Ämne: [Linuxptp-devel] [PATCH RFC V2 08/11] port: Implement the NetSync Monitor protocol. When NSM is enabled on a given port, that port always replies to a NSM delay request with a delay response, sync, and follow up, regardless of the current state of the port. Signed-off-by: Richard Cochran <ric...@gm...> --- port.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/port.c b/port.c index cc5a09e..52b9282 100644 --- a/port.c +++ b/port.c @@ -126,6 +126,7 @@ struct port { int freq_est_interval; int hybrid_e2e; int min_neighbor_prop_delay; + int net_sync_monitor; int path_trace_enabled; int rx_timestamp_offset; int tx_timestamp_offset; @@ -184,6 +185,29 @@ static int clear_fault_asap(struct fault_interval *faint) return 0; } +static void extract_address(struct ptp_message *m, struct PortAddress +*paddr) { + int len = 0; + + switch (paddr->networkProtocol) { + case TRANS_UDP_IPV4: + len = sizeof(m->address.sin.sin_addr.s_addr); + memcpy(paddr->address, &m->address.sin.sin_addr.s_addr, len); + break; + case TRANS_UDP_IPV6: + len = sizeof(m->address.sin6.sin6_addr.s6_addr); + memcpy(paddr->address, &m->address.sin6.sin6_addr.s6_addr, len); + break; + case TRANS_IEEE_802_3: + len = MAC_LEN; + memcpy(paddr->address, &m->address.sll.sll_addr, len); + break; + default: + return; + } + paddr->addressLength = len; +} + static int msg_current(struct ptp_message *m, struct timespec now) { int64_t t1, t2, tmo; @@ -449,6 +473,67 @@ static int follow_up_info_append(struct port *p, struct ptp_message *m) return 0; } +static int net_sync_resp_append(struct port *p, struct ptp_message *m) +{ + struct timePropertiesDS *tp = clock_time_properties(p->clock); + struct ClockIdentity cid = clock_identity(p->clock), pid; + struct currentDS *cds = clock_current_dataset(p->clock); + struct parent_ds *dad = clock_parent_ds(p->clock); + struct port *best = clock_best_port(p->clock); + struct nsm_resp_tlv_head *head; + struct Timestamp last_sync; + struct PortAddress paddr; + struct ptp_message *tmp; + struct tlv_extra *extra; + unsigned char *ptr; + int tlv_len; + + last_sync = tmv_to_Timestamp(clock_ingress_time(p->clock)); + pid = dad->pds.parentPortIdentity.clockIdentity; + + if (best && memcmp(&cid, &pid, sizeof(cid))) { + /* Extract the parent's protocol address. */ + paddr.networkProtocol = transport_type(best->trp); + paddr.addressLength = + transport_protocol_addr(best->trp, paddr.address); + if (best->best) { + tmp = TAILQ_FIRST(&best->best->messages); + extract_address(tmp, &paddr); + } + } else { + /* We are our own parent. */ + paddr.networkProtocol = transport_type(p->trp); + paddr.addressLength = + transport_protocol_addr(p->trp, paddr.address); + } + + tlv_len = sizeof(*head) + sizeof(*extra->foot) + paddr.addressLength; + + extra = msg_tlv_append(m, tlv_len); + if (!extra) { + return -1; + } + + head = (struct nsm_resp_tlv_head *) extra->tlv; + head->type = TLV_PTPMON_RESP; + head->length = tlv_len - sizeof(head->type) - sizeof(head->length); + head->port_state = p->state == PS_GRAND_MASTER ? PS_MASTER : p->state; + head->parent_addr.networkProtocol = paddr.networkProtocol; + head->parent_addr.addressLength = paddr.addressLength; + memcpy(head->parent_addr.address, paddr.address, paddr.addressLength); + + ptr = (unsigned char *) head; + ptr += sizeof(*head) + paddr.addressLength; + extra->foot = (struct nsm_resp_tlv_foot *) ptr; + + memcpy(&extra->foot->parent, &dad->pds, sizeof(extra->foot->parent)); + memcpy(&extra->foot->current, cds, sizeof(extra->foot->current)); + memcpy(&extra->foot->timeprop, tp, sizeof(extra->foot->timeprop)); + memcpy(&extra->foot->lastsync, &last_sync, +sizeof(extra->foot->lastsync)); + + return 0; +} + static struct follow_up_info_tlv *follow_up_info_extract(struct ptp_message *m) { struct follow_up_info_tlv *f; @@ -677,6 +762,27 @@ static int port_ignore(struct port *p, struct ptp_message *m) return 0; } +static int port_nsm_reply(struct port *p, struct ptp_message *m) { + struct tlv_extra *extra; + + if (!p->net_sync_monitor) { + return 0; + } + if (!p->hybrid_e2e) { + return 0; + } + if (!(m->header.flagField[0] & UNICAST)) { + return 0; + } + TAILQ_FOREACH(extra, &m->tlv_list, list) { + if (extra->tlv->type == TLV_PTPMON_REQ) { + return 1; + } + } + return 0; +} + /* * Test whether a 802.1AS port may transmit a sync message. */ @@ -1662,10 +1768,12 @@ static int process_announce(struct port *p, struct ptp_message *m) static int process_delay_req(struct port *p, struct ptp_message *m) { + int err, nsm, saved_seqnum_sync; struct ptp_message *msg; - int err; - if (p->state != PS_MASTER && p->state != PS_GRAND_MASTER) + nsm = port_nsm_reply(p, m); + + if (!nsm && p->state != PS_MASTER && p->state != PS_GRAND_MASTER) return 0; if (p->delayMechanism == DM_P2P) { @@ -1698,10 +1806,23 @@ static int process_delay_req(struct port *p, struct ptp_message *m) msg->header.flagField[0] |= UNICAST; msg->header.logMessageInterval = 0x7f; } - + if (nsm && net_sync_resp_append(p, msg)) { + pr_err("port %hu: append NSM failed", portnum(p)); + err = -1; + goto out; + } err = port_prepare_and_send(p, msg, 0); - if (err) + if (err) { pr_err("port %hu: send delay response failed", portnum(p)); + goto out; + } + if (nsm) { + saved_seqnum_sync = p->seqnum.sync; + p->seqnum.sync = m->header.sequenceId; + err = port_tx_sync(p, &m->address); + p->seqnum.sync = saved_seqnum_sync; + } +out: msg_put(msg); return err; } @@ -2728,6 +2849,9 @@ struct port *port_open(int phc_index, if (p->hybrid_e2e && p->delayMechanism != DM_E2E) { pr_warning("port %d: hybrid_e2e only works with E2E", number); } + if (p->net_sync_monitor && !p->hybrid_e2e) { + pr_warning("port %d: net_sync_monitor needs hybrid_e2e", number); + } /* Set fault timeouts to a default value */ for (i = 0; i < FT_CNT; i++) { -- 2.11.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linuxptp-devel mailing list Lin...@li... https://lists.sourceforge.net/lists/listinfo/linuxptp-devel |
From: Anders S. <and...@es...> - 2018-03-05 13:00:15
|
Shouldn't this be moved also from pmc.c to util: static char *bin2str(Octet *data, int len) { static char buf[BIN_BUF_SIZE]; return bin2str_impl(data, len, buf, sizeof(buf)); } /Anders -----Ursprungligt meddelande----- Från: Richard Cochran [mailto:ric...@gm...] Skickat: den 1 mars 2018 20:41 Till: lin...@li... Ämne: [Linuxptp-devel] [PATCH RFC V2 10/11] util: Relocate utility functions from pmc.c. The file, pmc.c, contains utility functions for printing out a port address structure. We will want to call these functions from pmc_common.c, and so this patch moves the utility functions where they belong. Signed-off-by: Richard Cochran <ric...@gm...> --- pmc.c | 48 ------------------------------------------------ util.c | 39 +++++++++++++++++++++++++++++++++++++++ util.h | 15 +++++++++++++++ 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/pmc.c b/pmc.c index fde2449..7c96a4d 100644 --- a/pmc.c +++ b/pmc.c @@ -127,60 +127,12 @@ static char *text2str(struct PTPText *text) return (char*)(s.text); } -#define MAX_PRINT_BYTES 16 -#define BIN_BUF_SIZE (MAX_PRINT_BYTES * 3 + 1) - -static char *bin2str_impl(Octet *data, int len, char *buf, int buf_len) -{ - int i, offset = 0; - if (len > MAX_PRINT_BYTES) - len = MAX_PRINT_BYTES; - buf[0] = '\0'; - if (!data) - return buf; - if (len) - offset += snprintf(buf, buf_len, "%02hhx", data[0]); - for (i = 1; i < len; i++) { - if (offset >= buf_len) - /* truncated output */ - break; - offset += snprintf(buf + offset, buf_len - offset, ":%02hhx", data[i]); - } - return buf; -} - static char *bin2str(Octet *data, int len) { static char buf[BIN_BUF_SIZE]; return bin2str_impl(data, len, buf, sizeof(buf)); } -static uint16_t align16(uint16_t *p) -{ - uint16_t v; - memcpy(&v, p, sizeof(v)); - return v; -} - -static char *portaddr2str(struct PortAddress *addr) -{ - static char buf[BIN_BUF_SIZE]; - switch(align16(&addr->networkProtocol)) { - case TRANS_UDP_IPV4: - if (align16(&addr->addressLength) == 4 - && inet_ntop(AF_INET, addr->address, buf, sizeof(buf))) - return buf; - break; - case TRANS_UDP_IPV6: - if (align16(&addr->addressLength) == 16 - && inet_ntop(AF_INET6, addr->address, buf, sizeof(buf))) - return buf; - break; - } - bin2str_impl(addr->address, align16(&addr->addressLength), buf, sizeof(buf)); - return buf; -} - static void pmc_show(struct ptp_message *msg, FILE *fp) { int action; diff --git a/util.c b/util.c index 62f2638..2eacafc 100644 --- a/util.c +++ b/util.c @@ -16,6 +16,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <arpa/inet.h> #include <errno.h> #include <signal.h> #include <stdarg.h> @@ -68,6 +69,25 @@ const char *ev_str[] = { "RS_PASSIVE", }; +char *bin2str_impl(Octet *data, int len, char *buf, int buf_len) { + int i, offset = 0; + if (len > MAX_PRINT_BYTES) + len = MAX_PRINT_BYTES; + buf[0] = '\0'; + if (!data) + return buf; + if (len) + offset += snprintf(buf, buf_len, "%02hhx", data[0]); + for (i = 1; i < len; i++) { + if (offset >= buf_len) + /* truncated output */ + break; + offset += snprintf(buf + offset, buf_len - offset, ":%02hhx", data[i]); + } + return buf; +} + char *cid2str(struct ClockIdentity *id) { static char buf[64]; @@ -100,6 +120,25 @@ char *pid2str(struct PortIdentity *id) return buf; } +char *portaddr2str(struct PortAddress *addr) { + static char buf[BIN_BUF_SIZE]; + switch (align16(&addr->networkProtocol)) { + case TRANS_UDP_IPV4: + if (align16(&addr->addressLength) == 4 + && inet_ntop(AF_INET, addr->address, buf, sizeof(buf))) + return buf; + break; + case TRANS_UDP_IPV6: + if (align16(&addr->addressLength) == 16 + && inet_ntop(AF_INET6, addr->address, buf, sizeof(buf))) + return buf; + break; + } + bin2str_impl(addr->address, align16(&addr->addressLength), buf, sizeof(buf)); + return buf; +} + int str2mac(const char *s, unsigned char mac[MAC_LEN]) { unsigned char buf[MAC_LEN]; diff --git a/util.h b/util.h index 0c1a357..41fbdb2 100644 --- a/util.h +++ b/util.h @@ -20,11 +20,15 @@ #ifndef HAVE_UTIL_H #define HAVE_UTIL_H +#include <string.h> #include <time.h> #include "ddt.h" #include "ether.h" +#define MAX_PRINT_BYTES 16 +#define BIN_BUF_SIZE (MAX_PRINT_BYTES * 3 + 1) + /** * Table of human readable strings, one for each port state. */ @@ -35,6 +39,15 @@ extern const char *ps_str[]; */ extern const char *ev_str[]; +static inline uint16_t align16(uint16_t *p) { + uint16_t v; + memcpy(&v, p, sizeof(v)); + return v; +} + +char *bin2str_impl(Octet *data, int len, char *buf, int buf_len); + /** * Convert a clock identity into a human readable string. * @@ -65,6 +78,8 @@ int count_char(const char *str, char c); */ char *pid2str(struct PortIdentity *id); +char *portaddr2str(struct PortAddress *addr); + /** * Scan a string containing a MAC address and convert it into binary form. * -- 2.11.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linuxptp-devel mailing list Lin...@li... https://lists.sourceforge.net/lists/listinfo/linuxptp-devel |
From: Richard C. <ric...@gm...> - 2018-03-06 23:02:05
|
On Mon, Mar 05, 2018 at 01:00:03PM +0000, Anders Selhammer wrote: > Shouldn't this be moved also from pmc.c to util: No, we only move code when we have to. That function is not (yet) needed outside of pmc.c. Thanks, Richard |
From: Richard C. <ric...@gm...> - 2018-03-05 14:59:20
|
On Mon, Mar 05, 2018 at 12:41:56PM +0000, Anders Selhammer wrote: > We are programming C, not Java, and so opening braces of a function belong on a line all by themselves. And they all are. Where is the problem? > +static void extract_address(struct ptp_message *m, struct PortAddress *paddr) { > static int msg_current(struct ptp_message *m, struct timespec now) { > static struct follow_up_info_tlv *follow_up_info_extract(struct ptp_message *m) { > +static int port_nsm_reply(struct port *p, struct ptp_message *m) { > static int process_delay_req(struct port *p, struct ptp_message *m) { ^^^ no idea where you got this from. > no line break on this: > + memcpy(&extra->foot->lastsync, &last_sync, > +sizeof(extra->foot->lastsync)); I appreciate your taking the effort to review the series. However, in the future, please do not top-post! Instead, comment directly in-line, and trim the reply to remove any patch hunks that are not being commented upon. Thanks, Richard |
From: Anders S. <and...@es...> - 2018-03-06 08:04:56
|
>I appreciate your taking the effort to review the series. However, in the future, please do not top-post! >Instead, comment directly in-line, and trim the reply to remove any patch hunks that are not being commented upon. Ok, I will comment inline in the future, sorry about that. >> +static void extract_address(struct ptp_message *m, struct PortAddress >> +*paddr) { >> static int msg_current(struct ptp_message *m, struct timespec now) { >> static struct follow_up_info_tlv *follow_up_info_extract(struct >> ptp_message *m) { >> +static int port_nsm_reply(struct port *p, struct ptp_message *m) { >> static int process_delay_req(struct port *p, struct ptp_message *m) { >^^^ no idea where you got this from. I got them all from PATCH RFC V2 08/11 sent to me by mail, just did copy and pasted on the top. If there is something that is mismatched with your implementation I cannot say. Normally this probably have slipped since I´ve seen a mixture of the two implementations, with or without linebreak, but since you last week sent a patch with these coding style updates, I spotted it. >> no line break on this: >> + memcpy(&extra->foot->lastsync, &last_sync, >> +sizeof(extra->foot->lastsync)); Above lines in a single line would be shorter than some other lines above. Easier to read without line break. Btw, I was just looking at this Netsync Monitoring myself and was surprised that you, the same week, implemented it. Got a question from Meinberg to implement it if I could/had time and I was planning to start the coding this week😊 I think the solution overall was nicely implemented. I will have a closer look at it when I can have all the changes infront of me and a can switch between all the files. I think that’s easier. Sorry if there were some incorrect comments. // Anders |
From: Richard C. <ric...@gm...> - 2018-03-06 13:48:11
|
On Tue, Mar 06, 2018 at 08:04:45AM +0000, Anders Selhammer wrote: > I got them all from PATCH RFC V2 08/11 sent to me by mail, just did > copy and pasted on the top. If there is something that is mismatched > with your implementation I cannot say. It appears that like your mail client is mangling patches. Look at this: https://www.mail-archive.com/lin...@li.../msg02391.html See the opening brace on extract_address() on a line all by itself? Thanks, Richard |
From: Richard C. <ric...@gm...> - 2018-03-08 15:03:54
|
On Thu, Mar 08, 2018 at 08:07:26AM +0000, Anders Selhammer wrote: > I reviewed it in outlook, but now when I open it in windows 10 built in client, it all look as it should. I strongly suggest getting a different email client. If your MTA is exchange, then you will have to create an outside email account, because exchange cannot send plain text messages correctly. See: linux/Documentation/process/email-clients.rst (Actually Gmail does work if you use the IMAP service. It is the web interface that does not work for sending patches.) > Is it possible to add the link to the patch in the mail archive in the end of the mail also? No, simply because the archive URL is not known at the time of transmission. Thanks, Richard |
From: Richard C. <ric...@gm...> - 2018-01-02 04:05:59
|
We indent with tabs, not spaces. Signed-off-by: Richard Cochran <ric...@gm...> --- pmc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pmc.c b/pmc.c index af9cc63..49282a6 100644 --- a/pmc.c +++ b/pmc.c @@ -233,19 +233,19 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) IFMT "physicalAddress %s" IFMT "protocolAddress %hu %s", align16(cd->clockType), - text2str(cd->physicalLayerProtocol), + text2str(cd->physicalLayerProtocol), bin2str(cd->physicalAddress->address, - align16(&cd->physicalAddress->length)), + align16(&cd->physicalAddress->length)), align16(&cd->protocolAddress->networkProtocol), portaddr2str(cd->protocolAddress)); fprintf(fp, IFMT "manufacturerId %s" - IFMT "productDescription %s", + IFMT "productDescription %s", bin2str(cd->manufacturerIdentity, OUI_LEN), text2str(cd->productDescription)); fprintf(fp, IFMT "revisionData %s", - text2str(cd->revisionData)); + text2str(cd->revisionData)); fprintf(fp, IFMT "userDescription %s" - IFMT "profileId %s", + IFMT "profileId %s", text2str(cd->userDescription), bin2str(cd->profileIdentity, PROFILE_ID_LEN)); break; -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-01-02 04:06:00
|
We always but braces around 'if' blocks. Signed-off-by: Richard Cochran <ric...@gm...> --- port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/port.c b/port.c index d8e29d5..b2647d3 100644 --- a/port.c +++ b/port.c @@ -2432,8 +2432,9 @@ int port_prepare_and_send(struct port *p, struct ptp_message *msg, int event) { int cnt; - if (msg_pre_send(msg)) + if (msg_pre_send(msg)) { return -1; + } if (msg->header.flagField[0] & UNICAST) { cnt = transport_sendto(p->trp, &p->fda, event, msg); } else { -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-01-02 04:06:01
|
We are programming C, not Java, and so opening braces of a function belong on a line all by themselves. Signed-off-by: Richard Cochran <ric...@gm...> --- tlv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tlv.c b/tlv.c index cef10a0..a5c2eb3 100644 --- a/tlv.c +++ b/tlv.c @@ -43,7 +43,8 @@ static void scaled_ns_h2n(ScaledNs *sns) sns->fractional_nanoseconds = htons(sns->fractional_nanoseconds); } -static uint16_t flip16(uint16_t *p) { +static uint16_t flip16(uint16_t *p) +{ uint16_t v; memcpy(&v, p, sizeof(v)); v = htons(v); -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-01-02 04:06:02
|
The NetSync Monitor protocol features a TLV with a length of zero. Our input message parsing assumes that every TLV will have some sort of payload, and up until now this was true. This patch adjusts the parsing code to accept TLVs of length zero. Signed-off-by: Richard Cochran <ric...@gm...> --- msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msg.c b/msg.c index 4b3d926..11ee730 100644 --- a/msg.c +++ b/msg.c @@ -126,7 +126,7 @@ static int suffix_post_recv(uint8_t *ptr, int len, struct tlv_extra *last) if (!ptr) return 0; - for (cnt = 0; len > sizeof(struct TLV); cnt++) { + for (cnt = 0; len >= sizeof(struct TLV); cnt++) { tlv = (struct TLV *) ptr; tlv->type = ntohs(tlv->type); tlv->length = ntohs(tlv->length); -- 2.11.0 |
From: Richard C. <ric...@gm...> - 2018-01-02 04:06:03
|
Any code that wants to call one_step() needs to link with the static global 'assume_two_step'. This patch moves that variable's definition from ptp4l.c to msg.c. Not only is that file the more natural choice (since the variable is used on msg.h) but also this allows other programs to call the one_step() function. Signed-off-by: Richard Cochran <ric...@gm...> --- msg.c | 2 ++ ptp4l.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/msg.c b/msg.c index 11ee730..29af416 100644 --- a/msg.c +++ b/msg.c @@ -32,6 +32,8 @@ #define VERSION_MASK 0x0f #define VERSION 0x02 +int assume_two_step = 0; + /* * Head room fits a VLAN Ethernet header, and 'msg' is 64 bit aligned. */ diff --git a/ptp4l.c b/ptp4l.c index f01ff6f..ee31718 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -36,8 +36,6 @@ #include "util.h" #include "version.h" -int assume_two_step = 0; - static void usage(char *progname) { fprintf(stderr, -- 2.11.0 |