/* * Sends release requests * * @param[in] request - selection request data * * @return 0 when successful, otherwise ERROR */ static int send_release_message(struct lacp_aggregation_message_data *request) { int err = 0; struct mlag_master_election_status me_status; err = mlag_master_election_get_status(&me_status); MLAG_BAIL_ERROR_MSG(err, "Failed getting ME status\n"); /* send message to logic */ request->mlag_id = me_status.my_peer_id; request->select = FALSE; if ((current_role == SLAVE) && (use_local_lacp_logic == TRUE)) { err = send_system_event(MLAG_LACP_SELECTION_EVENT, request, sizeof(*request)); MLAG_BAIL_ERROR_MSG(err, "Failed in sending MLAG_LACP_SELECTION_EVENT event\n"); } else { err = lacp_manager_message_send(MLAG_LACP_SELECTION_EVENT, request, sizeof(*request), me_status.master_peer_id, PEER_MANAGER); MLAG_BAIL_ERROR_MSG(err, "Failed sending release request id [%u] port [%lu]\n", request->request_id, request->port_id); } bail: return err; }
/** * This function handles local sync done event * * @param[in] data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_local_sync_done(uint8_t *data) { int err = 0; UNUSED_PARAM(data); struct sync_event_data ev; struct mlag_master_election_status master_election_current_status; MLAG_LOG(MLAG_LOG_NOTICE, "send MLAG_L3_SYNC_FINISH_EVENT to master logic\n"); err = mlag_master_election_get_status(&master_election_current_status); MLAG_BAIL_ERROR_MSG(err, "Failed to get status from master election in handling of local sync done event, err=%d\n", err); /* Send MLAG_L3_SYNC_FINISH_EVENT to Master Logic */ ev.peer_id = master_election_current_status.my_peer_id; ev.state = 1; err = mlag_dispatcher_message_send(MLAG_L3_SYNC_FINISH_EVENT, &ev, sizeof(ev), MASTER_PEER_ID, PEER_MANAGER); MLAG_BAIL_ERROR_MSG(err, "Failed in sending MLAG_L3_SYNC_FINISH_EVENT, err=%d\n", err); bail: return err; }
/** * This function inits lacp DB, it allocates MLAG_MAX_PORTS * port entries in pool * * @return 0 when successful, otherwise ERROR */ int lacp_db_init(void) { int err = 0; cl_status_t cl_status = CL_SUCCESS; cl_status = cl_qpool_init(&(mlag_lacp_db.port_pool), MLAG_MAX_PORTS, MLAG_MAX_PORTS, 0, sizeof(struct mlag_lacp_entry), lacp_entry_init, lacp_entry_deinit, NULL ); if (cl_status != CL_SUCCESS) { err = -ENOMEM; MLAG_BAIL_ERROR_MSG(err, "Failed to Init LACP DB port pool\n"); } cl_qmap_init(&(mlag_lacp_db.port_map)); cl_status = cl_qpool_init(&(mlag_lacp_db.pending_pool), MLAG_MAX_PORTS, MLAG_MAX_PORTS, 0, sizeof(struct lacp_pending_entry), pending_entry_init, pending_entry_deinit, NULL ); if (cl_status != CL_SUCCESS) { err = -ENOMEM; MLAG_BAIL_ERROR_MSG(err, "Failed to Init LACP DB pending pool\n"); } cl_qmap_init(&(mlag_lacp_db.pending_map)); mlag_lacp_db.local_sys_id = 0; mlag_lacp_db.master_sys_id = 0; bail: return err; }
/** * This function starts mlag l3 interface peer sub-module * * @param data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_start(uint8_t *data) { int err = 0; int i; UNUSED_PARAM(data); if (!is_inited) { err = ECANCELED; MLAG_BAIL_ERROR_MSG(err, "l3 interface peer start called before init\n"); } MLAG_LOG(MLAG_LOG_NOTICE, "l3 interface peer manager start\n"); is_started = 1; is_peer_start = 0; is_master_sync_done = 0; for (i = 0; i < VLAN_N_VID; i++) { ipl_vlan_list[i] = 0; } /* Configure IPL as member of vlan of ipl l3 interface for control messages */ if ((ipl_vlan_id > 0) && (ipl_vlan_id < VLAN_N_VID)) { err = mlag_topology_ipl_port_get(0, &ipl_ifindex); MLAG_BAIL_ERROR_MSG(err, "Failed to get ipl data from mlag topology database upon start, err=%d\n", err); /* For start after disable mlag protocol vlan_id as well as * ipl ifindex are not relevant. * In that case ipl ifindex 0 will be returned. * Ignore it up to peer add event that should configure * above mentioned parameters. */ if (ipl_ifindex == 0) { goto bail; } MLAG_LOG(MLAG_LOG_NOTICE, "Add ipl %lu to vlan %d\n", ipl_ifindex, ipl_vlan_id); /* Add IPL to vlan */ err = sl_api_ipl_vlan_membership_action(OES_ACCESS_CMD_ADD, ipl_ifindex, &ipl_vlan_id, 1); MLAG_BAIL_ERROR_MSG(err, "Failed to set ipl vlan membership, err=%d, ipl=%lu, vlan_id=%d\n", err, ipl_ifindex, ipl_vlan_id); ipl_vlan_list[ipl_vlan_id] = 1; mlag_l3_interface_inc_cnt(ADD_IPL_TO_VLAN_EVENTS_SENT); } bail: return err; }
/* * This function is called to handle IBC message * * @param[in] data - message body * * @return 0 when successful, otherwise ERROR */ static int rcv_msg_handler(uint8_t *data) { int err = 0; struct recv_payload_data *payload_data = (struct recv_payload_data*) data; uint16_t opcode; struct peer_lacp_sync_message *lacp_sync; struct lacp_aggregation_message_data *select_req; struct lacp_aggregator_release_message *rel_msg; opcode = *((uint16_t*)(payload_data->payload[0])); if ((started == FALSE) || (lacp_enabled == FALSE)) { goto bail; } MLAG_LOG(MLAG_LOG_INFO, "lacp manager rcv_msg_handler: opcode=%d\n", opcode); lacp_db_counters_inc(LM_CNT_PROTOCOL_RX); switch (opcode) { case MLAG_LACP_SYNC_MSG: lacp_sync = (struct peer_lacp_sync_message*) payload_data->payload[0]; err = handle_lacp_sync_msg(lacp_sync); MLAG_BAIL_ERROR_MSG(err, "Failed in handling LACP sync message\n"); break; case MLAG_LACP_SELECTION_EVENT: select_req = (struct lacp_aggregation_message_data *) payload_data->payload[0]; err = lacp_manager_aggregator_selection_handle(select_req); MLAG_BAIL_ERROR_MSG(err, "Failed to handle aggregation selection event\n"); break; case MLAG_LACP_RELEASE_EVENT: rel_msg = (struct lacp_aggregator_release_message *) payload_data->payload[0]; err = lacp_manager_aggregator_free_handle(rel_msg); MLAG_BAIL_ERROR_MSG(err, "Failed to handle aggregation free event\n"); break; default: /* Unknown opcode */ err = -ENOENT; MLAG_BAIL_ERROR_MSG(err, "Unknown opcode [%u] in lacp manager\n", opcode); break; } bail: return err; }
/** * This function adds IPL to vlan of l3 interface * to exchange control messages * * @param[in] data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_vlan_interface_add(struct peer_conf_event_data *data) { int err = 0; ASSERT(data); if (!is_inited) { MLAG_BAIL_ERROR_MSG(err, "Add ipl to vlan interface called before init\n"); } /* vlan_id can be 0 when delete peer event accepted */ if (!(data->vlan_id < VLAN_N_VID)) { MLAG_BAIL_ERROR_MSG(err, "vlan id %d is not valid\n", data->vlan_id); } MLAG_LOG(MLAG_LOG_NOTICE, "Add ipl to vlan interface %d\n", data->vlan_id); ipl_vlan_id = data->vlan_id; if (!is_started) { MLAG_LOG(MLAG_LOG_NOTICE, "Add ipl to vlan interface %d ignored because called before start\n", ipl_vlan_id); goto bail; } /* Check if IPL is not a member of the vlan */ if ((ipl_vlan_id != 0) && (ipl_vlan_list[ipl_vlan_id] == 0)) { /* Add IPL to vlan */ err = mlag_topology_ipl_port_get(0, &ipl_ifindex); MLAG_BAIL_ERROR_MSG(err, "Failed to get ipl port data from mlag topology: ipl vlan id=%d, ipl ifindex=%lu, err=%d\n", ipl_vlan_id, ipl_ifindex, err); if (ipl_ifindex == 0) { goto bail; } err = sl_api_ipl_vlan_membership_action(OES_ACCESS_CMD_ADD, ipl_ifindex, &ipl_vlan_id, 1); MLAG_BAIL_ERROR_MSG(err, "Failed to add ipl %lu to vlan interface %d, err %d\n", ipl_ifindex, ipl_vlan_id, err); ipl_vlan_list[ipl_vlan_id] = 1; mlag_l3_interface_inc_cnt(ADD_IPL_TO_VLAN_EVENTS_SENT); } bail: return err; }
/* * Sends notification to reject request * * @param[in] request - selection request data * * @return 0 when successful, otherwise ERROR */ static int reject_pending_request(struct lacp_aggregation_message_data *request) { int err = 0; MLAG_LOG(MLAG_LOG_DEBUG, "Reject pending request id [%u] port [%lu]\n", request->request_id, request->port_id); request->is_response = TRUE; request->response = LACP_AGGREGATE_DECLINE; err = notify_aggregator_selection_response(request); MLAG_BAIL_ERROR(err); err = lacp_db_pending_request_delete(request->port_id); if (err && (err != -ENOENT)) { MLAG_BAIL_ERROR_MSG(err, "Failed to clear pending request port [%lu] request [%u]", request->port_id, request->request_id); } else { err = 0; } bail: return err; }
/* * Used for sending messages * with implementation of counting mechanism * * @param[in] opcode - message opcode * @param[in] payload - pointer to message data * @param[in] payload_len - message data length * @param[in] dest_peer_id - mlag id of dest peer * @param[in] orig - message originator * * @return 0 if operation completes successfully. */ static int lacp_manager_message_send(enum mlag_events opcode, void* payload, uint32_t payload_len, uint8_t dest_peer_id, enum message_originator orig) { int err = 0; struct mlag_master_election_status me_status; err = mlag_dispatcher_message_send(opcode, payload, payload_len, dest_peer_id, orig); MLAG_BAIL_CHECK_NO_MSG(err); err = mlag_master_election_get_status(&me_status); MLAG_BAIL_ERROR_MSG(err, "Failed getting ME status\n"); /* Counters */ if ((dest_peer_id != me_status.my_peer_id) || ((orig == PEER_MANAGER) && (current_role == SLAVE))) { /* increment IPL counter */ lacp_db_counters_inc(LM_CNT_PROTOCOL_TX); } bail: return err; }
/** * This function inits mlag l3 interface peer sub-module * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_init(void) { int err = 0; int i; if (is_inited) { err = ECANCELED; MLAG_BAIL_ERROR_MSG(err, "l3 interface peer init called twice\n"); } MLAG_LOG(MLAG_LOG_NOTICE, "l3 interface peer init\n"); is_inited = 1; is_started = 0; is_peer_start = 0; ipl_ifindex = 0; ipl_vlan_id = 0; is_master_sync_done = 0; for (i = 0; i < VLAN_N_VID; i++) { ipl_vlan_list[i] = 0; } bail: return err; }
/* * This function implements LACP selection * * @param[in] mlag_id - mlag id of requester * @param[in] port_id - port ID * @param[out] is_free - indicate if aggregator became free * * @return 0 when successful, otherwise ERROR */ static int lacp_aggregator_free_logic(int mlag_id, unsigned long port_id, int *is_free) { int err = 0; int i; struct mlag_lacp_data *lacp_data = NULL; *is_free = TRUE; err = lacp_db_entry_get(port_id, &lacp_data); if (err == -ENOENT) { /* there is no entry for that port */ err = 0; *is_free = TRUE; goto bail; } /* Update users and ACCEPT request */ lacp_data->peer_state[mlag_id] = FALSE; for (i = 0; i < MLAG_MAX_PEERS; i++) { if (lacp_data->peer_state[i] == TRUE) { *is_free = FALSE; } } if (*is_free == TRUE) { /* delete entry from DB */ err = lacp_db_entry_delete(port_id); MLAG_BAIL_ERROR_MSG(err, "Failed to delete free lacp port [%lu]\n", port_id); } bail: return err; }
/* * Clear pending requests from pending queue * * @param[in] request - struct containing pending request * @param[in] data - an optional parameter, not in use * * @return 0 if operation completes successfully. */ static int clear_pending_request(struct lacp_aggregation_message_data *request, void *data) { int err = 0; struct mlag_notification notify; UNUSED_PARAM(data); ASSERT(request != NULL); /* fill notification msg */ notify.notification_type = MLAG_NOTIFY_AGGREGATOR_RESPONSE; notify.notification_info.agg_response.response = LACP_AGGREGATE_DECLINE; notify.notification_info.agg_response.request_id = request->request_id; notify.notification_info.agg_response.req_partner_id = request->partner_id; notify.notification_info.agg_response.req_partner_key = request->partner_key; notify.notification_info.agg_response.req_port_id = request->port_id; err = mlag_notify(¬ify); MLAG_BAIL_ERROR_MSG(err, "Failed to reject pending port [%lu] req [%u]\n", request->port_id, request->request_id); bail: return err; }
/** * This function stops mlag l3 interface peer sub-module * * @param data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_stop(uint8_t *data) { int err = 0; int i; UNUSED_PARAM(data); int num_vlans_to_del = 0; if (!is_started) { goto bail; } MLAG_LOG(MLAG_LOG_NOTICE, "l3 interface peer manager stop\n"); /* Check on ipl ifindex validity */ err = mlag_topology_ipl_port_get(0, &ipl_ifindex); MLAG_BAIL_ERROR_MSG(err, "Failed to get ipl data from mlag topology database upon stop, err=%d\n", err); if (ipl_ifindex == 0) { goto bail; } /* Remove IPL from all vlans */ for (i = 1; i < VLAN_N_VID; i++) { if (ipl_vlan_list[i]) { /* Remove IPL from vlan */ ipl_vlan_list[i] = 0; sl_vlan_list[num_vlans_to_del++] = i; mlag_l3_interface_inc_cnt(DEL_IPL_FROM_VLAN_EVENTS_SENT); } } if (num_vlans_to_del) { err = sl_api_ipl_vlan_membership_action(OES_ACCESS_CMD_DELETE, ipl_ifindex, sl_vlan_list, num_vlans_to_del); MLAG_BAIL_ERROR_MSG(err, "Failed to delete ipl vlan membership, err=%d, ipl_ifindex=%lu, num_vlans_to_del=%d\n", err, ipl_ifindex, num_vlans_to_del); } bail: is_started = 0; return err; }
/** * Returns actor attributes. The actor attributes are * system ID, system priority to be used in the LACP PDU * and a chassis ID which is an index of this node within the MLAG * cluster, with a value in the range of 0..15 * * @param[out] actor_sys_id - actor sys ID (for LACP PDU) * @param[out] chassis_id - MLAG cluster chassis ID, range 0..15 * * @return 0 when successful, otherwise ERROR */ int lacp_manager_actor_parameters_get(unsigned long long *actor_sys_id, unsigned int *chassis_id) { int err = 0; struct mlag_master_election_status me_status; ASSERT(actor_sys_id != NULL); ASSERT(chassis_id != NULL); if ((started == FALSE) || (lacp_enabled == FALSE)) { *chassis_id = 0; MLAG_LOG(MLAG_LOG_NOTICE, "Actor parameters requested although LACP module inactive\n"); err = lacp_db_local_system_id_get(actor_sys_id); MLAG_BAIL_ERROR_MSG(err, "Failed to retrieve local LACP attributes\n"); goto bail; } err = mlag_master_election_get_status(&me_status); MLAG_BAIL_ERROR_MSG(err, "Failed getting ME status\n"); /* If slave we return master's parameters, otherwise we * return the local parameters */ if ((me_status.current_status == SLAVE) && (use_local_lacp_logic == FALSE)) { err = lacp_db_master_system_id_get(actor_sys_id); MLAG_BAIL_ERROR_MSG(err, "Failed to retrieve master LACP attributes\n"); /* Chassis ID is set by master election module */ *chassis_id = me_status.my_peer_id; } else { *chassis_id = 0; err = lacp_db_local_system_id_get(actor_sys_id); MLAG_BAIL_ERROR_MSG(err, "Failed to retrieve master LACP attributes\n"); } bail: return err; }
/** * Handles peer start notification.Peer start * triggers lacp sync process start. The Master * sends its actor attributes to the remotes. * * @param[in] mlag_peer_id - peer global index * * @return 0 if operation completes successfully. */ int lacp_manager_peer_start(int mlag_peer_id) { int err = 0; struct peer_lacp_sync_message sync_message; struct mlag_master_election_status me_status; ASSERT(mlag_peer_id < MLAG_MAX_PEERS); if ((started == FALSE) || (lacp_enabled == FALSE)) { goto bail; } err = mlag_master_election_get_status(&me_status); MLAG_BAIL_ERROR_MSG(err, "Failed getting ME status\n"); /* Master will send sync done for itself */ if (me_status.current_status == SLAVE) { /* Slave will send sync start message */ sync_message.mlag_id = me_status.my_peer_id; sync_message.phase = LACP_SYNC_START; /* Send message to master */ MLAG_LOG(MLAG_LOG_DEBUG, "LACP peer [%d] sync send to master \n", sync_message.mlag_id); /* Send to master logic sync message */ err = lacp_manager_message_send(MLAG_LACP_SYNC_MSG, &sync_message, sizeof(sync_message), me_status.master_peer_id, PEER_MANAGER); MLAG_BAIL_ERROR_MSG(err, "Failed in sending ports sync message \n"); } else if (mlag_peer_id == me_status.my_peer_id) { MLAG_LOG(MLAG_LOG_NOTICE, "Send LACP peer sync\n"); err = lacp_send_sync_done(mlag_peer_id); MLAG_BAIL_ERROR_MSG(err, "Failed in sending lacp sync done\n"); } bail: return err; }
/** * This function handles peer state change notification. * * @param[in] state_change - state change data * * @return 0 if operation completes successfully. */ int lacp_manager_peer_state_change(struct peer_state_change_data *state_change) { int err = 0; int i; struct lacp_peer_down_ports_data peer_down_data; MLAG_LOG(MLAG_LOG_NOTICE, "LACP manager peer state change [%d]\n", state_change->state); if ((started == FALSE) || (lacp_enabled == FALSE)) { goto bail; } if ((current_role == SLAVE) && (state_change->state != HEALTH_PEER_UP)) { /* reject all pending requests */ err = lacp_db_pending_foreach(clear_pending_request, NULL); MLAG_BAIL_ERROR_MSG(err, "Failed to reject pending requests on peer down\n"); /* switch to local LACP logic */ set_lacp_logic_origin(TRUE); } if ((current_role == MASTER) && (state_change->state != HEALTH_PEER_UP)) { peer_down_data.mlag_id = state_change->mlag_id; peer_down_data.port_num = 0; /* peer down, clear all active system IDs taken by this peer */ err = lacp_db_port_foreach(clear_peer, &peer_down_data); MLAG_BAIL_ERROR_MSG(err, "Failed to clear peer usage on peer down\n"); /* clear DB from unused entries */ for (i = 0; i < peer_down_data.port_num; i++) { err = lacp_db_entry_delete(peer_down_data.ports_to_delete[i]); MLAG_BAIL_ERROR_MSG(err, "Failed to remove port [%lu] entry on peer down\n", peer_down_data.ports_to_delete[i]); } } bail: return err; }
/* * Sends notification to reject request * * @param[in] msg - selection request data * * @return 0 when successful, otherwise ERROR */ static int notify_aggregator_selection_response(struct lacp_aggregation_message_data *msg) { int err = 0; struct lacp_aggregation_message_data *db_req = NULL; struct mlag_notification notify; /* check if there is a pending request in DB */ err = lacp_db_pending_request_get(msg->port_id, &db_req); if ((err == -ENOENT) || (db_req == NULL) || (db_req->request_id != msg->request_id)) { /* no pending request - ignore */ err = 0; MLAG_LOG(MLAG_LOG_DEBUG, "Ignore response port ID [%lu] req ID [%u]\n", msg->port_id, msg->request_id); goto bail; } MLAG_BAIL_ERROR(err); /* fill notification msg */ notify.notification_type = MLAG_NOTIFY_AGGREGATOR_RESPONSE; notify.notification_info.agg_response.request_id = msg->request_id; notify.notification_info.agg_response.req_partner_id = msg->partner_id; notify.notification_info.agg_response.req_partner_key = msg->partner_key; notify.notification_info.agg_response.req_port_id = msg->port_id; notify.notification_info.agg_response.response = msg->response; err = mlag_notify(¬ify); MLAG_BAIL_ERROR_MSG(err, "Failed to notify response for port [%lu] req [%u]", msg->port_id, msg->request_id); err = lacp_db_pending_request_delete(msg->port_id); MLAG_BAIL_ERROR_MSG(err, "Failed to clear pending request port [%lu] request [%u]", msg->port_id, msg->request_id); bail: return err; }
/** * Handles a aggregator release * This may involve a remote peer, * * @param[in] request_id - index given by caller that will appear in reply * @param[in] port_id - Interface index of port. Must represent MLAG port. * * @return 0 when successful, otherwise ERROR */ int lacp_manager_aggregator_selection_release(unsigned int request_id, unsigned long port_id) { int err = 0; struct lacp_aggregation_message_data *previous_req = NULL; struct lacp_aggregation_message_data selection_req; if (lacp_enabled == FALSE) { MLAG_LOG(MLAG_LOG_NOTICE, "Request for selection release while LACP disabled\n"); goto bail; } /* Expect there is an outstanding request -> reject it */ err = lacp_db_pending_request_get(port_id, &previous_req); if (err && (err != -ENOENT)) { MLAG_BAIL_ERROR_MSG(err, "Failed in pending request lookup\n"); } else if (err == 0) { /* Found a pending request - drop it */ err = lacp_db_pending_request_delete(port_id); MLAG_BAIL_ERROR_MSG(err, "Failed to delete pending request for port [%lu]", port_id); } /* prepare selection request */ selection_req.is_response = FALSE; selection_req.request_id = request_id; selection_req.port_id = port_id; /* send selection request to master logic */ err = send_release_message(&selection_req); MLAG_BAIL_ERROR(err); bail: return err; }
/* * Insert to pending requests queue (according to role) * * @param[in] request - selection request data * * @return 0 when successful, otherwise ERROR */ static int update_pending_selection_queue(struct lacp_aggregation_message_data *request) { int err = 0; err = lacp_db_pending_request_add(request->port_id, request); MLAG_BAIL_ERROR_MSG(err, "Request ID [%u] port [%lu] insertion to pending DB Failed\n", request->request_id, request->port_id); bail: return err; }
/* * Move to use local or remote LACP logic * * @param[in] use_local - whether to use local LACP logic or not * */ void set_lacp_logic_origin(int use_local) { int err = 0; use_local_lacp_logic = use_local; err = lacp_db_port_clear(); MLAG_BAIL_ERROR_MSG(err, "Failed to clear LACP selection db on role change\n"); bail: return; }
/** * This function de-inits mlag l3 interface peer sub-module * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_deinit(void) { int err = 0; if (!is_inited) { err = ECANCELED; MLAG_BAIL_ERROR_MSG(err, "l3 interface peer deinit called before init\n"); } MLAG_LOG(MLAG_LOG_NOTICE, "l3 interface peer deinit\n"); bail: return err; }
/* * This function is called to handle network order for IBC message * * @param[in] payload_data - message body * @param[in] oper - on send or receive * * @return 0 when successful, otherwise ERROR */ static int net_order_msg_handler(uint8_t *data, int oper) { int err = 0; uint16_t opcode; struct peer_lacp_sync_message *lacp_sync; struct lacp_aggregator_release_message *rel_msg; struct lacp_aggregation_message_data *agg_msg; if (oper == MESSAGE_SENDING) { opcode = *(uint16_t*)data; *(uint16_t*)data = htons(opcode); } else { opcode = ntohs(*(uint16_t*)data); *(uint16_t*)data = opcode; } MLAG_LOG(MLAG_LOG_DEBUG, "lacp_manager net_order_msg_handler: opcode=%d\n", opcode); switch (opcode) { case MLAG_LACP_SYNC_MSG: lacp_sync = (struct peer_lacp_sync_message *) data; net_order_lacp_sync_data(lacp_sync, oper); break; case MLAG_LACP_SELECTION_EVENT: agg_msg = (struct lacp_aggregation_message_data *) data; net_order_aggregator_selection_data(agg_msg, oper); break; case MLAG_LACP_RELEASE_EVENT: rel_msg = (struct lacp_aggregator_release_message *) data; net_order_aggregator_release_data(rel_msg, oper); break; default: /* Unknown opcode */ err = -ENOENT; MLAG_BAIL_ERROR_MSG(err, "Unknown opcode [%u] in lacp manager\n", opcode); break; } bail: return err; }
/* * Sends notification to reject request * * @param[in] msg - selection request data * * @return 0 when successful, otherwise ERROR */ static int notify_aggregator_release(struct lacp_aggregator_release_message *msg) { int err = 0; struct mlag_notification notify; notify.notification_type = MLAG_NOTIFY_AGGREGATOR_RELEASE; notify.notification_info.agg_release.port_id = msg->port_id; /* notify on response */ err = mlag_notify(¬ify); MLAG_BAIL_ERROR_MSG(err, "Failed to notify aggregator release for port [%lu]\n", msg->port_id); bail: return err; }
/** * This function sets IPL port state * * @param[in] ipl_id - IPL index * @param[in] port_state - the IPL port state * * * @return 0 if operation completes successfully. * @return -EINVAL if IPL is not defined */ int mlag_topology_ipl_port_state_set(unsigned int ipl_id, enum oes_port_oper_state port_state) { int err = 0; ASSERT(ipl_id < MLAG_MAX_IPLS); if (ipl_db[ipl_id].valid == VALID) { ipl_db[ipl_id].current_state = port_state; } else { err = -EINVAL; MLAG_BAIL_ERROR_MSG(err, "IPL index [%u] not found\n", ipl_id); } bail: return err; }
/** * This function gets IPL peer IP * * @param[in] ipl_id - IPL index * @param[out] peer_ip - the peer IP of the IPL * * * @return 0 if operation completes successfully. * @return -EINVAL if IPL is not defined */ int mlag_topology_ipl_peer_ip_get(unsigned int ipl_id, struct oes_ip_addr *peer_ip) { int err = 0; ASSERT(ipl_id < MLAG_MAX_IPLS); ASSERT(peer_ip != NULL); if (ipl_db[ipl_id].valid == VALID) { *peer_ip = ipl_db[ipl_id].peer_ip; } else { err = -EINVAL; MLAG_BAIL_ERROR_MSG(err, "IPL index [%u] not found\n", ipl_id); } bail: return err; }
/** * This function sets IPL local IP. * * @param[in] ipl_id - IPL index. * @param[in] local_ip - the local IP of the IPL. * * @return 0 - Operation completed successfully. * @return -EINVAL if IPL is not defined. */ int mlag_topology_ipl_local_ip_set(unsigned int ipl_id, const struct oes_ip_addr *local_ip) { int err = 0; ASSERT(ipl_id < MLAG_MAX_IPLS); if (ipl_db[ipl_id].valid == VALID) { ipl_db[ipl_id].local_ip = *local_ip; } else { err = -EINVAL; MLAG_BAIL_ERROR_MSG(err, "IPL index [%u] not found\n", ipl_id); } bail: return err; }
/** * This function sets IPL vlan id. * * @param[in] ipl_id - IPL index. * @param[in] vlan_id - Vlan id of the IPL. * * @return 0 - Operation completed successfully. * @return -EINVAL if IPL is not defined. */ int mlag_topology_ipl_vlan_id_set(unsigned int ipl_id, const unsigned short vlan_id) { int err = 0; ASSERT(ipl_id < MLAG_MAX_IPLS); if (ipl_db[ipl_id].valid == VALID) { ipl_db[ipl_id].vlan_id = vlan_id; } else { err = -EINVAL; MLAG_BAIL_ERROR_MSG(err, "IPL index [%u] not found\n", ipl_id); } bail: return err; }
/** * This function handles master sync done event * * @param[in] data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_master_sync_done(uint8_t *data) { int err = 0; UNUSED_PARAM(data); is_master_sync_done = 1; MLAG_LOG(MLAG_LOG_NOTICE, "send local vlan oper status trigger\n"); /* Send query to update local vlans operational states */ err = sl_api_vlan_oper_status_trigger_get(); MLAG_BAIL_ERROR_MSG(err, "Failed in local vlan oper status trigger, err=%d\n", err); bail: return err; }
/* * This function implements LACP selection * * @param[in] mlag_id - mlag id of requestor * @param[in] port_id - port ID * @param[in] partner_id - request partner ID * @param[out] response - selected or not * @param[out] current_partner_id - currently selected partner id * @param[out] current_partner_key - currently selected partner key * * @return 0 when successful, otherwise ERROR */ static int lacp_aggregator_select_logic(int mlag_id, unsigned long port_id, unsigned long long partner_id, unsigned int partner_key, enum aggregate_select_response *response, unsigned long long *current_partner_id, unsigned int *current_partner_key) { int err = 0; int i; struct mlag_lacp_data *lacp_data = NULL; *response = LACP_AGGREGATE_DECLINE; MLAG_LOG(MLAG_LOG_INFO, "Aggregator select logic for port [%lu] partner [%llu] key [%u]\n", port_id, partner_id, partner_key); err = lacp_db_entry_get(port_id, &lacp_data); if (err == -ENOENT) { /* create entry for first entry */ err = lacp_db_entry_allocate(port_id, &lacp_data); MLAG_BAIL_ERROR_MSG(err, "Failed to create lacp entry port [%lu]\n", port_id); lacp_data->partner_id = partner_id; lacp_data->partner_key = partner_key; for (i = 0; i < MLAG_MAX_PEERS; i++) { lacp_data->peer_state[i] = FALSE; } } if ((lacp_data->partner_id == partner_id) && (lacp_data->partner_key == partner_key)) { /* Update users and ACCEPT request */ lacp_data->peer_state[mlag_id] = TRUE; *response = LACP_AGGREGATE_ACCEPT; } *current_partner_key = lacp_data->partner_key; *current_partner_id = lacp_data->partner_id; bail: return err; }
/** * This function removes IPL from vlan of l3 interface * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_vlan_interface_del() { int err = 0; if (!is_inited) { MLAG_BAIL_ERROR_MSG(err, "Delete ipl from vlan interface called before init\n"); } MLAG_LOG(MLAG_LOG_NOTICE, "Delete ipl from vlan interface: ipl_vlan_id=%d\n", ipl_vlan_id); /* Check if IPL is not a member of the vlan */ if ((ipl_vlan_id != 0) && (ipl_vlan_list[ipl_vlan_id] == 1)) { ipl_vlan_list[ipl_vlan_id] = 0; } bail: return err; }
/** * This function handles peer start event * * @param[in] data - event data * * @return 0 when successful, otherwise ERROR */ int mlag_l3_interface_peer_peer_start(struct peer_state_change_data *data) { int err = 0; struct sync_event_data ev; MLAG_LOG(MLAG_LOG_NOTICE, "Sending MLAG_L3_SYNC_START_EVENT to master logic\n"); is_peer_start = 1; /* Send MLAG_SYNC_START_EVENT event to Master Logic */ ev.peer_id = data->mlag_id; ev.state = 0; err = mlag_dispatcher_message_send(MLAG_L3_SYNC_START_EVENT, &ev, sizeof(ev), MASTER_PEER_ID, PEER_MANAGER); MLAG_BAIL_ERROR_MSG(err, "Failed in sending MLAG_L3_SYNC_START_EVENT, err=%d\n", err); bail: return err; }