in src/cdi/adapter_efa_probe_tx.c [194:339]
bool ProbeTxControlProcessPacket(ProbeEndpointState* probe_ptr, const CdiDecodedProbeHeader* probe_hdr_ptr,
uint64_t* wait_timeout_ms_ptr)
{
bool ret_new_state = false;
EfaEndpointState* efa_endpoint_state_ptr = (EfaEndpointState*)probe_ptr->app_adapter_endpoint_handle->type_specific_ptr;
CdiEndpointHandle cdi_endpoint_handle = probe_ptr->app_adapter_endpoint_handle->cdi_endpoint_handle;
switch (probe_hdr_ptr->command) {
case kProbeCommandReset:
CDI_LOG_THREAD_COMPONENT(kLogDebug, kLogComponentProbe,
"Probe Tx remote IP[%s:%d] got Reset command from Rx. Restarting EFA connection.",
probe_hdr_ptr->senders_ip_str, probe_hdr_ptr->senders_control_dest_port);
// Queue Endpoint Manager to reset the EFA connection and notify the application that we are disconnected.
ProbeControlEfaConnectionQueueReset(probe_ptr, NULL);
// Get latest GID from remote.
memcpy(efa_endpoint_state_ptr->remote_ipv6_gid_array, probe_hdr_ptr->senders_gid_array,
sizeof(efa_endpoint_state_ptr->remote_ipv6_gid_array));
if (NULL == probe_ptr->app_adapter_endpoint_handle->protocol_handle) {
// Negotiated protocol version has not been set yet, so do so now.
EndpointManagerProtocolVersionSet(cdi_endpoint_handle, &probe_hdr_ptr->senders_version);
}
probe_ptr->tx_probe_state.tx_state = kProbeStateResetting;
*wait_timeout_ms_ptr = ENDPOINT_MANAGER_COMPLETION_TIMEOUT_MSEC;
ret_new_state = true;
break;
case kProbeCommandAck:
CdiOsCritSectionReserve(probe_ptr->ack_lock); // Lock access to the ack state data.
const CdiDecodedProbeAck* packet_ack_ptr = &probe_hdr_ptr->ack_packet;
// Check if we sent a command and are waiting for an ACK for it. If not, ignore the ACK.
if (probe_ptr->ack_is_pending) {
// We are waiting for an ACK. Check if the ACK contains the same command and probe packet number of
// the command that was sent.
// Ensure the sizes of these values are the same, so wrapping doesn't affect results when comparing
// them.
CDI_STATIC_ASSERT(sizeof(packet_ack_ptr->ack_control_packet_num) == sizeof(probe_ptr->ack_control_packet_num), \
"Control packet sizes must match.");
if (packet_ack_ptr->ack_command == probe_ptr->ack_command &&
packet_ack_ptr->ack_control_packet_num == probe_ptr->ack_control_packet_num) {
// It matches, so we got the ACK for the command that was sent.
probe_ptr->ack_is_pending = false;
// Don't log the ping ACK commands (generates too many log messages).
if (kProbeCommandPing != packet_ack_ptr->ack_command) {
CDI_LOG_THREAD_COMPONENT(kLogDebug, kLogComponentProbe,
"Probe Tx remote IP[%s:%d] accepted ACK.",
probe_hdr_ptr->senders_ip_str,
probe_hdr_ptr->senders_control_dest_port);
CDI_LOG_THREAD(kLogInfo, "Received connection response");
}
if (kProbeCommandReset == packet_ack_ptr->ack_command) {
// Get latest GID from remote.
memcpy(efa_endpoint_state_ptr->remote_ipv6_gid_array, probe_hdr_ptr->senders_gid_array,
sizeof(efa_endpoint_state_ptr->remote_ipv6_gid_array));
char gid_name_str[MAX_IPV6_ADDRESS_STRING_LENGTH];
DeviceGidToString(efa_endpoint_state_ptr->remote_ipv6_gid_array,
sizeof(efa_endpoint_state_ptr->remote_ipv6_gid_array), gid_name_str,
sizeof(gid_name_str));
CDI_LOG_THREAD(kLogInfo, "Probe Tx remote IP[%s:%d] using remote EFA device GID[%s].",
probe_hdr_ptr->senders_ip_str, probe_hdr_ptr->senders_control_dest_port,
gid_name_str);
// Reset negotiated protocol version.
ProtocolVersionDestroy(probe_ptr->app_adapter_endpoint_handle->protocol_handle);
probe_ptr->app_adapter_endpoint_handle->protocol_handle = NULL;
// Check if we received a probe version in the ACK that only supports probe versions before
// 3. Probe version 3 and later support the kProbeStateSendProtocolVersion command.
if (probe_hdr_ptr->senders_version.probe_version_num < 3) {
// Remote is using probe version before 3. It does not support the version command. So,
// queue endpoint start and advance state to wait for it to complete.
EndpointManagerProtocolVersionSet(cdi_endpoint_handle, &probe_hdr_ptr->senders_version);
EndpointManagerQueueEndpointStart(probe_ptr->app_adapter_endpoint_handle->cdi_endpoint_handle);
probe_ptr->tx_probe_state.tx_state = kProbeStateWaitForStart;
*wait_timeout_ms_ptr = ENDPOINT_MANAGER_COMPLETION_TIMEOUT_MSEC;
} else {
// Remote supports probe later than version 2, so send it our protocol/probe version using a
// command that is only supported by probe versions later than 2.
probe_ptr->tx_probe_state.tx_state = kProbeStateSendProtocolVersion;
probe_ptr->tx_probe_state.send_command_retry_count = 0;
*wait_timeout_ms_ptr = 0; // Process immediately.
}
ret_new_state = true;
} else if (kProbeCommandProtocolVersion == packet_ack_ptr->ack_command) {
// Got an ACK for a protocol version command. Set protocol version.
EndpointManagerProtocolVersionSet(cdi_endpoint_handle, &probe_hdr_ptr->senders_version);
// Queue endpoint start and advance state to wait for it to complete.
EndpointManagerQueueEndpointStart(probe_ptr->app_adapter_endpoint_handle->cdi_endpoint_handle);
probe_ptr->tx_probe_state.tx_state = kProbeStateWaitForStart;
*wait_timeout_ms_ptr = ENDPOINT_MANAGER_COMPLETION_TIMEOUT_MSEC;
ret_new_state = true;
} else if (kProbeCommandPing == packet_ack_ptr->ack_command) {
// Got an ACK for a ping command. Drop back to the EFA connected state, which will repeat the
// ping process. Setup wait period for next ping based on ping frequency.
probe_ptr->tx_probe_state.tx_state = kProbeStateEfaConnected;
*wait_timeout_ms_ptr = SEND_PING_COMMAND_FREQUENCY_MSEC;
ret_new_state = true;
} else {
assert(false); // No other supported commands return an Ack.
}
} else {
CDI_LOG_THREAD_COMPONENT(kLogDebug, kLogComponentProbe,
"Probe Tx remote IP[%s:%d] ignoring ACK. Got ACK for command[%s] packet_num[%d]. Expected "
"command[%s] packet_num[%d].", probe_hdr_ptr->senders_ip_str,
probe_hdr_ptr->senders_control_dest_port,
InternalUtilityKeyEnumToString(kKeyProbeCommand, packet_ack_ptr->ack_command),
packet_ack_ptr->ack_control_packet_num,
InternalUtilityKeyEnumToString(kKeyProbeCommand, probe_ptr->ack_command),
probe_ptr->ack_control_packet_num);
}
} else {
CDI_LOG_THREAD_COMPONENT(kLogDebug, kLogComponentProbe,
"Probe Tx remote IP[%s:%d] ignoring unexpected ACK.",
probe_hdr_ptr->senders_ip_str, probe_hdr_ptr->senders_control_dest_port);
}
CdiOsCritSectionRelease(probe_ptr->ack_lock); // Release access to the ack state data.
break;
case kProbeCommandConnected:
if (kProbeStateEfaProbe != probe_ptr->tx_probe_state.tx_state) {
// We are not expecting a connection command yet, so send a reset.
probe_ptr->tx_probe_state.tx_state = kProbeStateSendReset;
*wait_timeout_ms_ptr = 0; // Take effect immediately.
ret_new_state = true;
} else {
// Got a connected command from receiver. Advance state to ensure probe ACKs have all been received.
probe_ptr->tx_probe_state.tx_state = kProbeStateEfaTxProbeAcks;
*wait_timeout_ms_ptr = 0; // Take effect immediately.
ret_new_state = true;
}
break;
// Should never get these commands.
case kProbeCommandPing:
default:
assert(false);
}
return ret_new_state;
}