Beispiel #1
0
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);
    }
}
Beispiel #3
0
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);
    }
}
Beispiel #16
0
/* 
 * 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;
}