port: add FD_RTNL event to track per-port status

With rtnl socket we can track link status per port(except UDS port).

We can make sure we get the correct interface and latest status with function
port_link_status().

At the same time we need to set clock sde after link down. But we return
EV_FAULT_DETECTED in port_event(), which will not set clock sde. So we need
to set it in port_link_status().

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
master
Hangbin Liu 2017-07-10 15:39:29 +08:00 committed by Richard Cochran
parent 17aa750a49
commit c149a3dbc1
4 changed files with 53 additions and 1 deletions

View File

@ -1469,6 +1469,11 @@ struct PortIdentity clock_parent_identity(struct clock *c)
return c->dad.pds.parentPortIdentity; return c->dad.pds.parentPortIdentity;
} }
void clock_set_sde(struct clock *c, int sde)
{
c->sde = sde;
}
int clock_poll(struct clock *c) int clock_poll(struct clock *c)
{ {
int cnt, i; int cnt, i;

View File

@ -204,6 +204,13 @@ void clock_path_delay(struct clock *c, tmv_t req, tmv_t rx);
void clock_peer_delay(struct clock *c, tmv_t ppd, tmv_t req, tmv_t rx, void clock_peer_delay(struct clock *c, tmv_t ppd, tmv_t req, tmv_t rx,
double nrr); double nrr);
/**
* Set clock sde
* @param c A pointer to a clock instance obtained with clock_create().
* @param sde Pass one (1) if need a decision event and zero if not.
*/
void clock_set_sde(struct clock *c, int sde);
/** /**
* Poll for events and dispatch them. * Poll for events and dispatch them.
* @param c A pointer to a clock instance obtained with clock_create(). * @param c A pointer to a clock instance obtained with clock_create().

1
fd.h
View File

@ -31,6 +31,7 @@ enum {
FD_QUALIFICATION_TIMER, FD_QUALIFICATION_TIMER,
FD_MANNO_TIMER, FD_MANNO_TIMER,
FD_SYNC_TX_TIMER, FD_SYNC_TX_TIMER,
FD_RTNL,
N_POLLFD, N_POLLFD,
}; };

41
port.c
View File

@ -23,6 +23,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <net/if.h>
#include "bmc.h" #include "bmc.h"
#include "clock.h" #include "clock.h"
@ -32,6 +33,7 @@
#include "phc.h" #include "phc.h"
#include "port.h" #include "port.h"
#include "print.h" #include "print.h"
#include "rtnl.h"
#include "sk.h" #include "sk.h"
#include "tlv.h" #include "tlv.h"
#include "tmv.h" #include "tmv.h"
@ -1458,7 +1460,9 @@ static void port_disable(struct port *p)
for (i = 0; i < N_TIMER_FDS; i++) { for (i = 0; i < N_TIMER_FDS; i++) {
close(p->fda.fd[FD_ANNOUNCE_TIMER + i]); close(p->fda.fd[FD_ANNOUNCE_TIMER + i]);
} }
port_clear_fda(p, N_POLLFD);
/* Keep rtnl socket to get link status info. */
port_clear_fda(p, FD_RTNL);
clock_fda_changed(p->clock); clock_fda_changed(p->clock);
} }
@ -1502,6 +1506,14 @@ static int port_initialize(struct port *p)
if (port_set_announce_tmo(p)) if (port_set_announce_tmo(p))
goto no_tmo; goto no_tmo;
/* No need to open rtnl socket on UDS port. */
if (transport_type(p->trp) != TRANS_UDS) {
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]);
}
port_nrate_initialize(p); port_nrate_initialize(p);
clock_fda_changed(p->clock); clock_fda_changed(p->clock);
@ -2025,6 +2037,10 @@ void port_close(struct port *p)
if (port_is_enabled(p)) { if (port_is_enabled(p)) {
port_disable(p); port_disable(p);
} }
if (p->fda.fd[FD_RTNL] >= 0)
rtnl_close(p->fda.fd[FD_RTNL]);
transport_destroy(p->trp); transport_destroy(p->trp);
tsproc_destroy(p->tsproc); tsproc_destroy(p->tsproc);
if (p->fault_fd >= 0) if (p->fault_fd >= 0)
@ -2204,6 +2220,24 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
} }
} }
static void port_link_status(void *ctx, int index, int linkup)
{
struct port *p = ctx;
if (index != if_nametoindex(p->name) || p->link_status == linkup)
return;
p->link_status = linkup;
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)
clock_set_sde(p->clock, 1);
}
enum fsm_event port_event(struct port *p, int fd_index) enum fsm_event port_event(struct port *p, int fd_index)
{ {
enum fsm_event event = EV_NONE; enum fsm_event event = EV_NONE;
@ -2242,6 +2276,11 @@ enum fsm_event port_event(struct port *p, int fd_index)
pr_debug("port %hu: master sync timeout", portnum(p)); pr_debug("port %hu: master sync timeout", portnum(p));
port_set_sync_tx_tmo(p); port_set_sync_tx_tmo(p);
return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE; return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE;
case FD_RTNL:
pr_debug("port %hu: received link status notification", portnum(p));
rtnl_link_status(fd, port_link_status, p);
return port_link_status_get(p) ? EV_FAULT_CLEARED : EV_FAULT_DETECTED;
} }
msg = msg_allocate(); msg = msg_allocate();