Commit cdf616d8 authored by Sven Meier's avatar Sven Meier Committed by Adam Wujek

bmc: add agging, call periodically and data sets

BMC fixed to be called periodically and data sets comparisments fixed
also changed the foreign master table adding and agging and some
minor adpatations in state pre-master
parent ed394bc1
...@@ -55,7 +55,7 @@ static int run_all_state_machines(struct pp_globals *ppg) ...@@ -55,7 +55,7 @@ static int run_all_state_machines(struct pp_globals *ppg)
else { else {
ppi->n_ops->exit(ppi); ppi->n_ops->exit(ppi);
ppi->frgn_rec_num = 0; ppi->frgn_rec_num = 0;
ppi->frgn_rec_best = -1; ppi->frgn_rec_best = 0;
if (ppg->ebest_idx == ppi->port_idx) if (ppg->ebest_idx == ppi->port_idx)
wr_servo_reset(ppi); wr_servo_reset(ppi);
} }
......
...@@ -167,7 +167,7 @@ static int type_length[__PP_NR_MESSAGES_TYPES] = { ...@@ -167,7 +167,7 @@ static int type_length[__PP_NR_MESSAGES_TYPES] = {
[PPM_DELAY_RESP] = PP_DELAY_RESP_LENGTH, [PPM_DELAY_RESP] = PP_DELAY_RESP_LENGTH,
[PPM_PDELAY_R_FUP] = PP_PDELAY_R_FUP_LENGTH, [PPM_PDELAY_R_FUP] = PP_PDELAY_R_FUP_LENGTH,
[PPM_ANNOUNCE] = PP_ANNOUNCE_LENGTH, [PPM_ANNOUNCE] = PP_ANNOUNCE_LENGTH,
[PPM_SIGNALING] = PP_HEADER_LENGTH, [PPM_SIGNALING] = PP_HEADER_LENGTH,
[PPM_MANAGEMENT] = PP_MANAGEMENT_LENGTH, [PPM_MANAGEMENT] = PP_MANAGEMENT_LENGTH,
}; };
...@@ -253,11 +253,18 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen) ...@@ -253,11 +253,18 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen)
plen = 0; plen = 0;
} }
} }
/* run bmc independent of state, and since not message driven do this
* here 9.2.6.8 */
if (pp_timeout(ppi, PP_TO_BMC))
ppi->next_state = bmc(ppi);
if (ppi->state != ppi->next_state) if (ppi->state != ppi->next_state)
return leave_current_state(ppi); return leave_current_state(ppi);
if (!plen) if (!plen)
ppi->received_ptp_header.messageType = PPM_NO_MESSAGE; ppi->received_ptp_header.messageType = PPM_NO_MESSAGE;
err = ip->f1(ppi, packet, plen); err = ip->f1(ppi, packet, plen);
if (err) if (err)
pp_printf("fsm for %s: Error %i in %s\n", pp_printf("fsm for %s: Error %i in %s\n",
...@@ -268,5 +275,10 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen) ...@@ -268,5 +275,10 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen)
return leave_current_state(ppi); return leave_current_state(ppi);
pp_diag_fsm(ppi, ip->name, STATE_LOOP, 0); pp_diag_fsm(ppi, ip->name, STATE_LOOP, 0);
/* check if the BMC timeout is the next to run */
if (pp_next_delay_1(ppi, PP_TO_BMC) < ppi->next_delay)
ppi->next_delay = pp_next_delay_1(ppi, PP_TO_BMC);
return ppi->next_delay; return ppi->next_delay;
} }
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
#define PP_DEFAULT_AP 10 #define PP_DEFAULT_AP 10
#define PP_DEFAULT_AI 1000 #define PP_DEFAULT_AI 1000
#define PP_DEFAULT_DELAY_S 6 #define PP_DEFAULT_DELAY_S 6
#define PP_DEFAULT_ANNOUNCE_INTERVAL 1 /* 0 in 802.1AS */ #define PP_DEFAULT_ANNOUNCE_INTERVAL 1 /* 0 in 802.1AS */
#define PP_DEFAULT_DELAYREQ_INTERVAL 0 #define PP_DEFAULT_DELAYREQ_INTERVAL 0
#define PP_DEFAULT_SYNC_INTERVAL 0 /* -7 in 802.1AS */ #define PP_DEFAULT_SYNC_INTERVAL 0 /* -7 in 802.1AS */
#define PP_DEFAULT_SYNC_RECEIPT_TIMEOUT 3 #define PP_DEFAULT_SYNC_RECEIPT_TIMEOUT 3
#define PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT 20 /* 3 by default */ #define PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT 3 /* 3 by default */
/* Clock classes (pag 55, PTP-2008). See ppsi-manual for an explanation */ /* Clock classes (pag 55, PTP-2008). See ppsi-manual for an explanation */
#define PP_CLASS_SLAVE_ONLY 255 #define PP_CLASS_SLAVE_ONLY 255
...@@ -43,12 +43,15 @@ ...@@ -43,12 +43,15 @@
* same value as in ptpdv1 * same value as in ptpdv1
*/ */
#define PP_NR_FOREIGN_RECORDS 5 #define PP_NR_FOREIGN_RECORDS 5
#define PP_FOREIGN_MASTER_TIME_WINDOW 4
#define PP_FOREIGN_MASTER_THRESHOLD 2
#define PP_DEFAULT_TTL 1 #define PP_DEFAULT_TTL 1
/* We use an array of timeouts, with these indexes */ /* We use an array of timeouts, with these indexes */
enum pp_timeouts { enum pp_timeouts {
PP_TO_REQUEST = 0, PP_TO_REQUEST = 0,
PP_TO_SYNC_SEND, PP_TO_SYNC_SEND,
PP_TO_BMC,
PP_TO_ANN_RECEIPT, PP_TO_ANN_RECEIPT,
PP_TO_ANN_SEND, PP_TO_ANN_SEND,
PP_TO_FAULT, PP_TO_FAULT,
......
...@@ -45,7 +45,7 @@ typedef struct Integer64 { ...@@ -45,7 +45,7 @@ typedef struct Integer64 {
typedef struct UInteger64 { typedef struct UInteger64 {
uint32_t lsb; uint32_t lsb;
uint32_t msb; uint32_t msb;
} UInteger64; } UInteger64;
struct TimeInterval { /* page 12 (32) -- never used */ struct TimeInterval { /* page 12 (32) -- never used */
...@@ -54,7 +54,7 @@ struct TimeInterval { /* page 12 (32) -- never used */ ...@@ -54,7 +54,7 @@ struct TimeInterval { /* page 12 (32) -- never used */
/* White Rabbit extension */ /* White Rabbit extension */
typedef struct FixedDelta { typedef struct FixedDelta {
UInteger64 scaledPicoseconds; UInteger64 scaledPicoseconds;
} FixedDelta; } FixedDelta;
typedef struct Timestamp { /* page 13 (33) -- no typedef expected */ typedef struct Timestamp { /* page 13 (33) -- no typedef expected */
...@@ -217,7 +217,7 @@ typedef struct DSCurrent { /* page 67 */ ...@@ -217,7 +217,7 @@ typedef struct DSCurrent { /* page 67 */
typedef struct DSParent { /* page 68 */ typedef struct DSParent { /* page 68 */
/* Dynamic */ /* Dynamic */
PortIdentity parentPortIdentity; PortIdentity parentPortIdentity;
/* Boolean parentStats; -- not used */ /* Boolean parentStats; -- not used */
UInteger16 observedParentOffsetScaledLogVariance; UInteger16 observedParentOffsetScaledLogVariance;
Integer32 observedParentClockPhaseChangeRate; Integer32 observedParentClockPhaseChangeRate;
ClockIdentity grandmasterIdentity; ClockIdentity grandmasterIdentity;
......
...@@ -65,6 +65,11 @@ struct pp_channel { ...@@ -65,6 +65,11 @@ struct pp_channel {
*/ */
struct pp_frgn_master { struct pp_frgn_master {
PortIdentity port_id; /* used to identify old/new masters */ PortIdentity port_id; /* used to identify old/new masters */
PortIdentity source_id; /* used for the dataset comparisment */
/* how many announce messages from this port where received in the
* interval */
int ann_cnt[PP_FOREIGN_MASTER_TIME_WINDOW];
/* We don't need all fields of the following ones */ /* We don't need all fields of the following ones */
MsgAnnounce ann; MsgAnnounce ann;
......
...@@ -231,6 +231,7 @@ extern struct pp_time_operations unix_time_ops; ...@@ -231,6 +231,7 @@ extern struct pp_time_operations unix_time_ops;
*/ */
extern void pp_timeout_init(struct pp_instance *ppi); extern void pp_timeout_init(struct pp_instance *ppi);
extern void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec); extern void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec);
extern void pp_timeout_clear(struct pp_instance *ppi, int index);
extern void pp_timeout_set(struct pp_instance *ppi, int index); extern void pp_timeout_set(struct pp_instance *ppi, int index);
extern void pp_timeout_setall(struct pp_instance *ppi); extern void pp_timeout_setall(struct pp_instance *ppi);
extern int pp_timeout(struct pp_instance *ppi, int index) extern int pp_timeout(struct pp_instance *ppi, int index)
...@@ -360,7 +361,9 @@ extern void pp_servo_got_presp(struct pp_instance *ppi); /* got all t3..t6 */ ...@@ -360,7 +361,9 @@ extern void pp_servo_got_presp(struct pp_instance *ppi); /* got all t3..t6 */
/* bmc.c */ /* bmc.c */
extern void m1(struct pp_instance *ppi); extern void m1(struct pp_instance *ppi);
extern int bmc(struct pp_instance *ppi); extern int bmc(struct pp_instance *ppi);
extern int bmc_dataset_cmp(struct pp_instance *ppi,
struct pp_frgn_master *a,
struct pp_frgn_master *b);
/* msg.c */ /* msg.c */
extern void msg_init_header(struct pp_instance *ppi, void *buf); extern void msg_init_header(struct pp_instance *ppi, void *buf);
extern int __attribute__((warn_unused_result)) extern int __attribute__((warn_unused_result))
...@@ -383,7 +386,7 @@ extern void msg_unpack_pdelay_req(void *buf, MsgPDelayReq * pdelay_req); ...@@ -383,7 +386,7 @@ extern void msg_unpack_pdelay_req(void *buf, MsgPDelayReq * pdelay_req);
#define PP_SEND_ERROR -1 #define PP_SEND_ERROR -1
#define PP_SEND_NO_STAMP 1 #define PP_SEND_NO_STAMP 1
#define PP_SEND_DROP -2 #define PP_SEND_DROP -2
#define PP_RECV_DROP PP_SEND_DROP #define PP_RECV_DROP PP_SEND_DROP
extern void *msg_copy_header(MsgHeader *dest, MsgHeader *src); /* REMOVE ME!! */ extern void *msg_copy_header(MsgHeader *dest, MsgHeader *src); /* REMOVE ME!! */
extern int msg_issue_announce(struct pp_instance *ppi); extern int msg_issue_announce(struct pp_instance *ppi);
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
/* Please increment WRS_PPSI_SHMEM_VERSION if you change any exported data /* Please increment WRS_PPSI_SHMEM_VERSION if you change any exported data
* structure */ * structure */
#define WRS_PPSI_SHMEM_VERSION 20 /* Replace cField, t4_cf and t6_cf with #define WRS_PPSI_SHMEM_VERSION 21 /* Added source_id and ann_cnt to struct
syncCF */ * pp_frgn_master */
/* Don't include the Following when this file is included in assembler. */ /* Don't include the Following when this file is included in assembler. */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
...@@ -43,6 +43,40 @@ void m1(struct pp_instance *ppi) ...@@ -43,6 +43,40 @@ void m1(struct pp_instance *ppi)
DSPRO(ppi)->timeSource = INTERNAL_OSCILLATOR; DSPRO(ppi)->timeSource = INTERNAL_OSCILLATOR;
} }
/* ppi->port_idx port is becoming Master. Table 13 (9.3.5) of the spec. */
static void m2(struct pp_instance *ppi)
{
struct DSParent *parent = DSPAR(ppi);
struct DSDefault *defds = DSDEF(ppi);
/* Current data set update */
DSCUR(ppi)->stepsRemoved = 0;
clear_time(&DSCUR(ppi)->offsetFromMaster);
clear_time(&DSCUR(ppi)->meanPathDelay);
/* Parent data set: we are the parent */
memset(parent, 0, sizeof(*parent));
parent->parentPortIdentity.clockIdentity = defds->clockIdentity;
parent->parentPortIdentity.portNumber = 0;
/* Copy grandmaster params from our defds (FIXME: is ir right?) */
parent->grandmasterIdentity = defds->clockIdentity;
parent->grandmasterClockQuality = defds->clockQuality;
parent->grandmasterPriority1 = defds->priority1;
parent->grandmasterPriority2 = defds->priority2;
/* Time Properties data set */
DSPRO(ppi)->ptpTimescale = TRUE;
DSPRO(ppi)->timeSource = INTERNAL_OSCILLATOR;
}
/* ppi->port_idx port is becoming Master. Table 14 (9.3.5) of the spec. */
static void m3(struct pp_instance *ppi)
{
/* In the default implementation, nothing should be done when a port
* goes to master state at m3. This empty function is a placeholder for
* extension-specific needs, to be implemented as a hook */
}
/* ppi->port_idx port is synchronized to Ebest Table 16 (9.3.5) of the spec. */ /* ppi->port_idx port is synchronized to Ebest Table 16 (9.3.5) of the spec. */
static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann) static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
...@@ -68,9 +102,7 @@ static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann) ...@@ -68,9 +102,7 @@ static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
prop->currentUtcOffset = ann->currentUtcOffset; prop->currentUtcOffset = ann->currentUtcOffset;
ppi->t_ops->set(ppi, NULL); ppi->t_ops->set(ppi, NULL);
} }
prop->currentUtcOffsetValid = ((hdr->flagField[1] & FFB_UTCV) != 0);
/* FIXME: can't we just copy the bit keeping values? */
prop->currentUtcOffsetValid = ((hdr->flagField[1] & FFB_UTCV) != 0);
prop->leap59 = ((hdr->flagField[1] & FFB_LI59) != 0); prop->leap59 = ((hdr->flagField[1] & FFB_LI59) != 0);
prop->leap61 = ((hdr->flagField[1] & FFB_LI61) != 0); prop->leap61 = ((hdr->flagField[1] & FFB_LI61) != 0);
prop->timeTraceable = ((hdr->flagField[1] & FFB_TTRA) != 0); prop->timeTraceable = ((hdr->flagField[1] & FFB_TTRA) != 0);
...@@ -81,25 +113,44 @@ static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann) ...@@ -81,25 +113,44 @@ static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
pp_hooks.s1(ppi, hdr, ann); pp_hooks.s1(ppi, hdr, ann);
} }
static void p1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann) static void p1(struct pp_instance *ppi)
{
/* In the default implementation, nothing should be done when a port
* goes to passive state. This empty function is a placeholder for
* extension-specific needs, to be implemented as a hook */
}
static void p2(struct pp_instance *ppi)
{ {
/* In the default implementation, nothing should be done when a port goes /* In the default implementation, nothing should be done when a port
* to passive state. This empty function is a placeholder for * goes to passive state. This empty function is a placeholder for
* extension-specific needs, to be implemented as a hook */ * extension-specific needs, to be implemented as a hook */
} }
/* Copy local data set into header and ann message. 9.3.4 table 12. */ /* Copy local data set into header and ann message. 9.3.4 table 12. */
static void copy_d0(struct pp_instance *ppi, struct pp_frgn_master *m) static void copy_d0(struct pp_instance *ppi, struct pp_frgn_master *m)
{ {
int i;
struct DSDefault *defds = DSDEF(ppi); struct DSDefault *defds = DSDEF(ppi);
struct PortIdentity *port_id = &m->port_id;
struct PortIdentity *source_id = &m->source_id;
int *ann_cnt = m->ann_cnt;
struct MsgHeader *hdr = &m->hdr; struct MsgHeader *hdr = &m->hdr;
struct MsgAnnounce *ann = &m->ann; struct MsgAnnounce *ann = &m->ann;
*port_id = DSPOR(ppi)->portIdentity;
*source_id = DSPOR(ppi)->portIdentity;
/* this shall be always qualified */
for (i = 0; i < PP_FOREIGN_MASTER_TIME_WINDOW; i++)
ann_cnt[i] = 1;
ann->grandmasterIdentity = defds->clockIdentity; ann->grandmasterIdentity = defds->clockIdentity;
ann->grandmasterClockQuality = defds->clockQuality; ann->grandmasterClockQuality = defds->clockQuality;
ann->grandmasterPriority1 = defds->priority1; ann->grandmasterPriority1 = defds->priority1;
ann->grandmasterPriority2 = defds->priority2; ann->grandmasterPriority2 = defds->priority2;
ann->stepsRemoved = 0; ann->stepsRemoved = 0;
hdr->sourcePortIdentity.clockIdentity = defds->clockIdentity; hdr->sourcePortIdentity.clockIdentity = defds->clockIdentity;
} }
...@@ -108,63 +159,54 @@ static int idcmp(struct ClockIdentity *a, struct ClockIdentity *b) ...@@ -108,63 +159,54 @@ static int idcmp(struct ClockIdentity *a, struct ClockIdentity *b)
return memcmp(a, b, sizeof(*a)); return memcmp(a, b, sizeof(*a));
} }
/* static int pidcmp(struct PortIdentity *a, struct PortIdentity *b)
* Data set comparison between two foreign masters. Return similar to {
* memcmp(). However, lower values take precedence, so in A-B (like return memcmp(a, b, sizeof(*a));
* in comparisons, > 0 means B wins (and < 0 means A wins). }
*/
static int bmc_dataset_cmp(struct pp_instance *ppi, /* compare part2 of the datasets which is the topology, fig 27, page 89 */
static int bmc_gm_cmp(struct pp_instance *ppi,
struct pp_frgn_master *a, struct pp_frgn_master *a,
struct pp_frgn_master *b) struct pp_frgn_master *b)
{ {
int i;
struct ClockQuality *qa, *qb; struct ClockQuality *qa, *qb;
struct MsgAnnounce *aa = &a->ann; struct MsgAnnounce *aa = &a->ann;
struct MsgAnnounce *ab = &b->ann; struct MsgAnnounce *ab = &b->ann;
struct ClockIdentity *ida = &a->hdr.sourcePortIdentity.clockIdentity; int *ca = a->ann_cnt;
struct ClockIdentity *idb = &b->hdr.sourcePortIdentity.clockIdentity; int *cb = b->ann_cnt;
struct ClockIdentity *idparent; int qualifieda = 0;
int diff; int qualifiedb = 0;
/* dataset_cmp is called several times, so report only at level 2 */ /* bmc_gm_cmp is called several times, so report only at level 2 */
pp_diag(ppi, bmc, 2,"%s\n", __func__); pp_diag(ppi, bmc, 2, "%s\n", __func__);
if (!idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity)) {
/* The grandmaster is the same: part 2, fig 28, page 90. */ for (i = 0; i < PP_FOREIGN_MASTER_TIME_WINDOW; i++) {
qualifieda += ca[i];
diff = aa->stepsRemoved - ab->stepsRemoved; qualifiedb += cb[i];
if (diff > 1 || diff < -1) }
return diff;
idparent = &DSPAR(ppi)->parentPortIdentity.clockIdentity; /* if B is not qualified 9.3.2.5 c) & 9.3.2.3 a) & b)*/
if ((qualifieda >= PP_FOREIGN_MASTER_THRESHOLD)
&& (qualifiedb < PP_FOREIGN_MASTER_THRESHOLD)) {
pp_diag(ppi, bmc, 2, "Dataset B not qualified\n");
return -1;
}
if (diff > 0) { /* if a is not qualified 9.3.2.5 c) & 9.3.2.3 a) & b) */
if (!idcmp(ida, idparent)) { if ((qualifiedb >= PP_FOREIGN_MASTER_THRESHOLD)
pp_diag(ppi, bmc, 1,"%s:%i: Error 1\n", && (qualifieda < PP_FOREIGN_MASTER_THRESHOLD)) {
__func__, __LINE__); pp_diag(ppi, bmc, 2, "Dataset A not qualified\n");
return 0; return 1;
} }
return 1;
} /* if both are not qualified 9.3.2.5 c) & 9.3.2.3 a) & b) */
if (diff < 0) { if ((qualifieda < PP_FOREIGN_MASTER_THRESHOLD)
if (!idcmp(idb, idparent)) { && (qualifiedb < PP_FOREIGN_MASTER_THRESHOLD)) {
pp_diag(ppi, bmc, 1,"%s:%i: Error 1\n", pp_diag(ppi, bmc, 2, "Dataset A & B not qualified\n");
__func__, __LINE__); return 0;
return 0;
}
return -1;
}
/* stepsRemoved is equal, compare identities */
diff = idcmp(ida, idb);
if (!diff) {
pp_diag(ppi, bmc, 1,"%s:%i: Error 2\n", __func__, __LINE__);
return 0;
}
return diff;
} }
/* The grandmasters are different: part 1, fig 27, page 89. */
qa = &aa->grandmasterClockQuality; qa = &aa->grandmasterClockQuality;
qb = &ab->grandmasterClockQuality; qb = &ab->grandmasterClockQuality;
...@@ -178,7 +220,8 @@ static int bmc_dataset_cmp(struct pp_instance *ppi, ...@@ -178,7 +220,8 @@ static int bmc_dataset_cmp(struct pp_instance *ppi,
return qa->clockAccuracy - qb->clockAccuracy; return qa->clockAccuracy - qb->clockAccuracy;
if (qa->offsetScaledLogVariance != qb->offsetScaledLogVariance) if (qa->offsetScaledLogVariance != qb->offsetScaledLogVariance)
return qa->clockClass - qb->clockClass; return qa->offsetScaledLogVariance
- qb->offsetScaledLogVariance;
if (aa->grandmasterPriority2 != ab->grandmasterPriority2) if (aa->grandmasterPriority2 != ab->grandmasterPriority2)
return aa->grandmasterPriority2 - ab->grandmasterPriority2; return aa->grandmasterPriority2 - ab->grandmasterPriority2;
...@@ -186,103 +229,440 @@ static int bmc_dataset_cmp(struct pp_instance *ppi, ...@@ -186,103 +229,440 @@ static int bmc_dataset_cmp(struct pp_instance *ppi,
return idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity); return idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity);
} }
/* State decision algorithm 9.3.3 Fig 26 */ /* compare part2 of the datasets which is the topology, fig 28, page 90 */
static int bmc_state_decision(struct pp_instance *ppi, static int bmc_topology_cmp(struct pp_instance *ppi,
struct pp_frgn_master *m) struct pp_frgn_master *a,
struct pp_frgn_master *b)
{ {
int cmpres, ret; int i;
struct pp_frgn_master myself; struct MsgAnnounce *aa = &a->ann;
struct MsgAnnounce *ab = &b->ann;
struct PortIdentity *pidtxa = &a->hdr.sourcePortIdentity;
struct PortIdentity *pidtxb = &b->hdr.sourcePortIdentity;
struct PortIdentity *pidrxa = &a->source_id;
struct PortIdentity *pidrxb = &b->source_id;
int *ca = a->ann_cnt;
int *cb = b->ann_cnt;
int qualifieda = 0;
int qualifiedb = 0;
int diff;
/* bmc_topology_cmp is called several times, so report only at level 2
*/
pp_diag(ppi, bmc, 2, "%s\n", __func__);
for (i = 0; i < PP_FOREIGN_MASTER_TIME_WINDOW; i++) {
qualifieda += ca[i];
qualifiedb += cb[i];
}
/* if B is not qualified 9.3.2.5 c) & 9.3.2.3 a) & b)*/
if ((qualifieda >= PP_FOREIGN_MASTER_THRESHOLD)
&& (qualifiedb < PP_FOREIGN_MASTER_THRESHOLD)) {
pp_diag(ppi, bmc, 2, "Dataset B not qualified\n");
return -1;
}
/* if a is not qualified 9.3.2.5 c) & 9.3.2.3 a) & b) */
if ((qualifiedb >= PP_FOREIGN_MASTER_THRESHOLD)
&& (qualifieda < PP_FOREIGN_MASTER_THRESHOLD)) {
pp_diag(ppi, bmc, 2, "Dataset A not qualified\n");
return 1;
}
/* if both are not qualified 9.3.2.5 c) & 9.3.2.3 a) & b) */
if ((qualifieda < PP_FOREIGN_MASTER_THRESHOLD)
&& (qualifiedb < PP_FOREIGN_MASTER_THRESHOLD)) {
pp_diag(ppi, bmc, 2, "Dataset A & B not qualified\n");
return 0;
}
diff = aa->stepsRemoved - ab->stepsRemoved;
if (diff > 1 || diff < -1)
return diff;
if (diff > 0) {
if (!pidcmp(pidtxa, pidrxa)) {
pp_diag(ppi, bmc, 1, "%s:%i: Error 1\n",
__func__, __LINE__);
return 0;
}
return 1;
if (ppi->role == PPSI_ROLE_SLAVE) }
goto slave; if (diff < 0) {
if (!pidcmp(pidtxb, pidrxb)) {
pp_diag(ppi, bmc, 1, "%s:%i: Error 1\n",
__func__, __LINE__);
return 0;
}
return -1;
}
/* stepsRemoved is equal, compare identities */
diff = pidcmp(pidtxa, pidtxb);
if (diff)
return diff;
/* sourcePortIdentity is equal, compare receive port identites, which
* is the last decision maker, which has to be different */
return pidcmp(pidrxa, pidrxb);
}
/*
* Data set comparison between two foreign masters. Return similar to
* memcmp(). However, lower values take precedence, so in A-B (like
* in comparisons, > 0 means B wins (and < 0 means A wins).
*/
int bmc_dataset_cmp(struct pp_instance *ppi,
struct pp_frgn_master *a,
struct pp_frgn_master *b)
{
struct MsgAnnounce *aa = &a->ann;
struct MsgAnnounce *ab = &b->ann;
/* dataset_cmp is called several times, so report only at level 2 */
pp_diag(ppi, bmc, 2, "%s\n", __func__);
if (!idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity)) {
/* Check topology */
return bmc_topology_cmp(ppi, a, b);
} else {
/* Check grandmasters */
return bmc_gm_cmp(ppi, a, b);
}
}
/* State decision algorithm 9.3.3 Fig 26 */
static int bmc_state_decision(struct pp_instance *ppi)
{
int cmpres;
struct pp_frgn_master d0;
struct pp_globals *ppg = GLBS(ppi);
struct pp_instance *ppi_best;
struct pp_frgn_master *erbest = &ppi->frgn_master[ppi->frgn_rec_best];
struct pp_frgn_master *ebest;
/* bmc_state_decision is called several times, so report only at
* level 2 */
pp_diag(ppi, bmc, 2, "%s\n", __func__);
if (ppi->role == PPSI_ROLE_SLAVE) {
/* if on this conigured port is ebest it will be taken as
* parent */
ebest = erbest;
goto slave_s1;
}
if ((!ppi->frgn_rec_num) && (ppi->state == PPS_LISTENING)) if ((!ppi->frgn_rec_num) && (ppi->state == PPS_LISTENING))
return PPS_LISTENING; return PPS_LISTENING;
/* copy local information to a foreign_master structure */ /* copy local information to a foreign_master structure */
copy_d0(ppi, &myself); copy_d0(ppi, &d0);
if (ppi->role == PPSI_ROLE_MASTER) {
/* if there is a better master show these values */
if (ppg->ebest_idx >= 0) {
/* don't update parent dataset */
goto master_m3;
} else {
/* provide our info */
goto master_m1;
}
}
/* dataset_cmp is "a - b" but lower values win */
cmpres = bmc_dataset_cmp(ppi, &myself, m);
if (ppi->role == PPSI_ROLE_MASTER) /* if there is a foreign master take it otherwise just go to master */
goto master; if (ppg->ebest_idx >= 0) {
ppi_best = INST(ppg, ppg->ebest_idx);
ebest = &ppi_best->frgn_master[ppi_best->frgn_rec_best];
pp_diag(ppi, bmc, 2, "Taking real Ebest at port %i foreign "
"master %i/%i\n", (ppg->ebest_idx+1),
ppi_best->frgn_rec_best, ppi_best->frgn_rec_num);
} else {
/* directly go to master state */
pp_diag(ppi, bmc, 2, "No real Ebest\n");
goto master_m1;
}
if (DSDEF(ppi)->clockQuality.clockClass < 128) { if (DSDEF(ppi)->clockQuality.clockClass < 128) {
/* dataset_cmp D0 with Erbest */
cmpres = bmc_dataset_cmp(ppi, &d0, erbest);
if (cmpres < 0) if (cmpres < 0)
goto master; goto master_m1;
if (cmpres > 0) if (cmpres > 0)
goto passive; goto passive_p1;
} else {
/* dataset_cmp D0 with Ebest */
cmpres = bmc_dataset_cmp(ppi, &d0, ebest);
if (cmpres < 0)
goto master_m2;
if (cmpres > 0) {
if (DSDEF(ppi)->numberPorts == 1)
goto slave_s1; /* directly skip to ordinary
* clock handling */
else
goto check_boundary_clk;
}
} }
pp_diag(ppi, bmc, 1, "%s: error\n", __func__);
return PPS_FAULTY;
check_boundary_clk:
/* If this port is the Ebest */
if (ppi->port_idx == GLBS(ppi)->ebest_idx)
goto slave_s1;
/* bmc_gm_cmp Ebest with Erbest */
cmpres = bmc_gm_cmp(ppi, ebest, erbest);
if (cmpres < 0) if (cmpres < 0)
goto master; goto master_m3;
if (cmpres > 0) {
if (DSDEF(ppi)->numberPorts == 1)
goto slave; /* directly skip to ordinary clock handling */
else
goto check_boundary_clk;
}
pp_diag(ppi, bmc, 1,"%s: error\n", __func__); /* topology_cmp Ebest with Erbest */
cmpres = bmc_topology_cmp(ppi, ebest, erbest);
if (cmpres < 0)
goto passive_p2;
if (cmpres > 0)
goto master_m3;
pp_diag(ppi, bmc, 1, "%s: error\n", __func__);
/* MB: Is this the return code below correct? */
/* Anyway, it's a valid return code. */
return PPS_FAULTY; return PPS_FAULTY;
check_boundary_clk: passive_p1:
if (ppi->port_idx == GLBS(ppi)->ebest_idx) /* This port is the Ebest */ p1(ppi);
goto slave; pp_diag(ppi, bmc, 1, "%s: passive p1\n", __func__);
/* If idcmp returns 0, it means that this port is not the best because
* Ebest is better by topology than Erbest */
if (!idcmp(&myself.ann.grandmasterIdentity,
&m->ann.grandmasterIdentity))
goto passive;
else
goto master;
passive:
p1(ppi, &m->hdr, &m->ann);
pp_diag(ppi, bmc, 1,"%s: passive\n", __func__);
return PPS_PASSIVE; return PPS_PASSIVE;
master: passive_p2:
//TODO: consider whether a smarter solution is needed for non-simple cases p2(ppi);
if(cmpres < 0) { // it is M1 and M2, see IEEE1588-2008, page 87, in short switch is a GM pp_diag(ppi, bmc, 1, "%s: passive p2\n", __func__);
m1(ppi); //GM return PPS_PASSIVE;
ret = PPS_MASTER;
master_m1:
m1(ppi);
pp_diag(ppi, bmc, 1, "%s: master m1\n", __func__);
if (ppi->state != PPS_MASTER) {
/* if not already in pre master state start qualification */
if (ppi->state != PPS_PRE_MASTER) {
/* 9.2.6.11 a) timeout 0 */
pp_timeout_clear(ppi, PP_TO_QUALIFICATION);
}
return PPS_PRE_MASTER;
} else } else
ret = PPS_PRE_MASTER; return PPS_MASTER;
pp_diag(ppi, bmc, 1,"%s: %smaster\n", __func__,
ret == PPS_PRE_MASTER ? "pre-" : ""); master_m2:
return ret; m2(ppi);
pp_diag(ppi, bmc, 1, "%s: master m2\n", __func__);
slave: if (ppi->state != PPS_MASTER) {
s1(ppi, &m->hdr, &m->ann); /* if not already in pre master state start qualification */
pp_diag(ppi, bmc, 1,"%s: slave\n", __func__); if (ppi->state != PPS_PRE_MASTER) {
/* 9.2.6.11 a) timeout 0 */
pp_timeout_clear(ppi, PP_TO_QUALIFICATION);
}
return PPS_PRE_MASTER;
} else
return PPS_MASTER;
master_m3:
m3(ppi);
pp_diag(ppi, bmc, 1, "%s: master m3\n", __func__);
if (ppi->state != PPS_MASTER) {
/* if not already in pre master state start qualification */
if (ppi->state != PPS_PRE_MASTER) {
/* 9.2.6.11 b) timeout steps removed+1 */
pp_timeout_set(ppi, PP_TO_QUALIFICATION);
}
return PPS_PRE_MASTER;
} else
return PPS_MASTER;
slave_s1:
/* only update parent dataset if best master is on this port */
if (ppi->port_idx == GLBS(ppi)->ebest_idx)
s1(ppi, &ebest->hdr, &ebest->ann);
pp_diag(ppi, bmc, 1, "%s: slave s1\n", __func__);
return PPS_SLAVE; return PPS_SLAVE;
} }
static void bmc_age_frgn_master(struct pp_instance *ppi)
{
int i, j;
int qualified;
/* bmc_age_frgn_master is called several times, so report only at
* level 2 */
pp_diag(ppi, bmc, 2, "%s\n", __func__);
for (i = 0; i < ppi->frgn_rec_num; i++) {
/* get qualification */
qualified = 0;
for (j = 0; j < PP_FOREIGN_MASTER_TIME_WINDOW; j++)
qualified += ppi->frgn_master[i].ann_cnt[j];
/* shift qualification */
for (j = 1; j < PP_FOREIGN_MASTER_TIME_WINDOW; j++)
ppi->frgn_master[i].ann_cnt[
(PP_FOREIGN_MASTER_TIME_WINDOW - j)] =
ppi->frgn_master[i].ann_cnt[
(PP_FOREIGN_MASTER_TIME_WINDOW - j - 1)];
/* clear lowest */
ppi->frgn_master[i].ann_cnt[0] = 0;
/* remove aged out and shift foreign masters*/
if (qualified == 0) {
for (j = i; j < PP_NR_FOREIGN_RECORDS; j++) {
if (j < (ppi->frgn_rec_num-1)) {
/* overwrite and shift next foreign
* master in */
memcpy(&ppi->frgn_master[j],
&ppi->frgn_master[(j+1)],
sizeof(ppi->frgn_master[j]));
} else {
/* clear the last (and others) since
* shifted */
memset(&ppi->frgn_master[j], 0,
sizeof(ppi->frgn_master[j]));
}
}
pp_diag(ppi, bmc, 1, "Aged out foreign master %i/%i\n",
i, ppi->frgn_rec_num);
/* one less and restart at the shifted one */
ppi->frgn_rec_num--;
i--;
}
}
}
/* Check if any port is in initilaizing state */
static int bmc_any_port_initializing(struct pp_globals *ppg)
{
int i;
struct pp_instance *ppi;
/* bmc_any_port_initializing is called several times, so report only at
* level 2 */
pp_diag(INST(ppg, 0), bmc, 2, "%s\n", __func__);
for (i = 0; i < ppg->defaultDS->numberPorts; i++) {
ppi = INST(ppg, i);
if ((WR_DSPOR(ppi)->linkUP)
&& (ppi->state == PPS_INITIALIZING)) {
pp_diag(ppi, bmc, 2, "The first port in INITIALIZING "
"state is %i\n", i);
return 1;
}
}
return 0;
}
/* Find Erbest, 9.3.2.2 */
static void bmc_update_erbest(struct pp_globals *ppg)
{
int i, j, best;
struct pp_instance *ppi;
struct pp_frgn_master *frgn_master;
struct PortIdentity *frgn_master_pid;
/* bmc_update_erbest is called several times, so report only at
* level 2 */
pp_diag(INST(ppg, 0), bmc, 2, "%s\n", __func__);
for (i = 0; i < ppg->defaultDS->numberPorts; i++) {
ppi = INST(ppg, i);
frgn_master = ppi->frgn_master;
if (ppi->frgn_rec_num > 0) {
/* Only if port is not in the FAULTY or DISABLED
* state 9.2.6.8 */
if ((ppi->state != PPS_FAULTY)
&& (ppi->state != PPS_DISABLED)) {
for (j = 1, best = 0; j < ppi->frgn_rec_num;
j++)
if (bmc_dataset_cmp(ppi,
&frgn_master[j],
&frgn_master[best]
) < 0)
best = j;
pp_diag(ppi, bmc, 1, "Best foreign master is "
"at index %i/%i\n", best,
ppi->frgn_rec_num);
frgn_master_pid = &frgn_master[best].hdr.sourcePortIdentity;
pp_diag(ppi, bmc, 3, "SourePortId = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x.%04x\n",
frgn_master_pid->clockIdentity.id[0], frgn_master_pid->clockIdentity.id[1],
frgn_master_pid->clockIdentity.id[2], frgn_master_pid->clockIdentity.id[3],
frgn_master_pid->clockIdentity.id[4], frgn_master_pid->clockIdentity.id[5],
frgn_master_pid->clockIdentity.id[6], frgn_master_pid->clockIdentity.id[7],
frgn_master_pid->portNumber);
ppi->frgn_rec_best = best;
} else {
ppi->frgn_rec_num = 0;
ppi->frgn_rec_best = 0;
memset(&ppi->frgn_master, 0,
sizeof(ppi->frgn_master));
}
} else {
/* lets just set the first one */
ppi->frgn_rec_best = 0;
}
}
}
/* Find Ebest, 9.3.2.2 */ /* Find Ebest, 9.3.2.2 */
static void bmc_update_ebest(struct pp_globals *ppg) static void bmc_update_ebest(struct pp_globals *ppg)
{ {
int i, best; int i, best;
struct pp_instance *ppi, *ppi_best; struct pp_instance *ppi, *ppi_best;
struct PortIdentity *frgn_master_pid;
/* bmc_update_ebest is called several times, so report only at
* level 2 */
pp_diag(INST(ppg, 0), bmc, 2, "%s\n", __func__);
for (i = 1, best = 0; i < ppg->defaultDS->numberPorts; i++) { for (i = 1, best = 0; i < ppg->defaultDS->numberPorts; i++) {
ppi_best = INST(ppg, best); ppi_best = INST(ppg, best);
ppi = INST(ppg, i); ppi = INST(ppg, i);
if ((ppi->frgn_rec_num > 0) && if ((ppi->frgn_rec_num > 0)
(bmc_dataset_cmp(ppi, && (bmc_dataset_cmp(ppi,
&ppi_best->frgn_master[ppi_best->frgn_rec_best], &ppi->frgn_master[ppi->frgn_rec_best],
&ppi->frgn_master[ppi->frgn_rec_best]) &ppi_best->frgn_master[ppi_best->frgn_rec_best]
< 0)) ) < 0))
best = i; best = i;
} }
/* check if best master is qualified */
ppi_best = INST(ppg, best);
if (ppi_best->frgn_rec_num == 0) {
pp_diag(ppi_best, bmc, 2, "No Ebest at port %i\n", (best+1));
best = -1;
} else {
pp_diag(ppi_best, bmc, 1, "Best foreign master is at port "
"%i\n", (best+1));
frgn_master_pid = &ppi_best->frgn_master[ppi_best->frgn_rec_best].hdr.sourcePortIdentity;
pp_diag(ppi_best, bmc, 3, "SourePortId = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x.%04x\n",
frgn_master_pid->clockIdentity.id[0], frgn_master_pid->clockIdentity.id[1],
frgn_master_pid->clockIdentity.id[2], frgn_master_pid->clockIdentity.id[3],
frgn_master_pid->clockIdentity.id[4], frgn_master_pid->clockIdentity.id[5],
frgn_master_pid->clockIdentity.id[6], frgn_master_pid->clockIdentity.id[7],
frgn_master_pid->portNumber);
}
if (ppg->ebest_idx != best) { if (ppg->ebest_idx != best) {
ppg->ebest_idx = best; ppg->ebest_idx = best;
ppg->ebest_updated = 1; ppg->ebest_updated = 1;
...@@ -291,27 +671,32 @@ static void bmc_update_ebest(struct pp_globals *ppg) ...@@ -291,27 +671,32 @@ static void bmc_update_ebest(struct pp_globals *ppg)
int bmc(struct pp_instance *ppi) int bmc(struct pp_instance *ppi)
{ {
struct pp_frgn_master *frgn_master = ppi->frgn_master; struct pp_globals *ppg = GLBS(ppi);
int i, best;
/* bmc is called several times, so report only at level 2 */
if (!ppi->frgn_rec_num) pp_diag(ppi, bmc, 2, "%s\n", __func__);
if (ppi->state == PPS_MASTER) {
m1(ppi); /* Age table only based on timeouts*/
return ppi->state; if (pp_timeout(ppi, PP_TO_BMC)) {
} bmc_age_frgn_master(ppi);
/* restart timer, shall occur at
least once per annnounce interval 9.2.6.8
*/
pp_timeout_set(ppi, PP_TO_BMC);
}
/* Find Erbest, 9.3.2.3 */ /* Only if port is not any port is in the INITIALIZING state 9.2.6.8 */
for (i = 1, best = 0; i < ppi->frgn_rec_num; i++) if (bmc_any_port_initializing(ppg)) {
if (bmc_dataset_cmp(ppi, &frgn_master[i], &frgn_master[best]) pp_diag(ppi, bmc, 2, "A Port is in intializing\n");
< 0) return ppi->state;
best = i;
pp_diag(ppi, bmc, 1,"Best foreign master is %i/%i\n", best,
ppi->frgn_rec_num);
if (ppi->frgn_rec_best != best) {
ppi->frgn_rec_best = best;
bmc_update_ebest(GLBS(ppi));
} }
return bmc_state_decision(ppi, &frgn_master[best]); /* Calculate Erbest of all ports Figure 25 */
bmc_update_erbest(ppg);
/* Calulate Ebest Figure 25 */
bmc_update_ebest(ppg);
/* Make state decision*/
return bmc_state_decision(ppi);
} }
...@@ -85,14 +85,13 @@ int st_com_execute_slave(struct pp_instance *ppi) ...@@ -85,14 +85,13 @@ int st_com_execute_slave(struct pp_instance *ppi)
if (pp_timeout(ppi, PP_TO_ANN_RECEIPT) if (pp_timeout(ppi, PP_TO_ANN_RECEIPT)
|| pp_timeout(ppi, PP_TO_FAULT)) { || pp_timeout(ppi, PP_TO_FAULT)) {
/* /*
* Note: TO_FAULTY == SYNCHRONIZATION_FAULT * Note: TO_FAULTY == SYNCHRONIZATION_FAULT
* should move us to UNCALIBRATED (not implemented) * should move us to UNCALIBRATED (not implemented)
*/ */
ppi->frgn_rec_num = 0;
if (DSDEF(ppi)->clockQuality.clockClass != PP_CLASS_SLAVE_ONLY if (DSDEF(ppi)->clockQuality.clockClass != PP_CLASS_SLAVE_ONLY
&& (ppi->role != PPSI_ROLE_SLAVE)) { && (ppi->role != PPSI_ROLE_SLAVE)) {
ppi->next_state = PPS_MASTER; ppi->next_state = PPS_MASTER;
} else { } else {
ppi->next_state = PPS_LISTENING; ppi->next_state = PPS_LISTENING;
pp_timeout_set(ppi, PP_TO_ANN_RECEIPT); pp_timeout_set(ppi, PP_TO_ANN_RECEIPT);
......
...@@ -111,14 +111,52 @@ int pp_lib_may_issue_request(struct pp_instance *ppi) ...@@ -111,14 +111,52 @@ int pp_lib_may_issue_request(struct pp_instance *ppi)
/* Called by this file, basically when an announce is got, all states */ /* Called by this file, basically when an announce is got, all states */
static void __lib_add_foreign(struct pp_instance *ppi, unsigned char *buf) static void __lib_add_foreign(struct pp_instance *ppi, unsigned char *buf)
{ {
int i; int i, worst, sel;
struct pp_frgn_master frgn_master;
MsgHeader *hdr = &ppi->received_ptp_header; MsgHeader *hdr = &ppi->received_ptp_header;
/* if we are a configured master don't add*/
if (ppi->role == PPSI_ROLE_MASTER)
return;
/*
* header and announce field of each Foreign Master are
* useful to run Best Master Clock Algorithm
*/
msg_copy_header(&frgn_master.hdr, hdr);
msg_unpack_announce(buf, &frgn_master.ann);
/* Copy new foreign master data set from announce message */
memcpy(&frgn_master.port_id,
&hdr->sourcePortIdentity, sizeof(hdr->sourcePortIdentity));
/* Copy the source port identity */
memcpy(&frgn_master.source_id,
&DSPOR(ppi)->portIdentity, sizeof(DSPOR(ppi)->portIdentity));
/* Check if announce from a port from this clock 9.3.2.5 a) */
if (!memcmp(&hdr->sourcePortIdentity.clockIdentity,
&DSDEF(ppi)->clockIdentity,
sizeof(DSDEF(ppi)->clockIdentity)))
return;
/* Check if announce has steps removed larger than 255 9.3.2.5 d) */
if (frgn_master.ann.stepsRemoved >= 255)
return;
/* Check if foreign master is already known */ /* Check if foreign master is already known */
for (i = 0; i < ppi->frgn_rec_num; i++) { for (i = 0; i < ppi->frgn_rec_num; i++) {
if (!memcmp(&hdr->sourcePortIdentity, if (!memcmp(&hdr->sourcePortIdentity,
&ppi->frgn_master[i].port_id, &ppi->frgn_master[i].port_id,
sizeof(hdr->sourcePortIdentity))) { sizeof(hdr->sourcePortIdentity))) {
pp_diag(ppi, bmc, 2, "Foreign Master %i updated\n", i);
/* update the number of announce received if correct
* sequence number 9.3.2.5 b) */
if (hdr->sequenceId
== (ppi->frgn_master[i].hdr.sequenceId + 1))
ppi->frgn_master[i].ann_cnt[0]++;
/* already in Foreign master data set, update info */ /* already in Foreign master data set, update info */
msg_copy_header(&ppi->frgn_master[i].hdr, hdr); msg_copy_header(&ppi->frgn_master[i].hdr, hdr);
msg_unpack_announce(buf, &ppi->frgn_master[i].ann); msg_unpack_announce(buf, &ppi->frgn_master[i].ann);
...@@ -126,32 +164,55 @@ static void __lib_add_foreign(struct pp_instance *ppi, unsigned char *buf) ...@@ -126,32 +164,55 @@ static void __lib_add_foreign(struct pp_instance *ppi, unsigned char *buf)
} }
} }
/* set qualification timeouts as valid to compare against worst*/
for (i = 0; i < PP_FOREIGN_MASTER_TIME_WINDOW; i++)
frgn_master.ann_cnt[i] = 1;
/* New foreign master */ /* New foreign master */
if (ppi->frgn_rec_num < PP_NR_FOREIGN_RECORDS) if (ppi->frgn_rec_num < PP_NR_FOREIGN_RECORDS) {
/* there is space for a new one */
sel = ppi->frgn_rec_num;
ppi->frgn_rec_num++; ppi->frgn_rec_num++;
/* FIXME: replace the worst */ } else {
i = ppi->frgn_rec_num - 1; /* find the worst to replace */
for (i = 1, worst = 0; i < ppi->frgn_rec_num; i++)
if (bmc_dataset_cmp(ppi, &ppi->frgn_master[i],
&ppi->frgn_master[worst]) > 0)
worst = i;
/* check if worst is better than the new one, and skip the new
* one if so */
if (bmc_dataset_cmp(ppi, &ppi->frgn_master[worst], &frgn_master)
< 0) {
pp_diag(ppi, bmc, 1, "%s:%i: New foreign "
"master worse than worst in the full "
"table, skipping\n",
__func__, __LINE__);
return;
}
/* Copy new foreign master data set from announce message */ sel = worst;
memcpy(&ppi->frgn_master[i].port_id, }
&hdr->sourcePortIdentity, sizeof(hdr->sourcePortIdentity));
/* /* clear qualification timeouts */
* header and announce field of each Foreign Master are for (i = 0; i < PP_FOREIGN_MASTER_TIME_WINDOW; i++)
* useful to run Best Master Clock Algorithm frgn_master.ann_cnt[i] = 0;
*/
msg_copy_header(&ppi->frgn_master[i].hdr, hdr); /* This is the first one qualified 9.3.2.5 e)*/
msg_unpack_announce(buf, &ppi->frgn_master[i].ann); frgn_master.ann_cnt[0] = 1;
/* Copy the temporary foreign master entry */
memcpy(&ppi->frgn_master[sel],
&frgn_master, sizeof(frgn_master));
pp_diag(ppi, bmc, 1, "New foreign Master %i added\n", i); pp_diag(ppi, bmc, 1, "New foreign Master %i added\n", sel);
} }
int pp_lib_handle_announce(struct pp_instance *ppi, unsigned char *buf, int len) int pp_lib_handle_announce(struct pp_instance *ppi, unsigned char *buf, int len)
{ {
__lib_add_foreign(ppi, buf); __lib_add_foreign(ppi, buf);
ppi->next_state = bmc(ppi); /* got a new announce: run bmc */
pp_timeout_set(ppi, PP_TO_ANN_RECEIPT); pp_timeout_set(ppi, PP_TO_ANN_RECEIPT);
if (pp_hooks.handle_announce) if (pp_hooks.handle_announce)
......
...@@ -20,8 +20,6 @@ void pp_servo_init(struct pp_instance *ppi) ...@@ -20,8 +20,6 @@ void pp_servo_init(struct pp_instance *ppi)
int d; int d;
SRV(ppi)->mpd_fltr.s_exp = 0; /* clears meanPathDelay filter */ SRV(ppi)->mpd_fltr.s_exp = 0; /* clears meanPathDelay filter */
ppi->frgn_rec_num = 0; /* no known master */
DSPAR(ppi)->parentPortIdentity.portNumber = 0; /* invalid */
if (ppi->t_ops->init_servo) { if (ppi->t_ops->init_servo) {
/* The system may pre-set us to keep current frequency */ /* The system may pre-set us to keep current frequency */
......
...@@ -16,7 +16,7 @@ static void init_parent_ds(struct pp_instance *ppi) ...@@ -16,7 +16,7 @@ static void init_parent_ds(struct pp_instance *ppi)
/* 8.2.3.2 */ /* 8.2.3.2 */
DSPAR(ppi)->parentPortIdentity.clockIdentity = DSPAR(ppi)->parentPortIdentity.clockIdentity =
DSDEF(ppi)->clockIdentity; DSDEF(ppi)->clockIdentity;
/* FIXME: portNumber ? */ DSPAR(ppi)->parentPortIdentity.portNumber = 0;
/* 8.2.3.3 skipped (parentStats is not used) */ /* 8.2.3.3 skipped (parentStats is not used) */
/* 8.2.3.4 */ /* 8.2.3.4 */
DSPAR(ppi)->observedParentOffsetScaledLogVariance = 0xffff; DSPAR(ppi)->observedParentOffsetScaledLogVariance = 0xffff;
......
...@@ -47,6 +47,10 @@ int pp_master(struct pp_instance *ppi, uint8_t *pkt, int plen) ...@@ -47,6 +47,10 @@ int pp_master(struct pp_instance *ppi, uint8_t *pkt, int plen)
/* upgrade from pre-master to master */ /* upgrade from pre-master to master */
if (pre && pp_timeout(ppi, PP_TO_QUALIFICATION)) { if (pre && pp_timeout(ppi, PP_TO_QUALIFICATION)) {
ppi->next_state = PPS_MASTER; ppi->next_state = PPS_MASTER;
/* start sending imediately and reenter */
pp_timeout_clear(ppi, PP_TO_SYNC_SEND);
pp_timeout_clear(ppi, PP_TO_ANN_SEND);
ppi->next_delay = 0;
return 0; return 0;
} }
...@@ -108,9 +112,13 @@ out: ...@@ -108,9 +112,13 @@ out:
break; break;
} }
/* we also use TO_QUALIFICATION, but avoid counting it here */ if (pre) {
ppi->next_delay = pp_next_delay_3(ppi, ppi->next_delay = pp_next_delay_2(ppi,
PP_TO_ANN_SEND, PP_TO_SYNC_SEND, PP_TO_REQUEST); PP_TO_QUALIFICATION, PP_TO_REQUEST);
} else {
ppi->next_delay = pp_next_delay_3(ppi,
PP_TO_ANN_SEND, PP_TO_SYNC_SEND, PP_TO_REQUEST);
}
return e; return e;
} }
...@@ -22,6 +22,7 @@ struct timeout_config { ...@@ -22,6 +22,7 @@ struct timeout_config {
static struct timeout_config to_configs[__PP_TO_ARRAY_SIZE] = { static struct timeout_config to_configs[__PP_TO_ARRAY_SIZE] = {
[PP_TO_REQUEST] = {"REQUEST", RAND_0_200,}, [PP_TO_REQUEST] = {"REQUEST", RAND_0_200,},
[PP_TO_SYNC_SEND] = {"SYNC_SEND", RAND_70_130,}, [PP_TO_SYNC_SEND] = {"SYNC_SEND", RAND_70_130,},
[PP_TO_BMC] = {"BMC", RAND_NONE,},
[PP_TO_ANN_RECEIPT] = {"ANN_RECEIPT", RAND_NONE,}, [PP_TO_ANN_RECEIPT] = {"ANN_RECEIPT", RAND_NONE,},
[PP_TO_ANN_SEND] = {"ANN_SEND", RAND_70_130,}, [PP_TO_ANN_SEND] = {"ANN_SEND", RAND_70_130,},
[PP_TO_FAULT] = {"FAULT", RAND_NONE, 4000}, [PP_TO_FAULT] = {"FAULT", RAND_NONE, 4000},
...@@ -40,6 +41,7 @@ void pp_timeout_init(struct pp_instance *ppi) ...@@ -40,6 +41,7 @@ void pp_timeout_init(struct pp_instance *ppi)
to_configs[PP_TO_FAULT].value = to_configs[PP_TO_FAULT].value =
1 << (port->logMinDelayReqInterval + 12); /* 0 -> 4096ms */ 1 << (port->logMinDelayReqInterval + 12); /* 0 -> 4096ms */
to_configs[PP_TO_SYNC_SEND].value = port->logSyncInterval; to_configs[PP_TO_SYNC_SEND].value = port->logSyncInterval;
to_configs[PP_TO_BMC].value = 1000 * (1 << port->logAnnounceInterval);
to_configs[PP_TO_ANN_RECEIPT].value = 1000 * ( to_configs[PP_TO_ANN_RECEIPT].value = 1000 * (
port->announceReceiptTimeout << port->logAnnounceInterval); port->announceReceiptTimeout << port->logAnnounceInterval);
to_configs[PP_TO_ANN_SEND].value = port->logAnnounceInterval; to_configs[PP_TO_ANN_SEND].value = port->logAnnounceInterval;
...@@ -54,6 +56,10 @@ void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec) ...@@ -54,6 +56,10 @@ void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec)
to_configs[index].name, millisec); to_configs[index].name, millisec);
} }
void pp_timeout_clear(struct pp_instance *ppi, int index)
{
__pp_timeout_set(ppi, index, 0);
}
void pp_timeout_set(struct pp_instance *ppi, int index) void pp_timeout_set(struct pp_instance *ppi, int index)
{ {
...@@ -111,8 +117,11 @@ void pp_timeout_set(struct pp_instance *ppi, int index) ...@@ -111,8 +117,11 @@ void pp_timeout_set(struct pp_instance *ppi, int index)
void pp_timeout_setall(struct pp_instance *ppi) void pp_timeout_setall(struct pp_instance *ppi)
{ {
int i; int i;
for (i = 0; i < __PP_TO_ARRAY_SIZE; i++) for (i = 0; i < __PP_TO_ARRAY_SIZE; i++) {
pp_timeout_set(ppi, i); /* keep BMC timeout */
if (i != PP_TO_BMC)
pp_timeout_set(ppi, i);
}
/* but announce_send must be send soon */ /* but announce_send must be send soon */
__pp_timeout_set(ppi, PP_TO_ANN_SEND, 20); __pp_timeout_set(ppi, PP_TO_ANN_SEND, 20);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment