Add BMCA support for IEEE 802.1AS-2011
According to IEEE 802.1AS-2011, the BMCA used in gPTP is the same as that used in IEEE 1588 with the following exceptions: (1) Announce messages received on a slave port that were not sent by the receiving time-aware system are used immediately, i.e., there is no foreign-master qualification. (2) A port that the BMCA determines should be a master port enters the master state immediately, i.e., there is no pre-master state. (3) The uncalibrated state is not needed and, therefore, not used. (4) All time-aware systems are required to participate in best master selection (even if it is not grandmaster capable). This patch is to support (1) by using a specific FOREIGN_MASTER_THRESHOLD case. (Treat FOREIGN_MASTER_THRESHOLD as 1.) To support (2) and (3), reuse ptp_fsm and drop pre-master/uncalibrated states. The (4) item is supported since IEEE 802.1AS reuses OC/BC. Signed-off-by: Erik Hons <erik.hons@ni.com> Signed-off-by: Rodney Greenstreet <rodney.greenstreet@ni.com> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
		
							parent
							
								
									1486660e95
								
							
						
					
					
						commit
						f8ffb2cf5a
					
				
							
								
								
									
										13
									
								
								fsm.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								fsm.c
									
									
									
									
									
								
							| @ -335,3 +335,16 @@ enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event, | |||||||
| 
 | 
 | ||||||
| 	return next; | 	return next; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | enum port_state ieee8021as_fsm(enum port_state state, enum fsm_event event, | ||||||
|  | 			       int mdiff) | ||||||
|  | { | ||||||
|  | 	enum port_state next = ptp_fsm(state, event, mdiff); | ||||||
|  | 
 | ||||||
|  | 	if (next == PS_UNCALIBRATED) | ||||||
|  | 		return PS_SLAVE; | ||||||
|  | 	if (next == PS_PRE_MASTER) | ||||||
|  | 		return PS_MASTER; | ||||||
|  | 
 | ||||||
|  | 	return next; | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								fsm.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								fsm.h
									
									
									
									
									
								
							| @ -79,4 +79,14 @@ enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff); | |||||||
| enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event, | enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event, | ||||||
| 			      int mdiff); | 			      int mdiff); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Run the state machine for a ieee8021as port. | ||||||
|  |  * @param state  The current state of the port. | ||||||
|  |  * @param event  The event to be processed. | ||||||
|  |  * @param mdiff  Whether a new master has been selected. | ||||||
|  |  * @return       The new state for the port. | ||||||
|  |  */ | ||||||
|  | enum port_state ieee8021as_fsm(enum port_state state, enum fsm_event event, | ||||||
|  | 			       int mdiff); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								port.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								port.c
									
									
									
									
									
								
							| @ -278,12 +278,16 @@ void fc_clear(struct foreign_clock *fc) | |||||||
| 
 | 
 | ||||||
| static void fc_prune(struct foreign_clock *fc) | static void fc_prune(struct foreign_clock *fc) | ||||||
| { | { | ||||||
|  | 	int threshold = FOREIGN_MASTER_THRESHOLD; | ||||||
| 	struct timespec now; | 	struct timespec now; | ||||||
| 	struct ptp_message *m; | 	struct ptp_message *m; | ||||||
| 
 | 
 | ||||||
| 	clock_gettime(CLOCK_MONOTONIC, &now); | 	clock_gettime(CLOCK_MONOTONIC, &now); | ||||||
| 
 | 
 | ||||||
| 	while (fc->n_messages > FOREIGN_MASTER_THRESHOLD) { | 	if (port_is_ieee8021as(fc->port)) | ||||||
|  | 		threshold = 1; | ||||||
|  | 
 | ||||||
|  | 	while (fc->n_messages > threshold) { | ||||||
| 		m = TAILQ_LAST(&fc->messages, messages); | 		m = TAILQ_LAST(&fc->messages, messages); | ||||||
| 		TAILQ_REMOVE(&fc->messages, m, list); | 		TAILQ_REMOVE(&fc->messages, m, list); | ||||||
| 		fc->n_messages--; | 		fc->n_messages--; | ||||||
| @ -339,6 +343,7 @@ void ts_add(tmv_t *ts, Integer64 correction) | |||||||
|  */ |  */ | ||||||
| static int add_foreign_master(struct port *p, struct ptp_message *m) | static int add_foreign_master(struct port *p, struct ptp_message *m) | ||||||
| { | { | ||||||
|  | 	int threshold = FOREIGN_MASTER_THRESHOLD; | ||||||
| 	struct foreign_clock *fc; | 	struct foreign_clock *fc; | ||||||
| 	struct ptp_message *tmp; | 	struct ptp_message *tmp; | ||||||
| 	int broke_threshold = 0, diff = 0; | 	int broke_threshold = 0, diff = 0; | ||||||
| @ -362,7 +367,8 @@ static int add_foreign_master(struct port *p, struct ptp_message *m) | |||||||
| 		LIST_INSERT_HEAD(&p->foreign_masters, fc, list); | 		LIST_INSERT_HEAD(&p->foreign_masters, fc, list); | ||||||
| 		fc->port = p; | 		fc->port = p; | ||||||
| 		fc->dataset.sender = m->header.sourcePortIdentity; | 		fc->dataset.sender = m->header.sourcePortIdentity; | ||||||
| 		/* We do not count this first message, see 9.5.3(b) */ | 		/* For 1588, we do not count this first message, see 9.5.3(b) */ | ||||||
|  | 		if (!port_is_ieee8021as(fc->port)) | ||||||
| 			return 0; | 			return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -370,7 +376,11 @@ static int add_foreign_master(struct port *p, struct ptp_message *m) | |||||||
| 	 * If this message breaks the threshold, that is an important change. | 	 * If this message breaks the threshold, that is an important change. | ||||||
| 	 */ | 	 */ | ||||||
| 	fc_prune(fc); | 	fc_prune(fc); | ||||||
| 	if (FOREIGN_MASTER_THRESHOLD - 1 == fc->n_messages) { | 
 | ||||||
|  | 	if (port_is_ieee8021as(fc->port)) | ||||||
|  | 		threshold = 1; | ||||||
|  | 
 | ||||||
|  | 	if (threshold - 1 == fc->n_messages) { | ||||||
| 		broke_threshold = 1; | 		broke_threshold = 1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -2445,6 +2455,7 @@ void port_close(struct port *p) | |||||||
| struct foreign_clock *port_compute_best(struct port *p) | struct foreign_clock *port_compute_best(struct port *p) | ||||||
| { | { | ||||||
| 	int (*dscmp)(struct dataset *a, struct dataset *b); | 	int (*dscmp)(struct dataset *a, struct dataset *b); | ||||||
|  | 	int threshold = FOREIGN_MASTER_THRESHOLD; | ||||||
| 	struct foreign_clock *fc; | 	struct foreign_clock *fc; | ||||||
| 	struct ptp_message *tmp; | 	struct ptp_message *tmp; | ||||||
| 
 | 
 | ||||||
| @ -2463,7 +2474,10 @@ struct foreign_clock *port_compute_best(struct port *p) | |||||||
| 
 | 
 | ||||||
| 		fc_prune(fc); | 		fc_prune(fc); | ||||||
| 
 | 
 | ||||||
| 		if (fc->n_messages < FOREIGN_MASTER_THRESHOLD) | 		if (port_is_ieee8021as(fc->port)) | ||||||
|  | 			threshold = 1; | ||||||
|  | 
 | ||||||
|  | 		if (fc->n_messages < threshold) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (!p->best) | 		if (!p->best) | ||||||
| @ -3104,19 +3118,6 @@ struct port *port_open(const char *phc_device, | |||||||
| 	p->master_only = config_get_int(cfg, interface_name(interface), "masterOnly"); | 	p->master_only = config_get_int(cfg, interface_name(interface), "masterOnly"); | ||||||
| 	p->bmca = config_get_int(cfg, interface_name(interface), "BMCA"); | 	p->bmca = config_get_int(cfg, interface_name(interface), "BMCA"); | ||||||
| 
 | 
 | ||||||
| 	if (p->bmca == BMCA_NOOP && transport != TRANS_UDS) { |  | ||||||
| 		if (p->master_only) { |  | ||||||
| 			p->state_machine = designated_master_fsm; |  | ||||||
| 		} else if (clock_slave_only(clock)) { |  | ||||||
| 			p->state_machine = designated_slave_fsm; |  | ||||||
| 		} else { |  | ||||||
| 			pr_err("Please enable at least one of masterOnly or slaveOnly when BMCA == noop.\n"); |  | ||||||
| 			goto err_port; |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : ptp_fsm; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (transport == TRANS_UDS) { | 	if (transport == TRANS_UDS) { | ||||||
| 		; /* UDS cannot have a PHC. */ | 		; /* UDS cannot have a PHC. */ | ||||||
| 	} else if (!interface_tsinfo_valid(interface)) { | 	} else if (!interface_tsinfo_valid(interface)) { | ||||||
| @ -3169,6 +3170,26 @@ struct port *port_open(const char *phc_device, | |||||||
| 	p->versionNumber = PTP_VERSION; | 	p->versionNumber = PTP_VERSION; | ||||||
| 	p->slave_event_monitor = clock_slave_monitor(clock); | 	p->slave_event_monitor = clock_slave_monitor(clock); | ||||||
| 
 | 
 | ||||||
|  | 	if (config_get_int(cfg, p->name, "asCapable") == AS_CAPABLE_TRUE) { | ||||||
|  | 		p->asCapable = ALWAYS_CAPABLE; | ||||||
|  | 	} else { | ||||||
|  | 		p->asCapable = NOT_CAPABLE; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p->bmca == BMCA_NOOP && transport != TRANS_UDS) { | ||||||
|  | 		if (p->master_only) { | ||||||
|  | 			p->state_machine = designated_master_fsm; | ||||||
|  | 		} else if (clock_slave_only(clock)) { | ||||||
|  | 			p->state_machine = designated_slave_fsm; | ||||||
|  | 		} else { | ||||||
|  | 			pr_err("Please enable at least one of masterOnly or slaveOnly when BMCA == noop.\n"); | ||||||
|  | 			goto err_transport; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : | ||||||
|  | 				   port_is_ieee8021as(p) ? ieee8021as_fsm : ptp_fsm; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (number && unicast_client_initialize(p)) { | 	if (number && unicast_client_initialize(p)) { | ||||||
| 		goto err_transport; | 		goto err_transport; | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user