static void listen_callback( int socket_id, void *cookie, int read_ready, int write_ready, int error_seen) { AIM_LOG_TRACE("Accepting CLI client"); int fd; if ((fd = accept(listen_socket, NULL, NULL)) < 0) { AIM_LOG_ERROR("Failed to accept on CLI socket: %s", strerror(errno)); return; } struct client *client = aim_zmalloc(sizeof(*client)); client->fd = fd; client->write_pvs = aim_pvs_buffer_create(); client->ucli = ucli_create("ivs", NULL, NULL); indigo_error_t rv = ind_soc_socket_register(fd, client_callback, client); if (rv < 0) { AIM_LOG_ERROR("Failed to register CLI client socket: %s", indigo_strerror(rv)); return; } }
/* * lacpa_update_partner * * Match/Update the partner info and set appropraite actor state flags */ static void lacpa_update_partner (lacpa_port_t *port, lacpa_pdu_t *pdu) { lacpa_state_t prev_state; if (!port || !pdu) return; if (!same_partner(&pdu->actor, &port->partner)) { AIM_LOG_TRACE("Mis-match in Partner info for port: %d, Updating Partner" " Info", port->actor.port_no); if (port->is_converged) { AIM_LOG_ERROR("Mis-match in Partner info for port: %d, Inform " "Controller", port->actor.port_no); port->is_converged = FALSE; lacpa_update_controller(port); } LACPA_CLR_STATE_SYNCHRONIZATION(port->actor.state); LACPA_CLR_STATE_COLLECTING(port->actor.state); LACPA_CLR_STATE_DISTRIBUTING(port->actor.state); } prev_state = port->partner.state; lacpa_copy_info(&pdu->actor, &port->partner); /* * Reset the Periodic timer if Partner's LACP Timeout value changes */ if (LACPA_IS_STATE_LACP_TIMEOUT(prev_state) != LACPA_IS_STATE_LACP_TIMEOUT(port->partner.state)) { lacpa_periodic_machine(port, TRUE); } }
static inline void cxn_data_hexdump(unsigned char *buf, int bytes) { int idx; char display[HEX_LEN]; int disp_offset = 0; int buf_offset = 0; while (bytes > 0) { disp_offset = 0; for (idx = 0; (idx < PER_LINE) && (idx < bytes); idx++) { disp_offset += sprintf(&display[disp_offset], "%02x", buf[buf_offset + idx]); } for (idx = bytes; idx < PER_LINE; ++idx) { disp_offset += sprintf(&display[disp_offset], " "); } disp_offset += sprintf(&display[disp_offset], " :"); for (idx = 0; (idx < PER_LINE) && (idx < bytes); idx++) { if (buf[idx] < 32) { disp_offset += sprintf(&display[disp_offset], "."); } else { disp_offset += sprintf(&display[disp_offset], "%c", buf[buf_offset + idx]); } } AIM_LOG_TRACE("%s", display); bytes -= PER_LINE; buf_offset += PER_LINE; } }
/* * lacp_init_port * * LACP Agent is being enabled/disabled. * * Start/Stop the necessay timers and enable/disable agent states. */ extern void lacpa_init_port (lacpa_system_t *system, lacpa_info_t *info, uint8_t lacp_enabled) { lacpa_port_t *port = NULL; if (!info || !system) return; /* * Find any port corresponding to the info received */ port = lacpa_find_port(system, info->port_no); if (!port) return; AIM_LOG_TRACE("LACP %s received for port: %d", lacp_enabled? "ENABLE": "DISABLE", port->actor.port_no); lacpa_copy_info(info, &port->actor); lacpa_dump_port(port); if (lacp_enabled) { port->lacp_event = LACPA_EVENT_ENABLED; } else { port->lacp_event = LACPA_EVENT_DISABLED; } port->system = system; lacpa_machine(port, NULL); }
/* * lacpa_current_while_expiration_timer_cb * * Current while Expiration callback */ static void lacpa_current_while_expiration_timer_cb (void *cookie) { lacpa_event_t event; if (!cookie) return; lacpa_port_t *port = (lacpa_port_t *)cookie; if (!port) return; AIM_LOG_TRACE("current_while timer callback for port: %d", port->actor.port_no); if (port->lacp_state == LACPA_MACHINE_AGENT_CURRENT) { event = LACPA_EVENT_CURRENT_TIMER_EXPIRED; } else if (port->lacp_state == LACPA_MACHINE_AGENT_EXPIRED) { event = LACPA_EVENT_EXPIRY_TIMER_EXPIRED; } else { /* * Sanity check, disable the timer */ lacpa_stop_current_while_timer(port); return; } lacpa_machine(port, NULL, event); }
/* * lacpa_stop_periodic_timer * * Periodic Timer */ void lacpa_stop_periodic_timer (lacpa_port_t * port) { if (!port) return; AIM_LOG_TRACE("Stop Periodic timer for port: %d", port->actor.port_no); ind_soc_timer_event_unregister(lacpa_periodic_expiration_timer_cb,port); }
/* * lacpa_update_controller * * This API communicates Protocol Converged/Unconverged to the Controller */ extern void lacpa_update_controller (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("Send %s msg to Controller for port: %d", port->is_converged? "Converged" : "Unconverged", port->actor.port_no); }
/* * lacpa_churn_detection_machine * * Churn Detection Timer */ extern void lacpa_churn_detection_machine (lacpa_port_t *port, bool timer_enabled) { if (!port) return; AIM_LOG_TRACE("Churn Detection timer %s received for port: %d", timer_enabled? "START": "STOP", port->actor.port_no); if (timer_enabled && port->lacp_state != LACPA_MACHINE_AGENT_DEFAULTED) { //ind_soc_timer_event_register(lacp_churn_expiration_timer_cb, port, // LACP_CHURN_DETECTION_TIMEOUT_MS); } else { if (timer_enabled && port->lacp_state == LACPA_MACHINE_AGENT_DEFAULTED) { AIM_LOG_TRACE("Failed to Start Churn Detection timer since Agent State: " "%{lacpa_machine}", port->lacp_state); } //ind_soc_timer_event_unregister(lacp_churn_expiration_timer_cb, port); } }
/* * lacpa_stop_current_while_timer */ void lacpa_stop_current_while_timer (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("Stop current_while timer for port: %d", port->actor.port_no); ind_soc_timer_event_unregister(lacpa_current_while_expiration_timer_cb, port); }
/* * lacpa_stop_churn_detection_timer * * Churn Detection Timer */ void lacpa_stop_churn_detection_timer (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("Stop Churn Detection timer for port: %d", port->actor.port_no); port->churn_detection_running = false; ind_soc_timer_event_unregister(lacpa_churn_expiration_timer_cb, port); }
/* * lacpa_start_current_while_timer */ void lacpa_start_current_while_timer (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("Start current_while timer for port: %d", port->actor.port_no); if (port->lacp_state == LACPA_MACHINE_AGENT_DEFAULTED) { AIM_LOG_TRACE("Failed to Start current_while timer since Agent State: " "%{lacpa_machine}", port->lacp_state); return; } if (ind_soc_timer_event_register(lacpa_current_while_expiration_timer_cb, port, LACPA_IS_STATE_LACP_TIMEOUT( port->actor.state)? LACP_SHORT_TIMEOUT_MS: LACP_LONG_TIMEOUT_MS) < 0) { AIM_LOG_ERROR("Failed to register timer for port %d", port->actor.port_no); } }
/* * lacpa_churn_expiration_timer_cb * * Churn Detection Timer Expiration callback */ static void lacpa_churn_expiration_timer_cb (void *cookie) { if (!cookie) return; lacpa_port_t *port = (lacpa_port_t *)cookie; if (!port) return; AIM_LOG_TRACE("Churn Detection timer callback for port: %d", port->actor.port_no); lacpa_machine(port, NULL, LACPA_EVENT_CHURN_DETECTION_EXPIRED); }
/* * lacpa_start_churn_detection_timer * * Churn Detection Timer */ void lacpa_start_churn_detection_timer (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("Start Churn Detection timer for port: %d", port->actor.port_no); if (port->lacp_state == LACPA_MACHINE_AGENT_DEFAULTED) { AIM_LOG_TRACE("Failed to Start Churn Detection timer since Agent State:" " %{lacpa_machine}", port->lacp_state); return; } if (ind_soc_timer_event_register(lacpa_churn_expiration_timer_cb, port, LACP_CHURN_DETECTION_TIMEOUT_MS) < 0) { AIM_LOG_ERROR("Failed to register timer for port %d", port->actor.port_no); return; } port->churn_detection_running = true; }
/* * lacpa_update_ntt * * Run the logic to decide if we need to Tx a new LACPDU */ static void lacpa_update_ntt (lacpa_port_t *port, lacpa_pdu_t *pdu, bool *ntt) { if (!port || !pdu || !ntt) return; if (!same_partner(&pdu->partner, &port->actor)) { port->ntt_reason = LACPA_TRANSMIT_INFO_MISMATCH; goto transmit; } if (LACPA_IS_STATE_LACP_ACTIVITY(pdu->partner.state) != LACPA_IS_STATE_LACP_ACTIVITY(port->actor.state)) { port->ntt_reason = LACPA_TRANSMIT_LCAP_ACTIVITY_MISTMATCH; goto transmit; } if (LACPA_IS_STATE_AGGREGATION(pdu->partner.state) != LACPA_IS_STATE_AGGREGATION(port->actor.state)) { port->ntt_reason = LACPA_TRANSMIT_AGGREGATION_MISTMATCH; goto transmit; } if (LACPA_IS_STATE_SYNCHRONIZATION(pdu->partner.state) != LACPA_IS_STATE_SYNCHRONIZATION(port->actor.state)) { port->ntt_reason = LACPA_TRANSMIT_SYNCHRONIZATION_MISTMATCH; goto transmit; } if (LACPA_IS_STATE_COLLECTING(pdu->partner.state) != LACPA_IS_STATE_COLLECTING(port->actor.state)) { port->ntt_reason = LACPA_TRANSMIT_COLLECTING_MISTMATCH; goto transmit; } if (LACPA_IS_STATE_DISTRIBUTING(pdu->partner.state) != LACPA_IS_STATE_DISTRIBUTING(port->actor.state)) { port->ntt_reason = LACPA_TRANSMIT_DISTRIBUTING_MISTMATCH; goto transmit; } *ntt = FALSE; return; transmit: AIM_LOG_TRACE("Setting ntt for Port: %d, reason: %{lacpa_transmit}", port->actor.port_no, port->ntt_reason); *ntt = TRUE; }
/* * lacpa_start_periodic_timer * * Periodic Timer */ void lacpa_start_periodic_timer (lacpa_port_t * port) { if (!port) return; AIM_LOG_TRACE("Start Periodic timer for port: %d", port->actor.port_no); if (ind_soc_timer_event_register(lacpa_periodic_expiration_timer_cb, port, LACPA_IS_STATE_LACP_TIMEOUT( port->partner.state)? LACP_FAST_PERIODIC_TIMEOUT_MS : LACP_SLOW_PERIODIC_TIMEOUT_MS) < 0) { AIM_LOG_ERROR("Failed to register timer for port %d", port->actor.port_no); } }
/* * arpra_lookup * * return true if target ip is one of the tunnel interface; * fill mac with addr associated with that interface * * else; returns false */ bool arpra_lookup (uint32_t ipv4, of_mac_addr_t *mac) { list_head_t *cache = arp_cache_list(); list_links_t *cur; LIST_FOREACH(cache, cur) { arp_cache_entry_t *cache_entry = container_of(cur, links, arp_cache_entry_t); if (cache_entry->entry.ipv4 == ipv4) { ARPRA_MEMCPY(mac->addr, cache_entry->entry.mac.addr, OF_MAC_ADDR_BYTES); AIM_LOG_TRACE("Target mac: %{mac} found", cache_entry->entry.mac.addr); return true; } }
/* * lacpa_periodic_expiration_timer_cb * * Periodic Timer Expiration callback */ static void lacpa_periodic_expiration_timer_cb (void *cookie) { if (!cookie) return; lacpa_port_t *port = (lacpa_port_t *)cookie; if (!port) return; AIM_LOG_TRACE("Periodic timer callback for port: %d", port->actor.port_no); if (port->lacp_state != LACPA_MACHINE_AGENT_STOPPED) { port->debug_info.ntt_reason = LACPA_TRANSMIT_PERIODIC_TIMER_EXPIRED; lacpa_transmit(port); } else { lacpa_stop_periodic_timer(port); } }
/* * lacpa_receive * * Process incoming LACPDU and take appropriate action */ extern bool lacpa_receive (lacpa_port_t *port, uint8_t *data, uint32_t bytes) { lacpa_pdu_t pdu; ppe_packet_t ppep; if (!port || !data) return FALSE; if (!port->lacp_enabled) { AIM_LOG_ERROR("LACPDU-Rx-FAILED - Agent is Disabled on port: %d", port->actor.port_no); return FALSE; } LACPA_MEMSET(&pdu, DEFAULT_ZERO, sizeof(lacpa_pdu_t)); AIM_LOG_TRACE("LACPDU Received on port: %d", port->actor.port_no); /* * Use ppe api's to fill info from data in our pdu */ ppe_packet_init(&ppep, data, bytes); if (ppe_parse(&ppep) < 0) { AIM_LOG_ERROR("Packet parsing failed. packet=%{data}", data, bytes); return FALSE; } if (!ppe_header_get(&ppep, PPE_HEADER_LACP)) { AIM_LOG_ERROR("Not a Valid LCAP Packet"); return FALSE; } /* * Retrieve the information from the LCAP packet */ if (!lacpa_parse_pdu(&ppep, &pdu)) { AIM_LOG_ERROR("Packet parsing failed."); return FALSE; } port->lacp_event = LACPA_EVENT_PDU_RECEIVED; lacpa_machine(port, &pdu); return TRUE; }
/* * lacpa_defaulted * * Agent_Defaulted State handling */ static void lacpa_defaulted (lacpa_port_t *port) { if (!port) return; lacpa_churn_detection_machine(port, FALSE); lacpa_current_while_timer(port, FALSE); /* * Set the Actor and Partner LACP_TIMEOUT to Long Timeout */ LACPA_CLR_STATE_LACP_TIMEOUT(port->actor.state); //LACPA_CLR_STATE_LACP_TIMEOUT(port->partner.state); AIM_LOG_TRACE("Actor State Defaulted for Port: %d, Inform Controller", port->actor.port_no); port->is_converged = FALSE; lacpa_update_controller(port); }
/* * lacpa_periodic_machine * * Periodic Timer */ extern void lacpa_periodic_machine (lacpa_port_t * port, bool timer_enabled) { if (!port) return; AIM_LOG_TRACE("Periodic timer %s received for port: %d", timer_enabled? "START": "STOP", port->actor.port_no); if (timer_enabled) { /*ind_soc_timer_event_register(lacp_periodic_expiration_timer_cb, port, LACPA_IS_STATE_LACP_TIMEOUT( port->partner.state) LACP_FAST_PERIODIC_TIMEOUT_MS : LACP_SLOW_PERIODIC_TIMEOUT_MS);*/ } else { //ind_soc_timer_event_unregister(lacp_periodic_expiration_timer_cb, port); } }
/* * lacpa_current_while_timer */ extern void lacpa_current_while_timer (lacpa_port_t *port, bool timer_enabled) { if (!port) return; AIM_LOG_TRACE("current_while timer %s received for port: %d", timer_enabled? "START": "STOP", port->actor.port_no); if (timer_enabled) { //ind_soc_timer_event_register(lacp_current_while_expiration_timer_cb, port, // port->actor.state.lacp_timeout? // LACP_SHORT_TIMEOUT_MS : // LACP_LONG_TIMEOUT_MS); } else { //ind_soc_timer_event_unregister(lacp_current_while_expiration_timer_cb, port); } }
/* * lacpa_dump_port * * Dumps the current port information */ extern void lacpa_dump_port (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("*************DUMPING PORT INFO*************\n"); AIM_LOG_TRACE("\nACTOR PORT INFO"); AIM_LOG_TRACE("ACTOR SYS PRIORITY : %d", port->actor.sys_priority); AIM_LOG_TRACE("ACTOR SYS MAC : %{mac}", port->actor.sys_mac); AIM_LOG_TRACE("ACTOR PORT PRIORITY : %d", port->actor.port_priority); AIM_LOG_TRACE("ACTOR PORT NUM : %d", port->actor.port_num); AIM_LOG_TRACE("ACTOR KEY : %d", port->actor.key); AIM_LOG_TRACE("ACTOR STATE : %02x", port->actor.state); AIM_LOG_TRACE("ACTOR OF_PORT_NO : %d", port->actor.port_no); AIM_LOG_TRACE("\nPARTNER PORT INFO"); AIM_LOG_TRACE("PARTNER SYS PRIORITY : %d", port->partner.sys_priority); AIM_LOG_TRACE("PARTNER SYS MAC : %{mac}", port->partner.sys_mac); AIM_LOG_TRACE("PARTNER PORT PRIORITY : %d", port->partner.port_priority); AIM_LOG_TRACE("PARTNER PORT NUM : %d", port->partner.port_num); AIM_LOG_TRACE("PARTNER KEY : %d", port->partner.key); AIM_LOG_TRACE("PARTNER STATE : %02x", port->partner.state); AIM_LOG_TRACE("PARTNER OF_PORT_NO : %d", port->partner.port_no); AIM_LOG_TRACE("\nPROTOCOL STATE INFO"); AIM_LOG_TRACE("LACP ENABLED : %s", port->lacp_enabled? "YES":"NO"); AIM_LOG_TRACE("PROTOCOL CONVERGED : %s", port->is_converged? "YES":"NO"); AIM_LOG_TRACE("LACP STATE : %{lacpa_machine}", port->lacp_state); AIM_LOG_TRACE("LACP EVENT : %{lacpa_event}", port->lacp_event); AIM_LOG_TRACE("LACP ERROR : %{lacpa_error}", port->error); AIM_LOG_TRACE("LACP TANSMIT REASON : %{lacpa_transmit}",port->ntt_reason); AIM_LOG_TRACE("*************END DUMPING INFO**************\n"); }
/* * lacpa_machine * * LACP Agent State Machine * * Rx/Tx and Processing of LACPDU's. */ extern void lacpa_machine (lacpa_port_t *port, lacpa_pdu_t *pdu) { lacpa_error_t prev_error; if (!port || !port->system) return; lacpa_machine_t prev_state = port->lacp_state; switch (port->lacp_event) { case LACPA_EVENT_DISABLED: port->lacp_state = LACPA_MACHINE_AGENT_STOPPED; port->lacp_enabled = FALSE; lacpa_periodic_machine(port, FALSE); lacpa_churn_detection_machine(port, FALSE); lacpa_current_while_timer(port, FALSE); port->system->lacp_active_port_count--; break; case LACPA_EVENT_ENABLED: port->lacp_state = LACPA_MACHINE_AGENT_CURRENT; port->lacp_enabled = TRUE; /* * Set Actor's LACP_ACTIVITY, LACP_TIMEOUT and AGGREGATION * to default values */ LACPA_SET_STATE_LACP_ACTIVITY(port->actor.state); LACPA_CLR_STATE_LACP_TIMEOUT(port->actor.state); LACPA_SET_STATE_AGGREGATION(port->actor.state); port->ntt_reason = LACPA_TRANSMIT_AGENT_ENABLED; lacpa_transmit(port); lacpa_periodic_machine(port, TRUE); lacpa_churn_detection_machine(port, TRUE); lacpa_current_while_timer(port, TRUE); port->system->lacp_active_port_count++; break; case LACPA_EVENT_PDU_RECEIVED: port->lacp_state = LACPA_MACHINE_AGENT_CURRENT; LACPA_CLR_STATE_LACP_TIMEOUT(port->actor.state); prev_error = port->error; /* * Process the received Partner LACPDU */ lacpa_process_pdu(port, pdu); /* * Restart the churn detection timer if: * 1. Converged * 2. Unconverged; but because of a different reason */ if (port->is_converged || (prev_error != port->error)) { AIM_LOG_TRACE("Restarting Churn Detection timer for port: %d, " "is_converged: %d, prev_error: %{lacpa_error}, " "new_error: %{lacpa_error}", port->actor.port_no, port->is_converged, prev_error, port->error); lacpa_churn_detection_machine(port, TRUE); } else if (prev_state == LACPA_MACHINE_AGENT_DEFAULTED) { AIM_LOG_TRACE("Prev State was AGENT_DEFAULTED due to same error: " "%{lacpa_error}, Staying in Defaulted State for port:" " %d", port->error, port->actor.port_no); port->lacp_state = LACPA_MACHINE_AGENT_DEFAULTED; } lacpa_current_while_timer(port, TRUE); break; case LACPA_EVENT_CURRENT_TIMER_EXPIRED: port->lacp_state = LACPA_MACHINE_AGENT_EXPIRED; /* * Set the Actor/Partner LACP Timeout to Short so that we can do * FAST Transmits of LACPDU's */ LACPA_SET_STATE_LACP_TIMEOUT(port->actor.state); if (!LACPA_IS_STATE_LACP_TIMEOUT(port->partner.state)) { LACPA_SET_STATE_LACP_TIMEOUT(port->partner.state); lacpa_periodic_machine(port, TRUE); } lacpa_transmit(port); lacpa_current_while_timer(port, TRUE); break; case LACPA_EVENT_EXPIRY_TIMER_EXPIRED: case LACPA_EVENT_CHURN_DETECTION_EXPIRED: case LACPA_EVENT_PROTOCOL_UNCONVERGED: port->lacp_state = LACPA_MACHINE_AGENT_DEFAULTED; lacpa_defaulted(port); break; default: break; } AIM_LOG_TRACE("State change for Port: %d, Event: %{lacpa_event}, Prev: " "%{lacpa_machine}, New: %{lacpa_machine}", port->actor.port_no, port->lacp_event, prev_state, port->lacp_state); }
/* * lacpa_dump_state * * Dumps the actor/partner state flags */ extern void lacpa_dump_state (lacpa_port_t *port) { if (!port) return; AIM_LOG_TRACE("*************DUMPING STATE INFO*************\n"); AIM_LOG_TRACE("\nACTOR STATE FLAGS"); AIM_LOG_TRACE("ACTOR LACP ACTIVITY : %s", LACPA_IS_STATE_LACP_ACTIVITY( port->actor.state)? "ACTIVE" : "PASSIVE"); AIM_LOG_TRACE("ACTOR LACP TIMEOUT : %s", LACPA_IS_STATE_LACP_TIMEOUT( port->actor.state)? "SHORT" : "LONG"); AIM_LOG_TRACE("ACTOR AGGREGATION : %s", LACPA_IS_STATE_AGGREGATION( port->actor.state)? "YES" : "NO"); AIM_LOG_TRACE("ACTOR SYNCHRONIZATION : %s",LACPA_IS_STATE_SYNCHRONIZATION( port->actor.state)? "INSYNC" : "OUTofSYNC"); AIM_LOG_TRACE("ACTOR COLLECTING : %s", LACPA_IS_STATE_COLLECTING( port->actor.state)? "YES" : "NO"); AIM_LOG_TRACE("ACTOR DISTRIBUTING : %s", LACPA_IS_STATE_DISTRIBUTING( port->actor.state)? "YES" : "NO"); AIM_LOG_TRACE("\nPARTNER STATE FLAGS"); AIM_LOG_TRACE("PARTNER LACP ACTIVITY : %s", LACPA_IS_STATE_LACP_ACTIVITY( port->partner.state)? "ACTIVE" : "PASSIVE"); AIM_LOG_TRACE("PARTNER LACP TIMEOUT : %s", LACPA_IS_STATE_LACP_TIMEOUT( port->partner.state)? "SHORT" : "LONG"); AIM_LOG_TRACE("PARTNER AGGREGATION : %s", LACPA_IS_STATE_AGGREGATION( port->partner.state)? "YES" : "NO"); AIM_LOG_TRACE("PARTNER SYNCHRONIZATION : %s",LACPA_IS_STATE_SYNCHRONIZATION( port->partner.state)? "INSYNC" : "OUTofSYNC"); AIM_LOG_TRACE("PARTNER COLLECTING : %s", LACPA_IS_STATE_COLLECTING( port->partner.state)? "YES" : "NO"); AIM_LOG_TRACE("PARTNER DISTRIBUTING : %s", LACPA_IS_STATE_DISTRIBUTING( port->partner.state)? "YES" : "NO"); AIM_LOG_TRACE("*************END DUMPING INFO**************\n"); }
/* * lacpa_transmit * * Construct an LACPDU for the given port and transmit it out */ extern bool lacpa_transmit (lacpa_port_t *port) { ppe_packet_t ppep; uint8_t data[LACP_PKT_BUF_SIZE]; if (!port) return FALSE; if (!port->lacp_enabled) { AIM_LOG_ERROR("LACPDU-Tx-FAILED - Agent is Disabled on port: %d", port->actor.port_no); return FALSE; } LACPA_MEMSET(data, DEFAULT_ZERO, LACP_PKT_BUF_SIZE); AIM_LOG_TRACE("Transmit Packet for port: %d, reason: %{lacpa_transmit}", port->actor.port_no, port->ntt_reason); lacpa_dump_port(port); ppe_packet_init(&ppep, data, LACP_PKT_BUF_SIZE); /* * Set ethertype as slow-protocols and Set LACP subtype * Parse to recognize LACP packet. */ data[12] = PPE_ETHERTYPE_SLOW_PROTOCOLS >> 8; data[13] = PPE_ETHERTYPE_SLOW_PROTOCOLS & 0xFF; data[14] = PPE_SLOW_PROTOCOL_LACP; if (ppe_parse(&ppep) < 0) { AIM_LOG_ERROR("Packet parsing failed after ethertype. packet=%{data}", data, LACP_PKT_BUF_SIZE); return FALSE; } /* * Set the Src and Dest Mac. * Src Mac is provided to us and Dest Mac is the slow-protocols-mac-address */ ppe_wide_field_set(&ppep, PPE_FIELD_ETHERNET_SRC_MAC, port->src_mac); ppe_wide_field_set(&ppep, PPE_FIELD_ETHERNET_DST_MAC, slow_protocols_address); /* * Build the rest of the LCAP packet */ if (!lacpa_build_pdu(&ppep, port)) { AIM_LOG_ERROR("Packet sending failed."); return FALSE; } /* * Dump out the packet to verify all the fields are set properly */ ppe_packet_dump(&ppep, &aim_pvs_stdout); lacpa_send(port, data, LACP_PKT_BUF_SIZE); return TRUE; }
/* * lacpa_update_convergence * * Decide Protocol Converged/Unconverged based on following: * 1. If Partner aggregation state = FALSE; Unconverged * 2. If Partner sync state = FALSE; Unconverged * 3. If Partner collecting state = FALSE; Unconverged * 4. If Partner distributing state = FALSE; Unconverged * Else, Converged */ static void lacpa_update_convergence (lacpa_port_t *port, bool *ntt) { lacpa_error_t prev_error = port->error; if (!port || !ntt) return; if (!LACPA_IS_STATE_AGGREGATION(port->partner.state)) { if (prev_error != LACPA_ERROR_PARTNER_AGGREGATION_OFF) { AIM_LOG_ERROR("Setting unconverged, Mis-match in aggregation state"); port->error = LACPA_ERROR_PARTNER_AGGREGATION_OFF; port->lacp_event = LACPA_EVENT_PROTOCOL_UNCONVERGED; lacpa_machine(port, NULL); } else { AIM_LOG_ERROR("Protocol Already Unconverged..No action required"); } return; } if (!LACPA_IS_STATE_SYNCHRONIZATION(port->actor.state)) { AIM_LOG_TRACE("Setting Actor sync state for Port: %d", port->actor.port_no); LACPA_SET_STATE_SYNCHRONIZATION(port->actor.state); port->ntt_reason = LACPA_TRANSMIT_SYNCHRONIZATION_SET; *ntt = TRUE; } if (!LACPA_IS_STATE_SYNCHRONIZATION(port->partner.state)) { port->error = LACPA_ERROR_PARTNER_INSYNC; goto unconverged; } if (!LACPA_IS_STATE_COLLECTING(port->actor.state)) { AIM_LOG_TRACE("Setting Actor collection state for Port: %d", port->actor.port_no); LACPA_SET_STATE_COLLECTING(port->actor.state); port->ntt_reason = LACPA_TRANSMIT_COLLECTING_SET; *ntt = TRUE; } if (!LACPA_IS_STATE_COLLECTING(port->partner.state)) { port->error = LACPA_ERROR_PARTNER_COLLECTION_OFF; goto unconverged; } if (!LACPA_IS_STATE_DISTRIBUTING(port->actor.state)) { AIM_LOG_TRACE("Setting Actor distribution state Port: %d", port->actor.port_no); LACPA_SET_STATE_DISTRIBUTING(port->actor.state); port->ntt_reason = LACPA_TRANSMIT_DISTRIBUTING_SET; *ntt = TRUE; } if (!LACPA_IS_STATE_DISTRIBUTING(port->partner.state)) { port->error = LACPA_ERROR_PARTNER_DISTRIBUTION_OFF; goto unconverged; } AIM_LOG_TRACE("Setting Port: %d to Converged, ntt_reason: %{lacpa_transmit}", port->actor.port_no, port->ntt_reason); port->error = LACPA_ERROR_NONE; port->is_converged = TRUE; return; unconverged: AIM_LOG_TRACE("Setting Port: %d to Unconverged, reason: %{lacpa_error}, " "ntt_reason: %{lacpa_transmit}", port->actor.port_no, port->error, port->ntt_reason); port->is_converged = FALSE; }
/* * icmp_packet_in_handler * * API for handling incoming packets */ indigo_core_listener_result_t icmpa_packet_in_handler (of_packet_in_t *packet_in) { of_octets_t octets; of_port_no_t port_no; of_match_t match; ppe_packet_t ppep; indigo_core_listener_result_t result = INDIGO_CORE_LISTENER_RESULT_PASS; uint32_t type, code; debug_counter_inc(&pkt_counters.icmp_total_in_packets); if (!packet_in) return INDIGO_CORE_LISTENER_RESULT_PASS; of_packet_in_data_get(packet_in, &octets); /* * Identify the recv port */ if (packet_in->version <= OF_VERSION_1_1) { return INDIGO_CORE_LISTENER_RESULT_PASS; } else { if (of_packet_in_match_get(packet_in, &match) < 0) { AIM_LOG_ERROR("ICMPA: match get failed"); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } port_no = match.fields.in_port; } if (port_no == OF_PORT_DEST_CONTROLLER) { debug_counter_inc(&pkt_counters.icmp_total_passed_packets); return INDIGO_CORE_LISTENER_RESULT_PASS; } if (port_no > MAX_PORTS) { AIM_LOG_ERROR("ICMPA: Port No: %d Out of Range %d", port_no, MAX_PORTS); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } /* * Check the packet-in reasons in metadata * * Icmp agent should not consume packets coming in due to L2 Src miss * and Station Move. */ if ((match.fields.metadata & OFP_BSN_PKTIN_FLAG_STATION_MOVE) || (match.fields.metadata & OFP_BSN_PKTIN_FLAG_NEW_HOST)) { debug_counter_inc(&pkt_counters.icmp_total_passed_packets); return INDIGO_CORE_LISTENER_RESULT_PASS; } ppe_packet_init(&ppep, octets.data, octets.bytes); if (ppe_parse(&ppep) < 0) { AIM_LOG_RL_ERROR(&icmp_pktin_log_limiter, os_time_monotonic(), "ICMPA: Packet_in parsing failed."); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } /* * Identify if this is an Echo Request, destined to one of VRouter */ if (ppe_header_get(&ppep, PPE_HEADER_ICMP)) { if (icmpa_reply(&ppep, port_no, &result)) { ++port_pkt_counters[port_no].icmp_echo_packets; return result; } } /* * To handle traceroute, we need to check for * a) UDP Packet * b) dest IP is Vrouter IP * c) UDP src and dest ports are ephemeral */ if (ppe_header_get(&ppep, PPE_HEADER_UDP) && ppe_header_get(&ppep, PPE_HEADER_IP4)) { uint32_t dest_ip, src_port, dest_port; ppe_field_get(&ppep, PPE_FIELD_IP4_DST_ADDR, &dest_ip); ppe_field_get(&ppep, PPE_FIELD_UDP_SRC_PORT, &src_port); ppe_field_get(&ppep, PPE_FIELD_UDP_DST_PORT, &dest_port); if (router_ip_check(dest_ip) && is_ephemeral(src_port) && is_ephemeral(dest_port)) { AIM_LOG_TRACE("ICMP Port Unreachable received on port: %d", port_no); type = ICMP_DEST_UNREACHABLE; code = 3; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_port_unreachable_packets; return result; } } } /* * Identify if the reason is valid for ICMP Agent to consume the packet */ if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_L3_MISS) { AIM_LOG_TRACE("ICMP Dest Network Unreachable received on port: %d", port_no); type = ICMP_DEST_UNREACHABLE; code = 0; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_net_unreachable_packets; } } else if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_TTL_EXPIRED) { AIM_LOG_TRACE("ICMP TTL Expired received on port: %d", port_no); type = ICMP_TIME_EXCEEDED; code = 0; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_time_exceeded_packets; } } return result; }