Thread: Re: [Linuxptp-devel] [PATCHv3 08/10] ptp4l: use ts label to get ts info (Page 4)
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
From: Hangbin L. <liu...@gm...> - 2017-09-10 14:32:26
|
Hi Richard, On Wed, Aug 16, 2017 at 09:32:09PM +0800, Hangbin Liu wrote: > @@ -2240,6 +2243,35 @@ static void port_link_status(void *ctx, int linkup, int ts_index) > pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down"); > } > > + /* ts_label changed */ > + if (if_indextoname(ts_index, ts_label) && strcmp(p->iface->ts_label, ts_label)) { > + strncpy(p->iface->ts_label, ts_label, MAX_IFNAME_SIZE); > + sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info); > + > + p->link_status |= TS_LABEL_CHANGED; > + pr_notice("port %hu: ts label changed to %s", portnum(p), ts_label); > + } > + > + /* We set the link status to down by force if its timestamp not > + * support required mode. But the link's status is actually up. > + * > + * So the next time we receive this link's rtnl message, we need > + * to check the required_modes again. If still not support > + * required_modes, then keep the link status down. > + */ > + if (p->iface->ts_info.valid) { > + required_modes = clock_required_modes(p->clock); > + if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) { > + pr_err("interface '%s' does not support requested " > + "timestamping mode, set link status down by force.", > + p->iface->ts_label); > + p->link_status = LINK_DOWN | LINK_STATE_CHANGED; > + } else if (p->link_status & TS_LABEL_CHANGED) { > + p->phc_index = p->iface->ts_info.phc_index; > + clock_switch_phc(p->clock, p->phc_index); > + } > + } > + FYI, I will changed this part with new version like: + /* ts_label changed */ + if (if_indextoname(ts_index, ts_label) && strcmp(p->iface->ts_label, ts_label)) { + strncpy(p->iface->ts_label, ts_label, MAX_IFNAME_SIZE); + p->link_status |= TS_LABEL_CHANGED; + pr_notice("port %hu: ts label changed to %s", portnum(p), ts_label); + } + + /* Both link down/up and change ts_label may change phc index. */ + if (p->link_status & LINK_UP && + (p->link_status & LINK_STATE_CHANGED || p->link_status & TS_LABEL_CHANGED)) { + sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info); + + if (p->iface->ts_info.valid) { + required_modes = clock_required_modes(p->clock); + if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) { + pr_err("interface '%s' does not support requested " + "timestamping mode, set link status down by force.", + p->iface->ts_label); + p->link_status = LINK_DOWN | LINK_STATE_CHANGED; + } else if (p->phc_index != p->iface->ts_info.phc_index) { + p->phc_index = p->iface->ts_info.phc_index; + + if (clock_switch_phc(p->clock, p->phc_index)) { + p->last_fault_type = FT_SWITCH_PHC; + port_dispatch(p, EV_FAULT_DETECTED, 0); + return; + } + clock_sync_interval(p->clock, p->log_sync_interval); + } + } + } + Thanks Hangbin |
From: Hangbin L. <liu...@gm...> - 2017-08-16 13:33:23
|
Pass struct interface so we can use ts_iface in HW filter. Signed-off-by: Hangbin Liu <liu...@gm...> --- pmc_common.c | 5 ++++- port.c | 4 ++-- raw.c | 5 +++-- transport.c | 4 ++-- transport.h | 3 ++- transport_private.h | 4 ++-- udp.c | 7 ++++--- udp6.c | 7 ++++--- uds.c | 3 ++- 9 files changed, 25 insertions(+), 17 deletions(-) diff --git a/pmc_common.c b/pmc_common.c index d92b0cd..447cf99 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -67,6 +67,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, int zero_datalen) { struct pmc *pmc; + struct interface iface; pmc = calloc(1, sizeof *pmc); if (!pmc) @@ -90,7 +91,9 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, pr_err("failed to create transport"); goto failed; } - if (transport_open(pmc->transport, iface_name, + + strncpy(iface.name, iface_name, MAX_IFNAME_SIZE); + if (transport_open(pmc->transport, &iface, &pmc->fdarray, TS_SOFTWARE)) { pr_err("failed to open transport"); goto failed; diff --git a/port.c b/port.c index 5f638c0..e4a1cc6 100644 --- a/port.c +++ b/port.c @@ -1504,7 +1504,7 @@ static int port_initialize(struct port *p) goto no_timers; } } - if (transport_open(p->trp, p->name, &p->fda, p->timestamping)) + if (transport_open(p->trp, p->iface, &p->fda, p->timestamping)) goto no_tropen; for (i = 0; i < N_TIMER_FDS; i++) { @@ -1547,7 +1547,7 @@ static int port_renew_transport(struct port *p) } transport_close(p->trp, &p->fda); port_clear_fda(p, FD_ANNOUNCE_TIMER); - res = transport_open(p->trp, p->name, &p->fda, p->timestamping); + res = transport_open(p->trp, p->iface, &p->fda, p->timestamping); /* Need to call clock_fda_changed even if transport_open failed in * order to update clock to the now closed descriptors. */ clock_fda_changed(p->clock); diff --git a/raw.c b/raw.c index 73e45b4..8b7bcf1 100644 --- a/raw.c +++ b/raw.c @@ -198,15 +198,16 @@ static void addr_to_mac(void *mac, struct address *addr) memcpy(mac, &addr->sll.sll_addr, MAC_LEN); } -static int raw_open(struct transport *t, const char *name, +static int raw_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type ts_type) { struct raw *raw = container_of(t, struct raw, t); unsigned char ptp_dst_mac[MAC_LEN]; unsigned char p2p_dst_mac[MAC_LEN]; int efd, gfd; - char *str; + char *str, *name; + name = iface->ts_label; str = config_get_string(t->cfg, name, "ptp_dst_mac"); if (str2mac(str, ptp_dst_mac)) { pr_err("invalid ptp_dst_mac %s", str); diff --git a/transport.c b/transport.c index d24c05b..3541394 100644 --- a/transport.c +++ b/transport.c @@ -31,10 +31,10 @@ int transport_close(struct transport *t, struct fdarray *fda) return t->close(t, fda); } -int transport_open(struct transport *t, const char *name, +int transport_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt) { - return t->open(t, name, fda, tt); + return t->open(t, iface, fda, tt); } int transport_recv(struct transport *t, int fd, struct ptp_message *msg) diff --git a/transport.h b/transport.h index 5d6ba98..15616bb 100644 --- a/transport.h +++ b/transport.h @@ -27,6 +27,7 @@ #include "msg.h" struct config; +struct interface; /* Values from networkProtocol enumeration 7.4.1 Table 3 */ enum transport_type { @@ -54,7 +55,7 @@ struct transport; int transport_close(struct transport *t, struct fdarray *fda); -int transport_open(struct transport *t, const char *name, +int transport_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt); int transport_recv(struct transport *t, int fd, struct ptp_message *msg); diff --git a/transport_private.h b/transport_private.h index b54f32a..7530896 100644 --- a/transport_private.h +++ b/transport_private.h @@ -32,8 +32,8 @@ struct transport { int (*close)(struct transport *t, struct fdarray *fda); - int (*open)(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type tt); + int (*open)(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type tt); int (*recv)(struct transport *t, int fd, void *buf, int buflen, struct address *addr, struct hw_timestamp *hwts); diff --git a/udp.c b/udp.c index 530a2ee..05c2ba0 100644 --- a/udp.c +++ b/udp.c @@ -152,12 +152,13 @@ enum { MC_PRIMARY, MC_PDELAY }; static struct in_addr mcast_addr[2]; -static int udp_open(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type ts_type) +static int udp_open(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type ts_type) { struct udp *udp = container_of(t, struct udp, t); uint8_t event_dscp, general_dscp; int efd, gfd, ttl; + char *name = iface->name; ttl = config_get_int(t->cfg, name, "udp_ttl"); udp->mac.len = 0; @@ -180,7 +181,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda, if (gfd < 0) goto no_general; - if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4)) + if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV4)) goto no_timestamping; if (sk_general_init(gfd)) diff --git a/udp6.c b/udp6.c index 89e27bf..7551e3f 100644 --- a/udp6.c +++ b/udp6.c @@ -160,12 +160,13 @@ enum { MC_PRIMARY, MC_PDELAY }; static struct in6_addr mc6_addr[2]; -static int udp6_open(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type ts_type) +static int udp6_open(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type ts_type) { struct udp6 *udp6 = container_of(t, struct udp6, t); uint8_t event_dscp, general_dscp; int efd, gfd, hop_limit; + char *name = iface->name; hop_limit = config_get_int(t->cfg, name, "udp_ttl"); udp6->mac.len = 0; @@ -190,7 +191,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda, if (gfd < 0) goto no_general; - if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6)) + if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV6)) goto no_timestamping; if (sk_general_init(gfd)) diff --git a/uds.c b/uds.c index d5e8f50..7e11f63 100644 --- a/uds.c +++ b/uds.c @@ -52,13 +52,14 @@ static int uds_close(struct transport *t, struct fdarray *fda) return 0; } -static int uds_open(struct transport *t, const char *name, struct fdarray *fda, +static int uds_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt) { int fd, err; struct sockaddr_un sa; struct uds *uds = container_of(t, struct uds, t); char *uds_path = config_get_string(t->cfg, NULL, "uds_address"); + char *name = iface->name; fd = socket(AF_LOCAL, SOCK_DGRAM, 0); if (fd < 0) { -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-08-16 13:33:25
|
Signed-off-by: Hangbin Liu <liu...@gm...> --- phc2sys.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- port.c | 2 +- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index b6f6719..35df731 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -128,6 +128,11 @@ static int clock_handle_leap(struct node *node, struct clock *clock, static int run_pmc_get_utc_offset(struct node *node, int timeout); static void run_pmc_events(struct node *node); +static int normalize_state(int state); +static int run_pmc_port_properties(struct node *node, int timeout, + unsigned int port, + int *state, int *tstamping, char *iface); + static clockid_t clock_open(char *device, int *phc_index) { struct sk_ts_info ts_info; @@ -294,8 +299,47 @@ static struct port *port_add(struct node *node, unsigned int number, return p; } -static void clock_reinit(struct clock *clock) +static void clock_reinit(struct node *node, struct clock *clock) { + struct port *p; + int state, timestamping, ret; + int phc_index = -1; + char iface[IFNAMSIZ]; + clockid_t clkid = CLOCK_INVALID; + + LIST_FOREACH(p, &node->ports, list) { + if (p->clock == clock) { + ret = run_pmc_port_properties(node, 1000, p->number, + &state, ×tamping, + iface); + if (ret == -1) { + /* port does not exist, ignore the port */ + continue; + } + if (ret <= 0) { + pr_err("failed to get port properties"); + return; + } + if (timestamping == TS_SOFTWARE) { + /* ignore ports with software time stamping */ + continue; + } + + p->state = normalize_state(state); + } + } + + if (strcmp(clock->device, iface)) { + free(clock->device); + clock->device = strdup(iface); + clkid = clock_open(clock->device, &phc_index); + if (clkid == CLOCK_INVALID) + return; + phc_close(clock->clkid); + clock->clkid = clkid; + clock->phc_index = phc_index; + } + servo_reset(clock->servo); clock->servo_state = SERVO_UNLOCKED; @@ -322,7 +366,7 @@ static void reconfigure(struct node *node) if (c->new_state) { if (c->new_state == PS_MASTER) - clock_reinit(c); + clock_reinit(node, c); c->state = c->new_state; c->new_state = 0; @@ -388,7 +432,7 @@ static void reconfigure(struct node *node) } else if (rt) { if (rt->state != PS_MASTER) { rt->state = PS_MASTER; - clock_reinit(rt); + clock_reinit(node, rt); } pr_info("selecting %s for synchronization", rt->device); } diff --git a/port.c b/port.c index e4a1cc6..134f5b4 100644 --- a/port.c +++ b/port.c @@ -861,7 +861,7 @@ static int port_management_fill_response(struct port *target, else ppn->port_state = target->state; ppn->timestamping = target->timestamping; - ptp_text_set(&ppn->interface, target->name); + ptp_text_set(&ppn->interface, target->iface->ts_label); datalen = sizeof(*ppn) + ppn->interface.length; respond = 1; break; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-08-17 09:37:48
|
Hi Richard, Today I get two machines that support HW timestamp. After more testing, I find some issues. The first one is as follows. On Wed, Aug 16, 2017 at 09:32:11PM +0800, Hangbin Liu wrote: > -static void clock_reinit(struct clock *clock) > +static void clock_reinit(struct node *node, struct clock *clock) > { > + struct port *p; > + int state, timestamping, ret; int state, timestamping, ret = -1; > + int phc_index = -1; > + char iface[IFNAMSIZ]; > + clockid_t clkid = CLOCK_INVALID; > + > + LIST_FOREACH(p, &node->ports, list) { > + if (p->clock == clock) { > + ret = run_pmc_port_properties(node, 1000, p->number, > + &state, ×tamping, > + iface); > + if (ret == -1) { > + /* port does not exist, ignore the port */ > + continue; > + } > + if (ret <= 0) { > + pr_err("failed to get port properties"); > + return; > + } > + if (timestamping == TS_SOFTWARE) { > + /* ignore ports with software time stamping */ > + continue; > + } > + > + p->state = normalize_state(state); > + } > + } > + > + if (strcmp(clock->device, iface)) { If no clock find or run_pmc_port_properties() return -1, the iface will be random strings since it's not initialized. Then strcmp will return none zero and set clock->device to wrong iface. So we should init ret and make sure run_pmc_port_properties() returns correct. if (ret != -1 && strcmp(clock->device, iface)) { > + free(clock->device); > + clock->device = strdup(iface); > + clkid = clock_open(clock->device, &phc_index); > + if (clkid == CLOCK_INVALID) > + return; > + phc_close(clock->clkid); > + clock->clkid = clkid; > + clock->phc_index = phc_index; > + } > + > servo_reset(clock->servo); > clock->servo_state = SERVO_UNLOCKED; The second issue is after failover, the offset will be very large. I'm still investigating how to fix it. Maybe increase step_threshold? I will wait for your comments about other issues and fix them toghther. Thanks Hangbin |
From: Hangbin L. <liu...@gm...> - 2017-09-10 14:36:58
|
On Wed, Aug 16, 2017 at 09:32:11PM +0800, Hangbin Liu wrote: > -static void clock_reinit(struct clock *clock) > +static void clock_reinit(struct node *node, struct clock *clock) > { > + struct port *p; > + int state, timestamping, ret; > + int phc_index = -1; > + char iface[IFNAMSIZ]; > + clockid_t clkid = CLOCK_INVALID; > + > + LIST_FOREACH(p, &node->ports, list) { > + if (p->clock == clock) { > + ret = run_pmc_port_properties(node, 1000, p->number, > + &state, ×tamping, > + iface); > + if (ret == -1) { > + /* port does not exist, ignore the port */ > + continue; > + } > + if (ret <= 0) { > + pr_err("failed to get port properties"); > + return; > + } > + if (timestamping == TS_SOFTWARE) { > + /* ignore ports with software time stamping */ > + continue; > + } > + > + p->state = normalize_state(state); > + } > + } > + > + if (strcmp(clock->device, iface)) { > + free(clock->device); > + clock->device = strdup(iface); > + clkid = clock_open(clock->device, &phc_index); > + if (clkid == CLOCK_INVALID) > + return; > + phc_close(clock->clkid); > + clock->clkid = clkid; > + clock->phc_index = phc_index; > + } > + > servo_reset(clock->servo); > clock->servo_state = SERVO_UNLOCKED; This part will be changed to + + if (ret != -1) { + /* Check if device changed */ + if (strcmp(clock->device, iface)) { + free(clock->device); + clock->device = strdup(iface); + } + /* Check if phc index changed */ + if (!sk_get_ts_info(clock->device, &ts_info) && + clock->phc_index != ts_info.phc_index) { + clkid = clock_open(clock->device, &phc_index); + if (clkid == CLOCK_INVALID) + return; + phc_close(clock->clkid); + clock->clkid = clkid; + clock->phc_index = phc_index; + } + } + servo_reset(clock->servo); clock->servo_state = SERVO_UNLOCKED; + servo_sync_interval(clock->servo, 1); That's what I have mainly chaned so far. If more stuff changed, I will add them in the cover letter. Thanks Hangbin |
From: Hangbin L. <liu...@gm...> - 2017-09-11 08:49:24
|
On Wed, Aug 16, 2017 at 09:32:11PM +0800, Hangbin Liu wrote: > @@ -322,7 +366,7 @@ static void reconfigure(struct node *node) > > if (c->new_state) { > if (c->new_state == PS_MASTER) Another issue here. When we run phc2sys in slave mode and phc index changed (normal link down/up or bond fail over). we also need do clock_reinit(). Or we will get error like ioctl PTP_SYS_OFFSET: No such device So the check should be if (c->new_state == PS_MASTER || c->new_state == PS_SLAVE) I will add this fix in new version patch set. > - clock_reinit(c); > + clock_reinit(node, c); > > c->state = c->new_state; > c->new_state = 0; Thanks Hangbin |
From: Richard C. <ric...@gm...> - 2017-08-27 15:05:45
|
On Wed, Aug 16, 2017 at 09:32:05PM +0800, Hangbin Liu wrote: > @@ -31,6 +31,9 @@ > > static int rtnl_len; > static char *rtnl_buf; > +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len); > +#define rtnl_nested_rtattr_parse(tb, max, rta) \ > + (rtnl_rtattr_parse((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) Instead of a #define, why not a static inline function? > @@ -84,15 +87,69 @@ int rtnl_link_query(int fd, char *device) > return 0; > } > > -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) > +static inline __u32 rta_getattr_u32(const struct rtattr *rta) > { > - int index, len; > + return *(__u32 *)RTA_DATA(rta); > +} > + > +static inline const char *rta_getattr_str(const struct rtattr *rta) > +{ > + return (const char *)RTA_DATA(rta); > +} > + > +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) > +{ > + unsigned short type; > + > + memset(tb, 0, sizeof(struct rtattr *) * max); > + while (RTA_OK(rta, len)) { > + type = rta->rta_type; > + if ((type <= max) && (!tb[type])) Test should be (type < max) because 'tb[]' has length 'max' and tb[max] is out of bounds. > + tb[type] = rta; > + rta = RTA_NEXT(rta, len); > + } > + if (len) > + pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len); > + return 0; > +} > + > +static int rtnl_linkinfo_parse(struct rtattr *rta) > +{ > + int index = -1; > + const char *kind; > + struct rtattr *linkinfo[IFLA_INFO_MAX]; > + struct rtattr *bond[IFLA_BOND_MAX]; > + > + rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta); > + > + if (linkinfo[IFLA_INFO_KIND]) { > + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); > + > + if (kind && !strncmp(kind, "bond", 4) && > + linkinfo[IFLA_INFO_DATA]) { > + rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, > + linkinfo[IFLA_INFO_DATA]); > + > + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { > + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); > + } > + } > + } > + return index; > +} Thanks, Richard |
From: Hangbin L. <liu...@gm...> - 2017-09-10 14:24:02
|
Hi Richard, Thanks for the comments. Any suggestions for the other patches. Regards Hangbin On Sun, Aug 27, 2017 at 08:05:30AM -0700, Richard Cochran wrote: > On Wed, Aug 16, 2017 at 09:32:05PM +0800, Hangbin Liu wrote: > > @@ -31,6 +31,9 @@ > > > > static int rtnl_len; > > static char *rtnl_buf; > > +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len); > > +#define rtnl_nested_rtattr_parse(tb, max, rta) \ > > + (rtnl_rtattr_parse((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) > > Instead of a #define, why not a static inline function? > > > @@ -84,15 +87,69 @@ int rtnl_link_query(int fd, char *device) > > return 0; > > } > > > > -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) > > +static inline __u32 rta_getattr_u32(const struct rtattr *rta) > > { > > - int index, len; > > + return *(__u32 *)RTA_DATA(rta); > > +} > > + > > +static inline const char *rta_getattr_str(const struct rtattr *rta) > > +{ > > + return (const char *)RTA_DATA(rta); > > +} > > + > > +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) > > +{ > > + unsigned short type; > > + > > + memset(tb, 0, sizeof(struct rtattr *) * max); > > + while (RTA_OK(rta, len)) { > > + type = rta->rta_type; > > + if ((type <= max) && (!tb[type])) > > Test should be (type < max) because 'tb[]' has length 'max' and > tb[max] is out of bounds. > > > + tb[type] = rta; > > + rta = RTA_NEXT(rta, len); > > + } > > + if (len) > > + pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len); > > + return 0; > > +} > > + > > +static int rtnl_linkinfo_parse(struct rtattr *rta) > > +{ > > + int index = -1; > > + const char *kind; > > + struct rtattr *linkinfo[IFLA_INFO_MAX]; > > + struct rtattr *bond[IFLA_BOND_MAX]; > > + > > + rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta); > > + > > + if (linkinfo[IFLA_INFO_KIND]) { > > + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); > > + > > + if (kind && !strncmp(kind, "bond", 4) && > > + linkinfo[IFLA_INFO_DATA]) { > > + rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, > > + linkinfo[IFLA_INFO_DATA]); > > + > > + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { > > + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); > > + } > > + } > > + } > > + return index; > > +} > > Thanks, > Richard |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:51:59
|
This patch set is to add linuxptp bond fail over support. The main idea is get bond's active slave interface via rtnl socket and store it in struct interface. When active interface changed, we update the port phc index and switch to new phc on clock. After we get true ts interface, we need to use this interface in sk_timestamping_init() in transport_open(). Also we need update clock and phc_index in phc2sys. --- v3 -> v4: 1. In [PATCHv3 04/10] rtnl: update function rtnl_link_status to get bond slave info - Make function rtnl_nested_rtattr_parse() static inline - Check type < max in function rtnl_rtattr_parse() 2. In [PATCHv3 08/10] ptp4l: use ts label to get ts info - In previous patch we only updated phc index when ts_label changed. But actually link down and up may also change the phc index. So in this new version we will check both states and update phc index when it changed. - Call clock_sync_interval() after clock_switch_phc() 3. In [PATCHv3 10/10] phc2sys: update clock clkid and phc_index if device changed - In clock_reinit(), we need to check phc index even clock->device not changed because device down and up will also cause phc index change. - In reconfigure(), we also need to reinit clock when new_state is PS_SLAVE because there may have bond failover on slave. v2 -> v3: 1. Change the ts_iface to ts_label 2. Separate the original fourth patch "rtnl: add function rtnl_link_info" into two parts. The first part is update function rtnl_link_status to get bond slave info. And the second part add the new function rtnl_get_ts_label() to get interface ts_label info. 3. update port link_status to enum 4. Some small fixes. v1 -> v2: 1. After the rtnl per port update, now we update ts_iface info in port_link_status(). 2. Fix port_dispatch event flood when change ts_iface info. This issue only happen with bond interface when fail over. Normal ethernet interface do not have this problem. --- Test with bond failover on Slave. ptp4l[1748483.379]: master offset -47 s2 freq -94594 path delay 1182 ptp4l[1748484.379]: master offset 0 s2 freq -94561 path delay 1181 ptp4l[1748485.379]: master offset 16 s2 freq -94545 path delay 1181 ptp4l[1748486.379]: master offset 101 s2 freq -94455 path delay 1174 ptp4l[1748486.833]: port 1: ts label changed to p7p1 ptp4l[1748486.833]: port 1: SLAVE to FAULTY on FAULT_DETECTED (FT_UNSPECIFIED) ptp4l[1748513.435]: port 1: FAULTY to LISTENING on INIT_COMPLETE ptp4l[1748514.368]: port 1: new foreign master 90e2ba.fffe.862e70-1 ptp4l[1748514.380]: clockcheck: clock jumped backward or running slower than expected! ptp4l[1748518.369]: selected best master clock 90e2ba.fffe.862e70 ptp4l[1748518.369]: port 1: LISTENING to UNCALIBRATED on RS_SLAVE ptp4l[1748518.380]: master offset -37104557373 s0 freq +0 path delay 1174 ptp4l[1748519.380]: master offset -37104651844 s1 freq -94480 path delay 1174 ptp4l[1748520.380]: master offset -14 s2 freq -94494 path delay 1174 ptp4l[1748520.380]: port 1: UNCALIBRATED to SLAVE on MASTER_CLOCK_SELECTED ptp4l[1748521.380]: master offset -88 s2 freq -94572 path delay 1174 ptp4l[1748522.380]: master offset -46 s2 freq -94556 path delay 1174 ptp4l[1748523.380]: master offset -27 s2 freq -94551 path delay 1169 ptp4l[1748524.380]: master offset 31 s2 freq -94501 path delay 1169 ptp4l[1748525.380]: master offset -64 s2 freq -94587 path delay 1169 ptp4l[1748526.380]: master offset -13 s2 freq -94555 path delay 1166 ptp4l[1748527.380]: master offset 23 s2 freq -94523 path delay 1160 ptp4l[1748528.380]: master offset 44 s2 freq -94495 path delay 1160 ptp4l[1748529.380]: master offset 7 s2 freq -94519 path delay 1166 phc2sys[1748483.286]: CLOCK_REALTIME phc offset 0 s2 freq -8043 delay 851 phc2sys[1748484.286]: CLOCK_REALTIME phc offset -27 s2 freq -8070 delay 986 phc2sys[1748485.286]: CLOCK_REALTIME phc offset -26 s2 freq -8077 delay 848 phc2sys[1748486.287]: CLOCK_REALTIME phc offset 37 s2 freq -8022 delay 983 phc2sys[1748487.287]: port 90e2ba.fffe.8675f4-1 changed state phc2sys[1748487.287]: reconfiguring after port state change phc2sys[1748487.287]: selecting p7p2 for synchronization phc2sys[1748487.287]: nothing to synchronize phc2sys[1748519.290]: port 90e2ba.fffe.8675f4-1 changed state phc2sys[1748519.290]: reconfiguring after port state change phc2sys[1748519.290]: master clock not ready, waiting... phc2sys[1748521.290]: port 90e2ba.fffe.8675f4-1 changed state phc2sys[1748521.290]: reconfiguring after port state change phc2sys[1748521.290]: selecting CLOCK_REALTIME for synchronization phc2sys[1748521.290]: selecting p7p1 as the master clock phc2sys[1748521.290]: CLOCK_REALTIME phc offset -290 s2 freq -8337 delay 844 phc2sys[1748522.290]: CLOCK_REALTIME phc offset -16 s2 freq -8150 delay 967 phc2sys[1748523.291]: CLOCK_REALTIME phc offset 75 s2 freq -8064 delay 840 phc2sys[1748524.291]: CLOCK_REALTIME phc offset 71 s2 freq -8046 delay 838 Thanks Hangbin Hangbin Liu (10): config: add new element ts_label in struct interface port: track interface info in port rtnl: update rtgenmsg to ifinfomsg when request link info rtnl: update function rtnl_link_status to get bond slave info rtnl: add function rtnl_get_ts_label to get interface ts_label info port: update port link_status to enum clock: add clock_required_modes to obtain the required time stamping mode ptp4l: use ts label to get ts info transport: pass struct interface to transport_open phc2sys: update clock clkid and phc_index if device changed clock.c | 63 +++++++++++++++++------- clock.h | 8 +++ config.c | 1 - config.h | 1 + phc2sys.c | 60 +++++++++++++++++++++-- pmc_common.c | 5 +- port.c | 84 ++++++++++++++++++++++++++------ raw.c | 5 +- rtnl.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++------ rtnl.h | 28 +++++++---- transport.c | 4 +- transport.h | 3 +- transport_private.h | 4 +- udp.c | 7 +-- udp6.c | 7 +-- uds.c | 3 +- 16 files changed, 344 insertions(+), 77 deletions(-) -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:00
|
Add new element ts_label in struct interface to track real ts interface. Signed-off-by: Hangbin Liu <liu...@gm...> --- config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.h b/config.h index 1cc7051..c79855e 100644 --- a/config.h +++ b/config.h @@ -36,6 +36,7 @@ struct interface { STAILQ_ENTRY(interface) list; char name[MAX_IFNAME_SIZE + 1]; + char ts_label[MAX_IFNAME_SIZE + 1]; struct sk_ts_info ts_info; }; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:03
|
Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/port.c b/port.c index 34837cc..849a7c1 100644 --- a/port.c +++ b/port.c @@ -68,6 +68,7 @@ struct nrate_estimator { struct port { LIST_ENTRY(port) list; char *name; + struct interface *iface; struct clock *clock; struct transport *trp; enum timestamp_type timestamping; @@ -2619,6 +2620,7 @@ struct port *port_open(int phc_index, } p->name = interface->name; + p->iface = interface; p->asymmetry = config_get_int(cfg, p->name, "delayAsymmetry"); p->asymmetry <<= 16; p->announce_span = transport == TRANS_UDS ? 0 : ANNOUNCE_SPAN; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:08
|
The previous function use general message and will dump all interfaces' information. Now update with ifinfomsg so we could get specific interface's information. We still could get all interfaces' info if set device to NULL. Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 2 +- rtnl.c | 12 +++++++----- rtnl.h | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/port.c b/port.c index 849a7c1..5b85d87 100644 --- a/port.c +++ b/port.c @@ -1512,7 +1512,7 @@ static int port_initialize(struct port *p) if (p->fda.fd[FD_RTNL] == -1) p->fda.fd[FD_RTNL] = rtnl_open(); if (p->fda.fd[FD_RTNL] >= 0) - rtnl_link_query(p->fda.fd[FD_RTNL]); + rtnl_link_query(p->fda.fd[FD_RTNL], p->iface->name); } port_nrate_initialize(p); diff --git a/rtnl.c b/rtnl.c index d7a430d..8ecf6fe 100644 --- a/rtnl.c +++ b/rtnl.c @@ -42,7 +42,7 @@ int rtnl_close(int fd) return close(fd); } -int rtnl_link_query(int fd) +int rtnl_link_query(int fd, char *device) { struct sockaddr_nl sa; struct msghdr msg; @@ -51,19 +51,21 @@ int rtnl_link_query(int fd) struct { struct nlmsghdr hdr; - struct rtgenmsg gen; + struct ifinfomsg ifm; } __attribute__((packed)) request; memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; memset(&request, 0, sizeof(request)); - request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen)); + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.ifm)); request.hdr.nlmsg_type = RTM_GETLINK; - request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + request.hdr.nlmsg_flags = NLM_F_REQUEST; request.hdr.nlmsg_seq = 1; request.hdr.nlmsg_pid = 0; - request.gen.rtgen_family = AF_UNSPEC; + request.ifm.ifi_family = AF_UNSPEC; + request.ifm.ifi_index = if_nametoindex(device ? device : ""); + request.ifm.ifi_change = 0xffffffff; iov.iov_base = &request; iov.iov_len = sizeof(request); diff --git a/rtnl.h b/rtnl.h index f1871f2..5c93eec 100644 --- a/rtnl.h +++ b/rtnl.h @@ -31,10 +31,11 @@ int rtnl_close(int fd); /** * Request the link status from the kernel. - * @param fd A socket obtained via rtnl_open(). - * @return Zero on success, non-zero otherwise. + * @param fd A socket obtained via rtnl_open(). + * @param device Interface name. Request all iface's status if set NULL. + * @return Zero on success, non-zero otherwise. */ -int rtnl_link_query(int fd); +int rtnl_link_query(int fd, char *device); /** * Read kernel messages looking for a link up/down events. -- 2.5.5 |
[Linuxptp-devel] [PATCHv4 05/10] rtnl: add function
rtnl_get_ts_label to get interface ts_label info
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:10
|
Signed-off-by: Hangbin Liu <liu...@gm...> --- rtnl.c | 31 +++++++++++++++++++++++++++++++ rtnl.h | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/rtnl.c b/rtnl.c index d841245..2ac0b96 100644 --- a/rtnl.c +++ b/rtnl.c @@ -244,3 +244,34 @@ int rtnl_open(void) } return fd; } + +static void rtnl_get_ts_label_callback(void *ctx, int linkup, int ts_index) +{ + int *dst = ctx; + *dst = ts_index; +} + +int rtnl_get_ts_label(struct interface *iface) +{ + int err, fd; + int ts_index = -1; + + fd = rtnl_open(); + if (fd < 0) + return fd; + + err = rtnl_link_query(fd, iface->name); + if (err) { + goto no_info; + } + + rtnl_link_status(fd, iface->name, rtnl_get_ts_label_callback, &ts_index); + if (ts_index > 0 && if_indextoname(ts_index, iface->ts_label)) + err = 0; + else + err = -1; + +no_info: + rtnl_close(fd); + return err; +} diff --git a/rtnl.h b/rtnl.h index 20f1491..d335c40 100644 --- a/rtnl.h +++ b/rtnl.h @@ -20,6 +20,8 @@ #ifndef HAVE_RTNL_H #define HAVE_RTNL_H +#include "config.h" + typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index); /** @@ -53,4 +55,10 @@ int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx); */ int rtnl_open(void); +/** + * Get interface ts_label information + * @param iface struct interface. + * @return Zero on success, or -1 on error. + */ +int rtnl_get_ts_label(struct interface *iface); #endif -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:09
|
Update function rtnl_link_status to get bond slave info. Pass the slave index to call back functions. i.e. port_link_status. Also check the interface index of rtnl message in function rtnl_link_status. Then we don't need to check it in port_link_status. Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 6 ++--- rtnl.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- rtnl.h | 13 ++++----- 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/port.c b/port.c index 5b85d87..05fc321 100644 --- a/port.c +++ b/port.c @@ -2221,11 +2221,11 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) } } -static void port_link_status(void *ctx, int index, int linkup) +static void port_link_status(void *ctx, int linkup, int ts_index) { struct port *p = ctx; - if (index != if_nametoindex(p->name) || p->link_status == linkup) + if (p->link_status == linkup) return; p->link_status = linkup; @@ -2280,7 +2280,7 @@ enum fsm_event port_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("port %hu: received link status notification", portnum(p)); - rtnl_link_status(fd, port_link_status, p); + rtnl_link_status(fd, p->name, port_link_status, p); return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED; } diff --git a/rtnl.c b/rtnl.c index 8ecf6fe..d841245 100644 --- a/rtnl.c +++ b/rtnl.c @@ -84,15 +84,79 @@ int rtnl_link_query(int fd, char *device) return 0; } -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) +static inline __u32 rta_getattr_u32(const struct rtattr *rta) { - int index, len; + return *(__u32 *)RTA_DATA(rta); +} + +static inline const char *rta_getattr_str(const struct rtattr *rta) +{ + return (const char *)RTA_DATA(rta); +} + +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * max); + while (RTA_OK(rta, len)) { + type = rta->rta_type; + if ((type < max) && (!tb[type])) + tb[type] = rta; + rta = RTA_NEXT(rta, len); + } + if (len) { + pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len); + return -1; + } + + return 0; +} + +static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta) +{ + return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); +} + +static int rtnl_linkinfo_parse(struct rtattr *rta) +{ + int index = -1; + const char *kind; + struct rtattr *linkinfo[IFLA_INFO_MAX]; + struct rtattr *bond[IFLA_BOND_MAX]; + + if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0) + return -1; + + if (linkinfo[IFLA_INFO_KIND]) { + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); + + if (kind && !strncmp(kind, "bond", 4) && + linkinfo[IFLA_INFO_DATA]) { + if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, + linkinfo[IFLA_INFO_DATA]) < 0) + return -1; + + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); + } + } + } + return index; +} + +int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) +{ + int index, len, link_up; + int slave_index = -1; struct iovec iov; struct sockaddr_nl sa; struct msghdr msg; struct nlmsghdr *nh; struct ifinfomsg *info = NULL; + struct rtattr *tb[IFLA_MAX+1]; + index = if_nametoindex(device); if (!rtnl_buf) { rtnl_len = 4096; rtnl_buf = malloc(rtnl_len); @@ -135,14 +199,27 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) nh = (struct nlmsghdr *) rtnl_buf; for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { - if (nh->nlmsg_type == RTM_NEWLINK) { - info = NLMSG_DATA(nh); - index = info->ifi_index; - pr_debug("interface index %d is %s", index, - info->ifi_flags & IFF_RUNNING ? "up" : "down"); - cb(ctx, index, info->ifi_flags & IFF_RUNNING ? 1 : 0); - } + if (nh->nlmsg_type != RTM_NEWLINK) + continue; + + info = NLMSG_DATA(nh); + if (index != info->ifi_index) + continue; + + link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0; + pr_debug("interface index %d is %s", index, + link_up ? "up" : "down"); + + rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info), + IFLA_PAYLOAD(nh)); + + if (tb[IFLA_LINKINFO]) + slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]); + + if (cb) + cb(ctx, link_up, slave_index); } + return 0; } diff --git a/rtnl.h b/rtnl.h index 5c93eec..20f1491 100644 --- a/rtnl.h +++ b/rtnl.h @@ -20,7 +20,7 @@ #ifndef HAVE_RTNL_H #define HAVE_RTNL_H -typedef void (*rtnl_callback)(void *ctx, int index, int linkup); +typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index); /** * Close a RT netlink socket. @@ -39,12 +39,13 @@ int rtnl_link_query(int fd, char *device); /** * Read kernel messages looking for a link up/down events. - * @param fd Readable socket obtained via rtnl_open(). - * @param cb Callback function to be invoked on each event. - * @param ctx Private context passed to the callback. - * @return Zero on success, non-zero otherwise. + * @param fd Readable socket obtained via rtnl_open(). + * @param device The device which we need to get link info. + * @param cb Callback function to be invoked on each event. + * @param ctx Private context passed to the callback. + * @return A slave index, or -1 on error. */ -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx); +int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx); /** * Open a RT netlink socket for monitoring link state. -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:13
|
Besides link up and down, we may also receive other rtnl message. For example the bond slave changed info, which the link state keep the same. So we should return EV_FAULT_CLEARED only when both LINK_UP and LINK_STATE_CHANGED. When the link state keep the same, we should return EV_NONE. Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/port.c b/port.c index 05fc321..81d52ff 100644 --- a/port.c +++ b/port.c @@ -56,6 +56,12 @@ enum syfu_event { FUP_MATCH, }; +enum link_state { + LINK_DOWN = (1<<0), + LINK_UP = (1<<1), + LINK_STATE_CHANGED = (1<<3), +}; + struct nrate_estimator { double ratio; tmv_t origin1; @@ -122,7 +128,7 @@ struct port { int path_trace_enabled; int rx_timestamp_offset; int tx_timestamp_offset; - int link_status; + enum link_state link_status; struct fault_interval flt_interval_pertype[FT_CNT]; enum fault_type last_fault_type; unsigned int versionNumber; /*UInteger4*/ @@ -2224,18 +2230,21 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) static void port_link_status(void *ctx, int linkup, int ts_index) { struct port *p = ctx; + int link_state; - if (p->link_status == linkup) - return; - - p->link_status = linkup; - pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down"); + link_state = linkup ? LINK_UP : LINK_DOWN; + if (p->link_status & link_state) { + p->link_status = link_state; + } else { + p->link_status = link_state | LINK_STATE_CHANGED; + pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down"); + } /* * A port going down can affect the BMCA result. * Force a state decision event. */ - if (!p->link_status) + if (p->link_status & LINK_DOWN) clock_set_sde(p->clock, 1); } @@ -2281,7 +2290,12 @@ enum fsm_event port_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("port %hu: received link status notification", portnum(p)); rtnl_link_status(fd, p->name, port_link_status, p); - return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED; + if (p->link_status == (LINK_UP | LINK_STATE_CHANGED)) + return EV_FAULT_CLEARED; + else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) + return EV_FAULT_DETECTED; + else + return EV_NONE; } msg = msg_allocate(); @@ -2409,7 +2423,7 @@ int port_number(struct port *p) int port_link_status_get(struct port *p) { - return p->link_status; + return !!(p->link_status & LINK_UP); } int port_manage(struct port *p, struct port *ingress, struct ptp_message *msg) @@ -2630,7 +2644,7 @@ struct port *port_open(int phc_index, 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"); - p->link_status = 1; + p->link_status = LINK_UP; p->clock = clock; p->trp = transport_create(cfg, transport); if (!p->trp) -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:15
|
Separate required_modes setting from clock_create so we can obtain the required time stamping flags from other place. Add enum timestamping in struct clock to store the time stamping mode. Signed-off-by: Hangbin Liu <liu...@gm...> --- clock.c | 49 +++++++++++++++++++++++++++++++------------------ clock.h | 8 ++++++++ 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/clock.c b/clock.c index da15882..bd2b91b 100644 --- a/clock.c +++ b/clock.c @@ -106,6 +106,7 @@ struct clock { int time_flags; /* grand master role */ int time_source; /* grand master role */ enum servo_state servo_state; + enum timestamp_type timestamping; tmv_t master_offset; tmv_t path_delay; tmv_t ingress_ts; @@ -805,6 +806,34 @@ static void clock_remove_port(struct clock *c, struct port *p) port_close(p); } +int clock_required_modes(struct clock *c) +{ + int required_modes = 0; + + switch (c->timestamping) { + case TS_SOFTWARE: + required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + break; + case TS_LEGACY_HW: + required_modes |= SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_SYS_HARDWARE; + break; + case TS_HARDWARE: + case TS_ONESTEP: + required_modes |= SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + break; + default: + break; + } + + return required_modes; +} + struct clock *clock_create(enum clock_type type, struct config *config, const char *phc_device) { @@ -913,24 +942,8 @@ struct clock *clock_create(enum clock_type type, struct config *config, } /* Check the time stamping mode on each interface. */ - switch (timestamping) { - case TS_SOFTWARE: - required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; - break; - case TS_LEGACY_HW: - required_modes |= SOF_TIMESTAMPING_TX_HARDWARE | - SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_SYS_HARDWARE; - break; - case TS_HARDWARE: - case TS_ONESTEP: - required_modes |= SOF_TIMESTAMPING_TX_HARDWARE | - SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE; - break; - } + c->timestamping = timestamping; + required_modes = clock_required_modes(c); STAILQ_FOREACH(iface, &config->interfaces, list) { if (iface->ts_info.valid && ((iface->ts_info.so_timestamping & required_modes) != required_modes)) { diff --git a/clock.h b/clock.h index 49ecb76..986d363 100644 --- a/clock.h +++ b/clock.h @@ -73,6 +73,14 @@ UInteger8 clock_class(struct clock *c); struct config *clock_config(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 + * of SOF_TIMESTAMPING_ flags. + */ +int clock_required_modes(struct clock *c); + +/** * Create a clock instance. There can only be one clock in any system, * so subsequent calls will destroy the previous clock instance. * -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:17
|
Now the ts label will be either the bond active slave or the interface name, which is the exactly interface we need to get ts info. When the link down/up or there is a fail over and ts_label changed, the phc index may also changed. So we need to check get new ts info and check clock_required_modes. We will set the link to LINK_DOWN by force if the new ts_label's timestamp do not support required mode. If all good, then we set phc index to new one. Also sync clock interval after switch phc. Signed-off-by: Hangbin Liu <liu...@gm...> --- clock.c | 14 ++++++++++++++ config.c | 1 - port.c | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/clock.c b/clock.c index bd2b91b..a9da8c6 100644 --- a/clock.c +++ b/clock.c @@ -38,6 +38,7 @@ #include "servo.h" #include "stats.h" #include "print.h" +#include "rtnl.h" #include "tlv.h" #include "tsproc.h" #include "uds.h" @@ -834,6 +835,16 @@ int clock_required_modes(struct clock *c) return required_modes; } +/* + * If we do not have a slave or the rtnl query failed, then use our + * own interface name as the time stamping interface name. + */ +static void ensure_ts_label(struct interface *iface) +{ + if (iface->ts_label[0] == '\0') + strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE); +} + struct clock *clock_create(enum clock_type type, struct config *config, const char *phc_device) { @@ -945,6 +956,9 @@ struct clock *clock_create(enum clock_type type, struct config *config, c->timestamping = timestamping; required_modes = clock_required_modes(c); STAILQ_FOREACH(iface, &config->interfaces, list) { + rtnl_get_ts_label(iface); + ensure_ts_label(iface); + sk_get_ts_info(iface->ts_label, &iface->ts_info); if (iface->ts_info.valid && ((iface->ts_info.so_timestamping & required_modes) != required_modes)) { pr_err("interface '%s' does not support " diff --git a/config.c b/config.c index e6fe676..bbaf36e 100644 --- a/config.c +++ b/config.c @@ -633,7 +633,6 @@ struct interface *config_create_interface(char *name, struct config *cfg) } strncpy(iface->name, name, MAX_IFNAME_SIZE); - sk_get_ts_info(iface->name, &iface->ts_info); STAILQ_INSERT_TAIL(&cfg->interfaces, iface, list); cfg->n_interfaces++; diff --git a/port.c b/port.c index 81d52ff..5d1210b 100644 --- a/port.c +++ b/port.c @@ -60,6 +60,7 @@ enum link_state { LINK_DOWN = (1<<0), LINK_UP = (1<<1), LINK_STATE_CHANGED = (1<<3), + TS_LABEL_CHANGED = (1<<4), }; struct nrate_estimator { @@ -2231,6 +2232,8 @@ static void port_link_status(void *ctx, int linkup, int ts_index) { struct port *p = ctx; int link_state; + char ts_label[MAX_IFNAME_SIZE + 1]; + int required_modes; link_state = linkup ? LINK_UP : LINK_DOWN; if (p->link_status & link_state) { @@ -2240,6 +2243,38 @@ static void port_link_status(void *ctx, int linkup, int ts_index) pr_notice("port %hu: link %s", portnum(p), linkup ? "up" : "down"); } + /* ts_label changed */ + if (if_indextoname(ts_index, ts_label) && strcmp(p->iface->ts_label, ts_label)) { + strncpy(p->iface->ts_label, ts_label, MAX_IFNAME_SIZE); + p->link_status |= TS_LABEL_CHANGED; + pr_notice("port %hu: ts label changed to %s", portnum(p), ts_label); + } + + /* Both link down/up and change ts_label may change phc index. */ + if (p->link_status & LINK_UP && + (p->link_status & LINK_STATE_CHANGED || p->link_status & TS_LABEL_CHANGED)) { + sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info); + + if (p->iface->ts_info.valid) { + required_modes = clock_required_modes(p->clock); + if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) { + pr_err("interface '%s' does not support requested " + "timestamping mode, set link status down by force.", + p->iface->ts_label); + p->link_status = LINK_DOWN | LINK_STATE_CHANGED; + } else if (p->phc_index != p->iface->ts_info.phc_index) { + p->phc_index = p->iface->ts_info.phc_index; + + if (clock_switch_phc(p->clock, p->phc_index)) { + p->last_fault_type = FT_SWITCH_PHC; + port_dispatch(p, EV_FAULT_DETECTED, 0); + return; + } + clock_sync_interval(p->clock, p->log_sync_interval); + } + } + } + /* * A port going down can affect the BMCA result. * Force a state decision event. @@ -2292,7 +2327,8 @@ enum fsm_event port_event(struct port *p, int fd_index) rtnl_link_status(fd, p->name, port_link_status, p); if (p->link_status == (LINK_UP | LINK_STATE_CHANGED)) return EV_FAULT_CLEARED; - else if (p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) + else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) || + (p->link_status & TS_LABEL_CHANGED)) return EV_FAULT_DETECTED; else return EV_NONE; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:21
|
Pass struct interface so we can use ts_iface in HW filter. Signed-off-by: Hangbin Liu <liu...@gm...> --- pmc_common.c | 5 ++++- port.c | 4 ++-- raw.c | 5 +++-- transport.c | 4 ++-- transport.h | 3 ++- transport_private.h | 4 ++-- udp.c | 7 ++++--- udp6.c | 7 ++++--- uds.c | 3 ++- 9 files changed, 25 insertions(+), 17 deletions(-) diff --git a/pmc_common.c b/pmc_common.c index d92b0cd..447cf99 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -67,6 +67,7 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, int zero_datalen) { struct pmc *pmc; + struct interface iface; pmc = calloc(1, sizeof *pmc); if (!pmc) @@ -90,7 +91,9 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, pr_err("failed to create transport"); goto failed; } - if (transport_open(pmc->transport, iface_name, + + strncpy(iface.name, iface_name, MAX_IFNAME_SIZE); + if (transport_open(pmc->transport, &iface, &pmc->fdarray, TS_SOFTWARE)) { pr_err("failed to open transport"); goto failed; diff --git a/port.c b/port.c index 5d1210b..e9728a7 100644 --- a/port.c +++ b/port.c @@ -1504,7 +1504,7 @@ static int port_initialize(struct port *p) goto no_timers; } } - if (transport_open(p->trp, p->name, &p->fda, p->timestamping)) + if (transport_open(p->trp, p->iface, &p->fda, p->timestamping)) goto no_tropen; for (i = 0; i < N_TIMER_FDS; i++) { @@ -1547,7 +1547,7 @@ static int port_renew_transport(struct port *p) } transport_close(p->trp, &p->fda); port_clear_fda(p, FD_ANNOUNCE_TIMER); - res = transport_open(p->trp, p->name, &p->fda, p->timestamping); + res = transport_open(p->trp, p->iface, &p->fda, p->timestamping); /* Need to call clock_fda_changed even if transport_open failed in * order to update clock to the now closed descriptors. */ clock_fda_changed(p->clock); diff --git a/raw.c b/raw.c index 73e45b4..8b7bcf1 100644 --- a/raw.c +++ b/raw.c @@ -198,15 +198,16 @@ static void addr_to_mac(void *mac, struct address *addr) memcpy(mac, &addr->sll.sll_addr, MAC_LEN); } -static int raw_open(struct transport *t, const char *name, +static int raw_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type ts_type) { struct raw *raw = container_of(t, struct raw, t); unsigned char ptp_dst_mac[MAC_LEN]; unsigned char p2p_dst_mac[MAC_LEN]; int efd, gfd; - char *str; + char *str, *name; + name = iface->ts_label; str = config_get_string(t->cfg, name, "ptp_dst_mac"); if (str2mac(str, ptp_dst_mac)) { pr_err("invalid ptp_dst_mac %s", str); diff --git a/transport.c b/transport.c index d24c05b..3541394 100644 --- a/transport.c +++ b/transport.c @@ -31,10 +31,10 @@ int transport_close(struct transport *t, struct fdarray *fda) return t->close(t, fda); } -int transport_open(struct transport *t, const char *name, +int transport_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt) { - return t->open(t, name, fda, tt); + return t->open(t, iface, fda, tt); } int transport_recv(struct transport *t, int fd, struct ptp_message *msg) diff --git a/transport.h b/transport.h index 5d6ba98..15616bb 100644 --- a/transport.h +++ b/transport.h @@ -27,6 +27,7 @@ #include "msg.h" struct config; +struct interface; /* Values from networkProtocol enumeration 7.4.1 Table 3 */ enum transport_type { @@ -54,7 +55,7 @@ struct transport; int transport_close(struct transport *t, struct fdarray *fda); -int transport_open(struct transport *t, const char *name, +int transport_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt); int transport_recv(struct transport *t, int fd, struct ptp_message *msg); diff --git a/transport_private.h b/transport_private.h index b54f32a..7530896 100644 --- a/transport_private.h +++ b/transport_private.h @@ -32,8 +32,8 @@ struct transport { int (*close)(struct transport *t, struct fdarray *fda); - int (*open)(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type tt); + int (*open)(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type tt); int (*recv)(struct transport *t, int fd, void *buf, int buflen, struct address *addr, struct hw_timestamp *hwts); diff --git a/udp.c b/udp.c index 530a2ee..05c2ba0 100644 --- a/udp.c +++ b/udp.c @@ -152,12 +152,13 @@ enum { MC_PRIMARY, MC_PDELAY }; static struct in_addr mcast_addr[2]; -static int udp_open(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type ts_type) +static int udp_open(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type ts_type) { struct udp *udp = container_of(t, struct udp, t); uint8_t event_dscp, general_dscp; int efd, gfd, ttl; + char *name = iface->name; ttl = config_get_int(t->cfg, name, "udp_ttl"); udp->mac.len = 0; @@ -180,7 +181,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda, if (gfd < 0) goto no_general; - if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4)) + if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV4)) goto no_timestamping; if (sk_general_init(gfd)) diff --git a/udp6.c b/udp6.c index 89e27bf..7551e3f 100644 --- a/udp6.c +++ b/udp6.c @@ -160,12 +160,13 @@ enum { MC_PRIMARY, MC_PDELAY }; static struct in6_addr mc6_addr[2]; -static int udp6_open(struct transport *t, const char *name, struct fdarray *fda, - enum timestamp_type ts_type) +static int udp6_open(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type ts_type) { struct udp6 *udp6 = container_of(t, struct udp6, t); uint8_t event_dscp, general_dscp; int efd, gfd, hop_limit; + char *name = iface->name; hop_limit = config_get_int(t->cfg, name, "udp_ttl"); udp6->mac.len = 0; @@ -190,7 +191,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda, if (gfd < 0) goto no_general; - if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6)) + if (sk_timestamping_init(efd, iface->ts_label, ts_type, TRANS_UDP_IPV6)) goto no_timestamping; if (sk_general_init(gfd)) diff --git a/uds.c b/uds.c index d5e8f50..7e11f63 100644 --- a/uds.c +++ b/uds.c @@ -52,13 +52,14 @@ static int uds_close(struct transport *t, struct fdarray *fda) return 0; } -static int uds_open(struct transport *t, const char *name, struct fdarray *fda, +static int uds_open(struct transport *t, struct interface *iface, struct fdarray *fda, enum timestamp_type tt) { int fd, err; struct sockaddr_un sa; struct uds *uds = container_of(t, struct uds, t); char *uds_path = config_get_string(t->cfg, NULL, "uds_address"); + char *name = iface->name; fd = socket(AF_LOCAL, SOCK_DGRAM, 0); if (fd < 0) { -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-20 01:52:22
|
Fix phc2sys could not find correct phc index in slave mode when fail over. Signed-off-by: Hangbin Liu <liu...@gm...> --- phc2sys.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- port.c | 2 +- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index b6f6719..9b1586e 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -128,6 +128,11 @@ static int clock_handle_leap(struct node *node, struct clock *clock, static int run_pmc_get_utc_offset(struct node *node, int timeout); static void run_pmc_events(struct node *node); +static int normalize_state(int state); +static int run_pmc_port_properties(struct node *node, int timeout, + unsigned int port, + int *state, int *tstamping, char *iface); + static clockid_t clock_open(char *device, int *phc_index) { struct sk_ts_info ts_info; @@ -294,8 +299,55 @@ static struct port *port_add(struct node *node, unsigned int number, return p; } -static void clock_reinit(struct clock *clock) +static void clock_reinit(struct node *node, struct clock *clock) { + struct port *p; + int state, timestamping, ret = -1; + int phc_index = -1; + char iface[IFNAMSIZ]; + clockid_t clkid = CLOCK_INVALID; + struct sk_ts_info ts_info; + + LIST_FOREACH(p, &node->ports, list) { + if (p->clock == clock) { + ret = run_pmc_port_properties(node, 1000, p->number, + &state, ×tamping, + iface); + if (ret == -1) { + /* port does not exist, ignore the port */ + continue; + } + if (ret <= 0) { + pr_err("failed to get port properties"); + return; + } + if (timestamping == TS_SOFTWARE) { + /* ignore ports with software time stamping */ + continue; + } + + p->state = normalize_state(state); + } + } + + if (ret != -1) { + /* Check if device changed */ + if (strcmp(clock->device, iface)) { + free(clock->device); + clock->device = strdup(iface); + } + /* Check if phc index changed */ + if (!sk_get_ts_info(clock->device, &ts_info) && + clock->phc_index != ts_info.phc_index) { + clkid = clock_open(clock->device, &phc_index); + if (clkid == CLOCK_INVALID) + return; + phc_close(clock->clkid); + clock->clkid = clkid; + clock->phc_index = phc_index; + } + } + servo_reset(clock->servo); clock->servo_state = SERVO_UNLOCKED; @@ -321,8 +373,8 @@ static void reconfigure(struct node *node) } if (c->new_state) { - if (c->new_state == PS_MASTER) - clock_reinit(c); + if (c->new_state == PS_MASTER || c->new_state == PS_SLAVE) + clock_reinit(node, c); c->state = c->new_state; c->new_state = 0; @@ -388,7 +440,7 @@ static void reconfigure(struct node *node) } else if (rt) { if (rt->state != PS_MASTER) { rt->state = PS_MASTER; - clock_reinit(rt); + clock_reinit(node, rt); } pr_info("selecting %s for synchronization", rt->device); } diff --git a/port.c b/port.c index e9728a7..915a8a8 100644 --- a/port.c +++ b/port.c @@ -861,7 +861,7 @@ static int port_management_fill_response(struct port *target, else ppn->port_state = target->state; ppn->timestamping = target->timestamping; - ptp_text_set(&ppn->interface, target->name); + ptp_text_set(&ppn->interface, target->iface->ts_label); datalen = sizeof(*ppn) + ppn->interface.length; respond = 1; break; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-30 08:25:54
|
This patch set is to add linuxptp bond fail over support. The main idea is get bond's active slave interface via rtnl socket and store it in struct interface. When active interface changed, we update the port phc index and switch to new phc on clock. After we get true ts interface, we need to use this interface in sk_timestamping_init() in transport_open(). Also we need update clock and phc_index in phc2sys. --- v4 -> v5: Based on Miroslav's tests and advises. 1. For [PATCHv4 08/10] ptp4l: use ts label to get ts info - In function port_link_status() we should only switch phc with HW time stamping mode. 2. For [PATCHv4 10/10] phc2sys: update clock clkid and phc_index if device changed - Split this patch into three small patches to make the logic more clear. So now we have two parts for this patchset. Patches 1-9 are to add ptp4l bond failover support. And patches 10-12 are to add phc2sys failover support. - Split servo_add from function clock_add for later use. - In reconfigure() we only do clock_reinit() when new state is PS_MASTER or PS_SLAVE. But when get failover the state changed to PS_FAULTY first, during this time we still choose the old phc device instead of new phc. Fix this by call clock_reinit() whenever we have a new state. - In clock_reinit(), the new phc device may have different maximum adjustment, then it will try to make a larger adjustment than the HW can handle and breaks the synchronization. So we need to destroy the old servo and create a new one. v3 -> v4: 1. In [PATCHv3 04/10] rtnl: update function rtnl_link_status to get bond slave info - Make function rtnl_nested_rtattr_parse() static inline - Check type < max in function rtnl_rtattr_parse() 2. In [PATCHv3 08/10] ptp4l: use ts label to get ts info - In previous patch we only updated phc index when ts_label changed. But actually link down and up may also change the phc index. So in this new version we will check both states and update phc index when it changed. - Call clock_sync_interval() after clock_switch_phc() 3. In [PATCHv3 10/10] phc2sys: update clock clkid and phc_index if device changed - In clock_reinit(), we need to check phc index even clock->device not changed because device down and up will also cause phc index change. - In reconfigure(), we also need to reinit clock when new_state is PS_SLAVE because there may have bond failover on slave. v2 -> v3: 1. Change the ts_iface to ts_label 2. Separate the original fourth patch "rtnl: add function rtnl_link_info" into two parts. The first part is update function rtnl_link_status to get bond slave info. And the second part add the new function rtnl_get_ts_label() to get interface ts_label info. 3. update port link_status to enum 4. Some small fixes. v1 -> v2: 1. After the rtnl per port update, now we update ts_iface info in port_link_status(). 2. Fix port_dispatch event flood when change ts_iface info. This issue only happen with bond interface when fail over. Normal ethernet interface do not have this problem. Hangbin Liu (12): config: add new element ts_label in struct interface port: track interface info in port rtnl: update rtgenmsg to ifinfomsg when request link info rtnl: update function rtnl_link_status to get bond slave info rtnl: add function rtnl_get_ts_label to get interface ts_label info port: update port link_status to enum clock: add clock_required_modes to obtain the required time stamping mode ptp4l: use ts label to get ts info transport: pass struct interface to transport_open phc2sys: split servo_add from function clock_add phc2sys: re-create clock clkid and servo when phc index changed port: return timestamping iface in port properties clock.c | 63 +++++++++++++++++------- clock.h | 8 +++ config.c | 1 - config.h | 1 + phc2sys.c | 129 ++++++++++++++++++++++++++++++++++++------------ pmc_common.c | 5 +- port.c | 85 ++++++++++++++++++++++++++------ raw.c | 5 +- rtnl.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++------ rtnl.h | 28 +++++++---- transport.c | 4 +- transport.h | 3 +- transport_private.h | 4 +- udp.c | 7 +-- udp6.c | 7 +-- uds.c | 3 +- 16 files changed, 386 insertions(+), 105 deletions(-) -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-30 08:25:56
|
Add new element ts_label in struct interface to track real ts interface. Signed-off-by: Hangbin Liu <liu...@gm...> --- config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.h b/config.h index 1cc7051..c79855e 100644 --- a/config.h +++ b/config.h @@ -36,6 +36,7 @@ struct interface { STAILQ_ENTRY(interface) list; char name[MAX_IFNAME_SIZE + 1]; + char ts_label[MAX_IFNAME_SIZE + 1]; struct sk_ts_info ts_info; }; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-30 08:25:58
|
Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/port.c b/port.c index 34837cc..849a7c1 100644 --- a/port.c +++ b/port.c @@ -68,6 +68,7 @@ struct nrate_estimator { struct port { LIST_ENTRY(port) list; char *name; + struct interface *iface; struct clock *clock; struct transport *trp; enum timestamp_type timestamping; @@ -2619,6 +2620,7 @@ struct port *port_open(int phc_index, } p->name = interface->name; + p->iface = interface; p->asymmetry = config_get_int(cfg, p->name, "delayAsymmetry"); p->asymmetry <<= 16; p->announce_span = transport == TRANS_UDS ? 0 : ANNOUNCE_SPAN; -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-30 08:26:00
|
The previous function use general message and will dump all interfaces' information. Now update with ifinfomsg so we could get specific interface's information. We still could get all interfaces' info if set device to NULL. Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 2 +- rtnl.c | 12 +++++++----- rtnl.h | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/port.c b/port.c index 849a7c1..5b85d87 100644 --- a/port.c +++ b/port.c @@ -1512,7 +1512,7 @@ static int port_initialize(struct port *p) if (p->fda.fd[FD_RTNL] == -1) p->fda.fd[FD_RTNL] = rtnl_open(); if (p->fda.fd[FD_RTNL] >= 0) - rtnl_link_query(p->fda.fd[FD_RTNL]); + rtnl_link_query(p->fda.fd[FD_RTNL], p->iface->name); } port_nrate_initialize(p); diff --git a/rtnl.c b/rtnl.c index d7a430d..8ecf6fe 100644 --- a/rtnl.c +++ b/rtnl.c @@ -42,7 +42,7 @@ int rtnl_close(int fd) return close(fd); } -int rtnl_link_query(int fd) +int rtnl_link_query(int fd, char *device) { struct sockaddr_nl sa; struct msghdr msg; @@ -51,19 +51,21 @@ int rtnl_link_query(int fd) struct { struct nlmsghdr hdr; - struct rtgenmsg gen; + struct ifinfomsg ifm; } __attribute__((packed)) request; memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; memset(&request, 0, sizeof(request)); - request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen)); + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.ifm)); request.hdr.nlmsg_type = RTM_GETLINK; - request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + request.hdr.nlmsg_flags = NLM_F_REQUEST; request.hdr.nlmsg_seq = 1; request.hdr.nlmsg_pid = 0; - request.gen.rtgen_family = AF_UNSPEC; + request.ifm.ifi_family = AF_UNSPEC; + request.ifm.ifi_index = if_nametoindex(device ? device : ""); + request.ifm.ifi_change = 0xffffffff; iov.iov_base = &request; iov.iov_len = sizeof(request); diff --git a/rtnl.h b/rtnl.h index f1871f2..5c93eec 100644 --- a/rtnl.h +++ b/rtnl.h @@ -31,10 +31,11 @@ int rtnl_close(int fd); /** * Request the link status from the kernel. - * @param fd A socket obtained via rtnl_open(). - * @return Zero on success, non-zero otherwise. + * @param fd A socket obtained via rtnl_open(). + * @param device Interface name. Request all iface's status if set NULL. + * @return Zero on success, non-zero otherwise. */ -int rtnl_link_query(int fd); +int rtnl_link_query(int fd, char *device); /** * Read kernel messages looking for a link up/down events. -- 2.5.5 |
From: Hangbin L. <liu...@gm...> - 2017-09-30 08:26:03
|
Update function rtnl_link_status to get bond slave info. Pass the slave index to call back functions. i.e. port_link_status. Also check the interface index of rtnl message in function rtnl_link_status. Then we don't need to check it in port_link_status. Signed-off-by: Hangbin Liu <liu...@gm...> --- port.c | 6 ++--- rtnl.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- rtnl.h | 13 ++++----- 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/port.c b/port.c index 5b85d87..05fc321 100644 --- a/port.c +++ b/port.c @@ -2221,11 +2221,11 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) } } -static void port_link_status(void *ctx, int index, int linkup) +static void port_link_status(void *ctx, int linkup, int ts_index) { struct port *p = ctx; - if (index != if_nametoindex(p->name) || p->link_status == linkup) + if (p->link_status == linkup) return; p->link_status = linkup; @@ -2280,7 +2280,7 @@ enum fsm_event port_event(struct port *p, int fd_index) case FD_RTNL: pr_debug("port %hu: received link status notification", portnum(p)); - rtnl_link_status(fd, port_link_status, p); + rtnl_link_status(fd, p->name, port_link_status, p); return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED; } diff --git a/rtnl.c b/rtnl.c index 8ecf6fe..d841245 100644 --- a/rtnl.c +++ b/rtnl.c @@ -84,15 +84,79 @@ int rtnl_link_query(int fd, char *device) return 0; } -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) +static inline __u32 rta_getattr_u32(const struct rtattr *rta) { - int index, len; + return *(__u32 *)RTA_DATA(rta); +} + +static inline const char *rta_getattr_str(const struct rtattr *rta) +{ + return (const char *)RTA_DATA(rta); +} + +static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * max); + while (RTA_OK(rta, len)) { + type = rta->rta_type; + if ((type < max) && (!tb[type])) + tb[type] = rta; + rta = RTA_NEXT(rta, len); + } + if (len) { + pr_err("Length mismatch: len %d, rta_len=%d\n", len, rta->rta_len); + return -1; + } + + return 0; +} + +static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta) +{ + return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); +} + +static int rtnl_linkinfo_parse(struct rtattr *rta) +{ + int index = -1; + const char *kind; + struct rtattr *linkinfo[IFLA_INFO_MAX]; + struct rtattr *bond[IFLA_BOND_MAX]; + + if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0) + return -1; + + if (linkinfo[IFLA_INFO_KIND]) { + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); + + if (kind && !strncmp(kind, "bond", 4) && + linkinfo[IFLA_INFO_DATA]) { + if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, + linkinfo[IFLA_INFO_DATA]) < 0) + return -1; + + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); + } + } + } + return index; +} + +int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) +{ + int index, len, link_up; + int slave_index = -1; struct iovec iov; struct sockaddr_nl sa; struct msghdr msg; struct nlmsghdr *nh; struct ifinfomsg *info = NULL; + struct rtattr *tb[IFLA_MAX+1]; + index = if_nametoindex(device); if (!rtnl_buf) { rtnl_len = 4096; rtnl_buf = malloc(rtnl_len); @@ -135,14 +199,27 @@ int rtnl_link_status(int fd, rtnl_callback cb, void *ctx) nh = (struct nlmsghdr *) rtnl_buf; for ( ; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { - if (nh->nlmsg_type == RTM_NEWLINK) { - info = NLMSG_DATA(nh); - index = info->ifi_index; - pr_debug("interface index %d is %s", index, - info->ifi_flags & IFF_RUNNING ? "up" : "down"); - cb(ctx, index, info->ifi_flags & IFF_RUNNING ? 1 : 0); - } + if (nh->nlmsg_type != RTM_NEWLINK) + continue; + + info = NLMSG_DATA(nh); + if (index != info->ifi_index) + continue; + + link_up = info->ifi_flags & IFF_RUNNING ? 1 : 0; + pr_debug("interface index %d is %s", index, + link_up ? "up" : "down"); + + rtnl_rtattr_parse(tb, IFLA_MAX, IFLA_RTA(info), + IFLA_PAYLOAD(nh)); + + if (tb[IFLA_LINKINFO]) + slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]); + + if (cb) + cb(ctx, link_up, slave_index); } + return 0; } diff --git a/rtnl.h b/rtnl.h index 5c93eec..20f1491 100644 --- a/rtnl.h +++ b/rtnl.h @@ -20,7 +20,7 @@ #ifndef HAVE_RTNL_H #define HAVE_RTNL_H -typedef void (*rtnl_callback)(void *ctx, int index, int linkup); +typedef void (*rtnl_callback)(void *ctx, int linkup, int ts_index); /** * Close a RT netlink socket. @@ -39,12 +39,13 @@ int rtnl_link_query(int fd, char *device); /** * Read kernel messages looking for a link up/down events. - * @param fd Readable socket obtained via rtnl_open(). - * @param cb Callback function to be invoked on each event. - * @param ctx Private context passed to the callback. - * @return Zero on success, non-zero otherwise. + * @param fd Readable socket obtained via rtnl_open(). + * @param device The device which we need to get link info. + * @param cb Callback function to be invoked on each event. + * @param ctx Private context passed to the callback. + * @return A slave index, or -1 on error. */ -int rtnl_link_status(int fd, rtnl_callback cb, void *ctx); +int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx); /** * Open a RT netlink socket for monitoring link state. -- 2.5.5 |
From: Richard C. <ric...@gm...> - 2017-10-07 15:30:53
|
On Sat, Sep 30, 2017 at 04:25:12PM +0800, Hangbin Liu wrote: > +static int rtnl_linkinfo_parse(struct rtattr *rta) > +{ > + int index = -1; > + const char *kind; > + struct rtattr *linkinfo[IFLA_INFO_MAX]; > + struct rtattr *bond[IFLA_BOND_MAX]; > + > + if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0) > + return -1; > + > + if (linkinfo[IFLA_INFO_KIND]) { > + kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]); > + > + if (kind && !strncmp(kind, "bond", 4) && > + linkinfo[IFLA_INFO_DATA]) { > + if (rtnl_nested_rtattr_parse(bond, IFLA_BOND_MAX, > + linkinfo[IFLA_INFO_DATA]) < 0) > + return -1; > + > + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { > + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); The IFLA_BOND_ macros first appeared in v3.13-rc1, and we need to allow compiling linuxptp with older kernel headers. How about adding something like this? Thanks, Richard --- diff --git a/missing.h b/missing.h index 7bc1776..cf989b5 100644 --- a/missing.h +++ b/missing.h @@ -69,6 +69,42 @@ static inline int clock_adjtime(clockid_t id, struct timex *tx) } #endif +#ifndef IFLA_BOND_MAX +enum { + IFLA_BOND_UNSPEC, + IFLA_BOND_MODE, + IFLA_BOND_ACTIVE_SLAVE, + IFLA_BOND_MIIMON, + IFLA_BOND_UPDELAY, + IFLA_BOND_DOWNDELAY, + IFLA_BOND_USE_CARRIER, + IFLA_BOND_ARP_INTERVAL, + IFLA_BOND_ARP_IP_TARGET, + IFLA_BOND_ARP_VALIDATE, + IFLA_BOND_ARP_ALL_TARGETS, + IFLA_BOND_PRIMARY, + IFLA_BOND_PRIMARY_RESELECT, + IFLA_BOND_FAIL_OVER_MAC, + IFLA_BOND_XMIT_HASH_POLICY, + IFLA_BOND_RESEND_IGMP, + IFLA_BOND_NUM_PEER_NOTIF, + IFLA_BOND_ALL_SLAVES_ACTIVE, + IFLA_BOND_MIN_LINKS, + IFLA_BOND_LP_INTERVAL, + IFLA_BOND_PACKETS_PER_SLAVE, + IFLA_BOND_AD_LACP_RATE, + IFLA_BOND_AD_SELECT, + IFLA_BOND_AD_INFO, + IFLA_BOND_AD_ACTOR_SYS_PRIO, + IFLA_BOND_AD_USER_PORT_KEY, + IFLA_BOND_AD_ACTOR_SYSTEM, + IFLA_BOND_TLB_DYNAMIC_LB, + __IFLA_BOND_MAX, +}; + +#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) +#endif /*IFLA_BOND_MAX*/ + #ifdef __UCLIBC__ #if (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L) && \ diff --git a/rtnl.c b/rtnl.c index 2ac0b96..0d3bef9 100644 --- a/rtnl.c +++ b/rtnl.c @@ -26,6 +26,7 @@ #include <string.h> #include <unistd.h> +#include "missing.h" #include "print.h" #include "rtnl.h" |