From 82b6bcfbb3f0306763850fc343ec9f6d100dc4a2 Mon Sep 17 00:00:00 2001 From: Praveen-Brcm <51765988+Praveen-Brcm@users.noreply.github.com> Date: Tue, 3 Aug 2021 17:32:50 -0700 Subject: [PATCH] MCLAG enhacements ICCPd initial code commit (#4819) * MCLAG enhacements ICCPd initial code commit * Resolving the merge conflicts with orighin * L3 MCLAG Enhancements and Unique IP Changes. * Addressed review comments Co-authored-by: Tapash Das --- src/iccpd/include/iccp_cli.h | 27 +- src/iccpd/include/iccp_cmd.h | 3 + src/iccpd/include/iccp_cmd_show.h | 2 + src/iccpd/include/iccp_csm.h | 11 +- src/iccpd/include/iccp_ifm.h | 4 +- src/iccpd/include/iccp_netlink.h | 16 +- src/iccpd/include/logger.h | 2 +- src/iccpd/include/mlacp_fsm.h | 96 +- src/iccpd/include/mlacp_link_handler.h | 45 +- src/iccpd/include/mlacp_sync_prepare.h | 13 +- src/iccpd/include/mlacp_sync_update.h | 7 +- src/iccpd/include/mlacp_tlv.h | 84 +- src/iccpd/include/msg_format.h | 95 +- src/iccpd/include/openbsd_tree.h | 571 +++++ src/iccpd/include/port.h | 56 +- src/iccpd/include/scheduler.h | 5 +- src/iccpd/include/system.h | 252 ++ src/iccpd/src/Makefile.am | 3 +- src/iccpd/src/app_csm.c | 2 +- src/iccpd/src/iccp_cli.c | 77 +- src/iccpd/src/iccp_cmd.c | 15 + src/iccpd/src/iccp_cmd_show.c | 296 ++- src/iccpd/src/iccp_consistency_check.c | 17 +- src/iccpd/src/iccp_csm.c | 88 +- src/iccpd/src/iccp_ifm.c | 821 ++++-- src/iccpd/src/iccp_main.c | 1 + src/iccpd/src/iccp_netlink.c | 1013 ++++++-- src/iccpd/src/logger.c | 4 +- src/iccpd/src/mclagdctl/mclagdctl.c | 376 ++- src/iccpd/src/mclagdctl/mclagdctl.h | 41 +- src/iccpd/src/mlacp_fsm.c | 470 +++- src/iccpd/src/mlacp_link_handler.c | 3229 ++++++++++++++++++++---- src/iccpd/src/mlacp_sync_prepare.c | 111 +- src/iccpd/src/mlacp_sync_update.c | 779 ++++-- src/iccpd/src/openbsd_tree.c | 618 +++++ src/iccpd/src/port.c | 259 +- src/iccpd/src/scheduler.c | 183 +- src/iccpd/src/system.c | 198 +- 38 files changed, 8501 insertions(+), 1389 deletions(-) create mode 100644 src/iccpd/include/openbsd_tree.h create mode 100644 src/iccpd/src/openbsd_tree.c diff --git a/src/iccpd/include/iccp_cli.h b/src/iccpd/include/iccp_cli.h index c85fc4316b5f..3365495d2caa 100644 --- a/src/iccpd/include/iccp_cli.h +++ b/src/iccpd/include/iccp_cli.h @@ -36,10 +36,10 @@ typedef enum typedef struct cli_param_queue { - char ifname[16]; + char ifname[16]; cli_queue_type_et type; - int param; - int itf_add; + int param; + int itf_add; LIST_ENTRY(cli_param_queue) cli_queue_next; } cli_param_queue_st; @@ -50,18 +50,21 @@ typedef struct cli_param_queue #define MCLAG_INTF_STR "mclag_interface" #define SYSTEM_MAC_STR "system_mac" -int set_mc_lag_id(struct CSM* csm, uint16_t domain); -int set_peer_link(int mid, const char* ifname); -int set_local_address(int mid, const char* addr); -int set_peer_address(int mid, const char* addr); -int unset_mc_lag_id(struct CSM* csm, uint16_t domain); +int set_mc_lag_id(struct CSM *csm, uint16_t domain); +int set_peer_link(int mid, const char *ifname); +int set_local_address(int mid, const char *addr); +int set_peer_address(int mid, const char *addr); +int unset_mc_lag_id(struct CSM *csm, uint16_t domain); int unset_peer_link(int mid); int unset_local_address(int mid); int unset_peer_address(int mid); -int iccp_cli_attach_mclag_domain_to_port_channel(int domain, const char* ifname); -int iccp_cli_detach_mclag_domain_to_port_channel(const char* ifname); -int set_local_system_id(const char* mac); -int unset_local_system_id( ); +int iccp_cli_attach_mclag_domain_to_port_channel(int domain, const char *ifname); +int iccp_cli_detach_mclag_domain_to_port_channel(const char *ifname); +int set_local_system_id(const char *mac); +int unset_local_system_id(); + +int set_keepalive_time(int mid, int keepalive_time); +int set_session_timeout(int mid, int session_timeout_val); #endif diff --git a/src/iccpd/include/iccp_cmd.h b/src/iccpd/include/iccp_cmd.h index 01f37456b71d..31c905c1eb92 100644 --- a/src/iccpd/include/iccp_cmd.h +++ b/src/iccpd/include/iccp_cmd.h @@ -26,4 +26,7 @@ int iccp_config_from_file(char *config_default_dir); +int set_mc_lag_by_id(uint16_t mid); +int unset_mc_lag_by_id(uint16_t mid); + #endif /* ICCP_CMD_H_ */ diff --git a/src/iccpd/include/iccp_cmd_show.h b/src/iccpd/include/iccp_cmd_show.h index a41fbadf8c77..7dad3ec1be1e 100644 --- a/src/iccpd/include/iccp_cmd_show.h +++ b/src/iccpd/include/iccp_cmd_show.h @@ -33,4 +33,6 @@ extern int iccp_ndisc_dump(char * *buf, int *num, int mclag_id); extern int iccp_mac_dump(char * *buf, int *num, int mclag_id); extern int iccp_local_if_dump(char * *buf, int *num, int mclag_id); extern int iccp_peer_if_dump(char * *buf, int *num, int mclag_id); +extern int iccp_cmd_dbg_counter_dump(char * *buf, int *data_len, int mclag_id); +extern int iccp_unique_ip_if_dump(char * *buf, int *num, int mclag_id); #endif diff --git a/src/iccpd/include/iccp_csm.h b/src/iccpd/include/iccp_csm.h index 01e424d13271..cc8879f8c835 100644 --- a/src/iccpd/include/iccp_csm.h +++ b/src/iccpd/include/iccp_csm.h @@ -45,10 +45,10 @@ #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 -#endif /* INET_ADDRSTRLEN */ +#endif /* INET_ADDRSTRLEN */ #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 -#endif /* INET6_ADDRSTRLEN */ +#endif /* INET6_ADDRSTRLEN */ /* For socket binding */ #define ICCP_TCP_PORT 8888 #define MAX_ACCEPT_CONNETIONS 20 @@ -113,10 +113,15 @@ struct CSM time_t peer_warm_reboot_time; time_t warm_reboot_disconn_time; char peer_itf_name[IFNAMSIZ]; + time_t peer_link_learning_retry_time; char peer_ip[INET_ADDRSTRLEN]; char sender_ip[INET_ADDRSTRLEN]; void* sock_read_event_ptr; + int keepalive_time; + int session_timeout; + int peer_link_learning_enable; + /* Msg queue */ TAILQ_HEAD(msg_list, Msg) msg_list; @@ -164,5 +169,5 @@ void iccp_csm_correspond_from_rg_connect_msg(struct CSM*, struct Msg*); void iccp_csm_correspond_from_rg_disconnect_msg(struct CSM*, struct Msg*); int mlacp_bind_port_channel_to_csm(struct CSM* csm, const char *ifname); - +int iccp_csm_init_mac_msg(struct MACMsg **mac_msg, char* data, int len); #endif /* ICCP_CSM_H_ */ diff --git a/src/iccpd/include/iccp_ifm.h b/src/iccpd/include/iccp_ifm.h index bbb1af67ee90..d668b569a869 100644 --- a/src/iccpd/include/iccp_ifm.h +++ b/src/iccpd/include/iccp_ifm.h @@ -37,6 +37,8 @@ int do_one_neigh_request(struct nlmsghdr *n); void iccp_from_netlink_port_state_handler( char * ifname, int state); -void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n); +void vlan_mbrship_change_handler(unsigned int vlan_id, char *mbr_if_name, int add_flag); +void del_all_pending_vlan_mbr_ifs(struct System *sys); +void move_pending_vlan_mbr_to_lif(struct System *sys, struct LocalInterface* lif); #endif // LACP_IFM_H diff --git a/src/iccpd/include/iccp_netlink.h b/src/iccpd/include/iccp_netlink.h index a4f321736d0c..483de43b2698 100644 --- a/src/iccpd/include/iccp_netlink.h +++ b/src/iccpd/include/iccp_netlink.h @@ -26,9 +26,7 @@ #include #include #include - #include - #include "../include/system.h" #include "../include/port.h" #include @@ -37,6 +35,7 @@ #define NDISC_NEIGHBOUR_ADVERTISEMENT 136 #define ND_OPT_TARGET_LL_ADDR 2 #define NEXTHDR_ICMP 58 +#define ICCP_NLE_SEQ_MISMATCH -16 struct nd_msg { @@ -51,17 +50,20 @@ struct in6_pktinfo unsigned int ipi6_ifindex; /* send/recv interface index */ }; -int iccp_get_port_member_list(struct LocalInterface* lif); +int iccp_get_port_member_list(struct LocalInterface *lif); void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg); void iccp_event_handler_obj_input_dellink(struct nl_object *obj, void *arg); int iccp_system_init_netlink_socket(); void iccp_system_dinit_netlink_socket(); int iccp_init_netlink_event_fd(struct System *sys); -int iccp_handle_events(struct System * sys); -void update_if_ipmac_on_standby(struct LocalInterface* lif_po); +int iccp_handle_events(struct System *sys); +void update_if_ipmac_on_standby(struct LocalInterface *lif_po, int dir); int iccp_sys_local_if_list_get_addr(); -int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *mac, char *portname); +int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *mac, char *portname, int permanent, int dir); int iccp_check_if_addr_from_netlink(int family, uint8_t *addr, struct LocalInterface *lif); +void recover_if_ipmac_on_standby(struct LocalInterface* lif_po, int dir); +void update_vlan_if_mac_on_standby(struct LocalInterface* lif_vlan, int dir); +void recover_vlan_if_mac_on_standby(struct LocalInterface* lif_vlan, int dir, uint8_t *remote_system_mac); +void update_vlan_if_mac_on_iccp_up(struct LocalInterface* lif_peer, int is_up, uint8_t *remote_system_mac); #endif - diff --git a/src/iccpd/include/logger.h b/src/iccpd/include/logger.h index a90fece2a4d9..9e7c90474fa4 100644 --- a/src/iccpd/include/logger.h +++ b/src/iccpd/include/logger.h @@ -32,7 +32,7 @@ typedef enum _iccpd_log_level_t { CRITICAL_LOG_LEVEL = 0, - ERR_LOG_LEVEL = 1, + ERR_LOG_LEVEL = 1, WARN_LOG_LEVEL = 2, NOTICE_LOG_LEVEL = 3, INFO_LOG_LEVEL = 4, diff --git a/src/iccpd/include/mlacp_fsm.h b/src/iccpd/include/mlacp_fsm.h index b335e78cd007..688fdcdd775f 100644 --- a/src/iccpd/include/mlacp_fsm.h +++ b/src/iccpd/include/mlacp_fsm.h @@ -26,9 +26,12 @@ #define _MLACP_FSM_H #include "../include/port.h" +#include "../include/mlacp_tlv.h" #define MLCAP_SYNC_PHY_DEV_SEC 1 /*every 1 sec*/ +#define MLACP_LOCAL_IF_DOWN_TIMER 600 // 600 seconds. + #define MLACP(csm_ptr) (csm_ptr->app_csm.mlacp) struct CSM; @@ -47,7 +50,7 @@ typedef enum MLACP_APP_STATE MLACP_APP_STATE_E; /* for sender only*/ enum MLACP_SYNC_STATE { - MLACP_SYNC_SYSCONF=0, + MLACP_SYNC_SYSCONF = 0, MLACP_SYNC_AGGCONF, MLACP_SYNC_AGGSTATE, MLACP_SYNC_AGGINFO, @@ -66,6 +69,85 @@ struct Remote_System uint32_t node_id; }; +/**************************************************************** + * Debug counters to track message sent and received between + * MC-LAG peers over ICCP + ***************************************************************/ +typedef uint8_t ICCP_DBG_CNTR_DIR_e; +enum ICCP_DBG_CNTR_DIR_e +{ + ICCP_DBG_CNTR_DIR_TX = 0, + ICCP_DBG_CNTR_DIR_RX = 1, + ICCP_DBG_CNTR_DIR_MAX +}; + +typedef uint8_t ICCP_DBG_CNTR_STS_e; +enum ICCP_DBG_CNTR_STS_e +{ + ICCP_DBG_CNTR_STS_OK = 0, + ICCP_DBG_CNTR_STS_ERR = 1, /* Send error or receive processing error*/ + ICCP_DBG_CNTR_STS_MAX +}; + +/* Change MCLAGDCTL_MAX_DBG_COUNTERS if ICCP_DBG_CNTR_MSG_MAX is more than 32 */ +enum ICCP_DBG_CNTR_MSG +{ + ICCP_DBG_CNTR_MSG_SYS_CONFIG = 0, + ICCP_DBG_CNTR_MSG_AGGR_CONFIG = 1, + ICCP_DBG_CNTR_MSG_AGGR_STATE = 2, + ICCP_DBG_CNTR_MSG_MAC_INFO = 3, + ICCP_DBG_CNTR_MSG_ARP_INFO = 4, + ICCP_DBG_CNTR_MSG_L2MC_INFO = 5, + ICCP_DBG_CNTR_MSG_PORTCHANNEL_INFO = 6, + ICCP_DBG_CNTR_MSG_PEER_LINK_INFO = 7, + ICCP_DBG_CNTR_MSG_HEART_BEAT = 8, + ICCP_DBG_CNTR_MSG_NAK = 9, + ICCP_DBG_CNTR_MSG_SYNC_DATA = 10, + ICCP_DBG_CNTR_MSG_SYNC_REQ = 11, + ICCP_DBG_CNTR_MSG_WARM_BOOT = 12, + ICCP_DBG_CNTR_MSG_IF_UP_ACK = 13, + ICCP_DBG_CNTR_MSG_STP_CONNECT = 14, + ICCP_DBG_CNTR_MSG_STP_DISCONNECT = 15, + ICCP_DBG_CNTR_MSG_STP_SYSTEM_CONFIG = 16, + ICCP_DBG_CNTR_MSG_STP_REGION_NAME = 17, + ICCP_DBG_CNTR_MSG_STP_REVISION_LEVEL = 18, + ICCP_DBG_CNTR_MSG_STP_INSTANCE_PRIORITY = 19, + ICCP_DBG_CNTR_MSG_STP_CONFIGURATION_DIGEST = 20, + ICCP_DBG_CNTR_MSG_STP_TC_INSTANCES = 21, + ICCP_DBG_CNTR_MSG_STP_ROOT_TIME_PARAM = 22, + ICCP_DBG_CNTR_MSG_STP_MIST_ROOT_TIME_PARAM = 23, + ICCP_DBG_CNTR_MSG_STP_SYNC_REQ = 24, + ICCP_DBG_CNTR_MSG_STP_SYNC_DATA = 25, + ICCP_DBG_CNTR_MSG_STP_PO_PORT_MAP = 26, + ICCP_DBG_CNTR_MSG_STP_AGE_OUT = 27, + ICCP_DBG_CNTR_MSG_STP_COMMON_MSG = 28, + ICCP_DBG_CNTR_MSG_MAX +}; +typedef enum ICCP_DBG_CNTR_MSG ICCP_DBG_CNTR_MSG_e; + +/* Count messages sent to MCLAG peer */ +#define MLACP_SET_ICCP_TX_DBG_COUNTER(csm, tlv_type, status)\ +do{\ + ICCP_DBG_CNTR_MSG_e dbg_type;\ + dbg_type = mlacp_fsm_iccp_to_dbg_msg_type(tlv_type);\ + if (csm && ((dbg_type) < ICCP_DBG_CNTR_MSG_MAX) && ((status) < ICCP_DBG_CNTR_STS_MAX))\ + ++MLACP(csm).dbg_counters.iccp_counters[dbg_type][ICCP_DBG_CNTR_DIR_TX][status];\ +}while(0); + +/* Count messages received from MCLAG peer */ +#define MLACP_SET_ICCP_RX_DBG_COUNTER(csm, tlv_type, status)\ +do{\ + ICCP_DBG_CNTR_MSG_e dbg_type;\ + dbg_type = mlacp_fsm_iccp_to_dbg_msg_type(tlv_type);\ + if (csm && ((dbg_type) < ICCP_DBG_CNTR_MSG_MAX) && ((status) < ICCP_DBG_CNTR_STS_MAX))\ + ++MLACP(csm).dbg_counters.iccp_counters[dbg_type][ICCP_DBG_CNTR_DIR_RX][status];\ +}while(0); + +typedef struct mlacp_dbg_counter_info +{ + uint64_t iccp_counters[ICCP_DBG_CNTR_MSG_MAX][ICCP_DBG_CNTR_DIR_MAX][ICCP_DBG_CNTR_STS_MAX]; +}mlacp_dbg_counter_info_t; + struct mLACP { int id; @@ -88,12 +170,16 @@ struct mLACP TAILQ_HEAD(arp_info_list, Msg) arp_list; TAILQ_HEAD(ndisc_msg_list, Msg) ndisc_msg_list; TAILQ_HEAD(ndisc_info_list, Msg) ndisc_list; - TAILQ_HEAD(mac_msg_list, Msg) mac_msg_list; - TAILQ_HEAD(mac_info_list, Msg) mac_list; + TAILQ_HEAD(mac_msg_list, MACMsg) mac_msg_list; + + struct mac_rb_tree mac_rb; LIST_HEAD(lif_list, LocalInterface) lif_list; LIST_HEAD(lif_purge_list, LocalInterface) lif_purge_list; LIST_HEAD(pif_list, PeerInterface) pif_list; + + /* ICCP message tx/rx debug counters */ + mlacp_dbg_counter_info_t dbg_counters; }; void mlacp_init(struct CSM* csm, int all); @@ -101,9 +187,13 @@ void mlacp_finalize(struct CSM* csm); void mlacp_fsm_transit(struct CSM* csm); void mlacp_enqueue_msg(struct CSM*, struct Msg*); struct Msg* mlacp_dequeue_msg(struct CSM*); +char* mlacp_state(struct CSM* csm); /* from app_csm*/ extern int mlacp_bind_local_if(struct CSM* csm, struct LocalInterface* local_if); extern int mlacp_unbind_local_if(struct LocalInterface* local_if); +/* Debug counter API */ +ICCP_DBG_CNTR_MSG_e mlacp_fsm_iccp_to_dbg_msg_type(uint32_t tlv_type); + #endif /* _MLACP_HANDLER_H */ diff --git a/src/iccpd/include/mlacp_link_handler.h b/src/iccpd/include/mlacp_link_handler.h index 624b4111a7ee..5de4dba5bb8b 100644 --- a/src/iccpd/include/mlacp_link_handler.h +++ b/src/iccpd/include/mlacp_link_handler.h @@ -23,9 +23,16 @@ #ifndef __MLACP_LINK_HANDLER__ #define __MLACP_LINK_HANDLER__ +#include #include "../include/iccp_csm.h" #include "../include/mlacp_tlv.h" +#define MCLAG_MAX_MSG_LEN 4096 +#define ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE MCLAG_MAX_MSG_LEN +#define ICCP_MLAGSYNCD_RECV_MSG_BUFFER_SIZE (MCLAG_MAX_MSG_LEN * 256) + +extern char g_iccp_recv_buf[]; + /***************************************** * Link Handler * @@ -43,18 +50,48 @@ void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable); void peerlink_port_isolate_cleanup(struct CSM* csm); void update_peerlink_isolate_from_all_csm_lif(struct CSM* csm); -void del_mac_from_chip(struct MACMsg *mac_msg); -void add_mac_to_chip(struct MACMsg *mac_msg, uint8_t mac_type); -uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg *mac_msg, uint8_t set); -void iccp_get_fdb_change_from_syncd(void); +ssize_t iccp_send_to_mclagsyncd(uint8_t msg_type, char *send_buff, uint16_t send_len); + +void del_mac_from_chip(struct MACMsg* mac_msg); +void add_mac_to_chip(struct MACMsg* mac_msg, uint8_t mac_type); +uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg* mac_msg, uint8_t set, uint8_t update_peer); extern int mclagd_ctl_sock_create(); extern int mclagd_ctl_sock_accept(int fd); extern int mclagd_ctl_interactive_process(int client_fd); extern int parseMacString(const char *str_mac, uint8_t *bin_mac); + char *show_ip_str(uint32_t ipv4_addr); char *show_ipv6_str(char *ipv6_addr); void syncd_info_close(); int iccp_connect_syncd(); + +void mlacp_link_disable_traffic_distribution(struct LocalInterface *lif); +void mlacp_link_enable_traffic_distribution(struct LocalInterface *lif); +int mlacp_link_set_iccp_state(int mlag_id, bool is_oper_up); +int mlacp_link_set_iccp_role(int mlag_id, bool is_active_role, uint8_t *system_id); +int mlacp_link_set_iccp_system_id(int mlag_id, uint8_t *system_id); +int mlacp_link_del_iccp_info(int mlag_id); +int mlacp_link_set_remote_if_state(int mlag_id, char *po_name, bool is_oper_up); +int mlacp_link_del_remote_if_info(int mlag_id, char *po_name); +int mlacp_link_set_peerlink_port_isolation(int mlag_id, char *po_name, bool is_isolation_enable); + +void mlacp_mlag_intf_detach_handler(struct CSM* csm, struct LocalInterface* local_if); +void mlacp_peer_mlag_intf_delete_handler(struct CSM* csm, char *mlag_if_name); + +int iccp_mclagsyncd_msg_handler(struct System *sys); +int syn_local_neigh_mac_info_to_peer(struct LocalInterface *local_if, int sync_add, + int is_v4, int is_v6, int sync_mac, int ack, int is_ipv6_ll, int dir); +int syn_local_mac_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int is_sag); +int syn_local_arp_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int ack); +int syn_local_nd_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int ack, int is_ipv6_ll, int dir); +int syn_ack_local_neigh_mac_info_to_peer(char *ifname, int is_ipv6_ll); +int is_unique_ip_configured(char *ifname); +void set_peerlink_learn_kernel(struct CSM* csm, int enable, int dir); +void set_peer_mac_in_kernel(char *mac, int vlan, int add); +void mlacp_fix_bridge_mac(struct CSM* csm); +void update_orphan_port_mac(struct CSM *csm, struct LocalInterface *lif, int state); +void mlacp_convert_remote_mac_to_local(struct CSM *csm, char *po_name); +int sync_unique_ip(); #endif diff --git a/src/iccpd/include/mlacp_sync_prepare.h b/src/iccpd/include/mlacp_sync_prepare.h index 17cd8f260155..d5dcce9c0b34 100644 --- a/src/iccpd/include/mlacp_sync_prepare.h +++ b/src/iccpd/include/mlacp_sync_prepare.h @@ -45,12 +45,19 @@ int mlacp_prepare_for_sync_request_tlv(struct CSM* csm, char* buf, size_t max_bu int mlacp_prepare_for_sync_data_tlv(struct CSM* csm, char* buf, size_t max_buf_size, int end); int mlacp_prepare_for_sys_config(struct CSM* csm, char* buf, size_t max_buf_size); int mlacp_prepare_for_mac_info_to_peer(struct CSM* csm, char* buf, size_t max_buf_size, struct MACMsg* mac_msg, int count); -int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count); -int mlacp_prepare_for_ndisc_info(struct CSM *csm, char *buf, size_t max_buf_size, struct NDISCMsg *ndisc_msg, int count); +int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count, int dir); +int mlacp_prepare_for_ndisc_info(struct CSM *csm, char *buf, size_t max_buf_size, struct NDISCMsg *ndisc_msg, int count, int dir); int mlacp_prepare_for_heartbeat(struct CSM* csm, char* buf, size_t max_buf_size); int mlacp_prepare_for_Aggport_state(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* local_if); int mlacp_prepare_for_Aggport_config(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* lif, int purge_flag); int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* port_channel); int mlacp_prepare_for_port_peerlink_info(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* peerlink_port); int iccp_netlink_if_hwaddr_set(uint32_t ifindex, uint8_t *addr, unsigned int addr_len); -#endif \ No newline at end of file +int mlacp_prepare_for_if_up_ack( + struct CSM *csm, + char *buf, + size_t max_buf_size, + uint8_t if_type, + uint16_t if_id, + uint8_t port_isolation_enable); +#endif diff --git a/src/iccpd/include/mlacp_sync_update.h b/src/iccpd/include/mlacp_sync_update.h index 2a5d5b598d05..612134e10795 100644 --- a/src/iccpd/include/mlacp_sync_update.h +++ b/src/iccpd/include/mlacp_sync_update.h @@ -36,15 +36,16 @@ int mlacp_fsm_update_system_conf(struct CSM* csm, mLACPSysConfigTLV* tlv); int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv); int mlacp_fsm_update_arp_info(struct CSM* csm, struct mLACPARPInfoTLV* tlv); -int mlacp_fsm_update_ndisc_info(struct CSM *csm, struct mLACPNDISCInfoTLV* tlv); +int mlacp_fsm_update_ndisc_info(struct CSM *csm, struct mLACPNDISCInfoTLV *tlv); int mlacp_fsm_update_heartbeat(struct CSM* csm, struct mLACPHeartbeatTLV* tlv); int mlacp_fsm_update_warmboot(struct CSM* csm, struct mLACPWarmbootTLV* tlv); + void mlacp_enqueue_arp(struct CSM* csm, struct Msg* msg); -void mlacp_enqueue_ndisc(struct CSM *csm, struct Msg* msg); +void mlacp_enqueue_ndisc(struct CSM *csm, struct Msg *msg); int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf); int mlacp_fsm_update_port_channel_info(struct CSM* csm, struct mLACPPortChannelInfoTLV* tlv); int mlacp_fsm_update_peerlink_info(struct CSM* csm, struct mLACPPeerLinkInfoTLV* tlv); int mlacp_fsm_update_mac_info_from_peer(struct CSM* csm, struct mLACPMACInfoTLV* tlv); -#endif \ No newline at end of file +#endif diff --git a/src/iccpd/include/mlacp_tlv.h b/src/iccpd/include/mlacp_tlv.h index 7d3a4e18e4e2..ae2b47c1dcaf 100644 --- a/src/iccpd/include/mlacp_tlv.h +++ b/src/iccpd/include/mlacp_tlv.h @@ -28,6 +28,9 @@ #include "../include/msg_format.h" #include "../include/port.h" +#include "../include/openbsd_tree.h" +#include "../include/mlacp_tlv.h" + #define MLACP_SYSCONF_NODEID_MSB_MASK 0x80 #define MLACP_SYSCONF_NODEID_NODEID_MASK 0x70 @@ -349,8 +352,9 @@ struct mLACPVLANInfoTLV /* Mac entry Information TLV*/ struct mLACPMACData { - uint8_t type;/*add or del*/ - char mac_str[ETHER_ADDR_STR_LEN]; + uint8_t type;/*add or del*/ + uint8_t mac_type; + uint8_t mac_addr[ETHER_ADDR_LEN]; uint16_t vid; /*Current if name that set in chip*/ char ifname[MAX_L_PORT_NAME]; @@ -366,17 +370,24 @@ struct mLACPMACInfoTLV struct mLACPMACData MacEntry[0]; } __attribute__ ((packed)); +#define NEIGH_LOCAL 1 +#define NEIGH_REMOTE 2 + struct ARPMsg { - uint8_t op_type; - char ifname[MAX_L_PORT_NAME]; - uint32_t ipv4_addr; - uint8_t mac_addr[ETHER_ADDR_LEN]; + uint8_t op_type; + uint8_t flag; + uint8_t learn_flag; /*Loacl or Remote*/ + char ifname[MAX_L_PORT_NAME]; + uint32_t ipv4_addr; // net order + uint8_t mac_addr[ETHER_ADDR_LEN]; }; struct NDISCMsg { uint8_t op_type; + uint8_t flag; + uint8_t learn_flag; /*Loacl or Remote*/ char ifname[MAX_L_PORT_NAME]; uint32_t ipv6_addr[4]; uint8_t mac_addr[ETHER_ADDR_LEN]; @@ -387,7 +398,7 @@ struct NDISCMsg */ struct mLACPARPInfoTLV { - ICCParameter icc_parameter; + ICCParameter icc_parameter; /* Local Interface ID */ uint16_t num_of_entry; struct ARPMsg ArpEntry[0]; @@ -432,11 +443,50 @@ struct mLACPWarmbootTLV uint8_t warmboot; } __attribute__ ((packed)); +/* + * NOS: interface up ack message + * ACK is sent by MLAG peer after processing MLAG interface up notification. + * The ack indicates that port-isolation is applied on the MLAG peer node + */ +typedef uint8_t PORT_ISOLATION_STATE_e; +enum PORT_ISOLATION_STATE_e +{ + PORT_ISOLATION_STATE_DISABLE = 0, + PORT_ISOLATION_STATE_ENABLE = 1 +}; + +typedef uint8_t IF_UP_ACK_TYPE_e; +enum IF_UP_ACK_TYPE_e +{ + IF_UP_ACK_TYPE_PHY_PORT = 0, + IF_UP_ACK_TYPE_PORT_CHANNEL = 1 +}; + +struct mLACPIfUpAckTLV { + ICCParameter icc_parameter; + uint8_t if_type; + uint8_t port_isolation_state; + uint16_t if_id; /* LAG: agg_id */ +}__attribute__ ((packed)); + enum NEIGH_OP_TYPE { - NEIGH_SYNC_LIF, - NEIGH_SYNC_ADD, - NEIGH_SYNC_DEL, + NEIGH_SYNC_LIF = 0, + NEIGH_SYNC_ADD = 1, + NEIGH_SYNC_DEL = 2, +}; + +enum NEIGH_FLAG +{ + NEIGH_SYNC_FLAG_ACK = 1, + NEIGH_SYNC_FLAG_SELF_LL = 2, + NEIGH_SYNC_FLAG_SELF_IP = 4, +}; + +enum NEIGH_SYNC_DIR +{ + NEIGH_SYNC_CLIENT_IP = 1, + NEIGH_SYNC_SELF_IP = 2, }; enum MAC_AGE_TYPE @@ -456,20 +506,30 @@ enum MAC_TYPE { MAC_TYPE_STATIC = 1, MAC_TYPE_DYNAMIC = 2, + MAC_TYPE_DYNAMIC_LOCAL = 3, /* Used while sending MAC to Syncd to program with aging enabled. */ }; struct MACMsg { + RB_ENTRY(MACMsg) mac_entry_rb; + uint16_t vid; + uint8_t mac_addr[ETHER_ADDR_LEN]; uint8_t op_type; /*add or del*/ uint8_t fdb_type; /*static or dynamic*/ - char mac_str[ETHER_ADDR_STR_LEN]; - uint16_t vid; + /*Current if name that set in chip*/ char ifname[MAX_L_PORT_NAME]; /*if we set the mac to peer-link, origin_ifname store the original if name that learned from chip*/ char origin_ifname[MAX_L_PORT_NAME]; uint8_t age_flag;/*local or peer is age?*/ + uint8_t pending_local_del; + uint8_t add_to_syncd; + + TAILQ_ENTRY(MACMsg) tail; // entry into mac_msg_list }; +RB_HEAD(mac_rb_tree, MACMsg); +RB_PROTOTYPE(mac_rb_tree, MACMsg, mac_entry_rb, MACMsg_compare); + #endif /* MLACP_TLV_H_ */ diff --git a/src/iccpd/include/msg_format.h b/src/iccpd/include/msg_format.h index 1af8bf8a46a8..b10b2db16130 100644 --- a/src/iccpd/include/msg_format.h +++ b/src/iccpd/include/msg_format.h @@ -29,6 +29,11 @@ #define MAX_MSG_LOG_SIZE 128 +#define ETHER_ADDR_LEN 6 + +/* Header version for message sent from ICCPd to Mclagsyncd */ +#define ICCPD_TO_MCLAGSYNCD_HDR_VERSION 1 + /* * RFC 5561 * 4. Capability Message @@ -99,7 +104,8 @@ #define TLV_T_MLACP_MAC_INFO 0x1038 #define TLV_T_MLACP_WARMBOOT_FLAG 0x1039 #define TLV_T_MLACP_NDISC_INFO 0x103A -#define TLV_T_MLACP_LIST_END 0x104a // list end +#define TLV_T_MLACP_IF_UP_ACK 0x103B +#define TLV_T_MLACP_LIST_END 0x104a //list end /* Debug */ static char* get_tlv_type_string(int type) @@ -178,6 +184,9 @@ static char* get_tlv_type_string(int type) case TLV_T_MLACP_STP_INFO: return "TLV_T_MLACP_STP_INFO"; + + case TLV_T_MLACP_IF_UP_ACK: + return "TLV_T_MLACP_IF_UP_ACK"; } return "UNKNOWN"; @@ -426,8 +435,12 @@ struct AppDisconnectCauseTLV /*syncd send msg type to iccpd*/ typedef enum mclag_syncd_msg_type_e_ { - MCLAG_SYNCD_MSG_TYPE_NONE = 0, - MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION = 1 + MCLAG_SYNCD_MSG_TYPE_NONE = 0, + MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION = 1, + MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_DOMAIN = 2, + MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_IFACE = 3, + MCLAG_SYNCD_MSG_TYPE_VLAN_MBR_UPDATES = 4, + MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_UNIQUE_IP = 5 }mclag_syncd_msg_type_e; typedef enum mclag_msg_type_e_ @@ -438,7 +451,16 @@ typedef enum mclag_msg_type_e_ MCLAG_MSG_TYPE_FLUSH_FDB = 3, MCLAG_MSG_TYPE_SET_MAC = 4, MCLAG_MSG_TYPE_SET_FDB = 5, - MCLAG_MSG_TYPE_GET_FDB_CHANGES = 20 + MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_ENABLE = 6, + MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_DISABLE = 7, + MCLAG_MSG_TYPE_SET_ICCP_STATE = 8, + MCLAG_MSG_TYPE_SET_ICCP_ROLE = 9, + MCLAG_MSG_TYPE_SET_ICCP_SYSTEM_ID = 10, + MCLAG_MSG_TYPE_DEL_ICCP_INFO = 11, + MCLAG_MSG_TYPE_SET_REMOTE_IF_STATE = 12, + MCLAG_MSG_TYPE_DEL_REMOTE_IF_INFO = 13, + MCLAG_MSG_TYPE_SET_PEER_LINK_ISOLATION = 14, + MCLAG_MSG_TYPE_SET_ICCP_PEER_SYSTEM_ID = 15 }mclag_msg_type_e; @@ -450,9 +472,33 @@ typedef enum mclag_sub_option_type_e_ MCLAG_SUB_OPTION_TYPE_MAC_LEARN_ENABLE = 3, MCLAG_SUB_OPTION_TYPE_MAC_LEARN_DISABLE = 4, MCLAG_SUB_OPTION_TYPE_SET_MAC_SRC = 5, - MCLAG_SUB_OPTION_TYPE_SET_MAC_DST = 6 + MCLAG_SUB_OPTION_TYPE_SET_MAC_DST = 6, + MCLAG_SUB_OPTION_TYPE_MCLAG_INTF_NAME = 7, + MCLAG_SUB_OPTION_TYPE_MCLAG_ID = 8, + MCLAG_SUB_OPTION_TYPE_ICCP_ROLE = 9, + MCLAG_SUB_OPTION_TYPE_SYSTEM_ID = 10, + MCLAG_SUB_OPTION_TYPE_OPER_STATUS = 11, + MCLAG_SUB_OPTION_TYPE_ISOLATION_STATE = 12, + MCLAG_SUB_OPTION_TYPE_PEER_SYSTEM_ID = 13 } mclag_sub_option_type_e; +enum MCLAG_DOMAIN_CFG_OP_TYPE { + MCLAG_CFG_OPER_NONE = 0, //NOP + MCLAG_CFG_OPER_ADD = 1, //Add domain + MCLAG_CFG_OPER_DEL = 2, //Delete domain + MCLAG_CFG_OPER_UPDATE = 3, //update domain + MCLAG_CFG_OPER_ATTR_DEL = 4 //Attribute del +}; + + +enum MCLAG_DOMAIN_CFG_ATTR_BMAP_FLAGS { + MCLAG_CFG_ATTR_NONE = 0x0, + MCLAG_CFG_ATTR_SRC_ADDR = 0x1, + MCLAG_CFG_ATTR_PEER_ADDR = 0x2, + MCLAG_CFG_ATTR_PEER_LINK = 0x4, + MCLAG_CFG_ATTR_KEEPALIVE_INTERVAL = 0x8, + MCLAG_CFG_ATTR_SESSION_TIMEOUT = 0x10 +}; struct IccpSyncdHDr { @@ -475,11 +521,37 @@ typedef struct mclag_sub_option_hdr_t_ struct mclag_fdb_info { - char mac[ETHER_ADDR_STR_LEN]; + uint8_t mac[ETHER_ADDR_LEN]; unsigned int vid; char port_name[MAX_L_PORT_NAME]; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +struct mclag_domain_cfg_info +{ + int op_type;/*add/del domain; add/del mclag domain */ + int domain_id; + int keepalive_time; + int session_timeout; + char local_ip[INET_ADDRSTRLEN]; + char peer_ip[INET_ADDRSTRLEN]; + char peer_ifname[MAX_L_PORT_NAME]; + uint8_t system_mac[ETHER_ADDR_LEN]; + int attr_bmap; +}; + +struct mclag_iface_cfg_info +{ + int op_type; /*add/del mclag iface */ + int domain_id; + char mclag_iface[MAX_L_PORT_NAME]; +}; + +struct mclag_unique_ip_cfg_info +{ + int op_type;/*add/del mclag unique ip iface */ + char mclag_unique_ip_ifname[MAX_L_PORT_NAME]; }; /* For storing message log: For Notification TLV */ @@ -491,6 +563,13 @@ struct MsgTypeSet }; +struct mclag_vlan_mbr_info +{ + int op_type;/*add/del vlan_member */ + unsigned int vid; + char mclag_iface[MAX_L_PORT_NAME]; +}; + struct MsgLog { struct MsgTypeSet msg[MAX_MSG_LOG_SIZE]; diff --git a/src/iccpd/include/openbsd_tree.h b/src/iccpd/include/openbsd_tree.h new file mode 100644 index 000000000000..c6dd8c1da9f0 --- /dev/null +++ b/src/iccpd/include/openbsd_tree.h @@ -0,0 +1,571 @@ +/* $OpenBSD: tree.h,v 1.14 2015/05/25 03:07:49 deraadt Exp $ */ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#ifndef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif + +#define SPLAY_HEAD(name, type) \ + struct name { \ + struct type *sph_root; /* root of the tree */ \ + } + +#define SPLAY_INITIALIZER(root) \ + { \ + NULL \ + } + +#define SPLAY_INIT(root) \ + do { \ + (root)->sph_root = NULL; \ + } while (0) + +#define SPLAY_ENTRY(type) \ + struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ + } + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) \ + do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) \ + do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) \ + do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + } while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) \ + do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) \ + do { \ + SPLAY_RIGHT(left, field) = \ + SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = \ + SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = \ + SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = \ + SPLAY_LEFT(node, field); \ + } while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ + void name##_SPLAY(struct name *, struct type *); \ + void name##_SPLAY_MINMAX(struct name *, int); \ + struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ + struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ + /* Finds the node with the same key as elm */ \ + static __inline struct type *name##_SPLAY_FIND(struct name *head, \ + struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ + } \ + \ + static __inline struct type *name##_SPLAY_NEXT(struct name *head, \ + struct type *elm) \ + { \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ + } \ + \ + static __inline struct type *name##_SPLAY_MIN_MAX(struct name *head, \ + int val) \ + { \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ + } + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ + struct type *name##_SPLAY_INSERT(struct name *head, struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = \ + NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if (__comp < 0) { \ + SPLAY_LEFT(elm, field) = \ + SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = \ + SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ + } \ + \ + struct type *name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = \ + SPLAY_RIGHT((head)->sph_root, field); \ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = \ + SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ + } \ + \ + void name##_SPLAY(struct name *head, struct type *elm) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = \ + NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0) { \ + SPLAY_ROTATE_RIGHT(head, __tmp, \ + field); \ + if (SPLAY_LEFT((head)->sph_root, \ + field) \ + == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, \ + field) \ + == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } \ + \ + /* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ + void name##_SPLAY_MINMAX(struct name *head, int __comp) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = \ + NULL; \ + __left = __right = &__node; \ + \ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0) { \ + SPLAY_ROTATE_RIGHT(head, __tmp, \ + field); \ + if (SPLAY_LEFT((head)->sph_root, \ + field) \ + == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, \ + field) \ + == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) \ + (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) \ + (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* + * Copyright (c) 2016 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define RB_BLACK 0 +#define RB_RED 1 + +struct rb_type { + int (*t_compare)(const void *, const void *); + void (*t_augment)(void *); + unsigned int t_offset; /* offset of rb_entry in type */ +}; + +struct rbt_tree { + struct rb_entry *rbt_root; +}; + +struct rb_entry { + struct rb_entry *rbt_parent; + struct rb_entry *rbt_left; + struct rb_entry *rbt_right; + unsigned int rbt_color; +}; + +#define RB_HEAD(_name, _type) \ + struct _name { \ + struct rbt_tree rbh_root; \ + } + +#define RB_ENTRY(_type) struct rb_entry + +static inline void _rb_init(struct rbt_tree *rbt) +{ + rbt->rbt_root = NULL; +} + +static inline int _rb_empty(struct rbt_tree *rbt) +{ + return (rbt->rbt_root == NULL); +} + +void *_rb_insert(const struct rb_type *, struct rbt_tree *, void *); +void *_rb_remove(const struct rb_type *, struct rbt_tree *, void *); +void *_rb_find(const struct rb_type *, struct rbt_tree *, const void *); +void *_rb_nfind(const struct rb_type *, struct rbt_tree *, const void *); +void *_rb_root(const struct rb_type *, struct rbt_tree *); +void *_rb_min(const struct rb_type *, struct rbt_tree *); +void *_rb_max(const struct rb_type *, struct rbt_tree *); +void *_rb_next(const struct rb_type *, void *); +void *_rb_prev(const struct rb_type *, void *); +void *_rb_left(const struct rb_type *, void *); +void *_rb_right(const struct rb_type *, void *); +void *_rb_parent(const struct rb_type *, void *); +void _rb_set_left(const struct rb_type *, void *, void *); +void _rb_set_right(const struct rb_type *, void *, void *); +void _rb_set_parent(const struct rb_type *, void *, void *); +void _rb_poison(const struct rb_type *, void *, unsigned long); +int _rb_check(const struct rb_type *, void *, unsigned long); + +#define RB_INITIALIZER(_head) { { NULL } } + +#define RB_PROTOTYPE(_name, _type, _field, _cmp) \ + extern const struct rb_type *const _name##_RB_TYPE; \ + \ + __attribute__((__unused__)) static inline void _name##_RB_INIT( \ + struct _name *head) \ + { \ + _rb_init(&head->rbh_root); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_INSERT(struct _name *head, struct _type *elm) \ + { \ + return _rb_insert(_name##_RB_TYPE, &head->rbh_root, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_REMOVE(struct _name *head, struct _type *elm) \ + { \ + return _rb_remove(_name##_RB_TYPE, &head->rbh_root, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_FIND(struct _name *head, const struct _type *key) \ + { \ + return _rb_find(_name##_RB_TYPE, &head->rbh_root, key); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_NFIND(struct _name *head, const struct _type *key) \ + { \ + return _rb_nfind(_name##_RB_TYPE, &head->rbh_root, key); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_ROOT(struct _name *head) \ + { \ + return _rb_root(_name##_RB_TYPE, &head->rbh_root); \ + } \ + \ + __attribute__((__unused__)) static inline int _name##_RB_EMPTY( \ + struct _name *head) \ + { \ + return _rb_empty(&head->rbh_root); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_MIN(struct _name *head) \ + { \ + return _rb_min(_name##_RB_TYPE, &head->rbh_root); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_MAX(struct _name *head) \ + { \ + return _rb_max(_name##_RB_TYPE, &head->rbh_root); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_NEXT(struct _type *elm) \ + { \ + return _rb_next(_name##_RB_TYPE, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_PREV(struct _type *elm) \ + { \ + return _rb_prev(_name##_RB_TYPE, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_LEFT(struct _type *elm) \ + { \ + return _rb_left(_name##_RB_TYPE, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_RIGHT(struct _type *elm) \ + { \ + return _rb_right(_name##_RB_TYPE, elm); \ + } \ + \ + __attribute__((__unused__)) static inline struct _type \ + *_name##_RB_PARENT(struct _type *elm) \ + { \ + return _rb_parent(_name##_RB_TYPE, elm); \ + } \ + \ + __attribute__((__unused__)) static inline void _name##_RB_SET_LEFT( \ + struct _type *elm, struct _type *left) \ + { \ + _rb_set_left(_name##_RB_TYPE, elm, left); \ + } \ + \ + __attribute__((__unused__)) static inline void _name##_RB_SET_RIGHT( \ + struct _type *elm, struct _type *right) \ + { \ + _rb_set_right(_name##_RB_TYPE, elm, right); \ + } \ + \ + __attribute__((__unused__)) static inline void _name##_RB_SET_PARENT( \ + struct _type *elm, struct _type *parent) \ + { \ + _rb_set_parent(_name##_RB_TYPE, elm, parent); \ + } \ + \ + __attribute__((__unused__)) static inline void _name##_RB_POISON( \ + struct _type *elm, unsigned long poison) \ + { \ + _rb_poison(_name##_RB_TYPE, elm, poison); \ + } \ + \ + __attribute__((__unused__)) static inline int _name##_RB_CHECK( \ + struct _type *elm, unsigned long poison) \ + { \ + return _rb_check(_name##_RB_TYPE, elm, poison); \ + } + +#define RB_GENERATE_INTERNAL(_name, _type, _field, _cmp, _aug) \ + static int _name##_RB_COMPARE(const void *lptr, const void *rptr) \ + { \ + const struct _type *l = lptr, *r = rptr; \ + return _cmp(l, r); \ + } \ + static const struct rb_type _name##_RB_INFO = { \ + _name##_RB_COMPARE, _aug, offsetof(struct _type, _field), \ + }; \ + const struct rb_type *const _name##_RB_TYPE = &_name##_RB_INFO; + +#define RB_GENERATE_AUGMENT(_name, _type, _field, _cmp, _aug) \ + static void _name##_RB_AUGMENT(void *ptr) \ + { \ + struct _type *p = ptr; \ + return _aug(p); \ + } \ + RB_GENERATE_INTERNAL(_name, _type, _field, _cmp, _name##_RB_AUGMENT) + +#define RB_GENERATE(_name, _type, _field, _cmp) \ + RB_GENERATE_INTERNAL(_name, _type, _field, _cmp, NULL) + +#define RB_INIT(_name, _head) _name##_RB_INIT(_head) +#define RB_INSERT(_name, _head, _elm) _name##_RB_INSERT(_head, _elm) +#define RB_REMOVE(_name, _head, _elm) _name##_RB_REMOVE(_head, _elm) +#define RB_FIND(_name, _head, _key) _name##_RB_FIND(_head, _key) +#define RB_NFIND(_name, _head, _key) _name##_RB_NFIND(_head, _key) +#define RB_ROOT(_name, _head) _name##_RB_ROOT(_head) +#define RB_EMPTY(_name, _head) _name##_RB_EMPTY(_head) +#define RB_MIN(_name, _head) _name##_RB_MIN(_head) +#define RB_MAX(_name, _head) _name##_RB_MAX(_head) +#define RB_NEXT(_name, _elm) _name##_RB_NEXT(_elm) +#define RB_PREV(_name, _elm) _name##_RB_PREV(_elm) +#define RB_LEFT(_name, _elm) _name##_RB_LEFT(_elm) +#define RB_RIGHT(_name, _elm) _name##_RB_RIGHT(_elm) +#define RB_PARENT(_name, _elm) _name##_RB_PARENT(_elm) +#define RB_SET_LEFT(_name, _elm, _l) _name##_RB_SET_LEFT(_elm, _l) +#define RB_SET_RIGHT(_name, _elm, _r) _name##_RB_SET_RIGHT(_elm, _r) +#define RB_SET_PARENT(_name, _elm, _p) _name##_RB_SET_PARENT(_elm, _p) +#define RB_POISON(_name, _elm, _p) _name##_RB_POISON(_elm, _p) +#define RB_CHECK(_name, _elm, _p) _name##_RB_CHECK(_elm, _p) + +#define RB_FOREACH(_e, _name, _head) \ + for ((_e) = RB_MIN(_name, (_head)); (_e) != NULL; \ + (_e) = RB_NEXT(_name, (_e))) + +#define RB_FOREACH_SAFE(_e, _name, _head, _n) \ + for ((_e) = RB_MIN(_name, (_head)); \ + (_e) != NULL && ((_n) = RB_NEXT(_name, (_e)), 1); (_e) = (_n)) + +#define RB_FOREACH_REVERSE(_e, _name, _head) \ + for ((_e) = RB_MAX(_name, (_head)); (_e) != NULL; \ + (_e) = RB_PREV(_name, (_e))) + +#define RB_FOREACH_REVERSE_SAFE(_e, _name, _head, _n) \ + for ((_e) = RB_MAX(_name, (_head)); \ + (_e) != NULL && ((_n) = RB_PREV(_name, (_e)), 1); (_e) = (_n)) + +#endif /* _SYS_TREE_H_ */ diff --git a/src/iccpd/include/port.h b/src/iccpd/include/port.h index dbd9d45fa83d..2275645e3a83 100644 --- a/src/iccpd/include/port.h +++ b/src/iccpd/include/port.h @@ -25,9 +25,17 @@ #define PORT_H_ #include +#include #include #include +#include "../include/openbsd_tree.h" + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif /* INET_ADDRSTRLEN */ + + #define ETHER_ADDR_LEN 6 #define ETHER_ADDR_STR_LEN 18 /* @@ -47,9 +55,10 @@ #define IF_T_UNKNOW -1 #define IF_T_PORT 0 #define IF_T_PORT_CHANNEL 1 -#define IF_T_VLAN 2 -#define IF_T_VXLAN 3 -#define IF_T_BRIDGE 4 +#define IF_T_VLAN 2 +#define IF_T_VXLAN 3 +#define IF_T_BRIDGE 4 + typedef struct { char *ifname; @@ -62,14 +71,38 @@ struct If_info LIST_ENTRY(If_info) csm_next; }; +struct Unq_ip_If_info +{ + char name[MAX_L_PORT_NAME]; + LIST_ENTRY(Unq_ip_If_info) if_next; +}; + struct VLAN_ID { uint16_t vid; uint16_t vlan_removed; struct LocalInterface* vlan_itf; /* loacl vlan interface */ - LIST_ENTRY(VLAN_ID) port_next; + RB_ENTRY(VLAN_ID) vlan_entry; }; +RB_HEAD(vlan_rb_tree, VLAN_ID); +RB_PROTOTYPE(vlan_rb_tree, VLAN_ID, vlan_rb_tree, vlan_node_compare); + +struct PendingVlanMbrIf +{ + char name[MAX_L_PORT_NAME]; + struct vlan_rb_tree vlan_tree; + LIST_ENTRY(PendingVlanMbrIf) if_next; +}; + +#define VLAN_RB_REMOVE(name, head, elm) do { \ + RB_REMOVE(name, head, elm); \ + (elm)->vlan_entry.rbt_parent = NULL; \ + (elm)->vlan_entry.rbt_left = NULL; \ + (elm)->vlan_entry.rbt_right = NULL; \ +} while (0) + + struct PeerInterface { int ifindex; @@ -88,7 +121,7 @@ struct PeerInterface struct CSM* csm; LIST_ENTRY(PeerInterface) mlacp_next; - LIST_HEAD(peer_vlan_list, VLAN_ID) vlan_list; + struct vlan_rb_tree vlan_tree; }; struct LocalInterface @@ -104,6 +137,8 @@ struct LocalInterface uint8_t prefixlen; uint32_t ipv6_addr[4]; uint8_t prefixlen_v6; + uint32_t ipv6_ll_addr[4]; + uint8_t ll_prefixlen_v6; uint8_t l3_mode; uint8_t l3_mac_addr[ETHER_ADDR_LEN]; @@ -115,12 +150,18 @@ struct LocalInterface int mlacp_state; /* Record mlacp state */ uint8_t isolate_to_peer_link; + time_t po_down_time; + struct CSM* csm; uint8_t changed; uint8_t port_config_sync; + bool is_traffic_disable; /* Disable traffic tx/rx */ + bool is_l3_proto_enabled; /* Enable L3 Protocol support */ + uint32_t vlan_count; + uint32_t master_ifindex; /* VRF ifindex*/ - LIST_HEAD(local_vlan_list, VLAN_ID) vlan_list; + struct vlan_rb_tree vlan_tree; LIST_ENTRY(LocalInterface) system_next; LIST_ENTRY(LocalInterface) system_purge_next; @@ -128,7 +169,7 @@ struct LocalInterface LIST_ENTRY(LocalInterface) mlacp_purge_next; }; -struct LocalInterface* local_if_create(int ifindex, char* ifname, int type); +struct LocalInterface* local_if_create(int ifindex, char* ifname, int type, uint8_t state); struct LocalInterface* local_if_find_by_name(const char* ifname); struct LocalInterface* local_if_find_by_ifindex(int ifindex); struct LocalInterface* local_if_find_by_po_id(int po_id); @@ -141,7 +182,6 @@ int local_if_is_l3_mode(struct LocalInterface* local_if); void local_if_init(struct LocalInterface*); void local_if_finalize(struct LocalInterface*); -void ether_mac_set_addr_with_if_name(char *name, uint8_t* mac); struct PeerInterface* peer_if_create(struct CSM* csm, int peer_if_number, int type); struct PeerInterface* peer_if_find_by_name(struct CSM* csm, char* name); diff --git a/src/iccpd/include/scheduler.h b/src/iccpd/include/scheduler.h index a1b31039d794..a4c791d3d73f 100644 --- a/src/iccpd/include/scheduler.h +++ b/src/iccpd/include/scheduler.h @@ -38,9 +38,9 @@ struct CSM; struct System; #define CONNECT_INTERVAL_SEC 1 -#define CONNECT_TIMEOUT_MSEC 100 +#define CONNECT_TIMEOUT_MSEC 100 #define HEARTBEAT_TIMEOUT_SEC 15 -#define TRANSIT_INTERVAL_SEC 1 +#define TRANSIT_INTERVAL_SEC 1 #define EPOLL_TIMEOUT_MSEC 100 int scheduler_prepare_session(struct CSM*); @@ -56,5 +56,6 @@ int scheduler_csm_read_callback(struct CSM* csm); int iccp_get_server_sock_fd(); int scheduler_server_accept(); int iccp_receive_signal_handler(struct System* sys); +void scheduler_csm_socket_cleanup(struct CSM* csm, int location); #endif /* SCHEDULER_H_ */ diff --git a/src/iccpd/include/system.h b/src/iccpd/include/system.h index 3ee314d253aa..c188d1a6d287 100644 --- a/src/iccpd/include/system.h +++ b/src/iccpd/include/system.h @@ -34,6 +34,7 @@ #include #include +#include #include "../include/port.h" @@ -52,6 +53,245 @@ struct CSM; #define MAX_BUFSIZE 4096 #endif +extern char mac_print_str[ETHER_ADDR_STR_LEN]; + +#define MAC_IN_MSG_LIST(head, elm, field) \ + (((elm)->field.tqe_next != NULL) || \ + ((elm)->field.tqe_prev != NULL)) + +#define CLEAR_MAC_IN_MSG_LIST(head, elm, field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = NULL; + +#define MAC_TAILQ_REMOVE(head, elm, field) do { \ + TAILQ_REMOVE(head, elm, field); \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = NULL; \ +} while (/*CONSTCOND*/0) + +#define MAC_RB_REMOVE(name, head, elm) do { \ + RB_REMOVE(name, head, elm); \ + (elm)->mac_entry_rb.rbt_parent = NULL; \ + (elm)->mac_entry_rb.rbt_left = NULL; \ + (elm)->mac_entry_rb.rbt_right = NULL; \ +} while (/*CONSTCOND*/0) + +/* Debug counters */ +/* Debug counters to track messages ICCPd sent to MclagSyncd */ +typedef uint8_t SYNCD_DBG_CNTR_STS_e; +enum SYNCD_DBG_CNTR_STS_e +{ + SYNCD_DBG_CNTR_STS_OK = 0, + SYNCD_DBG_CNTR_STS_ERR = 1, /* Send error or receive processing error*/ + SYNCD_DBG_CNTR_STS_MAX +}; + +typedef uint8_t SYNCD_TX_DBG_CNTR_MSG_e; +enum SYNCD_TX_DBG_CNTR_MSG_e +{ + SYNCD_TX_DBG_CNTR_MSG_PORT_ISOLATE = 0, + SYNCD_TX_DBG_CNTR_MSG_PORT_MAC_LEARN_MODE = 1, + SYNCD_TX_DBG_CNTR_MSG_FLUSH_FDB = 2, + SYNCD_TX_DBG_CNTR_MSG_SET_IF_MAC = 3, + SYNCD_TX_DBG_CNTR_MSG_SET_FDB = 4, + SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_ENABLE = 5, + SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_DISABLE = 6, + SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_STATE = 7, + SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_ROLE = 8, + SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_SYSTEM_ID = 9, + SYNCD_TX_DBG_CNTR_MSG_DEL_ICCP_INFO = 10, + SYNCD_TX_DBG_CNTR_MSG_SET_REMOTE_IF_STATE = 11, + SYNCD_TX_DBG_CNTR_MSG_DEL_REMOTE_IF_INFO = 12, + SYNCD_TX_DBG_CNTR_MSG_PEER_LINK_ISOLATION = 13, + SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_PEER_SYSTEM_ID = 14, + SYNCD_TX_DBG_CNTR_MSG_MAX +}; + +typedef uint8_t SYNCD_RX_DBG_CNTR_MSG_e; +enum SYNCD_RX_DBG_CNTR_MSG_e +{ + SYNCD_RX_DBG_CNTR_MSG_MAC = 0, + SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_DOMAIN = 1, + SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_IFACE = 2, + SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_UNIQUE_IP = 3, + SYNCD_RX_DBG_CNTR_MSG_VLAN_MBR_UPDATES = 4, + SYNCD_RX_DBG_CNTR_MSG_MAX +}; + +/* Count messages ICCP daemon sent to MclagSyncd */ +#define SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, syncd_msg_type, status)\ +do{\ + SYNCD_TX_DBG_CNTR_MSG_e dbg_type;\ + dbg_type = system_syncdtx_to_dbg_msg_type(syncd_msg_type);\ + if (sys && ((dbg_type) < SYNCD_TX_DBG_CNTR_MSG_MAX) && ((status) < SYNCD_DBG_CNTR_STS_MAX))\ + {\ + ++sys->dbg_counters.syncd_tx_counters[dbg_type][status];\ + }\ +}while(0); + +/* Count messages ICCP daemon received from MclagSyncd */ +#define SYSTEM_SET_SYNCD_RX_DBG_COUNTER(sys, syncd_msg_type, status)\ +do{\ + SYNCD_RX_DBG_CNTR_MSG_e dbg_type;\ + dbg_type = system_syncdrx_to_dbg_msg_type(syncd_msg_type);\ + if (sys && ((dbg_type) < SYNCD_RX_DBG_CNTR_MSG_MAX) && ((status) < SYNCD_DBG_CNTR_STS_MAX))\ + {\ + ++sys->dbg_counters.syncd_rx_counters[dbg_type][status];\ + }\ +}while(0); + +#define SYSTEM_INCR_SESSION_DOWN_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.session_down_counter;\ + +#define SYSTEM_GET_SESSION_DOWN_COUNTER(sys)\ + ( (sys) ? (sys)->dbg_counters.session_down_counter: 0) + +#define SYSTEM_INCR_PEER_LINK_DOWN_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.peer_link_down_counter;\ + +#define SYSTEM_INCR_WARMBOOT_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.warmboot_counter; + +#define SYSTEM_INCR_INVALID_PEER_MSG_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_peer_invalid_msg_counter; + +#define SYSTEM_GET_INVALID_PEER_MSG_COUNTER(sys)\ + ((sys) ? ((sys)->dbg_counters.rx_peer_invalid_msg_counter) ? 0) + +#define SYSTEM_INCR_RX_READ_SOCK_ZERO_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_read_sock_zero_len_counter; + +#define SYSTEM_INCR_HDR_READ_SOCK_ERR_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_peer_hdr_read_sock_err_counter; + +#define SYSTEM_INCR_HDR_READ_SOCK_ZERO_LEN_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_peer_hdr_read_sock_zero_len_counter; + +#define SYSTEM_INCR_TLV_READ_SOCK_ERR_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_peer_tlv_read_sock_err_counter; + +#define SYSTEM_INCR_TLV_READ_SOCK_ZERO_LEN_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_peer_tlv_read_sock_zero_len_counter; + +#define SYSTEM_INCR_SOCKET_CLOSE_ERR_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.socket_close_err_counter; + +#define SYSTEM_INCR_SOCKET_CLEANUP_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.socket_cleanup_counter; + +#define SYSTEM_INCR_RX_RETRY_FAIL_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_retry_fail_counter; + +#define SYSTEM_INCR_MAC_ENTRY_ALLOC_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.mac_entry_alloc_counter; + +#define SYSTEM_INCR_MAC_ENTRY_FREE_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.mac_entry_free_counter; + +#define SYSTEM_INCR_RX_READ_SOCK_ZERO_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_read_sock_zero_len_counter; + +#define SYSTEM_INCR_RX_READ_SOCK_ERR_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_read_sock_err_counter; + +#define SYSTEM_INCR_RX_READ_STP_SOCK_ZERO_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_read_stp_sock_zero_len_counter; + +#define SYSTEM_INCR_RX_READ_STP_SOCK_ERR_COUNTER(sys)\ + if (sys)\ + ++sys->dbg_counters.rx_read_stp_sock_err_counter; +#define SYSTEM_SET_RETRY_COUNTER(sys, num_retry)\ + if (sys)\ + {\ + sys->dbg_counters.rx_retry_total_counter += num_retry;\ + if (num_retry > sys->dbg_counters.rx_retry_max_counter)\ + sys->dbg_counters.rx_retry_max_counter = num_retry;\ + } + +#define SYSTEM_INCR_NETLINK_UNKNOWN_IF_NAME(ifname)\ +do {\ + struct System *sys;\ + sys = system_get_instance();\ + if (sys)\ + {\ + ++sys->dbg_counters.unknown_if_name_count;\ + if (sys->dbg_counters.unknown_if_name_count < 10)\ + {\ + ICCPD_LOG_NOTICE("ICCP_FSM","NETLINK_COUNTER: Unknown if_name %s", ifname);\ + }\ + }\ +}while(0) + +#define SYSTEM_INCR_NETLINK_RX_ERROR()\ +do {\ + struct System *sys;\ + sys = system_get_instance();\ + if (sys)\ + ++sys->dbg_counters.rx_error_count;\ +}while(0) + +typedef struct system_dbg_counter_info +{ + /* Netlink message counters */ + uint32_t newlink_count; + uint32_t dellink_count; + uint32_t newnbr_count; + uint32_t delnbr_count; + uint32_t newaddr_count; + uint32_t deladdr_count; + uint32_t unknown_type_count; + uint32_t rx_error_count; + + /* Netlink link sub-message count */ + uint32_t unknown_if_name_count; + + /* Netlink neighbor sub-message count */ + uint32_t newmac_count; + uint32_t delmac_count; + + uint32_t session_down_counter; //not counting down due to warmboot + uint32_t peer_link_down_counter; + uint32_t warmboot_counter; + uint32_t rx_peer_invalid_msg_counter; //counts partial msgs received as sending end is not sending partial msgs + uint32_t rx_peer_hdr_read_sock_err_counter; //counts socket header read errors + uint32_t rx_peer_hdr_read_sock_zero_len_counter; //counts socket header read zero length + uint32_t rx_peer_tlv_read_sock_err_counter; //counts socket data/tlv read errors + uint32_t rx_peer_tlv_read_sock_zero_len_counter; //counts socket data/tlv read zero length + uint32_t socket_close_err_counter; //socket close failure + uint32_t socket_cleanup_counter; //socket cleanup outside of session down + uint32_t rx_retry_max_counter; //max non-blocking RX retry for one message + uint32_t rx_retry_total_counter; //total number of non-blocking RX retry + uint32_t rx_retry_fail_counter; //total number of non-blocking RX retry failure + + uint32_t rx_read_sock_zero_len_counter; //counts socket header read zero length from sync_fd + uint32_t rx_read_sock_err_counter; //counts socket header read zero length from sync_fd + uint32_t rx_read_stp_sock_zero_len_counter; //counts socket header read zero length from syncd + uint32_t rx_read_stp_sock_err_counter; //counts socket header read zero length from syncd + + uint32_t mac_entry_alloc_counter; + uint32_t mac_entry_free_counter; + + uint64_t syncd_tx_counters[SYNCD_TX_DBG_CNTR_MSG_MAX][SYNCD_DBG_CNTR_STS_MAX]; + uint64_t syncd_rx_counters[SYNCD_RX_DBG_CNTR_MSG_MAX][SYNCD_DBG_CNTR_STS_MAX]; +}system_dbg_counter_info_t; + struct System { int server_fd;/* Peer-Link Socket*/ @@ -78,6 +318,8 @@ struct System LIST_HEAD(csm_list, CSM) csm_list; LIST_HEAD(lif_all_list, LocalInterface) lif_list; LIST_HEAD(lif_purge_all_list, LocalInterface) lif_purge_list; + LIST_HEAD(unq_ip_all_if_list, Unq_ip_If_info) unq_ip_if_list; + LIST_HEAD(pending_vlan_mbr_if_list, PendingVlanMbrIf) pending_vlan_mbr_if_list; /* Settings */ char* log_file_path; @@ -91,13 +333,23 @@ struct System time_t csm_trans_time; int need_sync_team_again; int need_sync_netlink_again; + + /* ICCDd/MclagSyncd debug counters */ + system_dbg_counter_info_t dbg_counters; }; struct CSM* system_create_csm(); struct CSM* system_get_csm_by_peer_ip(const char*); +struct CSM* system_get_csm_by_peer_ifname(char *ifname); struct CSM* system_get_csm_by_mlacp_id(int id); +struct CSM* system_get_first_csm(); struct System* system_get_instance(); void system_finalize(); void system_init(struct System*); +SYNCD_TX_DBG_CNTR_MSG_e system_syncdtx_to_dbg_msg_type(uint32_t msg_type); +SYNCD_RX_DBG_CNTR_MSG_e system_syncdrx_to_dbg_msg_type(uint32_t msg_type); + +char *mac_addr_to_str(uint8_t mac_addr[ETHER_ADDR_LEN]); +void system_update_netlink_counters(uint16_t netlink_msg_type, struct nlmsghdr *nlh); #endif /* SYSTEM_H_ */ diff --git a/src/iccpd/src/Makefile.am b/src/iccpd/src/Makefile.am index 9d19dbb5285c..7415f8d4dbb7 100644 --- a/src/iccpd/src/Makefile.am +++ b/src/iccpd/src/Makefile.am @@ -17,6 +17,7 @@ iccpd_SOURCES = \ mlacp_link_handler.c \ mlacp_sync_prepare.c mlacp_sync_update.c\ mlacp_fsm.c \ - iccp_netlink.c + iccp_netlink.c \ + openbsd_tree.c iccpd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) iccpd_LDADD = -lnl-genl-3 -lnl-route-3 -lnl-3 -lpthread diff --git a/src/iccpd/src/app_csm.c b/src/iccpd/src/app_csm.c index 589cf94015d8..4ef5f13b5e35 100644 --- a/src/iccpd/src/app_csm.c +++ b/src/iccpd/src/app_csm.c @@ -239,7 +239,7 @@ int mlacp_bind_local_if(struct CSM* csm, struct LocalInterface* lif) if (lif_po->type == IF_T_PORT_CHANNEL && lif_po->po_id == lif->po_id) { /*if join a po member, may swss restart, reset portchannel ip mac to mclagsyncd*/ - update_if_ipmac_on_standby(lif_po); + update_if_ipmac_on_standby(lif_po, 1); return 0; } } diff --git a/src/iccpd/src/iccp_cli.c b/src/iccpd/src/iccp_cli.c index 8d0ede8b3feb..59235215bffb 100644 --- a/src/iccpd/src/iccp_cli.c +++ b/src/iccpd/src/iccp_cli.c @@ -52,10 +52,8 @@ int unset_mc_lag_id( struct CSM *csm, uint16_t id) if (!csm) return MCLAG_ERROR; - /* Mlag-ID, RG-ID, MLACP-ID*/ - csm->mlag_id = 0; - csm->iccp_info.icc_rg_id = 0; - csm->app_csm.mlacp.id = 0; + /* Remove ICCP info from STATE_DB */ + mlacp_link_del_iccp_info(csm->mlag_id); iccp_csm_finalize(csm); @@ -73,7 +71,9 @@ int set_peer_link(int mid, const char* ifname) len = strlen(ifname); - if (strncmp(ifname, FRONT_PANEL_PORT_PREFIX, strlen(FRONT_PANEL_PORT_PREFIX)) != 0 && strncmp(ifname, PORTCHANNEL_PREFIX, strlen(PORTCHANNEL_PREFIX)) != 0 && strncmp(ifname, VXLAN_TUNNEL_PREFIX, strlen(VXLAN_TUNNEL_PREFIX)) != 0) + if (strncmp(ifname, FRONT_PANEL_PORT_PREFIX, strlen(FRONT_PANEL_PORT_PREFIX)) != 0 + && strncmp(ifname, PORTCHANNEL_PREFIX, strlen(PORTCHANNEL_PREFIX)) != 0 + && strncmp(ifname, VXLAN_TUNNEL_PREFIX, strlen(VXLAN_TUNNEL_PREFIX)) != 0) { ICCPD_LOG_ERR(__FUNCTION__, "Peer-link is %s, must be Ethernet or PortChannel or VTTNL(Vxlan tunnel)", ifname); return MCLAG_ERROR; @@ -83,8 +83,11 @@ int set_peer_link(int mid, const char* ifname) if (csm == NULL) return MCLAG_ERROR; - if (len > IFNAMSIZ) + if (len > MAX_L_PORT_NAME) + { + ICCPD_LOG_ERR(__FUNCTION__, "Peer-link %s, Strlen %d greater than MAX:%d ", ifname, len, MAX_L_PORT_NAME); return MCLAG_ERROR; + } if (strlen(csm->peer_itf_name) > 0) { @@ -114,7 +117,7 @@ int set_peer_link(int mid, const char* ifname) csm->mlag_id, ifname); } - memset(csm->peer_itf_name, 0, IFNAMSIZ); + memset(csm->peer_itf_name, 0, MAX_L_PORT_NAME); memcpy(csm->peer_itf_name, ifname, len); /* update peer-link link handler*/ @@ -128,6 +131,8 @@ int set_peer_link(int mid, const char* ifname) if (lif->type == IF_T_PORT_CHANNEL) iccp_get_port_member_list(lif); + + set_peerlink_learn_kernel(csm, 0, 4); } /*disconnect the link for mac and arp sync up*/ @@ -147,15 +152,17 @@ int unset_peer_link(int mid) if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { /*must be enabled mac learn*/ - if (csm->peer_link_if) + if (csm->peer_link_if) { set_peerlink_mlag_port_learn(csm->peer_link_if, 1); + set_peerlink_learn_kernel(csm, 1, 5); + } } /* update peer-link link handler*/ scheduler_session_disconnect_handler(csm); /* clean peer-link*/ - memset(csm->peer_itf_name, 0, IFNAMSIZ); + memset(csm->peer_itf_name, 0, MAX_L_PORT_NAME); if (csm->peer_link_if) { csm->peer_link_if->is_peer_link = 0; @@ -282,6 +289,42 @@ int unset_peer_address(int mid) return 0; } +int set_keepalive_time(int mid, int keepalive_time) +{ + struct CSM* csm = NULL; + size_t len = 0; + + csm = system_get_csm_by_mlacp_id(mid); + if (csm == NULL) + return MCLAG_ERROR; + + ICCPD_LOG_DEBUG(__FUNCTION__, "Set keepalive_time : %d", keepalive_time); + + if (csm->keepalive_time != keepalive_time) + { + csm->keepalive_time = keepalive_time; + //reset heartbeat send time to send keepalive immediately + csm->heartbeat_send_time = 0; + } + return 0; +} + +int set_session_timeout(int mid, int session_timeout_val) +{ + struct CSM* csm = NULL; + size_t len = 0; + + csm = system_get_csm_by_mlacp_id(mid); + if (csm == NULL) + return MCLAG_ERROR; + + ICCPD_LOG_DEBUG(__FUNCTION__, "Set session timeout : %d", session_timeout_val); + + csm->session_timeout = session_timeout_val; + return 0; +} + + int iccp_cli_attach_mclag_domain_to_port_channel( int domain, const char* ifname) { struct CSM* csm = NULL; @@ -352,17 +395,30 @@ int iccp_cli_detach_mclag_domain_to_port_channel( const char* ifname) || lif_po->po_id <= 0 || lif_po->csm == NULL) { + if (lif_po) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "CSM already detached for ifname = %s", lif_po->name); + } return MCLAG_ERROR; } /* find csm*/ csm = lif_po->csm; + if(!csm) + { + ICCPD_LOG_WARN(__FUNCTION__, "unexpected condition!!!; lif->csm not found!; Detach mclag from ifname = %s", lif_po->name); + return 0; + } + ICCPD_LOG_DEBUG(__FUNCTION__, "Detach mclag id = %d from ifname = %s", csm->mlag_id, lif_po->name); + //if it is standby node change back the mac to its original system mac + recover_if_ipmac_on_standby(lif_po, 1); + /* process link state handler before detaching it.*/ - mlacp_mlag_link_del_handler(csm, lif_po); + mlacp_mlag_intf_detach_handler(csm, lif_po); unbind_poid = lif_po->po_id; mlacp_unbind_local_if(lif_po); @@ -377,6 +433,7 @@ int iccp_cli_detach_mclag_domain_to_port_channel( const char* ifname) if (strcmp(ifname, cif->name) == 0) LIST_REMOVE(cif, csm_next); } + return 0; } diff --git a/src/iccpd/src/iccp_cmd.c b/src/iccpd/src/iccp_cmd.c index 50025a8e3810..8b39b73d0f6b 100644 --- a/src/iccpd/src/iccp_cmd.c +++ b/src/iccpd/src/iccp_cmd.c @@ -55,6 +55,21 @@ int set_mc_lag_by_id(uint16_t mid) return ret; } +int unset_mc_lag_by_id(uint16_t mid) +{ + int ret = 0; + struct CSM* csm = NULL; + + csm = system_get_csm_by_mlacp_id(mid); + if (csm) + { + ret = unset_mc_lag_id(csm, mid); + return ret; + } + + return MCLAG_ERROR; +} + #define CONFIG_LINE_LEN 512 int iccp_config_from_command(char * line) diff --git a/src/iccpd/src/iccp_cmd_show.c b/src/iccpd/src/iccp_cmd_show.c index 18b2e5bded8e..984984434dc0 100644 --- a/src/iccpd/src/iccp_cmd_show.c +++ b/src/iccpd/src/iccp_cmd_show.c @@ -20,6 +20,7 @@ * * Maintainer: jianjun, grace Li from nephos */ +#include #include #include #include @@ -33,6 +34,8 @@ #include "../include/iccp_cmd_show.h" #include "../include/mlacp_link_handler.h" +extern int local_if_l3_proto_enabled(const char* ifname); + int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id) { struct mclagd_state state_info; @@ -67,6 +70,11 @@ int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id) else state_info.keepalive = 0; + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + state_info.info_sync_done = 1; + else + state_info.info_sync_done = 0; + if (mclag_id > 0) { if (csm->mlag_id == mclag_id) @@ -93,13 +101,15 @@ int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id) if (peer_link_if) memcpy(state_info.peer_link_mac, peer_link_if->mac_addr, 6); + state_info.keepalive_time = csm->keepalive_time; + state_info.session_timeout = csm->session_timeout; + logconfig = logger_get_configuration(); memcpy(state_info.loglevel, log_level_to_string(logconfig->log_level), strlen( log_level_to_string(logconfig->log_level))); state_info.role = csm->role_type; str_size = MCLAGDCTL_PORT_MEMBER_BUF_LEN; - len = 0; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) { @@ -177,6 +187,7 @@ int iccp_arp_dump(char * *buf, int *num, int mclag_id) iccpd_arp = (struct ARPMsg*)msg->buf; mclagd_arp.op_type = iccpd_arp->op_type; + mclagd_arp.learn_flag = iccpd_arp->learn_flag; memcpy(mclagd_arp.ifname, iccpd_arp->ifname, strlen(iccpd_arp->ifname)); memcpy(mclagd_arp.ipv4_addr, show_ip_str(iccpd_arp->ipv4_addr), 16); memcpy(mclagd_arp.mac_addr, iccpd_arp->mac_addr, 6); @@ -219,7 +230,6 @@ int iccp_ndisc_dump(char * *buf, int *num, int mclag_id) if (!(sys = system_get_instance())) { - ICCPD_LOG_INFO(__FUNCTION__, "cannot find sys!\n"); return EXEC_TYPE_NO_EXIST_SYS; } @@ -243,12 +253,12 @@ int iccp_ndisc_dump(char * *buf, int *num, int mclag_id) iccpd_ndisc = (struct NDISCMsg *)msg->buf; mclagd_ndisc.op_type = iccpd_ndisc->op_type; + mclagd_ndisc.learn_flag = iccpd_ndisc->learn_flag; memcpy(mclagd_ndisc.ifname, iccpd_ndisc->ifname, strlen(iccpd_ndisc->ifname)); memcpy(mclagd_ndisc.ipv6_addr, show_ipv6_str((char *)iccpd_ndisc->ipv6_addr), 46); memcpy(mclagd_ndisc.mac_addr, iccpd_ndisc->mac_addr, 6); - memcpy(ndisc_buf + MCLAGD_REPLY_INFO_HDR + ndisc_num * sizeof(struct mclagd_ndisc_msg), - &mclagd_ndisc, sizeof(struct mclagd_ndisc_msg)); + memcpy(ndisc_buf + MCLAGD_REPLY_INFO_HDR + ndisc_num * sizeof(struct mclagd_ndisc_msg), &mclagd_ndisc, sizeof(struct mclagd_ndisc_msg)); ndisc_num++; @@ -302,14 +312,13 @@ int iccp_mac_dump(char * *buf, int *num, int mclag_id) continue; } - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + RB_FOREACH (iccpd_mac, mac_rb_tree, &MLACP(csm).mac_rb) { memset(&mclagd_mac, 0, sizeof(struct mclagd_mac_msg)); - iccpd_mac = (struct MACMsg*)msg->buf; mclagd_mac.op_type = iccpd_mac->op_type; mclagd_mac.fdb_type = iccpd_mac->fdb_type; - memcpy(mclagd_mac.mac_str, iccpd_mac->mac_str, ETHER_ADDR_STR_LEN); + memcpy(mclagd_mac.mac_addr, iccpd_mac->mac_addr, ETHER_ADDR_LEN); mclagd_mac.vid = iccpd_mac->vid; memcpy(mclagd_mac.ifname, iccpd_mac->ifname, strlen(iccpd_mac->ifname)); memcpy(mclagd_mac.origin_ifname, iccpd_mac->origin_ifname, strlen(iccpd_mac->origin_ifname)); @@ -328,7 +337,7 @@ int iccp_mac_dump(char * *buf, int *num, int mclag_id) return EXEC_TYPE_FAILED; } } - } + } *buf = mac_buf; *num = mac_num; @@ -344,6 +353,7 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) struct System *sys = NULL; struct CSM *csm = NULL; struct LocalInterface *lif_po = NULL; + struct LocalInterface *lif_peer = NULL; struct mclagd_local_if mclagd_lif; struct VLAN_ID* vlan_id = NULL; char * str_buf = NULL; @@ -398,7 +408,7 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) else if (lif_po->state == PORT_STATE_TEST) memcpy(mclagd_lif.state, "Test", 4); - memcpy(mclagd_lif.ipv4_addr, show_ip_str(htonl(lif_po->ipv4_addr)), 16); + memcpy(mclagd_lif.ipv4_addr, show_ip_str(lif_po->ipv4_addr), 16); mclagd_lif.prefixlen = lif_po->prefixlen; mclagd_lif.l3_mode = local_if_is_l3_mode(lif_po); @@ -422,17 +432,47 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) memcpy(mclagd_lif.mlacp_state, "ERROR", 5); mclagd_lif.isolate_to_peer_link = lif_po->isolate_to_peer_link; + mclagd_lif.is_traffic_disable = lif_po->is_traffic_disable; str_buf = mclagd_lif.vlanlist; len = 0; - LIST_FOREACH(vlan_id, &(lif_po->vlan_list), port_next) + int prev_vlan_id = 0; + int range = 0; + int to_be_printed = 0; + + RB_FOREACH (vlan_id, vlan_rb_tree, &(lif_po->vlan_tree)) { - if (vlan_id != NULL ) + if (str_size - len < 4) + break; + if (!prev_vlan_id || vlan_id->vid != prev_vlan_id + 1) { - if (str_size - len < 4) - break; + if (range) + { + if (str_size - len < (4 + ((range)?8:0))) + { + break; + } + len += snprintf(str_buf + len, str_size - len, "- %d ", prev_vlan_id); + } len += snprintf(str_buf + len, str_size - len, "%d ", vlan_id->vid); + range = 0; + to_be_printed = 0; + } + else + { + range = 1; + to_be_printed = 1; + } + prev_vlan_id = vlan_id->vid; + } + + if (to_be_printed && (str_size - len > (4 + ((range)?8:0)))) + { + if (prev_vlan_id) + { + len += snprintf(str_buf + len, str_size - len, "%s%d ", range?"- ":"", prev_vlan_id); + range = 0; } } @@ -449,6 +489,116 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) return EXEC_TYPE_FAILED; } } + + if (csm->peer_link_if) { + + lif_peer = csm->peer_link_if; + + memset(&mclagd_lif, 0, sizeof(struct mclagd_local_if)); + + mclagd_lif.ifindex = lif_peer->ifindex; + + if (lif_peer->type == IF_T_UNKNOW) + memcpy(mclagd_lif.type, "Unknown", strlen("unknown")); + else if (lif_peer->type == IF_T_PORT) + memcpy(mclagd_lif.type, "Ethernet", strlen("Ethernet")); + else if (lif_peer->type == IF_T_PORT_CHANNEL) + memcpy(mclagd_lif.type, "PortChannel", 11); + + memcpy(mclagd_lif.name, lif_peer->name, MAX_L_PORT_NAME); + memcpy(mclagd_lif.mac_addr, lif_peer->mac_addr, ETHER_ADDR_LEN); + + if (lif_peer->state == PORT_STATE_UP) + memcpy(mclagd_lif.state, "Up", strlen("Up")); + else if (lif_peer->state == PORT_STATE_DOWN) + memcpy(mclagd_lif.state, "Down", strlen("Down")); + else if (lif_peer->state == PORT_STATE_ADMIN_DOWN) + memcpy(mclagd_lif.state, "Admin-down", strlen("Admin-down")); + else if (lif_peer->state == PORT_STATE_TEST) + memcpy(mclagd_lif.state, "Test", strlen("Test")); + + memcpy(mclagd_lif.ipv4_addr, show_ip_str(lif_peer->ipv4_addr), 16); + mclagd_lif.prefixlen = lif_peer->prefixlen; + + mclagd_lif.l3_mode = local_if_is_l3_mode(lif_peer); + + mclagd_lif.is_peer_link = lif_peer->is_peer_link; + + memcpy(mclagd_lif.portchannel_member_buf, lif_peer->portchannel_member_buf, 512); + + mclagd_lif.po_id = lif_peer->po_id; + mclagd_lif.po_active = lif_peer->po_active; + /*mlacp_state*/ + if (lif_peer->mlacp_state == MLACP_STATE_INIT) + memcpy(mclagd_lif.mlacp_state, "INIT", strlen("INIT")); + else if (lif_peer->mlacp_state == MLACP_STATE_STAGE1) + memcpy(mclagd_lif.mlacp_state, "STAGE1", strlen("STAGE1")); + else if (lif_peer->mlacp_state == MLACP_STATE_STAGE2) + memcpy(mclagd_lif.mlacp_state, "STAGE2", strlen("STAGE2")); + else if (lif_peer->mlacp_state == MLACP_STATE_EXCHANGE) + memcpy(mclagd_lif.mlacp_state, "EXCHANGE", strlen("EXCHANGE")); + else if (lif_peer->mlacp_state == MLACP_STATE_ERROR) + memcpy(mclagd_lif.mlacp_state, "ERROR", strlen("ERROR")); + + mclagd_lif.isolate_to_peer_link = lif_peer->isolate_to_peer_link; + mclagd_lif.is_traffic_disable = lif_peer->is_traffic_disable; + + str_buf = mclagd_lif.vlanlist; + + len = 0; + int prev_vlan_id = 0; + int range = 0; + int to_be_printed = 0; + + RB_FOREACH (vlan_id, vlan_rb_tree, &(lif_peer->vlan_tree)) + { + if (str_size - len < 4) + break; + if (!prev_vlan_id || vlan_id->vid != prev_vlan_id + 1) + { + if (range) + { + if (str_size - len < (4 + ((range)?8:0))) + { + break; + } + len += snprintf(str_buf + len, str_size - len, "- %d ", prev_vlan_id); + } + len += snprintf(str_buf + len, str_size - len, "%d ", vlan_id->vid); + range = 0; + to_be_printed = 0; + } + else + { + range = 1; + to_be_printed = 1; + } + prev_vlan_id = vlan_id->vid; + } + + if (to_be_printed && (str_size - len > (4 + ((range)?8:0)))) + { + if (prev_vlan_id) + { + len += snprintf(str_buf + len, str_size - len, "%s%d ", range?"- ":"", prev_vlan_id); + range = 0; + } + } + + memcpy(lif_buf + MCLAGD_REPLY_INFO_HDR + lif_num * sizeof(struct mclagd_local_if), + &mclagd_lif, sizeof(struct mclagd_local_if)); + + lif_num++; + + if ((lif_num + 1) * sizeof(struct mclagd_local_if) > (lif_buf_size - MCLAGD_REPLY_INFO_HDR)) + { + lif_buf_size += MCLAGDCTL_CMD_SIZE; + lif_buf = (char*)realloc(lif_buf, lif_buf_size); + if (!lif_buf) + return EXEC_TYPE_FAILED; + } + + } } *buf = lif_buf; @@ -473,6 +623,7 @@ int iccp_peer_if_dump(char * *buf, int *num, int mclag_id) if (!(sys = system_get_instance())) { + ICCPD_LOG_INFO(__FUNCTION__, "cannot find sys!\n"); return EXEC_TYPE_NO_EXIST_SYS; } @@ -542,3 +693,122 @@ int iccp_peer_if_dump(char * *buf, int *num, int mclag_id) return EXEC_TYPE_SUCCESS; } +/* Allocate a buffer to return the internal debug counters + * The allocated buffer should include MCLAGD_REPLY_INFO_HDR byte header + * No buffer is allocated if error is returned + */ +int iccp_cmd_dbg_counter_dump(char **buf, int *data_len, int mclag_id) +{ + struct System *sys = NULL; + struct CSM *csm = NULL; + char *temp_ptr, *counter_buf = NULL; + mclagd_dbg_counter_info_t *counter_ptr; + int buf_size = 0; + int id_exist = 0; + int num_csm = 0; + bool is_first_csm; + + if (!(sys = system_get_instance())) + { + ICCPD_LOG_INFO(__FUNCTION__, "cannot find sys!\n"); + return EXEC_TYPE_NO_EXIST_SYS; + } + if (mclag_id >0) + num_csm = 1; + else + { + LIST_FOREACH(csm, &(sys->csm_list), next) + { + ++num_csm; + } + } + buf_size = MCLAGD_REPLY_INFO_HDR + sizeof(mclagd_dbg_counter_info_t) + + (sizeof(mlacp_dbg_counter_info_t) * num_csm); + counter_buf = (char*)malloc(buf_size); + if (!counter_buf) + return EXEC_TYPE_FAILED; + + memset(counter_buf, 0, buf_size); + counter_ptr = + (mclagd_dbg_counter_info_t *)(counter_buf + MCLAGD_REPLY_INFO_HDR); + memcpy(&counter_ptr->system_dbg, &sys->dbg_counters, sizeof(sys->dbg_counters)); + counter_ptr->num_iccp_counter_blocks = num_csm; + temp_ptr = counter_ptr->iccp_dbg_counters; + is_first_csm = true; + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + if (mclag_id >0) + { + if (csm->mlag_id == mclag_id) + id_exist = 1; + else + continue; + } + if (is_first_csm) + is_first_csm = false; + else + temp_ptr += sizeof(MLACP(csm).dbg_counters); + + memcpy(temp_ptr, &MLACP(csm).dbg_counters, + sizeof(MLACP(csm).dbg_counters)); + } + + if (mclag_id >0 && !id_exist) + { + if (counter_buf) + free(counter_buf); + return EXEC_TYPE_NO_EXIST_MCLAGID; + } + *buf = counter_buf; + *data_len = buf_size - MCLAGD_REPLY_INFO_HDR; + return EXEC_TYPE_SUCCESS; +} + +int iccp_unique_ip_if_dump(char **buf, int *num, int mclag_id) +{ + struct System *sys = NULL; + struct mclagd_unique_ip_if mclagd_lif; + char *str_buf = NULL; + int str_size = MCLAGDCTL_PARA3_LEN - 1; + int len = 0; + int lif_num = 0; + int lif_buf_size = MCLAGDCTL_CMD_SIZE; + char *lif_buf = NULL; + struct Unq_ip_If_info* unq_ip_if = NULL; + + if (!(sys = system_get_instance())) + { + ICCPD_LOG_INFO(__FUNCTION__, "cannot find sys!\n"); + return EXEC_TYPE_NO_EXIST_SYS; + } + + lif_buf = (char*)malloc(lif_buf_size); + if (!lif_buf) + return EXEC_TYPE_FAILED; + + LIST_FOREACH(unq_ip_if, &(sys->unq_ip_if_list), if_next) + { + memset(&mclagd_lif, 0, sizeof(struct mclagd_unique_ip_if)); + memcpy(mclagd_lif.name, unq_ip_if->name, MAX_L_PORT_NAME); + mclagd_lif.active = local_if_l3_proto_enabled(unq_ip_if->name); + + memcpy(lif_buf + MCLAGD_REPLY_INFO_HDR + lif_num * sizeof(struct mclagd_unique_ip_if), + &mclagd_lif, sizeof(struct mclagd_unique_ip_if)); + + lif_num++; + + if ((lif_num + 1) * sizeof(struct mclagd_unique_ip_if) > (lif_buf_size - MCLAGD_REPLY_INFO_HDR)) + { + lif_buf_size += MCLAGDCTL_CMD_SIZE; + lif_buf = (char*)realloc(lif_buf, lif_buf_size); + if (!lif_buf) + return EXEC_TYPE_FAILED; + } + } + + *buf = lif_buf; + *num = lif_num; + + return EXEC_TYPE_SUCCESS; +} diff --git a/src/iccpd/src/iccp_consistency_check.c b/src/iccpd/src/iccp_consistency_check.c index 90ac9cd9e790..6898b366f2bc 100644 --- a/src/iccpd/src/iccp_consistency_check.c +++ b/src/iccpd/src/iccp_consistency_check.c @@ -112,13 +112,9 @@ static int iccp_check_interface_vlan(char* ifname) if (peer_if == NULL) return -4; - LIST_FOREACH(local_vlan, &(local_if->vlan_list), port_next) + RB_FOREACH (local_vlan, vlan_rb_tree, &(local_if->vlan_tree)) { - LIST_FOREACH(peer_vlan, &(peer_if->vlan_list), port_next) - { - if (peer_vlan->vid == local_vlan->vid) - break; - } + peer_vlan = RB_FIND(vlan_rb_tree, &(peer_if->vlan_tree), local_vlan); if (peer_vlan == NULL) { @@ -126,14 +122,9 @@ static int iccp_check_interface_vlan(char* ifname) } } - LIST_FOREACH(peer_vlan, &(peer_if->vlan_list), port_next) + RB_FOREACH (peer_vlan, vlan_rb_tree, &(peer_if->vlan_tree)) { - - LIST_FOREACH(local_vlan, &(local_if->vlan_list), port_next) - { - if (peer_vlan->vid == local_vlan->vid) - break; - } + local_vlan = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), peer_vlan); if (local_vlan == NULL) { diff --git a/src/iccpd/src/iccp_csm.c b/src/iccpd/src/iccp_csm.c index 79e17b9e1ba2..1560b41f3d81 100644 --- a/src/iccpd/src/iccp_csm.c +++ b/src/iccpd/src/iccp_csm.c @@ -20,7 +20,7 @@ * * Maintainer: jianjun, grace Li from nephos */ - +#include #include #include @@ -29,6 +29,7 @@ #include "../include/scheduler.h" #include "../include/msg_format.h" #include "../include/iccp_csm.h" +#include "../include/iccp_cli.h" #include "../include/mlacp_link_handler.h" /***************************************** * Define @@ -121,6 +122,8 @@ void iccp_csm_init(struct CSM* csm) memset(csm->peer_ip, 0, INET_ADDRSTRLEN); memset(csm->iccp_info.sender_name, 0, MAX_L_ICC_SENDER_NAME); csm->iccp_info.icc_rg_id = 0x0; + csm->keepalive_time = CONNECT_INTERVAL_SEC; + csm->session_timeout = HEARTBEAT_TIMEOUT_SEC; } /* Connection State Machine instance status reset */ @@ -141,6 +144,8 @@ void iccp_csm_status_reset(struct CSM* csm, int all) csm->heartbeat_update_time = 0; csm->peer_warm_reboot_time = 0; csm->warm_reboot_disconn_time = 0; + csm->peer_link_learning_retry_time = 0; + csm->peer_link_learning_enable = 0; csm->role_type = STP_ROLE_NONE; csm->sock_read_event_ptr = NULL; csm->peer_link_if = NULL; @@ -165,6 +170,9 @@ void iccp_csm_finalize(struct CSM* csm) { struct If_info * cif = NULL; struct System* sys = NULL; + struct LocalInterface* lifp = NULL; + struct LocalInterface* local_if = NULL; + struct LocalInterface* local_if_next = NULL; if (csm == NULL) return; @@ -176,21 +184,40 @@ void iccp_csm_finalize(struct CSM* csm) if (sys->warmboot_exit != WARM_REBOOT) { /*Enable peer link port MAC learning*/ - if (csm->peer_link_if) + if (csm->peer_link_if) { set_peerlink_mlag_port_learn(csm->peer_link_if, 1); + set_peerlink_learn_kernel(csm, 1, 1); + } } /* Disconnect from peer */ scheduler_session_disconnect_handler(csm); + //Delete all MCLAG interfaces + local_if = LIST_FIRST(&(MLACP(csm).lif_list)); + while (local_if != NULL) + { + local_if_next = LIST_NEXT(local_if,mlacp_next); + iccp_cli_detach_mclag_domain_to_port_channel(local_if->name); + local_if = local_if_next; + } + /* Release all Connection State Machine instance */ app_csm_finalize(csm); - LIST_FOREACH(cif, &(csm->if_bind_list), csm_next) + LIST_FOREACH(lifp, &(MLACP(csm).lif_list), mlacp_next) { - LIST_REMOVE(cif, csm_next); + ICCPD_LOG_NOTICE(__FUNCTION__, "Resetting CSM pointer for %s", lifp->name); + lifp->csm = NULL; } + while (!LIST_EMPTY(&(csm->if_bind_list))) + { + cif = LIST_FIRST(&(csm->if_bind_list)); + LIST_REMOVE(cif,csm_next); + free(cif); + } + /* Release iccp_csm */ pthread_mutex_destroy(&(csm->conn_mutex)); iccp_csm_msg_list_finalize(csm); @@ -219,6 +246,8 @@ int iccp_csm_send(struct CSM* csm, char* buf, int msg_len) { LDPHdr* ldp_hdr = (LDPHdr*)buf; ICCParameter* param = NULL; + ssize_t rc; + uint16_t tlv_type; if (csm == NULL || buf == NULL || csm->sock_fd <= 0 || msg_len <= 0) return MCLAG_ERROR; @@ -228,7 +257,7 @@ int iccp_csm_send(struct CSM* csm, char* buf, int msg_len) else param = (struct ICCParameter*)&buf[sizeof(ICCHdr)]; - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Send(%d): len=[%d] msg_type=[%s (0x%X, 0x%X)]", csm->sock_fd, msg_len, get_tlv_type_string(param->type), ldp_hdr->msg_type, param->type);*/ + ICCPD_LOG_DEBUG(__FUNCTION__, "Send(%d): len=[%d] msg_type=[%s (0x%X, 0x%X)]", csm->sock_fd, msg_len, get_tlv_type_string(ntohs(param->type)), ldp_hdr->msg_type, ntohs(param->type)); csm->msg_log.msg[csm->msg_log.end_index].msg_id = ntohl(ldp_hdr->msg_id); csm->msg_log.msg[csm->msg_log.end_index].type = ntohs(ldp_hdr->msg_type); csm->msg_log.msg[csm->msg_log.end_index].tlv = ntohs(param->type); @@ -236,7 +265,20 @@ int iccp_csm_send(struct CSM* csm, char* buf, int msg_len) if (csm->msg_log.end_index >= 128) csm->msg_log.end_index = 0; - return write(csm->sock_fd, buf, msg_len); + tlv_type = ntohs(param->type); + rc = write(csm->sock_fd, buf, msg_len); + if ((rc <= 0) || (rc != msg_len)) + { + MLACP_SET_ICCP_TX_DBG_COUNTER( + csm, tlv_type, ICCP_DBG_CNTR_STS_ERR); + ICCPD_LOG_ERR("ICCP_FSM", "Failed to write msg %s/0x%x, msg_len:%d, rc %d Error:%s ", get_tlv_type_string(tlv_type), tlv_type, msg_len, rc, strerror(errno)); + } + else + { + MLACP_SET_ICCP_TX_DBG_COUNTER( + csm, tlv_type, ICCP_DBG_CNTR_STS_OK); + } + return (rc); } /* Connection State Machine Transition */ @@ -776,8 +818,34 @@ int iccp_csm_init_msg(struct Msg** msg, char* data, int len) return MCLAG_ERROR; } +/* MAC Message initialization */ +int iccp_csm_init_mac_msg(struct MACMsg **mac_msg, char* data, int len) +{ + struct MACMsg* iccp_mac_msg = NULL; + + if (mac_msg == NULL) + return -2; + + if (data == NULL || len <= 0) + return MCLAG_ERROR; + + iccp_mac_msg = (struct MACMsg*)malloc(sizeof(struct MACMsg)); + if (iccp_mac_msg == NULL) + return -3; + + memset(iccp_mac_msg, 0, sizeof(struct MACMsg)); + memcpy(iccp_mac_msg, data, len); + + *mac_msg = iccp_mac_msg; + + return 0; +} + + void iccp_csm_stp_role_count(struct CSM *csm) { + struct If_info * cif = NULL; + /* decide the role, lower ip to be active & socket client*/ if (csm->role_type == STP_ROLE_NONE) { @@ -786,12 +854,18 @@ void iccp_csm_stp_role_count(struct CSM *csm) /* Active*/ ICCPD_LOG_INFO(__FUNCTION__, "Role: [Active]"); csm->role_type = STP_ROLE_ACTIVE; + /* Send ICCP role update and system ID */ + mlacp_link_set_iccp_role(csm->mlag_id, true, MLACP(csm).system_id); } else { /* Standby*/ ICCPD_LOG_INFO(__FUNCTION__, "Role [Standby]"); csm->role_type = STP_ROLE_STANDBY; + /* Send ICCP role update */ + mlacp_link_set_iccp_role(csm->mlag_id, false, NULL); + /*Set Bridge MAC to MY MAC*/ + mlacp_fix_bridge_mac(csm); } } -} \ No newline at end of file +} diff --git a/src/iccpd/src/iccp_ifm.c b/src/iccpd/src/iccp_ifm.c index 258c661e03a4..4349599f5308 100644 --- a/src/iccpd/src/iccp_ifm.c +++ b/src/iccpd/src/iccp_ifm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -99,9 +100,12 @@ int iccp_sys_local_if_list_get_init() nl_cb_put(cb); if (ret < 0) { - ICCPD_LOG_ERR(__FUNCTION__, "receive netlink msg error. ret = %d errno = %d ", ret, errno); if (ret != -NLE_DUMP_INTR) + { + ICCPD_LOG_ERR(__FUNCTION__, "No retry, receive netlink msg error. ret = %d errno = %d ", ret, errno); return ret; + } + ICCPD_LOG_NOTICE(__FUNCTION__, "Retry: receive netlink msg error. ret = %d errno = %d ", ret, errno); retry = 1; } } @@ -109,7 +113,7 @@ int iccp_sys_local_if_list_get_init() return ret; } -static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype) +static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype, int is_del) { struct System *sys = NULL; struct CSM *csm = NULL; @@ -117,6 +121,12 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int struct ARPMsg *arp_msg = NULL, *arp_info = NULL; struct VLAN_ID *vlan_id_list = NULL; struct Msg *msg_send = NULL; + uint16_t vid = 0; + int entry_exists = 0; + struct LocalInterface *peer_link_if = NULL; + int ln = 0; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; char buf[MAX_BUFSIZE]; size_t msg_len = 0; @@ -136,12 +146,12 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int /* create ARP msg*/ memset(buf, 0, MAX_BUFSIZE); msg_len = sizeof(struct ARPMsg); - arp_msg = (struct ARPMsg*)&buf; + arp_msg = (struct ARPMsg *)&buf; arp_msg->op_type = NEIGH_SYNC_LIF; sprintf(arp_msg->ifname, "%s", arp_lif->name); if (tb[NDA_DST]) memcpy(&arp_msg->ipv4_addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); - if (tb[NDA_LLADDR]) + if (!is_del && tb[NDA_LLADDR]) memcpy(arp_msg->mac_addr, RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR])); arp_msg->ipv4_addr = arp_msg->ipv4_addr; @@ -153,36 +163,72 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4], arp_msg->mac_addr[5]); + if (msgtype != RTM_DELNEIGH) { + if (arp_lif->ipv4_addr == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, "IP not configured on %s, ignore ARP", arp_lif->name); + return; + } + } + + uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (memcmp(arp_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr"); + msgtype = RTM_DELNEIGH; + } + + if ((strncmp(arp_msg->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) { + sscanf (arp_msg->ifname, "Vlan%hu", &vlan_id); + } + + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + } + /* Find MLACP itf, member of port-channel*/ LIST_FOREACH(csm, &(sys->csm_list), next) { + vid = 0; + ln = __LINE__; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) { - if (lif_po->type != IF_T_PORT_CHANNEL) + if (lif_po->type != IF_T_PORT_CHANNEL) { + ln = __LINE__; continue; + } if (!local_if_is_l3_mode(lif_po)) { + vid = 0; /* Is the L2 MLAG itf belong to a vlan?*/ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) - { - if ( !(vlan_id_list->vlan_itf - && vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex)) - continue; - break; + vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key); + + if (!vlan_id_list) { + ln = __LINE__; + continue; + } + + if (!vlan_id_list->vlan_itf) { + ln = __LINE__; + continue; } - if (!vlan_id_list) + if (vlan_id_list->vlan_itf->ifindex != ndm->ndm_ifindex) { + ln = __LINE__; continue; + } - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %s", - vlan_id_list->vlan_itf->name); + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %d", vid); } else { /* Is the ARP belong to a L3 mode MLAG itf?*/ - if (ndm->ndm_ifindex != lif_po->ifindex) + if (ndm->ndm_ifindex != lif_po->ifindex) { + ln = __LINE__; continue; + } ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name); } @@ -192,22 +238,53 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int break; } - if (lif_po) + if (lif_po) { break; + } else if (csm->peer_link_if){ + peer_link_if = csm->peer_link_if; + if (!local_if_is_l3_mode(peer_link_if)) { + vid = 0; + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list && vlan_id_list->vlan_itf) { + if (vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex) { + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from peer link vlan %d", vid); + verify_arp = 1; + lif_po = peer_link_if; + break; + } + } + } + } } - if (!(csm && lif_po)) + if (!(csm && lif_po)) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no PO ln %d", ln); return; - if (!verify_arp) + } + if (!verify_arp) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no verify_arp ln %d", ln); return; + } + + if (vid != 0) { + if (vid && vlan_id_list && vlan_id_list->vlan_itf) { + if (arp_msg->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignore My ip %s", show_ip_str(arp_msg->ipv4_addr)); + return; + } + } + } /* update lif ARP*/ TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail) { - arp_info = (struct ARPMsg*)msg->buf; + arp_info = (struct ARPMsg *)msg->buf; if (arp_info->ipv4_addr != arp_msg->ipv4_addr) continue; + entry_exists = 1; if (msgtype == RTM_DELNEIGH) { /* delete ARP*/ @@ -222,8 +299,7 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int /* update ARP*/ if (arp_info->op_type != arp_msg->op_type || strcmp(arp_info->ifname, arp_msg->ifname) != 0 - || memcmp(arp_info->mac_addr, arp_msg->mac_addr, - ETHER_ADDR_LEN) != 0) + || memcmp(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN) != 0) { arp_update = 1; arp_info->op_type = arp_msg->op_type; @@ -244,11 +320,12 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int if (!msg) { arp_msg->op_type = NEIGH_SYNC_LIF; - if (iccp_csm_init_msg(&msg, (char*)arp_msg, msg_len) == 0) + arp_msg->learn_flag = NEIGH_LOCAL; + if (iccp_csm_init_msg(&msg, (char *)arp_msg, msg_len) == 0) { mlacp_enqueue_arp(csm, msg); /*ICCPD_LOG_DEBUG(__FUNCTION__, "ARP-list enqueue: %s, add %s", - arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr));*/ + arp_msg->ifname, show_ip_str((arp_msg->ipv4_addr));*/ } else ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP-list: %s, add %s", @@ -259,7 +336,8 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { arp_msg->op_type = NEIGH_SYNC_ADD; - if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0) + arp_msg->flag = 0; + if (iccp_csm_init_msg(&msg_send, (char *)arp_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] message for %s", @@ -268,16 +346,16 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int else ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] message for %s", show_ip_str(arp_msg->ipv4_addr)); - } } else { /* enqueue iccp_msg (delete)*/ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && entry_exists) { arp_msg->op_type = NEIGH_SYNC_DEL; - if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0) + arp_msg->flag = 0; + if (iccp_csm_init_msg(&msg_send, (char *)arp_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[DEL] message for %s", @@ -286,14 +364,16 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int else ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[DEL] message for %s", show_ip_str(arp_msg->ipv4_addr)); - + } else { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP[DEL] message for %s skipped. entry_exists %d", + show_ip_str(arp_msg->ipv4_addr), entry_exists); } } return; } -static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype) +static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype, int is_del) { struct System *sys = NULL; struct CSM *csm = NULL; @@ -301,11 +381,19 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i struct NDISCMsg *ndisc_msg = NULL, *ndisc_info = NULL; struct VLAN_ID *vlan_id_list = NULL; struct Msg *msg_send = NULL; + uint16_t vid = 0; + int entry_exists = 0; + int is_link_local = 0; + int ln = 0; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; char buf[MAX_BUFSIZE]; size_t msg_len = 0; + char addr_null[16] = { 0 }; struct LocalInterface *lif_po = NULL, *ndisc_lif = NULL; + struct LocalInterface *peer_link_if = NULL; int verify_neigh = 0; int neigh_update = 0; @@ -325,7 +413,7 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i sprintf(ndisc_msg->ifname, "%s", ndisc_lif->name); if (tb[NDA_DST]) memcpy(&ndisc_msg->ipv6_addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); - if (tb[NDA_LLADDR]) + if (!is_del && tb[NDA_LLADDR]) memcpy(ndisc_msg->mac_addr, RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR])); ICCPD_LOG_NOTICE(__FUNCTION__, "ndisc type %s, state (%04X)(%d), ifindex [%d] (%s), ip %s, mac [%02X:%02X:%02X:%02X:%02X:%02X]", @@ -335,36 +423,75 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i ndisc_msg->mac_addr[0], ndisc_msg->mac_addr[1], ndisc_msg->mac_addr[2], ndisc_msg->mac_addr[3], ndisc_msg->mac_addr[4], ndisc_msg->mac_addr[5]); + + if (msgtype != RTM_DELNEIGH) { + if (memcmp(ndisc_lif->ipv6_addr, addr_null, 16) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, "IPv6 address not configured on %s, ignore ND", ndisc_lif->name); + return; + } + } + + uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (memcmp(ndisc_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr"); + msgtype = RTM_DELNEIGH; + return; + } + + if ((strncmp(ndisc_msg->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) { + sscanf (ndisc_msg->ifname, "Vlan%hu", &vlan_id); + } + + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + } /* Find MLACP itf, member of port-channel */ LIST_FOREACH(csm, &(sys->csm_list), next) { + vid = 0; + ln = __LINE__; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) { - if (lif_po->type != IF_T_PORT_CHANNEL) + if (lif_po->type != IF_T_PORT_CHANNEL) { + ln = __LINE__; continue; + } + vid = 0; if (!local_if_is_l3_mode(lif_po)) { - /* Is the L2 MLAG itf belong to a vlan? */ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) - { - if (!(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex)) - continue; - break; + /* Is the L2 MLAG itf belong to a vlan?*/ + vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key); + + if (!vlan_id_list) { + ln = __LINE__; + continue; } - if (!vlan_id_list) + if (!vlan_id_list->vlan_itf) { + ln = __LINE__; continue; + } - ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from mclag enabled member port of vlan %s", vlan_id_list->vlan_itf->name); + if (vlan_id_list->vlan_itf->ifindex != ndm->ndm_ifindex) { + ln = __LINE__; + continue; + } + + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "neighor is from intf %s of vlan %d", lif_po->name, vid); } else { /* Is the ND belong to a L3 mode MLAG itf? */ - if (ndm->ndm_ifindex != lif_po->ifindex) + if (ndm->ndm_ifindex != lif_po->ifindex) { + ln = __LINE__; continue; + } - ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from mclag enabled intf %s", lif_po->name); + ICCPD_LOG_DEBUG(__FUNCTION__, "neighbor is from intf %s", lif_po->name); } verify_neigh = 1; @@ -372,14 +499,58 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i break; } - if (lif_po) + if (lif_po) { break; + } else if (csm->peer_link_if){ + peer_link_if = csm->peer_link_if; + if (!local_if_is_l3_mode(peer_link_if)) { + vid = 0; + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list && vlan_id_list->vlan_itf) { + if (vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex) { + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from peer link vlan %d", vid); + verify_neigh = 1; + lif_po = peer_link_if; + break; + } + } + } + } } - if (!(csm && lif_po)) + if (!(csm && lif_po)) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no PO ln %d", ln); return; - if (!verify_neigh) + } + if (!verify_neigh) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no verify_ndisc ln %d", ln); return; + } + + if ((memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "FE80", 4) == 0) + || (memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "fe80", 4) == 0)) + { + is_link_local = 1; + } + + if (vid && vlan_id_list && vlan_id_list->vlan_itf) { + if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + return; + } + + if (is_link_local) + { + if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_ll_addr, 16) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + return; + } + } + } /* update lif ND */ TAILQ_FOREACH(msg, &MLACP(csm).ndisc_list, tail) @@ -389,6 +560,7 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i if (memcmp(&ndisc_info->ipv6_addr, &ndisc_msg->ipv6_addr, 16) != 0) continue; + entry_exists = 1; if (msgtype == RTM_DELNEIGH) { /* delete ND */ @@ -402,8 +574,7 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i { /* update ND */ if (ndisc_info->op_type != ndisc_info->op_type - || strcmp(ndisc_info->ifname, ndisc_info->ifname) != 0 - || memcmp(ndisc_info->mac_addr, ndisc_info->mac_addr, ETHER_ADDR_LEN) != 0) + || strcmp(ndisc_info->ifname, ndisc_info->ifname) != 0 || memcmp(ndisc_info->mac_addr, ndisc_info->mac_addr, ETHER_ADDR_LEN) != 0) { neigh_update = 1; ndisc_info->op_type = ndisc_msg->op_type; @@ -424,6 +595,7 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i if (!msg) { ndisc_msg->op_type = NEIGH_SYNC_LIF; + ndisc_msg->learn_flag = NEIGH_LOCAL; if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, msg_len) == 0) { mlacp_enqueue_ndisc(csm, msg); @@ -438,6 +610,7 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { ndisc_msg->op_type = NEIGH_SYNC_ADD; + ndisc_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); @@ -445,23 +618,26 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i } else ICCPD_LOG_DEBUG(__FUNCTION__, "Failed to enqueue Ndisc[ADD] message for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); - } } else { /* enqueue iccp_msg (delete) */ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + /* send delete notification, only if entry is present in DB*/ + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && entry_exists) { ndisc_msg->op_type = NEIGH_SYNC_DEL; + ndisc_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); /* ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue Ndisc[DEL] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); */ } else - ICCPD_LOG_DEBUG(__FUNCTION__, "Failed to enqueue Ndisc[DEL] message for [%x:%x:%x:%x]", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); - + ICCPD_LOG_DEBUG(__FUNCTION__, "Failed to enqueue Ndisc[DEL] message for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + } else { + ICCPD_LOG_DEBUG(__FUNCTION__, " Ndisc[DEL] message for %s skipped. entry_exists %d", + show_ipv6_str((char *)ndisc_msg->ipv6_addr), entry_exists); } } @@ -502,7 +678,10 @@ int do_one_neigh_request(struct nlmsghdr *n) { struct ndmsg *ndm = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr *tb[NDA_MAX + 1] = {0}; + struct rtattr *tb[NDA_MAX + 1] = {{0}}; + int is_del = 0; + int msgtype = n->nlmsg_type; + struct CSM* csm = NULL; if (n->nlmsg_type == NLMSG_DONE) { @@ -513,20 +692,33 @@ int do_one_neigh_request(struct nlmsghdr *n) if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH ) return(0); + /*Check if mclag configured*/ + csm = system_get_first_csm(); + if (!csm) + return(0); + len -= NLMSG_LENGTH(sizeof(*ndm)); if (len < 0) return MCLAG_ERROR; ifm_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); - if (n->nlmsg_type == RTM_NEWNEIGH - && (ndm->ndm_state == NUD_INCOMPLETE + if (ndm->ndm_state == NUD_INCOMPLETE || ndm->ndm_state == NUD_FAILED || ndm->ndm_state == NUD_NOARP || ndm->ndm_state == NUD_PERMANENT - || ndm->ndm_state == NUD_NONE)) + || ndm->ndm_state == NUD_NONE) { - return(0); + if ((ndm->ndm_state == NUD_FAILED) + || (ndm->ndm_state == NUD_INCOMPLETE)) + { + is_del = 1; + msgtype = RTM_DELNEIGH; + } + + if (!is_del) { + return(0); + } } if (!tb[NDA_DST] || ndm->ndm_type != RTN_UNICAST) @@ -536,16 +728,18 @@ int do_one_neigh_request(struct nlmsghdr *n) if (ndm->ndm_family == AF_INET) { - do_arp_learn_from_kernel(ndm, tb, n->nlmsg_type); + do_arp_learn_from_kernel(ndm, tb, msgtype, is_del); } if (ndm->ndm_family == AF_INET6) { - do_ndisc_learn_from_kernel(ndm, tb, n->nlmsg_type); + do_ndisc_learn_from_kernel(ndm, tb, msgtype, is_del); } - return(0); + + return (0); } +/*Handle arp received from kernel*/ static int iccp_neigh_valid_handler(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); @@ -615,6 +809,11 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui struct ARPMsg *arp_msg = NULL, *arp_info = NULL; struct VLAN_ID *vlan_id_list = NULL; struct Msg *msg_send = NULL; + uint16_t vid = 0; + struct LocalInterface *peer_link_if = NULL; + int ln = 0; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; char buf[MAX_BUFSIZE]; size_t msg_len = 0; @@ -645,35 +844,70 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4], arp_msg->mac_addr[5]); + if (arp_lif->ipv4_addr == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, "IP not configured on %s, ignore ARP", arp_lif->name); + return; + } + + uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (memcmp(arp_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr"); + return; + } + + if ((strncmp(arp_lif->name, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) { + sscanf (arp_lif->name, "Vlan%hu", &vlan_id); + } + + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + } /* Find MLACP itf, member of port-channel*/ LIST_FOREACH(csm, &(sys->csm_list), next) { + vid = 0; + ln = __LINE__; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) { - if (lif_po->type != IF_T_PORT_CHANNEL) + if (lif_po->type != IF_T_PORT_CHANNEL) { + ln = __LINE__; continue; + } + vid = 0; if (!local_if_is_l3_mode(lif_po)) { /* Is the L2 MLAG itf belong to a vlan?*/ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) - { - if ( !(vlan_id_list->vlan_itf - && vlan_id_list->vlan_itf->ifindex == ifindex)) - continue; - break; + vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key); + + if (!vlan_id_list) { + ln = __LINE__; + continue; + } + + if (!vlan_id_list->vlan_itf) { + ln = __LINE__; + continue; } - if (!vlan_id_list) + if (vlan_id_list->vlan_itf->ifindex != ifindex) { + ln = __LINE__; continue; - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled port %s of vlan %s", - lif_po->name, vlan_id_list->vlan_itf->name); + } + + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled port %s of vlan %d", + lif_po->name, vid); } else { /* Is the ARP belong to a L3 mode MLAG itf?*/ - if (ifindex != lif_po->ifindex) + if (ifindex != lif_po->ifindex) { + ln = __LINE__; continue; + } ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name); } @@ -682,20 +916,50 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui break; } - if (lif_po) + if (lif_po) { break; + } else if (csm->peer_link_if){ + peer_link_if = csm->peer_link_if; + if (!local_if_is_l3_mode(peer_link_if)) { + vid = 0; + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list && vlan_id_list->vlan_itf) { + if (vlan_id_list->vlan_itf->ifindex == ifindex) { + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from peer link vlan %d", vid); + verify_arp = 1; + lif_po = peer_link_if; + break; + } + } + } + } } - if (!(csm && lif_po)) + if (!(csm && lif_po)) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no PO ln %d", ln); return; - if (!verify_arp) + } + if (!verify_arp) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no verify_arp ln %d", ln); return; + } - if (iccp_check_if_addr_from_netlink(AF_INET, (uint8_t *)&addr, arp_lif)) - { - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP %s is identical with the ip address of interface %s", - show_ip_str(arp_msg->ipv4_addr), arp_lif->name); - return; + if (vid == 0) { + if (iccp_check_if_addr_from_netlink(AF_INET, (uint8_t *)&addr, arp_lif)) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP %s is identical with the ip address of interface %s", + show_ip_str(arp_msg->ipv4_addr), arp_lif->name); + return; + } + } else { + if (vid && vlan_id_list && vlan_id_list->vlan_itf) { + if (arp_msg->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignore My ip %s", show_ip_str(arp_msg->ipv4_addr)); + return; + } + } } /* update lif ARP*/ @@ -708,15 +972,13 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui /* update ARP*/ if (arp_info->op_type != arp_msg->op_type || strcmp(arp_info->ifname, arp_msg->ifname) != 0 - || memcmp(arp_info->mac_addr, arp_msg->mac_addr, - ETHER_ADDR_LEN) != 0) + || memcmp(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN) != 0) { arp_info->op_type = arp_msg->op_type; sprintf(arp_info->ifname, "%s", arp_msg->ifname); memcpy(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN); - ICCPD_LOG_NOTICE(__FUNCTION__, "Update ARP for %s by ARP reply, intf %s mac [%02X:%02X:%02X:%02X:%02X:%02X]", - show_ip_str(arp_msg->ipv4_addr), arp_msg->ifname, - arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4], arp_msg->mac_addr[5]); + ICCPD_LOG_DEBUG(__FUNCTION__, "Update ARP for %s", + show_ip_str(arp_msg->ipv4_addr)); } break; } @@ -725,6 +987,7 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui if (!msg) { arp_msg->op_type = NEIGH_SYNC_LIF; + arp_msg->learn_flag = NEIGH_LOCAL; if (iccp_csm_init_msg(&msg, (char*)arp_msg, msg_len) == 0) { mlacp_enqueue_arp(csm, msg); @@ -740,6 +1003,7 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { arp_msg->op_type = NEIGH_SYNC_ADD; + arp_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); @@ -764,9 +1028,16 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui struct Msg *msg_send = NULL; char mac_str[18] = ""; uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint16_t vid = 0; + int err = 0, ln = 0; + struct LocalInterface *peer_link_if = NULL; + int is_link_local = 0; char buf[MAX_BUFSIZE]; size_t msg_len = 0; + char addr_null[16] = { 0 }; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; struct LocalInterface *lif_po = NULL, *ndisc_lif = NULL; @@ -790,37 +1061,70 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui memcpy((char *)ndisc_msg->ipv6_addr, ipv6_addr, 16); memcpy(ndisc_msg->mac_addr, mac_addr, ETHER_ADDR_LEN); - ICCPD_LOG_DEBUG(__FUNCTION__, "nd ifindex [%d] (%s) ip %s mac %s", - ifindex, ndisc_lif->name, show_ipv6_str(ipv6_addr), mac_str); + ICCPD_LOG_DEBUG(__FUNCTION__, "nd ifindex [%d] (%s) ip %s mac %s", ifindex, ndisc_lif->name, show_ipv6_str(ipv6_addr), mac_str); + + if (memcmp(ndisc_lif->ipv6_addr, addr_null, 16) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, "IPv6 address not configured on %s, ignore ND", ndisc_lif->name); + return; + } + + uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (memcmp(ndisc_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr"); + return; + } + if ((strncmp(ndisc_lif->name, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) { + sscanf (ndisc_lif->name, "Vlan%hu", &vlan_id); + } + + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + } /* Find MLACP itf, member of port-channel */ LIST_FOREACH(csm, &(sys->csm_list), next) { + vid = 0; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) { - if (lif_po->type != IF_T_PORT_CHANNEL) + if (lif_po->type != IF_T_PORT_CHANNEL) { + ln = __LINE__; continue; + } + vid = 0; if (!local_if_is_l3_mode(lif_po)) { - /* Is the L2 MLAG itf belong to a vlan? */ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) - { - if (!(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ifindex)) - continue; - break; + /* Is the L2 MLAG itf belong to a vlan?*/ + vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key); + + if (!vlan_id_list) { + ln = __LINE__; + continue; } - if (!vlan_id_list) + if (!vlan_id_list->vlan_itf) { + ln = __LINE__; continue; - ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from mclag enabled port %s of vlan %s", lif_po->name, vlan_id_list->vlan_itf->name); + } + + if (vlan_id_list->vlan_itf->ifindex != ifindex) { + ln = __LINE__; + continue; + } + + vid = vlan_id_list->vid; } else { /* Is the ND belong to a L3 mode MLAG itf? */ - if (ifindex != lif_po->ifindex) + if (ifindex != lif_po->ifindex) { + ln = __LINE__; continue; - ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from mclag enabled port %s", lif_po->name); + } + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from intf %s", lif_po->name); } verify_ndisc = 1; @@ -828,20 +1132,57 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui break; } - if (lif_po) + if (lif_po) { break; + } else if (csm->peer_link_if) { + peer_link_if = csm->peer_link_if; + if (!local_if_is_l3_mode(peer_link_if)) { + vid = 0; + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list && vlan_id_list->vlan_itf) { + if (vlan_id_list->vlan_itf->ifindex == ifindex) { + vid = vlan_id_list->vid; + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from peer link vlan %d", vid); + verify_ndisc = 1; + lif_po = peer_link_if; + break; + } + } + } + } } - if (!(csm && lif_po)) + if (!(csm && lif_po)) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no PO ln %d", ln); return; - if (!verify_ndisc) + } + if (!verify_ndisc) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no verify_ndisc ln %d", ln); return; + } - if (iccp_check_if_addr_from_netlink(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, ndisc_lif)) + if ((memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "FE80", 4) == 0) + || (memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "fe80", 4) == 0)) { - ICCPD_LOG_DEBUG(__FUNCTION__, "NA %s is identical with the ipv6 address of interface %s", - show_ipv6_str((char *)ndisc_msg->ipv6_addr), ndisc_lif->name); - return; + is_link_local = 1; + } + + if (vid && vlan_id_list && vlan_id_list->vlan_itf) { + if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + return; + } + + if (is_link_local) + { + if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_ll_addr, 16) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + return; + } + } } /* update lif ND */ @@ -862,13 +1203,12 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui /* update ND */ if (ndisc_info->op_type != ndisc_msg->op_type - || strcmp(ndisc_info->ifname, ndisc_msg->ifname) != 0 - || memcmp(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN) != 0) + || strcmp(ndisc_info->ifname, ndisc_msg->ifname) != 0 || memcmp(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN) != 0) { ndisc_info->op_type = ndisc_msg->op_type; sprintf(ndisc_info->ifname, "%s", ndisc_msg->ifname); memcpy(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN); - ICCPD_LOG_DEBUG(__FUNCTION__, "Update ND for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + ICCPD_LOG_DEBUG(__FUNCTION__, "Update ND for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } break; } @@ -883,6 +1223,7 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui } ndisc_msg->op_type = NEIGH_SYNC_LIF; + ndisc_msg->learn_flag = NEIGH_LOCAL; if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, msg_len) == 0) { mlacp_enqueue_ndisc(csm, msg); @@ -892,17 +1233,22 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue NDISC-list: %s, add %s", ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } - if (iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname) < 0) + ICCPD_LOG_DEBUG(__FUNCTION__, "add nd entry(%s, %s, %s) to kernel", + ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr), mac_str); + if ((err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname, 0, 3)) < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to add ND entry(%s, %s, %s) to kernel", - ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr), mac_str); - return; + if (err != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to add nd entry(%s, %s, %s) to kernel, status %d", + ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr), mac_str, err); + return; + } } /* enqueue iccp_msg (add) */ if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { ndisc_msg->op_type = NEIGH_SYNC_ADD; + ndisc_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); @@ -914,12 +1260,14 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui return; } + void iccp_from_netlink_port_state_handler( char * ifname, int state) { struct CSM *csm = NULL; struct LocalInterface *lif_po = NULL; struct System *sys; int po_is_active = 0; + int is_mclag_intf = 0; if ((sys = system_get_instance()) == NULL) { @@ -948,91 +1296,240 @@ void iccp_from_netlink_port_state_handler( char * ifname, int state) if (lif_po->type == IF_T_PORT_CHANNEL && strncmp(lif_po->name, ifname, MAX_L_PORT_NAME) == 0) { mlacp_portchannel_state_handler(csm, lif_po, po_is_active); + is_mclag_intf = 1; } } + if (!is_mclag_intf) + { + lif_po = local_if_find_by_name(ifname); + update_orphan_port_mac(csm, lif_po, po_is_active); + } + } return; } -void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n) + +//find pending vlan member interface +struct PendingVlanMbrIf* find_pending_vlan_mbr_if(struct System *sys, const char* ifname) { - struct LocalInterface *lif = NULL; - int msglen = 0; + struct PendingVlanMbrIf* mbr_if = NULL; - msglen = n->nlmsg_len; + if (!ifname || !sys) + return NULL; - while (NLMSG_OK(n, msglen)) + LIST_FOREACH(mbr_if, &(sys->pending_vlan_mbr_if_list), if_next) { - struct ifinfomsg *ifm = NLMSG_DATA(n); - int len = n->nlmsg_len; - struct rtattr *tb[IFLA_MAX + 1] = {0}; + if (strcmp(mbr_if->name, ifname) == 0) + return mbr_if; + } + + return NULL; +} - if (n->nlmsg_type != RTM_NEWLINK) +//add specific vlan id to pending vlan membership interface +int add_pending_vlan_mbr(struct PendingVlanMbrIf* mbr_if, uint16_t vid) +{ + struct VLAN_ID *vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; + char vlan_name[16] = ""; + if (!mbr_if) + { + return MCLAG_ERROR; + } + + sprintf(vlan_name, "Vlan%d", vid); + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + + vlan = RB_FIND(vlan_rb_tree, &(mbr_if->vlan_tree), &vlan_key); + + if (!vlan) + { + vlan = (struct VLAN_ID*)malloc(sizeof(struct VLAN_ID)); + if (!vlan) { - return; + ICCPD_LOG_WARN(__FUNCTION__, "Add Pending Vlan Member for If:%s Vlan:%d creation, malloc failed", mbr_if->name, vid); + return MCLAG_ERROR; } - len -= NLMSG_LENGTH(sizeof(*ifm)); - if (len < 0) + memset(vlan, 0, sizeof(struct VLAN_ID)); + vlan->vid = vid; + + ICCPD_LOG_DEBUG(__FUNCTION__, "Add VLAN %d to pending vlan member if:%s ", vid, mbr_if->name); + RB_INSERT(vlan_rb_tree, &(mbr_if->vlan_tree), vlan); + } + return 0; +} + +//delete specific vlan id from pending vlan membership interface +void del_pending_vlan_mbr(struct PendingVlanMbrIf* mbr_if, uint16_t vid) +{ + struct VLAN_ID *vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; + if (!mbr_if) + { + return; + } + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + + vlan = RB_FIND(vlan_rb_tree, &(mbr_if->vlan_tree), &vlan_key); + + if (vlan != NULL) + { + VLAN_RB_REMOVE(vlan_rb_tree, &(mbr_if->vlan_tree), vlan); + free(vlan); + ICCPD_LOG_DEBUG(__FUNCTION__, "Remove VLAN %d from pending vlan mbr If:%s ",vid, mbr_if->name); + } + return; +} + + +//delete all pending vlan members for a given vlan member interface +void del_all_pending_vlan_mbrs(struct PendingVlanMbrIf* lif) +{ + struct VLAN_ID* vlan = NULL; + struct VLAN_ID* vlan_temp = NULL; + + ICCPD_LOG_DEBUG(__FUNCTION__, "Remove all Pending VLANs from %s", lif->name); + RB_FOREACH_SAFE(vlan, vlan_rb_tree, &(lif->vlan_tree), vlan_temp) + { + VLAN_RB_REMOVE(vlan_rb_tree, &(lif->vlan_tree), vlan); + free(vlan); + } + return; +} + +//update vlan membership for a given interface; this function can be called +//whenever vlan membership is received from mclagsyncd and local interface is not found +void update_pending_vlan_mbr(char *mbr_if_name, unsigned int vlan_id, int add_flag) +{ + struct System *sys = NULL; + struct PendingVlanMbrIf *mbr_if; + struct VLAN_ID* vlan = NULL; + struct VLAN_ID* vlan_temp = NULL; + + if (!(sys = system_get_instance())) + { + return; + } + + ICCPD_LOG_DEBUG(__FUNCTION__, "update pending vlan:%d member for if:%s event:%s \n", vlan_id, mbr_if_name, add_flag ? "add":"delete"); + mbr_if = find_pending_vlan_mbr_if(sys, mbr_if_name); + //if mbr_if not found create + if (!mbr_if) + { + if (!add_flag) { - ICCPD_LOG_WARN(__FUNCTION__, "BUG: wrong nlmsg len %d\n", len); return; } - if (ifm->ifi_family != AF_BRIDGE) + ICCPD_LOG_DEBUG(__FUNCTION__, "Create pending vlan member if %s \n", mbr_if_name); + if (!(mbr_if = (struct PendingVlanMbrIf *)malloc(sizeof(struct PendingVlanMbrIf)))) { + ICCPD_LOG_WARN(__FUNCTION__, "Pending Vlan Member If:%s creation, malloc failed", mbr_if_name); return; } + snprintf(mbr_if->name, MAX_L_PORT_NAME, "%s", mbr_if_name); + RB_INIT(vlan_rb_tree, &mbr_if->vlan_tree); + LIST_INSERT_HEAD(&(sys->pending_vlan_mbr_if_list), mbr_if, if_next); + } + if (add_flag) + { + //add to pending vlan member if + add_pending_vlan_mbr(mbr_if, vlan_id); + } + else + { + //delete from pending vlan member if + del_pending_vlan_mbr(mbr_if, vlan_id); + } +} - if ((lif = local_if_find_by_ifindex(ifm->ifi_index)) != NULL) - { - parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); - /* if AF_SPEC isn't there, vlan table is not preset for this port */ - if (!tb[IFLA_AF_SPEC]) - { - ICCPD_LOG_WARN(__FUNCTION__, "Vlan table is not preset for %d", ifm->ifi_index); - return; - } - else - { - struct rtattr *i, *list = tb[IFLA_AF_SPEC]; - int rem = RTA_PAYLOAD(list); - struct VLAN_ID *vlan = NULL; - - /*set vlan flag is removed*/ - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) - { - vlan->vlan_removed = 1; - } +//move pending vlan membership from pending member interface to system lif +void move_pending_vlan_mbr_to_lif(struct System *sys, struct LocalInterface* lif) +{ + struct PendingVlanMbrIf *mbr_if; + struct VLAN_ID* vlan = NULL; + struct VLAN_ID* vlan_temp = NULL; + if (!sys || !lif) + { + return; + } + ICCPD_LOG_NOTICE(__FUNCTION__, "Move pending vlan members for %s, %d\n", lif->name, lif->ifindex); + mbr_if = find_pending_vlan_mbr_if(sys, lif->name); + if (!mbr_if) + { + ICCPD_LOG_INFO(__FUNCTION__, "No pending vlan members for %s, %d\n", lif->name, lif->ifindex); + return; + } - for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) - { - struct bridge_vlan_info *vinfo; + RB_FOREACH_SAFE(vlan, vlan_rb_tree, &(mbr_if->vlan_tree), vlan_temp) + { + //add vlan to system lif + local_if_add_vlan(lif, vlan->vid); - if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) - continue; + //delete from pending vlan member if + del_pending_vlan_mbr(mbr_if, vlan->vid); + } - vinfo = RTA_DATA(i); + ICCPD_LOG_DEBUG(__FUNCTION__, "Delete pending vlan member if %s \n", lif->name); + LIST_REMOVE(mbr_if, if_next); + free(mbr_if); - local_if_add_vlan(lif, vinfo->vid); - } +} - /*After update vlan list, remove unused item*/ - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) - { - if (vlan->vlan_removed == 1) - { - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", lif->name, vlan->vid); +//remove all pending vlan member interface and vlan memberships +void del_all_pending_vlan_mbr_ifs(struct System *sys) +{ + struct PendingVlanMbrIf *pending_vlan_mbr_if = NULL; - LIST_REMOVE(vlan, port_next); - free(vlan); - } - } + ICCPD_LOG_NOTICE(__FUNCTION__, "Delete all pending vlan members \n"); + + while (!LIST_EMPTY(&(sys->pending_vlan_mbr_if_list))) + { + pending_vlan_mbr_if = LIST_FIRST(&(sys->pending_vlan_mbr_if_list)); + LIST_REMOVE(pending_vlan_mbr_if, if_next); + del_all_pending_vlan_mbrs(pending_vlan_mbr_if); + free(pending_vlan_mbr_if); + } +} + +void vlan_mbrship_change_handler(unsigned int vlan_id, char *mbr_if_name, int add_flag) +{ + struct LocalInterface *lif = NULL; + struct LocalInterface *vlan_lif = NULL; + char vlan_name[16] = ""; + + lif = local_if_find_by_name(mbr_if_name); + if (!lif) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "Rx vlan:%d mbr if:%s event %s; No MCLAG If", vlan_id, mbr_if_name, add_flag ? "add":"delete"); + update_pending_vlan_mbr(mbr_if_name, vlan_id, add_flag); + return; + } + ICCPD_LOG_DEBUG(__FUNCTION__, "Rx vlan:%d mbr if:%s event %s", vlan_id, mbr_if_name, add_flag ? "add":"delete"); + + if (add_flag) //vlan membership got added + { + sprintf(vlan_name, "Vlan%d", vlan_id); + vlan_lif = local_if_find_by_name(vlan_name); + if (!vlan_lif) { + ICCPD_LOG_NOTICE(__FUNCTION__, "%s LIF not present", vlan_name); + vlan_lif = local_if_create( -1, vlan_name, IF_T_VLAN, IF_OPER_DOWN); + if (vlan_lif) { + ICCPD_LOG_NOTICE(__FUNCTION__, "%s LIF created with ifindex -1", vlan_name); } } - n = NLMSG_NEXT(n, msglen); + local_if_add_vlan(lif, vlan_id); } + else //vlan membership got deleted + { + local_if_del_vlan(lif, vlan_id); + } + return; } diff --git a/src/iccpd/src/iccp_main.c b/src/iccpd/src/iccp_main.c index 86920f07e1fb..fe3594583a51 100644 --- a/src/iccpd/src/iccp_main.c +++ b/src/iccpd/src/iccp_main.c @@ -134,6 +134,7 @@ void iccpd_signal_handler(int sig) if (err == -1 && errno == EINTR) goto retry; + SYSTEM_INCR_WARMBOOT_COUNTER(sys); return; } diff --git a/src/iccpd/src/iccp_netlink.c b/src/iccpd/src/iccp_netlink.c index 002c254ae9c1..1143f370ffc5 100644 --- a/src/iccpd/src/iccp_netlink.c +++ b/src/iccpd/src/iccp_netlink.c @@ -35,10 +35,9 @@ #include #include #include -#include -#include #include #include +#include #include #include @@ -57,6 +56,8 @@ #include "../include/mlacp_link_handler.h" #include "../include/msg_format.h" #include "../include/iccp_netlink.h" +#include "../include/mlacp_sync_update.h" +#include "../include/mlacp_tlv.h" /** * SECTION: Netlink helpers @@ -72,6 +73,9 @@ #define NETLINK_BROADCAST_SEND_ERROR 0x4 #endif +/* Use the same socket buffer size as in SwSS common */ +#define NETLINK_SOCKET_BUFFER_SIZE 16777216 + static int iccp_ack_handler(struct nl_msg *msg, void *arg) { bool *acked = arg; @@ -141,7 +145,7 @@ int iccp_send_and_recv(struct System *sys, struct nl_msg *msg, } err = 0; - put_cb: +put_cb: nl_cb_put(cb); return err; } @@ -416,7 +420,7 @@ int iccp_get_port_member_list(struct LocalInterface* lif) int iccp_netlink_if_hwaddr_set(uint32_t ifindex, uint8_t *addr, unsigned int addr_len) { struct rtnl_link *link; - int err; + int err = 0; struct nl_addr *nl_addr; struct System* sys = NULL; @@ -441,8 +445,10 @@ int iccp_netlink_if_hwaddr_set(uint32_t ifindex, uint8_t *addr, unsigned int add nl_addr_put(nl_addr); - errout: +errout: rtnl_link_put(link); + ICCPD_LOG_NOTICE(__FUNCTION__, "ifindex %x, mac %02x:%02x:%02x:%02x:%02x:%02x, err %d", + ifindex, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], err); return err; } @@ -489,7 +495,7 @@ void iccp_set_interface_ipadd_mac(struct LocalInterface *lif, char * mac_addr ) dst_len = strlen(mac_addr); memcpy(sub_msg->data, mac_addr, dst_len); - ICCPD_LOG_NOTICE(__FUNCTION__, "If name %s ip %s mac %s", lif->name, show_ip_str(htonl(lif->ipv4_addr)), sub_msg->data); + ICCPD_LOG_NOTICE(__FUNCTION__, "If name %s ip %s mac %s", lif->name, show_ip_str(lif->ipv4_addr), sub_msg->data); sub_msg->op_len = dst_len; msg_hdr->len += sizeof(mclag_sub_option_hdr_t); @@ -497,8 +503,18 @@ void iccp_set_interface_ipadd_mac(struct LocalInterface *lif, char * mac_addr ) /*send msg*/ if (sys->sync_fd) - write(sys->sync_fd, msg_buf, msg_hdr->len); - + { + if (write(sys->sync_fd,msg_buf, msg_hdr->len) == -1) + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_ERR); + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + } + } return; } @@ -547,7 +563,67 @@ int iccp_netlink_if_shutdown_set(uint32_t ifindex) rtnl_link_put(link); return err; } -void update_if_ipmac_on_standby(struct LocalInterface* lif_po) + +//Set IFF up flag for all member ports of a port-channel +static int iccp_netlink_set_portchannel_iff_flag( + struct LocalInterface* lif_po, + bool is_iff_up, + int location) +{ + int rv, ret_rv = 0; + char* token; + struct LocalInterface* member_if; + char *tmp_member_buf = NULL; + + if (!lif_po) + return MCLAG_ERROR; + + tmp_member_buf = strdup(lif_po->portchannel_member_buf); + if (!tmp_member_buf) + { + ICCPD_LOG_ERR(__FUNCTION__, "Fail to allocate memory to bring %s %s", + is_iff_up ? "up" : "down", lif_po->name); + return MCLAG_ERROR; + } + else + { + ICCPD_LOG_NOTICE(__FUNCTION__, "Bring %s %s, members %s", + is_iff_up ? "up" : "down", lif_po->name, + lif_po->portchannel_member_buf); + } + /* Port-channel members are stored as comma separated strings */ + token = strtok(tmp_member_buf, ","); + while (token != NULL) + { + member_if = local_if_find_by_name(token); + if (member_if) + { + if (is_iff_up) + rv = iccp_netlink_if_startup_set(member_if->ifindex); + else + rv = iccp_netlink_if_shutdown_set(member_if->ifindex); + if (rv != 0) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Set %s:%s, if_up(%d), location(%d) failed, rv %d", + lif_po->name, member_if->name, is_iff_up, location, rv); + ret_rv = rv; + } + } + else + { + ICCPD_LOG_ERR(__FUNCTION__, + "Can't find member %s:%s, if_up(%d), location %d", + lif_po->name, token, is_iff_up, location); + } + token = strtok(NULL, ","); + } + if (tmp_member_buf) + free(tmp_member_buf); + return ret_rv; +} + +void update_if_ipmac_on_standby(struct LocalInterface* lif_po, int dir) { struct CSM* csm; uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -557,6 +633,7 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) struct LocalInterface* lif_Bri; char macaddr[64]; int ret = 0; + struct PeerInterface* pif = NULL; if (!csm) return; @@ -572,17 +649,22 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) if (memcmp(MLACP(csm).remote_system.system_id, null_mac, ETHER_ADDR_LEN) == 0) return; - /*Set new mac*/ - if (memcmp( lif_po->mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN) != 0) + pif = peer_if_find_by_name(csm, lif_po->name); + + /*Set new mac only if remote MLAG interface also exists */ + if (pif && (memcmp( lif_po->mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN) != 0)) { /*Backup old sysmac*/ memcpy(lif_po->mac_addr_ori, lif_po->mac_addr, ETHER_ADDR_LEN); ICCPD_LOG_NOTICE(__FUNCTION__, - "%s Change the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X].", + "%s Change the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X], dir %d", (csm->role_type == STP_ROLE_STANDBY) ? "Standby" : "Active", - lif_po->name, lif_po->mac_addr[0], lif_po->mac_addr[1], lif_po->mac_addr[2], lif_po->mac_addr[3], lif_po->mac_addr[4], lif_po->mac_addr[5], - MLACP(csm).remote_system.system_id[0], MLACP(csm).remote_system.system_id[1], MLACP(csm).remote_system.system_id[2], MLACP(csm).remote_system.system_id[3], MLACP(csm).remote_system.system_id[4], MLACP(csm).remote_system.system_id[5]); + lif_po->name, lif_po->mac_addr[0], lif_po->mac_addr[1], lif_po->mac_addr[2], + lif_po->mac_addr[3], lif_po->mac_addr[4], lif_po->mac_addr[5], + MLACP(csm).remote_system.system_id[0], MLACP(csm).remote_system.system_id[1], + MLACP(csm).remote_system.system_id[2], MLACP(csm).remote_system.system_id[3], + MLACP(csm).remote_system.system_id[4], MLACP(csm).remote_system.system_id[5], dir); ret = iccp_netlink_if_hwaddr_set(lif_po->ifindex, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); if (ret != 0) @@ -602,13 +684,13 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) { if (memcmp(lif_po->l3_mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN) != 0) { - iccp_set_interface_ipadd_mac(lif_po, macaddr ); + iccp_set_interface_ipadd_mac(lif_po, macaddr); memcpy(lif_po->l3_mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); } } else { - LIST_FOREACH(vlan, &(lif_po->vlan_list), port_next) + RB_FOREACH(vlan, vlan_rb_tree, &(lif_po->vlan_tree)) { if (!vlan->vlan_itf) continue; @@ -616,12 +698,25 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) /*If the po is under a vlan, update vlan mac*/ if (local_if_is_l3_mode(vlan->vlan_itf)) { - if (memcmp(vlan->vlan_itf->l3_mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN) != 0) + + ICCPD_LOG_NOTICE(__FUNCTION__, + "%s Change the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X], proto %d, dir %d", + (csm->role_type == STP_ROLE_STANDBY) ? "Standby" : "Active", + vlan->vlan_itf->name, vlan->vlan_itf->l3_mac_addr[0], vlan->vlan_itf->l3_mac_addr[1], + vlan->vlan_itf->l3_mac_addr[2], vlan->vlan_itf->l3_mac_addr[3], + vlan->vlan_itf->l3_mac_addr[4], vlan->vlan_itf->l3_mac_addr[5], + MLACP(csm).remote_system.system_id[0], MLACP(csm).remote_system.system_id[1], + MLACP(csm).remote_system.system_id[2], MLACP(csm).remote_system.system_id[3], + MLACP(csm).remote_system.system_id[4], MLACP(csm).remote_system.system_id[5], + vlan->vlan_itf->is_l3_proto_enabled, dir); + + if ((memcmp(vlan->vlan_itf->l3_mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN) != 0) + && (vlan->vlan_itf->is_l3_proto_enabled == false)) { - ret = iccp_netlink_if_hwaddr_set(vlan->vlan_itf->ifindex, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); + ret = iccp_netlink_if_hwaddr_set(vlan->vlan_itf->ifindex, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); if (ret != 0) { - ICCPD_LOG_ERR(__FUNCTION__, "Set %s mac error, ret = %d", vlan->vlan_itf->name, ret); + ICCPD_LOG_NOTICE(__FUNCTION__, "Set %s mac error, ret = %d, dir %d", vlan->vlan_itf->name, ret, dir); } /* Refresh link local address according the new MAC */ @@ -631,6 +726,8 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) iccp_set_interface_ipadd_mac(vlan->vlan_itf, macaddr); memcpy(vlan->vlan_itf->l3_mac_addr, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); } + } else { + ICCPD_LOG_NOTICE(__FUNCTION__, "%s not L3 interface, dir %d", vlan->vlan_itf->name, dir); } } } @@ -638,9 +735,9 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) return; } -void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) +void recover_if_ipmac_on_standby(struct LocalInterface *lif_po, int dir) { - struct CSM* csm; + struct CSM *csm; uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct VLAN_ID *vlan = NULL; @@ -663,20 +760,27 @@ void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) if (memcmp( lif_po->mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN) != 0) { ICCPD_LOG_NOTICE(__FUNCTION__, - "%s Recover the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X].", + "%s Recover the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X], dir %d", (csm->role_type == STP_ROLE_STANDBY) ? "Standby" : "Active", - lif_po->name, lif_po->mac_addr[0], lif_po->mac_addr[1], lif_po->mac_addr[2], lif_po->mac_addr[3], lif_po->mac_addr[4], lif_po->mac_addr[5], - MLACP(csm).system_id[0], MLACP(csm).system_id[1], MLACP(csm).system_id[2], MLACP(csm).system_id[3], MLACP(csm).system_id[4], MLACP(csm).system_id[5]); + lif_po->name, lif_po->mac_addr[0], lif_po->mac_addr[1], lif_po->mac_addr[2], + lif_po->mac_addr[3], lif_po->mac_addr[4], lif_po->mac_addr[5], + MLACP(csm).system_id[0], MLACP(csm).system_id[1], MLACP(csm).system_id[2], + MLACP(csm).system_id[3], MLACP(csm).system_id[4], MLACP(csm).system_id[5], dir); ret = iccp_netlink_if_hwaddr_set(lif_po->ifindex, MLACP(csm).system_id, ETHER_ADDR_LEN); if (ret != 0) { - ICCPD_LOG_ERR(__FUNCTION__, "Set %s mac error, ret = %d", lif_po->name, ret); + ICCPD_LOG_NOTICE(__FUNCTION__, "Set %s mac error, ret = %d, dir %d", lif_po->name, ret, dir); } /* Refresh link local address according the new MAC */ iccp_netlink_if_shutdown_set(lif_po->ifindex); iccp_netlink_if_startup_set(lif_po->ifindex); + /* Set the interface MAC address back to its local address so that subsequent vlan member + * add processing (local_if_add_vlan) will not use the old MAC address for + * update_if_ipmac_on_standby() + */ + memcpy(lif_po->mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN); } /*Set portchannel ip mac */ @@ -684,23 +788,25 @@ void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) SET_MAC_STR(macaddr, MLACP(csm).system_id); if (local_if_is_l3_mode(lif_po)) { - iccp_set_interface_ipadd_mac(lif_po, macaddr ); + iccp_set_interface_ipadd_mac(lif_po, macaddr); memcpy(lif_po->l3_mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN); } else { - LIST_FOREACH(vlan, &(lif_po->vlan_list), port_next) + RB_FOREACH(vlan, vlan_rb_tree, &(lif_po->vlan_tree)) { if (!vlan->vlan_itf) continue; /*If the po is under a vlan, update vlan mac*/ - if (local_if_is_l3_mode(vlan->vlan_itf)) + if (local_if_is_l3_mode(vlan->vlan_itf) && (vlan->vlan_itf->is_l3_proto_enabled == false)) { - ret = iccp_netlink_if_hwaddr_set(vlan->vlan_itf->ifindex, MLACP(csm).system_id, ETHER_ADDR_LEN); + ret = iccp_netlink_if_hwaddr_set(vlan->vlan_itf->ifindex, MLACP(csm).system_id, ETHER_ADDR_LEN); if (ret != 0) { - ICCPD_LOG_ERR(__FUNCTION__, "Set %s mac error, ret = %d", vlan->vlan_itf->name, ret); + if (ret != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Set %s mac error, ret = %d", vlan->vlan_itf->name, ret); + } } /* Refresh link local address according the new MAC */ @@ -709,6 +815,9 @@ void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) iccp_set_interface_ipadd_mac(vlan->vlan_itf, macaddr); memcpy(vlan->vlan_itf->l3_mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN); + } else { + ICCPD_LOG_NOTICE(__FUNCTION__, "%s not L3 interface, proto %d, dir %d", + vlan->vlan_itf->name, vlan->vlan_itf->is_l3_proto_enabled, dir); } } } @@ -716,7 +825,7 @@ void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) return; } -int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *mac, char *portname) +int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *mac, char *portname, int permanent, int dir) { struct System *sys = NULL; struct rtnl_neigh *neigh = NULL; @@ -728,29 +837,29 @@ int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *m int err = 0; if (!(sys = system_get_instance())) - return MCLAG_ERROR; + return -2; lif = local_if_find_by_name(portname); if (!lif) - return MCLAG_ERROR; + return -3; neigh = rtnl_neigh_alloc(); if (!neigh) { ICCPD_LOG_INFO(__FUNCTION__, "Unable to allocate neighbour object"); - return MCLAG_ERROR; + return -4; } sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - ICCPD_LOG_NOTICE(__FUNCTION__, "Notify kernel %s %s entry(ip:%s, mac:%s, intf:%s)", + ICCPD_LOG_DEBUG(__FUNCTION__, "notify kernel %s %s entry(ip:%s, mac:%s, intf:%s), dir %d", add ? "add" : "del", (family == AF_INET) ? "ARP" : "ND", - (family == AF_INET) ? show_ip_str(*((int *)addr)) : show_ipv6_str(addr), mac_str, portname); + (family == AF_INET) ? show_ip_str(*((int *)addr)) : show_ipv6_str(addr), mac_str, portname, dir); nl_addr_mac = nl_addr_build(AF_LLC, (void *)mac, ETHER_ADDR_LEN); if (!nl_addr_mac) { - err = MCLAG_ERROR; + err = -5; goto errout; } @@ -761,26 +870,29 @@ int iccp_netlink_neighbor_request(int family, uint8_t *addr, int add, uint8_t *m if (!nl_addr_dst) { - err = MCLAG_ERROR; + err = -6; goto errout; } rtnl_neigh_set_lladdr(neigh, nl_addr_mac); rtnl_neigh_set_dst(neigh, nl_addr_dst); rtnl_neigh_set_ifindex(neigh, lif->ifindex); - rtnl_neigh_set_state(neigh, NUD_REACHABLE); + if (permanent) { + rtnl_neigh_set_state(neigh, NUD_PERMANENT|NUD_NOARP); + rtnl_neigh_set_flags(neigh, NTF_EXT_LEARNED); + } else { + rtnl_neigh_set_state(neigh, NUD_REACHABLE); + } if (add) { if ((err = rtnl_neigh_add(sys->route_sock, neigh, NLM_F_REPLACE | NLM_F_CREATE)) < 0) - ICCPD_LOG_WARN(__FUNCTION__, "Add %s (ip:%s, mac:%s) error, err = %d", (family == AF_INET) ? "ARP" : "ND", - (family == AF_INET) ? show_ip_str(*((int *)addr)) : show_ipv6_str(addr), mac_str, err); + ICCPD_LOG_DEBUG(__FUNCTION__, "add neigh error, err = %d", err); } else { if ((err = rtnl_neigh_delete(sys->route_sock, neigh, 0)) < 0) - ICCPD_LOG_WARN(__FUNCTION__, "Del %s (ip:%s, mac:%s) error, err = %d", (family == AF_INET) ? "ARP" : "ND", - (family == AF_INET) ? show_ip_str(*((int *)addr)) : show_ipv6_str(addr), mac_str, err); + ICCPD_LOG_DEBUG(__FUNCTION__, "del neigh error, err = %d", err); } errout: @@ -794,13 +906,15 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) { struct rtnl_link *link; unsigned int *event = arg; - uint32_t ifindex; + uint32_t ifindex = 0; char * ifname, *p; struct LocalInterface *lif = NULL; struct nl_addr *nl_addr; int addr_type = 0; int op_state = 0; int link_flag = 0; + uint32_t master_ifindex = 0; + char addr_null[16] = { 0 }; link = (struct rtnl_link *)obj; ifindex = rtnl_link_get_ifindex(link); @@ -808,6 +922,12 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) ifname = rtnl_link_get_name(link); nl_addr = rtnl_link_get_addr(link); link_flag = rtnl_link_get_flags(link); + master_ifindex = rtnl_link_get_master(link); + + if (ifindex < 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, "invalid ifindex %d", ifindex); + return; + } if (nl_addr) addr_type = nl_addr_guess_family(nl_addr); @@ -825,15 +945,33 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) lif = local_if_find_by_name(ifname); if (!lif) { - lif = local_if_create(ifindex, ifname, IF_T_VXLAN); + lif = local_if_create(ifindex, ifname, IF_T_VXLAN, + (op_state == IF_OPER_UP) ? PORT_STATE_UP : PORT_STATE_DOWN); lif->state = PORT_STATE_UP; } return; } else - lif = local_if_find_by_ifindex(ifindex); + { + lif = local_if_find_by_name(ifname); + } - if (!lif) + if (lif && (lif->ifindex == -1) && (lif->type == IF_T_VLAN)) + { + lif->ifindex = ifindex; + lif->state = (op_state == IF_OPER_UP) ? PORT_STATE_UP : PORT_STATE_DOWN; + + if (addr_type == AF_LLC) + { + memcpy( lif->mac_addr, nl_addr_get_binary_addr(nl_addr), ETHER_ADDR_LEN); + } + + ICCPD_LOG_NOTICE(__FUNCTION__, + "Update Vlan local_if = %s ifindex = %d MAC = %02x:%02x:%02x:%02x:%02x:%02x, state = %s", + ifname, lif->ifindex, lif->mac_addr[0], lif->mac_addr[1], lif->mac_addr[2], + lif->mac_addr[3], lif->mac_addr[4], lif->mac_addr[5], lif->state ? "down" : "up"); + } + else if (!lif || lif->ifindex != ifindex) { const itf_type_t if_whitelist[] = { { PORTCHANNEL_PREFIX, IF_T_PORT_CHANNEL }, @@ -849,15 +987,36 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) if ((strncmp(ifname, if_whitelist[i].ifname, strlen(if_whitelist[i].ifname)) == 0)) { - lif = local_if_create(ifindex, ifname, if_whitelist[i].type); - - lif->state = PORT_STATE_DOWN; - - if (IF_OPER_UP == op_state ) + + /*if the iface exists, but the ifindex changed, then delete old + * interface and add the new interface + * possible scenario is due to many kernel events, there is + * possiblility of losing if deletion event and just + * getting a add of same iface with new ifindex. + * to address this possibility if add event of interface is + * received with new ifindex different from old interace, + * then delete the old ifindex interface and add new if with new + * ifindex + */ + if (lif && lif->ifindex != ifindex) { - lif->state = PORT_STATE_UP; + ICCPD_LOG_NOTICE(__FUNCTION__, "%s ifindex changed from old ifindex:%d to new ifindex:%d ", ifname, lif->ifindex, ifindex); + if ((strncmp(ifname, FRONT_PANEL_PORT_PREFIX, strlen(FRONT_PANEL_PORT_PREFIX)) == 0)) + { + ICCPD_LOG_ERR(__FUNCTION__, "Front panel port %s ifindex changed !!! from old ifindex:%d to new ifindex:%d ", ifname, lif->ifindex, ifindex); + } + local_if_destroy(lif->name); } + /* Provide state info when local_if is created so that po_active + * flag can be set correctly instead of assuming it is always + * active. This helps address the issue where MLAG interface + * up update to remote MLAG peer is not sent if port-channel + * is configured as MLAG interface when it is down + */ + lif = local_if_create(ifindex, ifname, if_whitelist[i].type, + (op_state == IF_OPER_UP) ? PORT_STATE_UP : PORT_STATE_DOWN); + switch (addr_type) { case AF_LLC: @@ -865,28 +1024,45 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) default: break; } - break; } } + if (if_whitelist[i].ifname == NULL) + { + SYSTEM_INCR_NETLINK_UNKNOWN_IF_NAME(ifname); + } } else /*update*/ { /*update*/ - if (lif->state == PORT_STATE_DOWN && op_state == IF_OPER_UP) + if (lif->state == PORT_STATE_DOWN && (link_flag & IFF_LOWER_UP)) { lif->state = PORT_STATE_UP; /*if(lif->type ==IF_T_PORT_CHANNEL)*/ ICCPD_LOG_NOTICE(__FUNCTION__, "Update local port %s state up", ifname); + /* If local interface is not configured as MLAG interface yet, + * its po_active status must be updated. Otherwise, incorrect + * status will be used to determine the traffic_disable setting + */ + if ((lif->type == IF_T_PORT_CHANNEL) && (lif->csm == NULL)) + lif->po_active = 1; + iccp_from_netlink_port_state_handler(lif->name, lif->state); } - else if (lif->state == PORT_STATE_UP && ( IF_OPER_UP != op_state || !(link_flag & IFF_LOWER_UP))) + else if (lif->state == PORT_STATE_UP && ( !(link_flag & IFF_LOWER_UP))) { lif->state = PORT_STATE_DOWN; /*if(lif->type ==IF_T_PORT_CHANNEL)*/ ICCPD_LOG_NOTICE(__FUNCTION__, "Update local port %s state down", ifname); + /* If local interface is not configured as MLAG interface yet, + * its po_active status must be updated. Otherwise, incorrect + * status will be used to determine the traffic_disable setting + */ + if ((lif->type == IF_T_PORT_CHANNEL) && (lif->csm == NULL)) + lif->po_active = 0; + iccp_from_netlink_port_state_handler(lif->name, lif->state); } @@ -902,6 +1078,26 @@ void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg) default: break; } + + if ((lif->type == IF_T_VLAN) && (lif->master_ifindex != master_ifindex)) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "master idx %d - %d, l3_proto %d", + lif->master_ifindex, master_ifindex, lif->is_l3_proto_enabled); + if (master_ifindex) { + lif->master_ifindex = master_ifindex; + lif->l3_mode = 1; + update_vlan_if_mac_on_standby(lif, 5); + } else { + if ((lif->ipv4_addr == 0) && (memcmp(lif->ipv6_addr, addr_null, 16) == 0)) { + if (lif->is_l3_proto_enabled == false) { + recover_vlan_if_mac_on_standby(lif, 5, NULL); + } + lif->l3_mode = 0; + memset(lif->l3_mac_addr, 0, ETHER_ADDR_LEN); + } + lif->master_ifindex = 0; + } + } } return; @@ -922,103 +1118,6 @@ void iccp_event_handler_obj_input_dellink(struct nl_object *obj, void *arg) return; } -void iccp_event_handler_obj_input_newaddr(struct nl_object *obj, void *arg) -{ - struct rtnl_addr *addr; - struct nl_addr *nl_addr; - struct LocalInterface *lif; - uint32_t ifindex; - char addrStr[65] = { 0 }; - char addr_null[16] = { 0 }; - addr = (struct rtnl_addr *)obj; - - ifindex = rtnl_addr_get_ifindex(addr); - nl_addr = rtnl_addr_get_local(addr); - - if (!(lif = local_if_find_by_ifindex(ifindex))) - return; - - if (rtnl_addr_get_family(addr) == AF_INET) - { - lif->ipv4_addr = *(uint32_t *) nl_addr_get_binary_addr(nl_addr); - lif->prefixlen = nl_addr_get_prefixlen(nl_addr); - lif->l3_mode = 1; - lif->port_config_sync = 1; - if (memcmp((char *)lif->ipv6_addr, addr_null, 16) == 0) - update_if_ipmac_on_standby(lif); - ICCPD_LOG_DEBUG(__FUNCTION__, "Ifname %s index %d address %s", lif->name, lif->ifindex, show_ip_str(lif->ipv4_addr)); - } - else if (rtnl_addr_get_family(addr) == AF_INET6) - { - if (memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "FE80", 4) == 0 - || memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "fe80", 4) == 0) - return; - - memcpy((char *)lif->ipv6_addr, nl_addr_get_binary_addr(nl_addr), 16); - lif->prefixlen = nl_addr_get_prefixlen(nl_addr); - lif->l3_mode = 1; - lif->port_config_sync = 1; - if (lif->ipv4_addr == 0) - update_if_ipmac_on_standby(lif); - ICCPD_LOG_DEBUG(__FUNCTION__, "Ifname %s index %d address %s", lif->name, lif->ifindex, show_ipv6_str((char *)lif->ipv6_addr)); - } - - return; -} - -void iccp_event_handler_obj_input_deladdr(struct nl_object *obj, void *arg) -{ - struct rtnl_addr *addr; - struct nl_addr *nl_addr; - struct LocalInterface *lif; - uint32_t ifindex; - char addr_null[16] = { 0 }; - - addr = (struct rtnl_addr *)obj; - - ifindex = rtnl_addr_get_ifindex(addr); - nl_addr = rtnl_addr_get_local(addr); - - if (!(lif = local_if_find_by_ifindex(ifindex))) - return; - - if (rtnl_addr_get_family(addr) == AF_INET) - { - lif->ipv4_addr = 0; - lif->prefixlen = 0; - } - else if (rtnl_addr_get_family(addr) == AF_INET6) - { - if (memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "FE80", 4) == 0 - || memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "fe80", 4) == 0) - return; - - memset((char *)lif->ipv6_addr, 0, 16); - lif->prefixlen_v6 = 0; - } - - if (lif->ipv4_addr == 0 && memcmp((char *)lif->ipv6_addr, addr_null, 16) == 0) - { - lif->l3_mode = 0; - memset(lif->l3_mac_addr, 0, ETHER_ADDR_LEN); - } - - return; -} - -int iccp_addr_valid_handler(struct nl_msg *msg, void *arg) -{ - struct nlmsghdr *nlh = nlmsg_hdr(msg); - unsigned int event = 0; - if (nlh->nlmsg_type != RTM_NEWADDR) - return 0; - - if (nl_msg_parse(msg, &iccp_event_handler_obj_input_newaddr, &event) < 0) - ICCPD_LOG_ERR(__FUNCTION__, "Unknown message type."); - - return 0; -} - int iccp_check_if_addr_from_netlink(int family, uint8_t *addr, struct LocalInterface *lif) { struct @@ -1123,6 +1222,268 @@ int iccp_check_if_addr_from_netlink(int family, uint8_t *addr, struct LocalInter return 0; } +int iccp_del_self_ip_from_neigh_table (struct LocalInterface *lif, int addr_family) +{ + struct System *sys = NULL; + struct CSM *csm = NULL; + struct Msg *msg = NULL; + struct ARPMsg *arp_msg = NULL, *arp_info = NULL; + struct NDISCMsg *ndisc_msg = NULL, *ndisc_info = NULL; + int err = 0; + + if (!(sys = system_get_instance())) + { + return -1; + } + + if (addr_family == AF_INET) { + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail) + { + arp_info = (struct ARPMsg *)msg->buf; + if (arp_info->ipv4_addr == lif->ipv4_addr) { + ICCPD_LOG_NOTICE(__FUNCTION__, " Delete ARP %s", show_ip_str(lif->ipv4_addr)); + break; + } + } + + if (msg) + { + TAILQ_REMOVE(&(MLACP(csm).arp_list), msg, tail); + free(msg->buf); + free(msg); + msg = NULL; + break; + } + } + } else if (addr_family == AF_INET6) { + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + TAILQ_FOREACH(msg, &MLACP(csm).ndisc_list, tail) + { + ndisc_info = (struct NDISCMsg *)msg->buf; + + if (memcmp(&ndisc_info->ipv6_addr, &lif->ipv6_addr, 16) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, " Delete neighbor %s", show_ipv6_str((char *)lif->ipv6_addr)); + break; + } + } + + if (msg) + { + TAILQ_REMOVE(&MLACP(csm).ndisc_list, msg, tail); + free(msg->buf); + free(msg); + msg = NULL; + break; + } + } + } + + return 0; +} + +void iccp_event_handler_obj_input_newaddr(struct nl_object *obj, void *arg) +{ + struct rtnl_addr *addr; + struct nl_addr *nl_addr; + struct LocalInterface *lif; + uint32_t ifindex; + char addrStr[65] = { 0 }; + char addr_null[16] = { 0 }; + addr = (struct rtnl_addr *)obj; + int sync_add = 1, is_v4 = 0, is_v6 = 0, sync_mac = 0; + + ifindex = rtnl_addr_get_ifindex(addr); + nl_addr = rtnl_addr_get_local(addr); + + if (!(lif = local_if_find_by_ifindex(ifindex))) + return; + + if (rtnl_addr_get_family(addr) == AF_INET) + { + if (lif->ipv4_addr != 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Ignore Multiple IP Add on ifname %s index %d present address %s l3_proto %d\n", + lif->name, lif->ifindex, show_ip_str(lif->ipv4_addr), lif->is_l3_proto_enabled); + return; + } + + lif->ipv4_addr = *(uint32_t *) nl_addr_get_binary_addr(nl_addr); + lif->prefixlen = nl_addr_get_prefixlen(nl_addr); + lif->l3_mode = 1; + lif->port_config_sync = 1; + if (memcmp((char *)lif->ipv6_addr, addr_null, 16) == 0) + { + update_if_ipmac_on_standby(lif, 6); + update_vlan_if_mac_on_standby(lif, 2); + sync_mac = 1; + } + iccp_del_self_ip_from_neigh_table (lif, AF_INET); + if (lif->is_l3_proto_enabled) + { + is_v4 = 1; + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, sync_mac, 1, 0, 4); + } + ICCPD_LOG_NOTICE(__FUNCTION__, " ifname %s index %d address %s l3_proto %d\n", + lif->name, lif->ifindex, show_ip_str(lif->ipv4_addr), lif->is_l3_proto_enabled); + } + else if (rtnl_addr_get_family(addr) == AF_INET6) + { + if (memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "FE80", 4) == 0 + || memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "fe80", 4) == 0) { + + memcpy((char *)lif->ipv6_ll_addr, nl_addr_get_binary_addr(nl_addr), 16); + lif->ll_prefixlen_v6 = nl_addr_get_prefixlen(nl_addr); + ICCPD_LOG_NOTICE(__FUNCTION__, " ifname %s index %d address %s l3_proto %d, prefix_len %d\n", + lif->name, lif->ifindex, show_ipv6_str((char *)lif->ipv6_ll_addr), lif->is_l3_proto_enabled, lif->ll_prefixlen_v6); + return; + } + + if (memcmp((char *)lif->ipv6_addr, addr_null, 16) != 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Ignore Multiple IP Add on ifname %s index %d present address %s l3_proto %d\n", + lif->name, lif->ifindex, show_ipv6_str((char *)lif->ipv6_addr), lif->is_l3_proto_enabled); + return; + } + + memcpy((char *)lif->ipv6_addr, nl_addr_get_binary_addr(nl_addr), 16); + lif->prefixlen_v6 = nl_addr_get_prefixlen(nl_addr); + lif->l3_mode = 1; + lif->port_config_sync = 1; + if (lif->ipv4_addr == 0) + { + update_if_ipmac_on_standby(lif, 7); + update_vlan_if_mac_on_standby(lif, 3); + sync_mac = 1; + } + iccp_del_self_ip_from_neigh_table (lif, AF_INET6); + if (lif->is_l3_proto_enabled) + { + is_v6 = 1; + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, sync_mac, 1, 0, 6); + } + ICCPD_LOG_NOTICE(__FUNCTION__, " ifname %s index %d address %s l3_proto %d\n", + lif->name, lif->ifindex, show_ipv6_str((char *)lif->ipv6_addr), lif->is_l3_proto_enabled); + } + + return; +} + +void iccp_event_handler_obj_input_deladdr(struct nl_object *obj, void *arg) +{ + struct rtnl_addr *addr; + struct nl_addr *nl_addr; + struct LocalInterface *lif; + uint32_t ifindex; + char addr_null[16] = { 0 }; + int sync_add = 0, is_v4 = 0, is_v6 = 0, sync_mac = 0; + + uint32_t ipv4_addr = 0; + uint32_t ipv6_addr[4]; + + addr = (struct rtnl_addr *)obj; + + ifindex = rtnl_addr_get_ifindex(addr); + nl_addr = rtnl_addr_get_local(addr); + + if (!(lif = local_if_find_by_ifindex(ifindex))) + return; + + if (rtnl_addr_get_family(addr) == AF_INET) + { + ipv4_addr = *(uint32_t *) nl_addr_get_binary_addr(nl_addr); + + if (lif->ipv4_addr != ipv4_addr) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Received address DEL ip %s", show_ip_str(ipv4_addr)); + ICCPD_LOG_NOTICE(__FUNCTION__, "IP Mismatch. Ignore DEL on ifname %s index %d present address %s l3_proto %d\n", + lif->name, lif->ifindex, show_ip_str(lif->ipv4_addr), lif->is_l3_proto_enabled); + return; + } + + ICCPD_LOG_NOTICE(__FUNCTION__, "l3_proto %d, ifname %s index %d is_vrf %d address %s\n", + lif->is_l3_proto_enabled, lif->name, lif->ifindex, lif->master_ifindex, show_ip_str(lif->ipv4_addr)); + if (memcmp((char *)lif->ipv6_addr, addr_null, 16) == 0) + { + sync_mac = 1; + if (lif->master_ifindex == 0) { + recover_vlan_if_mac_on_standby(lif, 2, NULL); + } + } + + if (lif->is_l3_proto_enabled) + { + is_v4 = 1; + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, sync_mac, 0, 0, 7); + } + lif->ipv4_addr = 0; + lif->prefixlen = 0; + } + else if (rtnl_addr_get_family(addr) == AF_INET6) + { + if (memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "FE80", 4) == 0 + || memcmp(show_ipv6_str((char *)nl_addr_get_binary_addr(nl_addr)), "fe80", 4) == 0) { + + ICCPD_LOG_NOTICE(__FUNCTION__, "l3_proto %d, ifname %s index %d is_vrf %d address %s\n", + lif->is_l3_proto_enabled, lif->name, lif->ifindex, lif->master_ifindex, show_ipv6_str((char *)lif->ipv6_ll_addr)); + + memset((char *)lif->ipv6_ll_addr, 0, 16); + lif->ll_prefixlen_v6 = 0; + return; + } + + memcpy((char *)ipv6_addr, nl_addr_get_binary_addr(nl_addr), 16); + + if (memcmp((char *)lif->ipv6_addr, ipv6_addr, 16) != 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "Received address DEL for ip %s", show_ipv6_str((char *)ipv6_addr)); + ICCPD_LOG_NOTICE(__FUNCTION__, "IP Mismatch. Ignore DEL on ifname %s index %d, l3_proto %d, is_vrf %d present address %s\n", + lif->name, lif->ifindex, lif->is_l3_proto_enabled, lif->master_ifindex, show_ipv6_str((char *)lif->ipv6_addr)); + return; + } + + ICCPD_LOG_NOTICE(__FUNCTION__, "l3_proto %d, ifname %s index %d is_vrf %d address %s\n", + lif->is_l3_proto_enabled, lif->name, lif->ifindex, lif->master_ifindex, show_ipv6_str((char *)lif->ipv6_addr)); + if (lif->ipv4_addr == 0) + { + sync_mac = 1; + if (lif->master_ifindex == 0) { + recover_vlan_if_mac_on_standby(lif, 3, NULL); + } + } + + if (lif->is_l3_proto_enabled) + { + is_v6 = 1; + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, sync_mac, 0, 0, 9); + } + memset((char *)lif->ipv6_addr, 0, 16); + lif->prefixlen_v6 = 0; + } + + if ((lif->ipv4_addr == 0) && (lif->master_ifindex == 0) && (memcmp((char *)lif->ipv6_addr, addr_null, 16) == 0)) + { + lif->l3_mode = 0; + memset(lif->l3_mac_addr, 0, ETHER_ADDR_LEN); + } + + return; +} + +int iccp_addr_valid_handler(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + unsigned int event = 0; + if (nlh->nlmsg_type != RTM_NEWADDR) + return 0; + + if (nl_msg_parse(msg, &iccp_event_handler_obj_input_newaddr, &event) < 0) + ICCPD_LOG_ERR(__FUNCTION__, "Unknown message type."); + + return 0; +} + int iccp_sys_local_if_list_get_addr() { struct System *sys = NULL; @@ -1178,12 +1539,16 @@ static int iccp_route_event_handler(struct nl_msg *msg, void *arg) struct nlmsghdr *nlh = nlmsg_hdr(msg); unsigned int event = 1; + /* Update netlink message counters */ + system_update_netlink_counters(nlh->nlmsg_type, nlh); + switch (nlh->nlmsg_type) { case RTM_NEWLINK: if (nl_msg_parse(msg, &iccp_event_handler_obj_input_newlink, &event) < 0) ICCPD_LOG_DEBUG(__FUNCTION__, "Unknown message type(RTM_NEWLINK)"); - iccp_parse_if_vlan_info_from_netlink(nlh); + //vlan membership changes are handled through state db updates + //iccp_parse_if_vlan_info_from_netlink(nlh); break; case RTM_DELLINK: @@ -1198,12 +1563,13 @@ static int iccp_route_event_handler(struct nl_msg *msg, void *arg) case RTM_NEWADDR: if (nl_msg_parse(msg, &iccp_event_handler_obj_input_newaddr, NULL) < 0) - ICCPD_LOG_DEBUG(__FUNCTION__, "Unknown message type(RTM_NEWADDR)."); + ICCPD_LOG_DEBUG(__FUNCTION__, "Unknown message type."); break; case RTM_DELADDR: if (nl_msg_parse(msg, &iccp_event_handler_obj_input_deladdr, NULL) < 0) - ICCPD_LOG_DEBUG(__FUNCTION__, "Unknown message type(RTM_DELADDR)."); + ICCPD_LOG_DEBUG(__FUNCTION__, "Unknown message type."); break; + default: return NL_OK; } @@ -1314,7 +1680,9 @@ int iccp_system_init_netlink_socket() if (err) goto err_route_sock_connect; - err = nl_socket_set_buffer_size(sys->route_sock, 98304, 0); + /* Set the same buffer size as done in SwSS common*/ + //err = nl_socket_set_buffer_size(sys->route_sock, 98304, 0); + err = nl_socket_set_buffer_size(sys->route_sock, NETLINK_SOCKET_BUFFER_SIZE, 0); if (err) { ICCPD_LOG_ERR(__FUNCTION__, "Failed to set buffer size of netlink route event sock."); @@ -1332,7 +1700,9 @@ int iccp_system_init_netlink_socket() goto err_route_event_sock_connect; } - err = nl_socket_set_buffer_size(sys->route_event_sock, 983040, 0); + /* Set the same buffer size as done in SwSS common*/ + //err = nl_socket_set_buffer_size(sys->route_event_sock, 98304, 0); + err = nl_socket_set_buffer_size(sys->route_event_sock, NETLINK_SOCKET_BUFFER_SIZE, 0); if (err) { ICCPD_LOG_ERR(__FUNCTION__, "Failed to set buffer size of netlink route event sock."); @@ -1387,7 +1757,7 @@ int iccp_system_init_netlink_socket() err = nl_socket_add_membership(sys->route_event_sock, RTNLGRP_IPV4_IFADDR); if (err < 0) { - ICCPD_LOG_ERR(__FUNCTION__, "Failed to add netlink membership."); + ICCPD_LOG_ERR(__FUNCTION__, "Failed to add netlink membership."); goto err_return; } err = nl_socket_add_membership(sys->route_event_sock, RTNLGRP_IPV6_IFADDR); @@ -1396,7 +1766,8 @@ int iccp_system_init_netlink_socket() ICCPD_LOG_ERR(__FUNCTION__, "Failed to add netlink membership."); goto err_return; } - /* receive arp packet socket */ + + /*receive arp packet socket*/ sys->arp_receive_fd = socket(PF_PACKET, SOCK_DGRAM, 0); if (sys->arp_receive_fd < 0) { @@ -1418,37 +1789,52 @@ int iccp_system_init_netlink_socket() } } + /* receive ipv6 packet socket */ + //sys->ndisc_receive_fd = socket(PF_PACKET, SOCK_DGRAM, 0); sys->ndisc_receive_fd = iccp_make_nd_socket(); - if (sys->ndisc_receive_fd < 0) { + // ICCPD_LOG_ERR(__FUNCTION__, "socket error "); goto err_return; } + if (0) + { + struct sockaddr_ll sll; + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons(ETH_P_IPV6); + sll.sll_ifindex = 0; + if (bind(sys->ndisc_receive_fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "socket bind error"); + goto err_return; + } + } goto succes_return; - err_return: +err_return: - err_route_event_sock_connect: +err_route_event_sock_connect: nl_socket_free(sys->route_event_sock); - err_route_sock_alloc: - err_route_sock_connect: +err_route_sock_alloc: +err_route_sock_connect: nl_socket_free(sys->route_sock); - err_route_event_sock_alloc: - err_genric_event_sock_connect: +err_route_event_sock_alloc: +err_genric_event_sock_connect: nl_socket_free(sys->genric_event_sock); - err_genric_event_sock_alloc: - err_genric_sock_connect: +err_genric_event_sock_alloc: +err_genric_sock_connect: nl_socket_free(sys->genric_sock); return err; - err_genric_sock_alloc: +err_genric_sock_alloc: - succes_return: +succes_return: return 0; } @@ -1510,6 +1896,7 @@ static int iccp_receive_arp_packet_handler(struct System *sys) unsigned int ifindex; unsigned int addr; uint8_t mac_addr[ETHER_ADDR_LEN]; + struct CSM* csm = NULL; n = recvfrom(sys->arp_receive_fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len); @@ -1529,6 +1916,11 @@ static int iccp_receive_arp_packet_handler(struct System *sys) sizeof(*a) + 2 * 4 + 2 * a->ar_hln > n) return 0; + /*Check if mclag configured*/ + csm = system_get_first_csm(); + if (!csm) + return 0; + ifindex = sll.sll_ifindex; memcpy(mac_addr, (char*)(a + 1), ETHER_ADDR_LEN); memcpy(&addr, (char*)(a + 1) + a->ar_hln, 4); @@ -1554,6 +1946,7 @@ int iccp_receive_ndisc_packet_handler(struct System *sys) int8_t *opt = NULL; int opt_len = 0, l = 0; int len; + struct CSM* csm = NULL; memset(mac_addr, 0, ETHER_ADDR_LEN); @@ -1571,7 +1964,7 @@ int iccp_receive_ndisc_packet_handler(struct System *sys) if (len < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Ndisc recvmsg error!"); + ICCPD_LOG_DEBUG(__FUNCTION__, "ndisc recvmsg error!"); return MCLAG_ERROR; } @@ -1590,6 +1983,11 @@ int iccp_receive_ndisc_packet_handler(struct System *sys) ndmsg = (struct nd_msg *)buf; + /*Check if mclag configured*/ + csm = system_get_first_csm(); + if (!csm) + return 0; + if (ndmsg->icmph.icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT) return 0; @@ -1624,8 +2022,6 @@ int iccp_receive_ndisc_packet_handler(struct System *sys) } } - /* ICCPD_LOG_DEBUG(__FUNCTION__, "Recv na pkt(%s,%02X:%02X:%02X:%02X:%02X:%02X)!", show_ipv6_str((char *)&target), mac_addr[0], mac_addr[1], - mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); */ do_ndisc_update_from_reply_packet(ifindex, (char *)&target, mac_addr); return 0; @@ -1672,7 +2068,8 @@ static int iccp_netlink_route_sock_event_handler(struct System *sys) if (ret) { sys->need_sync_netlink_again = 1; - ICCPD_LOG_DEBUG(__FUNCTION__, "fd %d recvmsg error ret = %d errno = %d ", nl_socket_get_fd(sys->route_event_sock), ret, errno); + ICCPD_LOG_NOTICE(__FUNCTION__, "fd %d recvmsg error ret = %d errno = %d ", nl_socket_get_fd(sys->route_event_sock), ret, errno); + SYSTEM_INCR_NETLINK_RX_ERROR(); } /*get netlink info again when error happens */ if (ret == 0 && sys->need_sync_netlink_again == 1) @@ -1684,7 +2081,6 @@ static int iccp_netlink_route_sock_event_handler(struct System *sys) } extern int iccp_get_receive_fdb_sock_fd(struct System *sys); -extern int iccp_receive_fdb_handler_from_syncd(struct System *sys); /* cond HIDDEN_SYMBOLS */ struct iccp_eventfd @@ -1710,11 +2106,11 @@ static const struct iccp_eventfd iccp_eventfds[] = { { .get_fd = iccp_get_receive_arp_packet_sock_fd, .event_handler = iccp_receive_arp_packet_handler, - }, + }, { - .get_fd = iccp_get_receive_ndisc_packet_sock_fd, - .event_handler = iccp_receive_ndisc_packet_handler, - } + .get_fd = iccp_get_receive_ndisc_packet_sock_fd, + .event_handler = iccp_receive_ndisc_packet_handler, + } }; /* \cond HIDDEN_SYMBOLS */ @@ -1759,7 +2155,7 @@ int iccp_init_netlink_event_fd(struct System *sys) return 0; - close_efd: +close_efd: close(efd); return err; @@ -1781,6 +2177,7 @@ int iccp_handle_events(struct System * sys) int i; int err; int max_nfds; + struct mLACPHeartbeatTLV dummy_tlv; max_nfds = ICCP_EVENT_FDS_COUNT + sys->readfd_count; @@ -1817,8 +2214,7 @@ int iccp_handle_events(struct System * sys) if (events[i].data.fd == sys->sync_fd) { - iccp_receive_fdb_handler_from_syncd(sys); - + iccp_mclagsyncd_msg_handler(sys); continue; } @@ -1835,7 +2231,11 @@ int iccp_handle_events(struct System * sys) { if (csm->sock_fd == events[i].data.fd ) { - scheduler_csm_read_callback(csm); + if (scheduler_csm_read_callback(csm) != MCLAG_ERROR) + { + //consider any msg from peer as heartbeat update, this will be in scenarios of scaled msg sync b/w peers + mlacp_fsm_update_heartbeat(csm, &dummy_tlv); + } break; } } @@ -1845,3 +2245,248 @@ int iccp_handle_events(struct System * sys) return 0; } +void update_vlan_if_mac_on_standby(struct LocalInterface* lif_vlan, int dir) +{ + struct CSM* csm = NULL; + struct System* sys = NULL; + struct LocalInterface *lif_po = NULL; + struct LocalInterface *lif_peer = NULL; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + char macaddr[64]; + uint8_t system_mac[ETHER_ADDR_LEN]; + int ret = 0; + struct VLAN_ID vlan_key = { 0 }; + struct VLAN_ID *vlan = NULL; + int vid = 0, vlan_member = 0; + + if (lif_vlan->type != IF_T_VLAN) + return; + + if ((sys = system_get_instance()) == NULL) + return; + + sscanf (lif_vlan->name, "Vlan%d", &vid); + + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + + ICCPD_LOG_DEBUG(__FUNCTION__, " ifname %s vid %d, l3_proto %d, dir %d\n", + lif_vlan->name, vid, lif_vlan->is_l3_proto_enabled, dir); + LIST_FOREACH(csm, &(sys->csm_list), next) + { + if (csm->peer_link_if) { + lif_peer = csm->peer_link_if; + vlan = RB_FIND(vlan_rb_tree, &(lif_peer->vlan_tree), &vlan_key); + if (vlan && vlan->vlan_itf) + { + vlan_member = 1; + break; + } + } + + LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) + { + if (lif_po->type == IF_T_PORT_CHANNEL) + { + vlan = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key); + if (vlan) + { + vlan_member = 1; + break; + } + } + } + if (vlan_member) + { + break; + } + } + + if (!csm) { + ICCPD_LOG_NOTICE(__FUNCTION__, " csm not initialised."); + return; + } + + if (csm->role_type != STP_ROLE_STANDBY) + return; + + memset(macaddr, 0, 64); + memset(system_mac, 0, ETHER_ADDR_LEN); + if (lif_vlan->is_l3_proto_enabled == false) + { + if (memcmp(MLACP(csm).remote_system.system_id, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, " remote system_id not initialised."); + return; + } + memcpy(system_mac, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); + SET_MAC_STR(macaddr, MLACP(csm).remote_system.system_id); + } else { + if (memcmp(MLACP(csm).system_id, null_mac, ETHER_ADDR_LEN) == 0){ + ICCPD_LOG_NOTICE(__FUNCTION__, " system_id not initialised."); + return; + } + memcpy(system_mac, MLACP(csm).system_id, ETHER_ADDR_LEN); + SET_MAC_STR(macaddr, MLACP(csm).system_id); + } + + if (memcmp(system_mac, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, " system_id not present."); + return; + } + + ICCPD_LOG_DEBUG(__FUNCTION__, + "%s Change the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X], dir %d", + (csm->role_type == STP_ROLE_STANDBY) ? "Standby" : "Active", + lif_vlan->name, lif_vlan->mac_addr[0], lif_vlan->mac_addr[1], lif_vlan->mac_addr[2], + lif_vlan->mac_addr[3], lif_vlan->mac_addr[4], lif_vlan->mac_addr[5], + system_mac[0], system_mac[1], system_mac[2], system_mac[3], system_mac[4], system_mac[5], dir); + + if (local_if_is_l3_mode(lif_vlan)) + { + if (memcmp(lif_vlan->l3_mac_addr, system_mac, ETHER_ADDR_LEN) != 0) + { + ret = iccp_netlink_if_hwaddr_set(lif_vlan->ifindex, system_mac, ETHER_ADDR_LEN); + if (ret != 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, " set %s mac error, ret = %d, dir %d", lif_vlan->name, ret, dir); + } + + /* Refresh link local address according the new MAC */ + iccp_netlink_if_shutdown_set(lif_vlan->ifindex); + iccp_netlink_if_startup_set(lif_vlan->ifindex); + + iccp_set_interface_ipadd_mac(lif_vlan, macaddr); + memcpy(lif_vlan->l3_mac_addr, system_mac, ETHER_ADDR_LEN); + if (lif_vlan->is_l3_proto_enabled == false) { + set_peer_mac_in_kernel (macaddr, vid, 1); + } + } else { + ICCPD_LOG_DEBUG(__FUNCTION__, "%s mac alreay updated, dir %d", lif_vlan->name, dir); + } + } else { + ICCPD_LOG_DEBUG(__FUNCTION__, "%s not L3 interface, dir %d", lif_vlan->name, dir); + } + + return; +} + +void recover_vlan_if_mac_on_standby(struct LocalInterface* lif_vlan, int dir, uint8_t *remote_system_mac) +{ + struct CSM *csm = NULL; + struct System* sys = NULL; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + char macaddr[64]; + char remote_macaddr[64]; + uint8_t system_mac[ETHER_ADDR_LEN]; + int ret = 0; + int vid = 0; + + if (lif_vlan->type != IF_T_VLAN) + return; + + if ((sys = system_get_instance()) == NULL) + return; + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + if (csm->peer_link_if) { + break; + } + } + + if (csm == NULL) { + ICCPD_LOG_NOTICE(__FUNCTION__, " csm not initialised."); + return; + } + + if (csm->role_type != STP_ROLE_STANDBY) + return; + + sscanf (lif_vlan->name, "Vlan%d", &vid); + + memset(macaddr, 0, 64); + memset(remote_macaddr, 0, 64); + memset(system_mac, 0, ETHER_ADDR_LEN); + ICCPD_LOG_DEBUG(__FUNCTION__, " ifname %s, l3_proto %d, dir %d\n", + lif_vlan->name, lif_vlan->is_l3_proto_enabled, dir); + if (lif_vlan->is_l3_proto_enabled == true) + { + if (memcmp(MLACP(csm).remote_system.system_id, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, " remote system_id not initialised."); + return; + } + memcpy(system_mac, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); + SET_MAC_STR(macaddr, MLACP(csm).remote_system.system_id); + } else { + if (memcmp(MLACP(csm).system_id, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, " system_id not initialised."); + return; + } + memcpy(system_mac, MLACP(csm).system_id, ETHER_ADDR_LEN); + SET_MAC_STR(macaddr, MLACP(csm).system_id); + } + + if (memcmp(system_mac, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, " system_id not present."); + return; + } + + ICCPD_LOG_DEBUG(__FUNCTION__, + "%s Change the system-id of %s from [%02X:%02X:%02X:%02X:%02X:%02X] to [%02X:%02X:%02X:%02X:%02X:%02X], dir %d", + (csm->role_type == STP_ROLE_STANDBY) ? "Standby" : "Active", lif_vlan->name, + lif_vlan->l3_mac_addr[0], lif_vlan->l3_mac_addr[1], lif_vlan->l3_mac_addr[2], + lif_vlan->l3_mac_addr[3], lif_vlan->l3_mac_addr[4], lif_vlan->l3_mac_addr[5], + system_mac[0], system_mac[1], system_mac[2], system_mac[3], system_mac[4], system_mac[5], dir); + + if (local_if_is_l3_mode(lif_vlan)) + { + if (memcmp(lif_vlan->l3_mac_addr, system_mac, ETHER_ADDR_LEN) != 0) + { + ret = iccp_netlink_if_hwaddr_set(lif_vlan->ifindex, system_mac, ETHER_ADDR_LEN); + if (ret != 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, " set %s mac error, ret = %d, dir %d", lif_vlan->name, ret, dir); + } + + /* Refresh link local address according the new MAC */ + iccp_netlink_if_shutdown_set(lif_vlan->ifindex); + iccp_netlink_if_startup_set(lif_vlan->ifindex); + + iccp_set_interface_ipadd_mac(lif_vlan, macaddr); + memcpy(lif_vlan->l3_mac_addr, system_mac, ETHER_ADDR_LEN); + + if (memcmp(MLACP(csm).remote_system.system_id, null_mac, ETHER_ADDR_LEN) != 0) { + SET_MAC_STR(remote_macaddr, MLACP(csm).remote_system.system_id); + set_peer_mac_in_kernel (remote_macaddr, vid, 0); + } else if ((dir == 4) && remote_system_mac) { + if (memcmp(remote_system_mac, null_mac, ETHER_ADDR_LEN) != 0) { + SET_MAC_STR(remote_macaddr, remote_system_mac); + set_peer_mac_in_kernel (remote_macaddr, vid, 0); + } + } + } + } else { + ICCPD_LOG_DEBUG(__FUNCTION__, "%s not L3 interface, dir %d", lif_vlan->name, dir); + } + + return; +} + +void update_vlan_if_mac_on_iccp_up(struct LocalInterface* lif_peer, int is_up, uint8_t *remote_system_mac) +{ + struct VLAN_ID *vlan_id_list = NULL; + + ICCPD_LOG_NOTICE(__FUNCTION__, " lif name %s, up %d", lif_peer->name, is_up); + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(lif_peer->vlan_tree)) + { + if (!vlan_id_list->vlan_itf) + continue; + + if (is_up) { + update_vlan_if_mac_on_standby(vlan_id_list->vlan_itf, 4); + } else { + recover_vlan_if_mac_on_standby(vlan_id_list->vlan_itf, 4, remote_system_mac); + } + + } +} diff --git a/src/iccpd/src/logger.c b/src/iccpd/src/logger.c index 2c17610f7afc..3ed9f79bfea5 100644 --- a/src/iccpd/src/logger.c +++ b/src/iccpd/src/logger.c @@ -35,7 +35,7 @@ static uint32_t _iccpd_log_level_map[] = LOG_WARNING, LOG_NOTICE, LOG_INFO, - LOG_DEBUG, + LOG_DEBUG }; char* log_level_to_string(int level) @@ -100,7 +100,7 @@ void log_finalize() /*do nothing*/ } -void write_log(const int level, const char* tag, const char* format, ...) +void write_log(int level, const char* tag, const char* format, ...) { struct LoggerConfig* config = logger_get_configuration(); char buf[LOGBUF_SIZE]; diff --git a/src/iccpd/src/mclagdctl/mclagdctl.c b/src/iccpd/src/mclagdctl/mclagdctl.c index 630e333be6ed..2eccd944636a 100644 --- a/src/iccpd/src/mclagdctl/mclagdctl.c +++ b/src/iccpd/src/mclagdctl/mclagdctl.c @@ -29,7 +29,11 @@ #include #include #include +#include +#include #include "mclagdctl.h" +#include "../../include/mlacp_fsm.h" +#include "../../include/system.h" static int mclagdctl_sock_fd = -1; char *mclagdctl_sock_path = "/var/run/iccpd/mclagdctl.sock"; @@ -38,11 +42,25 @@ char *mclagdctl_sock_path = "/var/run/iccpd/mclagdctl.sock"; Already implemented command: mclagdctl -i dump state mclagdctl -i dump arp + mclagdctl -i dump nd mclagdctl -i dump mac + mclagdctl -i dump unique_ip mclagdctl -i dump portlist local mclagdctl -i dump portlist peer */ +#define ETHER_ADDR_LEN 6 +char mac_print_str[18]; + +char *mac_addr_to_str(uint8_t* mac_addr) +{ + memset(mac_print_str, 0, sizeof(mac_print_str)); + snprintf(mac_print_str, sizeof(mac_print_str), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + return mac_print_str; +} + static struct command_type command_types[] = { { @@ -68,13 +86,13 @@ static struct command_type command_types[] = .parse_msg = mclagdctl_parse_dump_arp, }, { - .id = ID_CMDTYPE_D_A, - .parent_id = ID_CMDTYPE_D, - .info_type = INFO_TYPE_DUMP_NDISC, - .name = "nd", - .enca_msg = mclagdctl_enca_dump_ndisc, - .parse_msg = mclagdctl_parse_dump_ndisc, - }, + .id = ID_CMDTYPE_D_A, + .parent_id = ID_CMDTYPE_D, + .info_type = INFO_TYPE_DUMP_NDISC, + .name = "nd", + .enca_msg = mclagdctl_enca_dump_ndisc, + .parse_msg = mclagdctl_parse_dump_ndisc, + }, { .id = ID_CMDTYPE_D_A, .parent_id = ID_CMDTYPE_D, @@ -83,6 +101,14 @@ static struct command_type command_types[] = .enca_msg = mclagdctl_enca_dump_mac, .parse_msg = mclagdctl_parse_dump_mac, }, + { + .id = ID_CMDTYPE_D_A, + .parent_id = ID_CMDTYPE_D, + .info_type = INFO_TYPE_DUMP_UNIQUE_IP, + .name = "unique_ip", + .enca_msg = mclagdctl_enca_dump_unique_ip, + .parse_msg = mclagdctl_parse_dump_unique_ip, + }, { .id = ID_CMDTYPE_D_P, .parent_id = ID_CMDTYPE_D, @@ -104,6 +130,19 @@ static struct command_type command_types[] = .enca_msg = mclagdctl_enca_dump_peer_portlist, .parse_msg = mclagdctl_parse_dump_peer_portlist, }, + { + .id = ID_CMDTYPE_D_D, + .parent_id = ID_CMDTYPE_D, + .name = "debug", + }, + { + .id = ID_CMDTYPE_D_D_C, + .parent_id = ID_CMDTYPE_D_D, + .info_type = INFO_TYPE_DUMP_DBG_COUNTERS, + .name = "counters", + .enca_msg = mclagdctl_enca_dump_dbg_counters, + .parse_msg = mclagdctl_parse_dump_dbg_counters, + }, { .id = ID_CMDTYPE_C, .name = "config", @@ -117,7 +156,7 @@ static struct command_type command_types[] = .name = "loglevel", .enca_msg = mclagdctl_enca_config_loglevel, .parse_msg = mclagdctl_parse_config_loglevel, - }, + }, }; #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -250,8 +289,18 @@ int mclagdctl_parse_dump_state(char *msg, int data_len) { state_info = (struct mclagd_state*)(msg + len * count); - fprintf(stdout, "%s: %s\n", "The MCLAG's keepalive is", state_info->keepalive ? "OK" : "ERROR"); + if (inet_addr(state_info->local_ip) < inet_addr(state_info->peer_ip)) + { + state_info->role = 1; + } + else + { + state_info->role = 2; + } + fprintf(stdout, "%s: %s\n", "The MCLAG's keepalive is", state_info->keepalive ? "OK" : "ERROR"); + fprintf(stdout, "%s: %s\n", "MCLAG info sync is", + state_info->info_sync_done ? "completed" : "incomplete"); if (state_info->mclag_id <= 0) fprintf(stdout, "%s: %s\n", "Domain id", "Unknown"); else @@ -260,6 +309,8 @@ int mclagdctl_parse_dump_state(char *msg, int data_len) fprintf(stdout, "%s: %s\n", "Local Ip", state_info->local_ip); fprintf(stdout, "%s: %s\n", "Peer Ip", state_info->peer_ip); fprintf(stdout, "%s: %s\n", "Peer Link Interface", state_info->peer_link_if); + fprintf(stdout, "%s: %d\n", "Keepalive time", state_info->keepalive_time); + fprintf(stdout, "%s: %d\n", "sesssion Timeout ", state_info->session_timeout); fprintf(stdout, "%s: %02x:%02x:%02x:%02x:%02x:%02x \n", "Peer Link Mac", @@ -267,9 +318,10 @@ int mclagdctl_parse_dump_state(char *msg, int data_len) state_info->peer_link_mac[2], state_info->peer_link_mac[3], state_info->peer_link_mac[4], state_info->peer_link_mac[5]); - if (state_info->role == 0) + /*if (state_info->role == 0) fprintf(stdout, "%s: %s\n", "Role", "None"); - else if (state_info->role == 1) + */ + if (state_info->role == 1) fprintf(stdout, "%s: %s\n", "Role", "Active"); else if (state_info->role == 2) fprintf(stdout, "%s: %s\n", "Role", "Standby"); @@ -328,6 +380,7 @@ int mclagdctl_parse_dump_arp(char *msg, int data_len) fprintf(stdout, "%-20s", "IP"); fprintf(stdout, "%-20s", "MAC"); fprintf(stdout, "%-20s", "DEV"); + fprintf(stdout, "%s", "Flag"); fprintf(stdout, "\n"); len = sizeof(struct mclagd_arp_msg); @@ -344,6 +397,13 @@ int mclagdctl_parse_dump_arp(char *msg, int data_len) arp_info->mac_addr[4], arp_info->mac_addr[5]); fprintf(stdout, " "); fprintf(stdout, "%-20s", arp_info->ifname); + if (arp_info->learn_flag == NEIGH_REMOTE) { + fprintf(stdout, "%s", "R"); + } else if (arp_info->learn_flag == NEIGH_LOCAL) { + fprintf(stdout, "%s", "L"); + } else { + fprintf(stdout, "%s", "-"); + } fprintf(stdout, "\n"); } @@ -360,6 +420,7 @@ int mclagdctl_parse_dump_ndisc(char *msg, int data_len) fprintf(stdout, "%-52s", "IPv6"); fprintf(stdout, "%-20s", "MAC"); fprintf(stdout, "%-20s", "DEV"); + fprintf(stdout, "%s", "Flag"); fprintf(stdout, "\n"); len = sizeof(struct mclagd_ndisc_msg); @@ -372,10 +433,16 @@ int mclagdctl_parse_dump_ndisc(char *msg, int data_len) fprintf(stdout, "%-52s", ndisc_info->ipv6_addr); fprintf(stdout, "%02x:%02x:%02x:%02x:%02x:%02x", ndisc_info->mac_addr[0], ndisc_info->mac_addr[1], - ndisc_info->mac_addr[2], ndisc_info->mac_addr[3], - ndisc_info->mac_addr[4], ndisc_info->mac_addr[5]); + ndisc_info->mac_addr[2], ndisc_info->mac_addr[3], ndisc_info->mac_addr[4], ndisc_info->mac_addr[5]); fprintf(stdout, " "); fprintf(stdout, "%-20s", ndisc_info->ifname); + if (ndisc_info->learn_flag == NEIGH_REMOTE) { + fprintf(stdout, "%s", "R"); + } else if (ndisc_info->learn_flag == NEIGH_LOCAL) { + fprintf(stdout, "%s", "L"); + } else { + fprintf(stdout, "%s", "-"); + } fprintf(stdout, "\n"); } @@ -430,7 +497,8 @@ int mclagdctl_parse_dump_mac(char *msg, int data_len) else fprintf(stdout, "%-5s", "D"); - fprintf(stdout, "%-20s", mac_info->mac_str); + fprintf(stdout, "%-20s", mac_addr_to_str(mac_info->mac_addr)); + fprintf(stdout, "%-5d", mac_info->vid); fprintf(stdout, "%-20s", mac_info->ifname); fprintf(stdout, "%-20s", mac_info->origin_ifname); @@ -502,10 +570,11 @@ int mclagdctl_parse_dump_local_portlist(char *msg, int data_len) fprintf(stdout, "%s: %s\n", "IsL3Interface", lif_info->l3_mode ? "Yes" : "No"); /*fprintf(stdout, "%s: %s\n", "IsPeerlink", lif_info->is_peer_link ? "Yes" : "No");*/ fprintf(stdout, "%s: %s\n", "MemberPorts", lif_info->portchannel_member_buf); - /*fprintf(stdout,"%s: %d\n" ,"PortchannelId", lif_info->po_id); - fprintf(stdout,"%s: %d\n" ,"PortchannelIsUp", lif_info->po_active); - fprintf(stdout,"%s: %s\n", "MlacpState", lif_info->mlacp_state);*/ + /*fprintf(stdout,"%s: %d\n" ,"PortchannelId", lif_info->po_id);*/ + fprintf(stdout,"%s: %d\n" ,"PortchannelIsUp", lif_info->po_active); + /*fprintf(stdout,"%s: %s\n", "MlacpState", lif_info->mlacp_state);*/ fprintf(stdout, "%s: %s\n", "IsIsolateWithPeerlink", lif_info->isolate_to_peer_link ? "Yes" : "No"); + fprintf(stdout,"%s: %s\n" ,"IsTrafficDisable", lif_info->is_traffic_disable ? "Yes":"No"); fprintf(stdout, "%s: %s\n", "VlanList", lif_info->vlanlist); } else @@ -514,6 +583,7 @@ int mclagdctl_parse_dump_local_portlist(char *msg, int data_len) fprintf(stdout, "%s: %s\n", "Type", lif_info->type); fprintf(stdout, "%s: %s\n", "PortName", lif_info->name); fprintf(stdout, "%s: %s\n", "State", lif_info->state); + fprintf(stdout, "%s: %s\n", "VlanList", lif_info->vlanlist); /*fprintf(stdout,"%s: %d\n" ,"PortchannelId", lif_info->po_id);*/ } @@ -584,6 +654,277 @@ int mclagdctl_parse_dump_peer_portlist(char *msg, int data_len) return 0; } +int mclagdctl_enca_dump_unique_ip(char *msg, int mclag_id, int argc, char **argv) +{ + struct mclagdctl_req_hdr req; + + if (mclag_id <= 0) + { + fprintf(stderr, "Need to specify mclag-id through the parameter i !\n"); + return MCLAG_ERROR; + } + + memset(&req, 0, sizeof(struct mclagdctl_req_hdr)); + req.info_type = INFO_TYPE_DUMP_UNIQUE_IP; + req.mclag_id = mclag_id; + memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr)); + + return 1; +} + +int mclagdctl_parse_dump_unique_ip(char *msg, int data_len) +{ + struct mclagd_unique_ip_if *ip_if_info = NULL; + int len = 0; + int count = 0; + int pos = 0; + + for (pos = 0; pos < 60; ++pos) + fprintf(stdout, "-"); + fprintf(stdout, "\n"); + fprintf(stdout, "%-20s", "Ifname"); + fprintf(stdout, "%-5s", "Active"); + fprintf(stdout, "\n"); + + for (pos = 0; pos < 60; ++pos) + fprintf(stdout, "-"); + fprintf(stdout, "\n"); + + len = sizeof(struct mclagd_unique_ip_if); + + for (; data_len >= len; data_len -= len, count++) + { + ip_if_info = (struct mclagd_unique_ip_if*)(msg + len * count); + + fprintf(stdout, "%-20s %-5s\n", ip_if_info->name, ip_if_info->active?"Yes":"No"); + } + + if (count == 0) + { + fprintf(stdout, "%s\n", "Unique IP configuration not enabled on any interface"); + } + + for (pos = 0; pos < 60; ++pos) + fprintf(stdout, "-"); + + fprintf(stdout, "\n\n"); + return 0; +} + +/* mclag_id parameter is optional */ +int mclagdctl_enca_dump_dbg_counters(char *msg, int mclag_id, int argc, char **argv) +{ + struct mclagdctl_req_hdr req; + + memset(&req, 0, sizeof(struct mclagdctl_req_hdr)); + req.info_type = INFO_TYPE_DUMP_DBG_COUNTERS; + req.mclag_id = mclag_id; + memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr)); + + return 1; +} + +static char *mclagdctl_dbg_counter_iccpid2str(ICCP_DBG_CNTR_MSG_e iccp_cntr_id) +{ + /* Keep the string to 15 characters. + * Update mclagdctl_parse_dump_dbg_counters if increase + */ + switch(iccp_cntr_id) + { + case ICCP_DBG_CNTR_MSG_SYS_CONFIG: + return "SysConfig"; + case ICCP_DBG_CNTR_MSG_AGGR_CONFIG: + return "AggrConfig"; + case ICCP_DBG_CNTR_MSG_AGGR_STATE: + return "AggrState"; + case ICCP_DBG_CNTR_MSG_MAC_INFO: + return "MacInfo"; + case ICCP_DBG_CNTR_MSG_ARP_INFO: + return "ArpInfo"; + case ICCP_DBG_CNTR_MSG_PORTCHANNEL_INFO: + return "PoInfo"; + case ICCP_DBG_CNTR_MSG_PEER_LINK_INFO: + return "PeerLinkInfo"; + case ICCP_DBG_CNTR_MSG_HEART_BEAT: + return "Heartbeat"; + case ICCP_DBG_CNTR_MSG_NAK: + return "Nak"; + case ICCP_DBG_CNTR_MSG_SYNC_DATA: + return "SyncData"; + case ICCP_DBG_CNTR_MSG_SYNC_REQ: + return "SyncReq"; + case ICCP_DBG_CNTR_MSG_WARM_BOOT: + return "Warmboot"; + case ICCP_DBG_CNTR_MSG_IF_UP_ACK: + return "IfUpAck"; + default: + return "Unknown"; + } +} + +static char *mclagdctl_dbg_counter_syncdtx2str(SYNCD_TX_DBG_CNTR_MSG_e syncdtx_id) +{ + /* Keep the string to 20 characters. + * Update mclagdctl_parse_dump_dbg_counters if increase + */ + switch(syncdtx_id) + { + case SYNCD_TX_DBG_CNTR_MSG_PORT_ISOLATE: + return "PortIsolation"; + case SYNCD_TX_DBG_CNTR_MSG_PORT_MAC_LEARN_MODE: + return "MacLearnMode"; + case SYNCD_TX_DBG_CNTR_MSG_FLUSH_FDB: + return "FlushFdb"; + case SYNCD_TX_DBG_CNTR_MSG_SET_IF_MAC: + return "SetIfMac"; + case SYNCD_TX_DBG_CNTR_MSG_SET_FDB: + return "SetFdb"; + case SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_ENABLE: + return "TrafficDistEnable"; + case SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_DISABLE: + return "TrafficDistDisable"; + case SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_STATE: + return "SetIccpState"; + case SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_ROLE: + return "SetIccpRole"; + case SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_SYSTEM_ID: + return "SetSystemId"; + case SYNCD_TX_DBG_CNTR_MSG_DEL_ICCP_INFO: + return "DelIccpInfo"; + case SYNCD_TX_DBG_CNTR_MSG_SET_REMOTE_IF_STATE: + return "SetRemoteIntfSts"; + case SYNCD_TX_DBG_CNTR_MSG_DEL_REMOTE_IF_INFO: + return "DelRemoteIntf"; + case SYNCD_TX_DBG_CNTR_MSG_PEER_LINK_ISOLATION: + return "PeerLinkIsolation"; + case SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_PEER_SYSTEM_ID: + return "SetPeerSystemId"; + default: + return "Unknown"; + } +} + +static char *mclagdctl_dbg_counter_syncdrx2str(SYNCD_RX_DBG_CNTR_MSG_e syncdrx_id) +{ + /* Keep the string to 20 characters. + * Update mclagdctl_parse_dump_dbg_counters if increase + */ + switch(syncdrx_id) + { + case SYNCD_RX_DBG_CNTR_MSG_MAC: + return "FdbChange"; + case SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_DOMAIN: + return "CfgMclag"; + case SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_IFACE: + return "CfgMclagIface"; + case SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_UNIQUE_IP: + return "CfgMclagUniqueIp"; + case SYNCD_RX_DBG_CNTR_MSG_VLAN_MBR_UPDATES: + return "vlanMbrshipChange"; + default: + return "Unknown"; + } +} + +int mclagdctl_parse_dump_dbg_counters(char *msg, int data_len) +{ + mclagd_dbg_counter_info_t *dbg_counter_p; + system_dbg_counter_info_t *sys_counter_p; + mlacp_dbg_counter_info_t *iccp_counter_p; + int i, j; + + dbg_counter_p = (mclagd_dbg_counter_info_t *)msg; + sys_counter_p = (system_dbg_counter_info_t *)&dbg_counter_p->system_dbg; + + /* Global counters */ + fprintf(stdout, "%-20s%u\n", "ICCP session down:", + sys_counter_p->session_down_counter); + fprintf(stdout, "%-20s%u\n", "Peer link down:", + sys_counter_p->peer_link_down_counter); + fprintf(stdout, "%-20s%u\n", "Rx invalid msg:", + sys_counter_p->rx_peer_invalid_msg_counter); + fprintf(stdout, "%-20s%u\n", "Rx sock error(hdr):", + sys_counter_p->rx_peer_hdr_read_sock_err_counter); + fprintf(stdout, "%-20s%u\n", "Rx zero len(hdr):", + sys_counter_p->rx_peer_hdr_read_sock_zero_len_counter); + fprintf(stdout, "%-20s%u\n", "Rx sock error(tlv):", + sys_counter_p->rx_peer_tlv_read_sock_err_counter); + fprintf(stdout, "%-20s%u\n", "Rx zero len(tlv):", + sys_counter_p->rx_peer_tlv_read_sock_zero_len_counter); + fprintf(stdout, "%-20s%u\n", "Rx retry max:", + sys_counter_p->rx_retry_max_counter); + fprintf(stdout, "%-20s%u\n", "Rx retry total:", + sys_counter_p->rx_retry_total_counter); + fprintf(stdout, "%-20s%u\n", "Rx retry fail:", + sys_counter_p->rx_retry_fail_counter); + fprintf(stdout, "%-20s%u\n", "Socket close err:", + sys_counter_p->socket_close_err_counter); + fprintf(stdout, "%-20s%u\n", "Socket cleanup:", + sys_counter_p->socket_cleanup_counter); + + fprintf(stdout, "\n"); + fprintf(stdout, "%-20s%u\n\n", "Warmboot:", sys_counter_p->warmboot_counter); + + /* ICCP daemon to Mclagsyncd messages */ + fprintf(stdout, "%-20s%-20s%-20s\n", "ICCP to MclagSyncd", "TX_OK", "TX_ERROR"); + fprintf(stdout, "%-20s%-20s%-20s\n", "------------------", "-----", "--------"); + for (i = 0; i < SYNCD_TX_DBG_CNTR_MSG_MAX; ++i) + { + fprintf(stdout, "%-20s%-20lu%-20lu\n", + mclagdctl_dbg_counter_syncdtx2str(i), + sys_counter_p->syncd_tx_counters[i][0], + sys_counter_p->syncd_tx_counters[i][1]); + } + + fprintf(stdout, "\n%-20s%-20s%-20s\n", "MclagSyncd to ICCP", "RX_OK", "RX_ERROR"); + fprintf(stdout, "%-20s%-20s%-20s\n", "------------------", "-----", "--------"); + for (i = 0; i < SYNCD_RX_DBG_CNTR_MSG_MAX; ++i) + { + fprintf(stdout, "%-20s%-20lu%-20lu\n", + mclagdctl_dbg_counter_syncdrx2str(i), + sys_counter_p->syncd_rx_counters[i][0], + sys_counter_p->syncd_rx_counters[i][1]); + } + /* Print ICCP messages exchanged between MLAG peers */ + fprintf(stdout, "\n%-20s%-20s%-20s%-20s%-20s\n", + "ICCP to Peer", "TX_OK", "RX_OK", "TX_ERROR", "RX_ERROR"); + fprintf(stdout, "%-20s%-20s%-20s%-20s%-20s\n", + "------------", "-----", "-----", "--------", "--------"); + + iccp_counter_p = (mlacp_dbg_counter_info_t *)dbg_counter_p->iccp_dbg_counters; + for (i = 0; i < dbg_counter_p->num_iccp_counter_blocks; ++i) + { + if (i > 0) + ++iccp_counter_p; + + for (j = 0; j < ICCP_DBG_CNTR_MSG_MAX; ++j) + { + fprintf(stdout, "%-20s%-20lu%-20lu%-20lu%-20lu\n", + mclagdctl_dbg_counter_iccpid2str(j), + iccp_counter_p->iccp_counters[j][0][0], + iccp_counter_p->iccp_counters[j][1][0], + iccp_counter_p->iccp_counters[j][0][1], + iccp_counter_p->iccp_counters[j][1][1]); + } + fprintf(stdout, "\n"); + } + /* Netlink counters */ + fprintf(stdout, "\nNetlink Counters\n"); + fprintf(stdout, "-----------------\n"); + fprintf(stdout, "Link add/del: %u/%u\n", + sys_counter_p->newlink_count, sys_counter_p->dellink_count); + fprintf(stdout, " Unknown if_name: %u\n", sys_counter_p->unknown_if_name_count); + fprintf(stdout, "Neighbor(ARP) add/del: %u/%u\n", + sys_counter_p->newnbr_count, sys_counter_p->delnbr_count); + fprintf(stdout, " MAC entry add/del: %u/%u\n", + sys_counter_p->newmac_count, sys_counter_p->delmac_count); + fprintf(stdout, "Address add/del: %u/%u\n", + sys_counter_p->newaddr_count, sys_counter_p->deladdr_count); + fprintf(stdout, "Unexpected message type: %u\n", sys_counter_p->unknown_type_count); + fprintf(stdout, "Receive error: %u\n\n", sys_counter_p->rx_error_count); + return 0; +} + int mclagdctl_enca_config_loglevel(char *msg, int log_level, int argc, char **argv) { struct mclagdctl_req_hdr req; @@ -940,4 +1281,3 @@ int main(int argc, char **argv) return ret; } - diff --git a/src/iccpd/src/mclagdctl/mclagdctl.h b/src/iccpd/src/mclagdctl/mclagdctl.h index 91155ecb7321..ce31b58a1871 100644 --- a/src/iccpd/src/mclagdctl/mclagdctl.h +++ b/src/iccpd/src/mclagdctl/mclagdctl.h @@ -17,7 +17,11 @@ * * Maintainer: Jim Jiang from nephos */ +#include +#include +#include "../../include/system.h" +#define ETHER_ADDR_LEN 6 #define MCLAGDCTL_PARA1_LEN 16 #define MCLAGDCTL_PARA2_LEN 32 #define MCLAGDCTL_PARA3_LEN 64 @@ -54,8 +58,11 @@ enum id_command_type ID_CMDTYPE_D_P, ID_CMDTYPE_D_P_L, ID_CMDTYPE_D_P_P, + ID_CMDTYPE_D_D, + ID_CMDTYPE_D_D_C, ID_CMDTYPE_C, ID_CMDTYPE_C_L, + ID_CMDTYPE_C_D, }; enum mclagdctl_notify_peer_type @@ -65,9 +72,12 @@ enum mclagdctl_notify_peer_type INFO_TYPE_DUMP_ARP, INFO_TYPE_DUMP_NDISC, INFO_TYPE_DUMP_MAC, + INFO_TYPE_DUMP_UNIQUE_IP, INFO_TYPE_DUMP_LOCAL_PORTLIST, INFO_TYPE_DUMP_PEER_PORTLIST, + INFO_TYPE_DUMP_DBG_COUNTERS, INFO_TYPE_CONFIG_LOGLEVEL, + INFO_TYPE_CONFIG_DOWN, INFO_TYPE_FINISH, }; @@ -122,21 +132,28 @@ struct mclagd_state { int mclag_id; int keepalive; + int info_sync_done; char local_ip[MCLAGDCTL_INET_ADDR_LEN]; char peer_ip[MCLAGDCTL_INET_ADDR_LEN]; char peer_link_if[MCLAGDCTL_MAX_L_PORT_NANE]; unsigned char peer_link_mac[MCLAGDCTL_ETHER_ADDR_LEN]; int role; char enabled_po[MCLAGDCTL_PORT_MEMBER_BUF_LEN]; + int session_timeout; + int keepalive_time; char loglevel[MCLAGDCTL_PARA1_LEN]; }; +#define NEIGH_LOCAL 1 +#define NEIGH_REMOTE 2 + struct mclagd_arp_msg { char op_type; char ifname[MCLAGDCTL_MAX_L_PORT_NANE]; char ipv4_addr[MCLAGDCTL_INET_ADDR_LEN]; unsigned char mac_addr[MCLAGDCTL_ETHER_ADDR_LEN]; + uint8_t learn_flag; }; struct mclagd_ndisc_msg @@ -145,13 +162,14 @@ struct mclagd_ndisc_msg char ifname[MCLAGDCTL_MAX_L_PORT_NANE]; char ipv6_addr[MCLAGDCTL_INET6_ADDR_LEN]; unsigned char mac_addr[MCLAGDCTL_ETHER_ADDR_LEN]; + uint8_t learn_flag; }; struct mclagd_mac_msg { unsigned char op_type;/*add or del*/ unsigned char fdb_type;/*static or dynamic*/ - char mac_str[ETHER_ADDR_STR_LEN]; + uint8_t mac_addr[ETHER_ADDR_LEN]; unsigned short vid; /*Current if name that set in chip*/ char ifname[MCLAGDCTL_MAX_L_PORT_NANE]; @@ -178,7 +196,7 @@ struct mclagd_local_if unsigned char po_active; char mlacp_state[MCLAGDCTL_PARA1_LEN]; unsigned char isolate_to_peer_link; - + bool is_traffic_disable; char vlanlist[MCLAGDCTL_PARA3_LEN]; }; @@ -193,6 +211,21 @@ struct mclagd_peer_if unsigned char po_active; }; +typedef struct mclagd_dbg_counter_info +{ + system_dbg_counter_info_t system_dbg; + uint8_t num_iccp_counter_blocks; + uint8_t iccp_dbg_counters[0]; + /* Variable length counter buffers containing N mlacp_dbg_counter_info_t + */ +}mclagd_dbg_counter_info_t; + +struct mclagd_unique_ip_if +{ + int active; + char name[MCLAGDCTL_MAX_L_PORT_NANE]; +}; + extern int mclagdctl_enca_dump_state(char *msg, int mclag_id, int argc, char **argv); extern int mclagdctl_parse_dump_state(char *msg, int data_len); extern int mclagdctl_enca_dump_arp(char *msg, int mclag_id, int argc, char **argv); @@ -208,3 +241,7 @@ extern int mclagdctl_parse_dump_peer_portlist(char *msg, int data_len); int mclagdctl_enca_config_loglevel(char *msg, int log_level, int argc, char **argv); int mclagdctl_parse_config_loglevel(char *msg, int data_len); +extern int mclagdctl_enca_dump_dbg_counters(char *msg, int mclag_id, int argc, char **argv); +extern int mclagdctl_parse_dump_dbg_counters(char *msg, int data_len); +extern int mclagdctl_enca_dump_unique_ip(char *msg, int mclag_id, int argc, char **argv); +extern int mclagdctl_parse_dump_unique_ip(char *msg, int data_len); diff --git a/src/iccpd/src/mlacp_fsm.c b/src/iccpd/src/mlacp_fsm.c index c56eb9051736..b64369775403 100644 --- a/src/iccpd/src/mlacp_fsm.c +++ b/src/iccpd/src/mlacp_fsm.c @@ -35,10 +35,13 @@ #include #include #include +#include #include "../include/mlacp_tlv.h" #include "../include/mlacp_sync_prepare.h" #include "../include/mlacp_link_handler.h" #include "../include/mlacp_sync_update.h" +#include "../include/system.h" +#include "../include/scheduler.h" #include @@ -58,6 +61,18 @@ TAILQ_INIT(&(list)); \ } +#define MLACP_MAC_MSG_QUEUE_REINIT(list) \ + { \ + struct MACMsg* mac_msg = NULL; \ + while (!TAILQ_EMPTY(&(list))) { \ + mac_msg = TAILQ_FIRST(&(list)); \ + TAILQ_REMOVE(&(list), mac_msg, tail); \ + if (mac_msg->op_type == MAC_SYNC_DEL) \ + free(mac_msg); \ + } \ + TAILQ_INIT(&(list)); \ + } + #define PIF_QUEUE_REINIT(list) \ { \ while (!LIST_EMPTY(&(list))) { \ @@ -76,7 +91,7 @@ lif = LIST_FIRST(&(list)); \ if (lif->type == IF_T_PORT_CHANNEL && lif->is_arp_accept) { \ if ((set_sys_arp_accept_flag(lif->name, 0)) == 0) \ - lif->is_arp_accept = 0; \ + lif->is_arp_accept = 0; \ } \ LIST_REMOVE (lif, mlacp_next); \ } \ @@ -93,22 +108,48 @@ LIST_INIT(&(list)); \ } + +void mlacp_local_lif_clear_pending_mac(struct CSM* csm, struct LocalInterface *local_lif); +/***************************************** +* Rb tree Functions +* +* ***************************************/ + +static int MACMsg_compare(const struct MACMsg *mac1, const struct MACMsg *mac2) +{ + if (mac1->vid < mac2->vid) + return -1; + + if (mac1->vid > mac2->vid) + return 1; + + if(memcmp((char *)&mac1->mac_addr, (char *)&mac2->mac_addr, ETHER_ADDR_LEN) < 0) + return -1; + + if(memcmp((char *)&mac1->mac_addr, (char *)&mac2->mac_addr, ETHER_ADDR_LEN) > 0) + return 1; + + return 0; +} + +RB_GENERATE(mac_rb_tree, MACMsg, mac_entry_rb, MACMsg_compare); + #define WARM_REBOOT_TIMEOUT 90 +#define PEER_REBOOT_TIMEOUT 300 /***************************************** * Static Function * * ***************************************/ -static char *mlacp_state(struct CSM* csm); +char *mlacp_state(struct CSM* csm); static void mlacp_resync_arp(struct CSM* csm); -static void mlacp_resync_ndisc(struct CSM* csm); -static void mlacp_resync_mac(struct CSM* csm); +static void mlacp_resync_ndisc(struct CSM *csm); /* Sync Sender APIs*/ static void mlacp_sync_send_sysConf(struct CSM* csm); static void mlacp_sync_send_aggConf(struct CSM* csm); static void mlacp_sync_send_aggState(struct CSM* csm); static void mlacp_sync_send_syncArpInfo(struct CSM* csm); -static void mlacp_sync_send_syncNdiscInfo(struct CSM* csm); +static void mlacp_sync_send_syncNdiscInfo(struct CSM *csm); static void mlacp_sync_send_heartbeat(struct CSM* csm); static void mlacp_sync_send_syncDoneData(struct CSM* csm); /* Sync Reciever APIs*/ @@ -138,6 +179,15 @@ static void mlacp_stage_sync_request_handler(struct CSM* csm, struct Msg* msg); static void mlacp_stage_handler(struct CSM* csm, struct Msg* msg); static void mlacp_exchange_handler(struct CSM* csm, struct Msg* msg); +void mlacp_local_lif_state_mac_handler(struct CSM* csm); + +/* Interface up ack */ +static void mlacp_fsm_send_if_up_ack( + struct CSM *csm, + uint8_t if_type, + uint16_t if_id, + uint8_t port_isolation_enable); + /****************************************************************** * Sync Sender APIs * @@ -210,19 +260,35 @@ static void mlacp_sync_send_aggState(struct CSM* csm) static void mlacp_sync_send_syncMacInfo(struct CSM* csm) { int msg_len = 0; - struct Msg* msg = NULL; + struct MACMsg* mac_msg = NULL; + struct MACMsg mac_find; int count = 0; memset(g_csm_buf, 0, CSM_BUFFER_SIZE); + memset(&mac_find, 0, sizeof(struct MACMsg)); while (!TAILQ_EMPTY(&(MLACP(csm).mac_msg_list))) { - msg = TAILQ_FIRST(&(MLACP(csm).mac_msg_list)); - TAILQ_REMOVE(&(MLACP(csm).mac_msg_list), msg, tail); - msg_len = mlacp_prepare_for_mac_info_to_peer(csm, g_csm_buf, CSM_BUFFER_SIZE, (struct MACMsg*)msg->buf, count); + mac_msg = TAILQ_FIRST(&(MLACP(csm).mac_msg_list)); + MAC_TAILQ_REMOVE(&(MLACP(csm).mac_msg_list), mac_msg, tail); + + msg_len = mlacp_prepare_for_mac_info_to_peer(csm, g_csm_buf, CSM_BUFFER_SIZE, mac_msg, count); count++; - free(msg->buf); - free(msg); + + //free mac_msg if marked for delete. + if (mac_msg->op_type == MAC_SYNC_DEL) + { + if (!(mac_msg->mac_entry_rb.rbt_parent)) + { + //If the entry is parent then the parent pointer would be null + //search to confirm if the MAC is present in RB tree. if not then free. + mac_find.vid = mac_msg->vid ; + memcpy(mac_find.mac_addr, mac_msg->mac_addr, ETHER_ADDR_LEN); + if (!RB_FIND(mac_rb_tree, &MLACP(csm).mac_rb ,&mac_find)) + free(mac_msg); + } + } + if (count >= MAX_MAC_ENTRY_NUM) { iccp_csm_send(csm, g_csm_buf, msg_len); @@ -251,7 +317,7 @@ static void mlacp_sync_send_syncArpInfo(struct CSM* csm) msg = TAILQ_FIRST(&(MLACP(csm).arp_msg_list)); TAILQ_REMOVE(&(MLACP(csm).arp_msg_list), msg, tail); - msg_len = mlacp_prepare_for_arp_info(csm, g_csm_buf, CSM_BUFFER_SIZE, (struct ARPMsg*)msg->buf, count); + msg_len = mlacp_prepare_for_arp_info(csm, g_csm_buf, CSM_BUFFER_SIZE, (struct ARPMsg*)msg->buf, count, NEIGH_SYNC_CLIENT_IP); count++; free(msg->buf); free(msg); @@ -283,7 +349,7 @@ static void mlacp_sync_send_syncNdiscInfo(struct CSM *csm) msg = TAILQ_FIRST(&(MLACP(csm).ndisc_msg_list)); TAILQ_REMOVE(&(MLACP(csm).ndisc_msg_list), msg, tail); - msg_len = mlacp_prepare_for_ndisc_info(csm, g_csm_buf, CSM_BUFFER_SIZE, (struct NDISCMsg *)msg->buf, count); + msg_len = mlacp_prepare_for_ndisc_info(csm, g_csm_buf, CSM_BUFFER_SIZE, (struct NDISCMsg *)msg->buf, count, NEIGH_SYNC_CLIENT_IP); count++; free(msg->buf); free(msg); @@ -301,6 +367,7 @@ static void mlacp_sync_send_syncNdiscInfo(struct CSM *csm) return; } + static void mlacp_sync_send_syncPortChannelInfo(struct CSM* csm) { struct System* sys = NULL; @@ -348,7 +415,7 @@ static void mlacp_sync_send_heartbeat(struct CSM* csm) int msg_len = 0; if ((csm->heartbeat_send_time == 0) || - ((time(NULL) - csm->heartbeat_send_time) > 1)) + ((time(NULL) - csm->heartbeat_send_time) > csm->keepalive_time)) { memset(g_csm_buf, 0, CSM_BUFFER_SIZE); msg_len = mlacp_prepare_for_heartbeat(csm, g_csm_buf, CSM_BUFFER_SIZE); @@ -386,8 +453,15 @@ static void mlacp_sync_recv_sysConf(struct CSM* csm, struct Msg* msg) if (mlacp_fsm_update_system_conf(csm, sysconf) == MCLAG_ERROR) { /*NOTE: we just change the node ID local side without sending NAK msg*/ - ICCPD_LOG_WARN(__FUNCTION__, "Same Node ID = %d, send NAK", MLACP(csm).remote_system.node_id); + ICCPD_LOG_DEBUG("ICCP_FSM", "RX same Node ID = %d, send NAK", MLACP(csm).remote_system.node_id); mlacp_sync_send_nak_handler(csm, msg); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + sysconf->icc_parameter.type, ICCP_DBG_CNTR_STS_ERR); + } + else + { + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + sysconf->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); } return; @@ -419,6 +493,13 @@ static void mlacp_sync_recv_aggConf(struct CSM* csm, struct Msg* msg) if (mlacp_fsm_update_Agg_conf(csm, portconf) == MCLAG_ERROR) { mlacp_sync_send_nak_handler(csm, msg); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portconf->icc_parameter.type, ICCP_DBG_CNTR_STS_ERR); + } + else + { + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portconf->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); } return; @@ -433,7 +514,22 @@ static void mlacp_sync_recv_aggState(struct CSM* csm, struct Msg* msg) { mlacp_sync_send_nak_handler(csm, msg); /*MLACP(csm).error_msg = "Receive a port state update on an non-existed port. It is suggest to check the environment and re-initialize mLACP again.";*/ - return; + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portstate->icc_parameter.type, ICCP_DBG_CNTR_STS_ERR); + } + else + { + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portstate->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); + } + /* Send interface up ack for MLAG interface regardless of the + * processing return code + */ + if (portstate->agg_state == PORT_STATE_UP) + { + mlacp_fsm_send_if_up_ack( + csm, IF_UP_ACK_TYPE_PORT_CHANNEL, ntohs(portstate->agg_id), + PORT_ISOLATION_STATE_ENABLE); } return; @@ -448,7 +544,12 @@ static void mlacp_sync_recv_syncData(struct CSM* csm, struct Msg* msg) { /* Sync done*/ MLACP(csm).wait_for_sync_data = 0; + ICCPD_LOG_DEBUG("ICCP_FSM", "RX sync done"); } + else + ICCPD_LOG_DEBUG("ICCP_FSM", "RX sync start"); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + syncdata->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -460,8 +561,13 @@ static void mlacp_sync_recv_syncReq(struct CSM* csm, struct Msg* msg) mlacp_sync_req = (mLACPSyncReqTLV*)&msg->buf[sizeof(ICCHdr)]; MLACP(csm).sync_req_num = ntohs(mlacp_sync_req->req_num); + ICCPD_LOG_DEBUG("ICCP_FSM", "RX sync_requrest: req_no %d", + MLACP(csm).sync_req_num); + /* Reply the peer all sync info*/ mlacp_sync_send_all_info_handler(csm); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + mlacp_sync_req->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -474,6 +580,13 @@ static void mlacp_sync_recv_portChanInfo(struct CSM* csm, struct Msg* msg) if (mlacp_fsm_update_port_channel_info(csm, portconf) == MCLAG_ERROR) { mlacp_sync_send_nak_handler(csm, msg); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portconf->icc_parameter.type, ICCP_DBG_CNTR_STS_ERR); + } + else + { + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + portconf->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); } return; @@ -485,6 +598,8 @@ static void mlacp_sync_recv_peerLlinkInfo(struct CSM* csm, struct Msg* msg) peerlink = (mLACPPeerLinkInfoTLV*)&(msg->buf[sizeof(ICCHdr)]); mlacp_fsm_update_peerlink_info( csm, peerlink); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + peerlink->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -495,6 +610,8 @@ static void mlacp_sync_recv_macInfo(struct CSM* csm, struct Msg* msg) mac_info = (struct mLACPMACInfoTLV *)&(msg->buf[sizeof(ICCHdr)]); mlacp_fsm_update_mac_info_from_peer(csm, mac_info); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + mac_info->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -505,6 +622,8 @@ static void mlacp_sync_recv_arpInfo(struct CSM* csm, struct Msg* msg) arp_info = (struct mLACPARPInfoTLV *)&(msg->buf[sizeof(ICCHdr)]); mlacp_fsm_update_arp_info(csm, arp_info); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + arp_info->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -518,6 +637,7 @@ static void mlacp_sync_recv_ndiscInfo(struct CSM *csm, struct Msg *msg) return; } + static void mlacp_sync_recv_stpInfo(struct CSM* csm, struct Msg* msg) { /*Don't support currently*/ @@ -530,6 +650,8 @@ static void mlacp_sync_recv_heartbeat(struct CSM* csm, struct Msg* msg) tlv = (struct mLACPHeartbeatTLV *)(&msg->buf[sizeof(ICCHdr)]); mlacp_fsm_update_heartbeat(csm, tlv); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + tlv->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } @@ -540,10 +662,102 @@ static void mlacp_sync_recv_warmboot(struct CSM* csm, struct Msg* msg) tlv = (struct mLACPWarmbootTLV *)(&msg->buf[sizeof(ICCHdr)]); mlacp_fsm_update_warmboot(csm, tlv); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + tlv->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); return; } +static void mlacp_fsm_recv_if_up_ack(struct CSM* csm, struct Msg* msg) +{ + struct mLACPIfUpAckTLV *tlv = NULL; + struct LocalInterface *local_if = NULL; + uint16_t if_id; + + tlv = (struct mLACPIfUpAckTLV *)(&msg->buf[sizeof(ICCHdr)]); + if (tlv == NULL) + return; + + if_id = ntohs(tlv->if_id); + + if (tlv->if_type == IF_UP_ACK_TYPE_PORT_CHANNEL) + { + local_if = local_if_find_by_po_id(if_id); + + ICCPD_LOG_DEBUG("ICCP_FSM", + "RX if_up_ack: po_id %d, local if 0x%x, active %u", + if_id, local_if, local_if ? local_if->po_active : 0); + + /* Ignore the ack if MLAG interface has gone down */ + if (local_if && local_if->po_active) + mlacp_link_enable_traffic_distribution(local_if); + + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + tlv->icc_parameter.type, ICCP_DBG_CNTR_STS_OK); + } + else + { + ICCPD_LOG_ERR("ICCP_FSM", "RX if_up_ack: invalid i/f type %u, i/f ID %u", + tlv->if_type, if_id); + MLACP_SET_ICCP_RX_DBG_COUNTER(csm, + tlv->icc_parameter.type, ICCP_DBG_CNTR_STS_ERR); + } +} + +void mlacp_local_lif_state_mac_handler(struct CSM* csm) +{ + struct LocalInterface* local_if = NULL; + + LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) + { + if ((local_if->state == PORT_STATE_DOWN) && (local_if->type == IF_T_PORT_CHANNEL)) + { + // clear the pending macs if timer is expired. + if (local_if->po_down_time && ((time(NULL) - local_if->po_down_time) > MLACP_LOCAL_IF_DOWN_TIMER)) + { + mlacp_local_lif_clear_pending_mac(csm, local_if); + local_if->po_down_time = 0; + } + } + } +} + +void mlacp_peer_link_learning_handler(struct CSM* csm) +{ + if (csm->peer_link_if == NULL) + return; + + if (csm->peer_link_if->vlan_count == 0) { + return; + } + + if (csm->peer_link_learning_retry_time && ((time(NULL) - csm->peer_link_learning_retry_time) > 2)) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "peer_link_learning_enable %d", csm->peer_link_learning_enable); + set_peerlink_learn_kernel(csm, csm->peer_link_learning_enable, 10); + } +} + +void mlacp_mac_msg_queue_reinit(struct CSM* csm) +{ + + struct MACMsg* mac_msg = NULL; + + MLACP_MAC_MSG_QUEUE_REINIT(MLACP(csm).mac_msg_list); + + ICCPD_LOG_NOTICE("ICCP_FDB", "mlacp_mac_msg_queue_reinit clear mac_msg_list pointers in existing MAC entries"); + + // unset the mac_msg_list pointers for existing MAC entries. + RB_FOREACH (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb) + { + if (MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + CLEAR_MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } + } + return; +} + /***************************************** * MLACP Init * @@ -563,7 +777,8 @@ void mlacp_init(struct CSM* csm, int all) MLACP_MSG_QUEUE_REINIT(MLACP(csm).mlacp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).arp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).ndisc_msg_list); - MLACP_MSG_QUEUE_REINIT(MLACP(csm).mac_msg_list); + mlacp_mac_msg_queue_reinit(csm); + PIF_QUEUE_REINIT(MLACP(csm).pif_list); LIF_PURGE_QUEUE_REINIT(MLACP(csm).lif_purge_list); @@ -572,7 +787,7 @@ void mlacp_init(struct CSM* csm, int all) /* if no clean all, keep the arp info & local interface info for next connection*/ MLACP_MSG_QUEUE_REINIT(MLACP(csm).arp_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).ndisc_list); - MLACP_MSG_QUEUE_REINIT(MLACP(csm).mac_list); + RB_INIT(mac_rb_tree, &MLACP(csm).mac_rb ); LIF_QUEUE_REINIT(MLACP(csm).lif_list); MLACP(csm).node_id = MLACP_SYSCONF_NODEID_MSB_MASK; @@ -596,10 +811,11 @@ void mlacp_finalize(struct CSM* csm) MLACP_MSG_QUEUE_REINIT(MLACP(csm).mlacp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).arp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).ndisc_msg_list); - MLACP_MSG_QUEUE_REINIT(MLACP(csm).mac_msg_list); + mlacp_mac_msg_queue_reinit(csm); MLACP_MSG_QUEUE_REINIT(MLACP(csm).arp_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).ndisc_list); - MLACP_MSG_QUEUE_REINIT(MLACP(csm).mac_list); + + RB_INIT(mac_rb_tree, &MLACP(csm).mac_rb ); /* remove lif & lif-purge queue */ LIF_QUEUE_REINIT(MLACP(csm).lif_list); @@ -637,8 +853,14 @@ void mlacp_fsm_transit(struct CSM* csm) MLACP_MSG_QUEUE_REINIT(MLACP(csm).mlacp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).arp_msg_list); MLACP_MSG_QUEUE_REINIT(MLACP(csm).ndisc_msg_list); - MLACP_MSG_QUEUE_REINIT(MLACP(csm).mac_msg_list); + mlacp_mac_msg_queue_reinit(csm); MLACP(csm).current_state = MLACP_STATE_INIT; + if (csm->sock_fd > 0) + { + /* Close CSM socket and reset its value */ + scheduler_csm_socket_cleanup(csm, 2); + SYSTEM_INCR_SOCKET_CLEANUP_COUNTER(system_get_instance()); + } } return; } @@ -657,6 +879,9 @@ void mlacp_fsm_transit(struct CSM* csm) mlacp_sync_send_heartbeat(csm); + mlacp_local_lif_state_mac_handler(csm); + mlacp_peer_link_learning_handler(csm); + /* Dequeue msg if any*/ while (have_msg) { @@ -728,7 +953,7 @@ void mlacp_fsm_transit(struct CSM* csm) } /* Helper function for dumping application state machine */ -static char* mlacp_state(struct CSM* csm) +char* mlacp_state(struct CSM* csm) { if (csm == NULL ) return "MLACP_NULL"; @@ -767,12 +992,6 @@ void mlacp_enqueue_msg(struct CSM* csm, struct Msg* msg) if (msg == NULL ) return; - #if 0 - icc_hdr = (ICCHdr*)msg->buf; - icc_param = (ICCParameter*)&msg->buf[sizeof(ICCHdr)]; - ICCPD_LOG_DEBUG("mlacp_fsm", " mLACP enqueue: tlv = 0x%04x", icc_param->type); - #endif - TAILQ_INSERT_TAIL(&(MLACP(csm).mlacp_msg_list), msg, tail); return; @@ -792,32 +1011,77 @@ struct Msg* mlacp_dequeue_msg(struct CSM* csm) return msg; } -/****************************************** -* When peerlink ready, prepare the MACMsg -* -******************************************/ -static void mlacp_resync_mac(struct CSM* csm) +void mlacp_sync_mac(struct CSM* csm) { - struct Msg* msg = NULL; struct MACMsg* mac_msg = NULL; - struct Msg *msg_send = NULL; - - /* recover MAC info sync from peer*/ - if (!TAILQ_EMPTY(&(MLACP(csm).mac_list))) + RB_FOREACH (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb) { - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + /*If MAC with local age flag, dont sync to peer. Such MAC only exist when peer is warm-reboot. + If peer is warm-reboot, peer age flag is not set when connection is lost. + When MAC is aged in local switch, this MAC is not deleted for no peer age flag. + After warm-reboot, this MAC must be learnt by peer and sync to local switch*/ + if (!(mac_msg->age_flag & MAC_AGE_LOCAL)) { - mac_msg = (struct MACMsg*)msg->buf; mac_msg->op_type = MAC_SYNC_ADD; - if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + //As part of local sync do not delete peer age + //mac_msg->age_flag &= ~MAC_AGE_PEER; + + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } + + ICCPD_LOG_DEBUG("ICCP_FDB", "Sync MAC: MAC-msg-list enqueue interface %s, " + "MAC %s vlan %d, age_flag %d", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + } + else + { + /*If MAC with local age flag and is point to MCLAG enabled port, reomove local age flag*/ + if (strcmp(mac_msg->ifname, csm->peer_itf_name) != 0) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Sync MAC: MAC-msg-list not enqueue for local age flag: %s, mac %s vlan-id %d, age_flag %d", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + /* After warmboot remote mac can exist, should not + update existing flag + */ + //mac_msg->age_flag &= ~MAC_AGE_LOCAL; + } + } + } + return; +} + +void mlacp_local_lif_clear_pending_mac(struct CSM* csm, struct LocalInterface *local_lif) +{ + ICCPD_LOG_DEBUG("ICCP_FDB", "mlacp_local_lif_clear_pending_mac If: %s ", local_lif->name ); + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) + { + if (mac_msg->pending_local_del && strcmp(mac_msg->origin_ifname, local_lif->name) == 0) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Clear pending MAC: MAC-msg-list not enqueue for local age flag: %s, mac %s vlan-id %d, age_flag %d, remove local age flag", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + + del_mac_from_chip(mac_msg); + + // if static dont delete mac + if (mac_msg->fdb_type != MAC_TYPE_STATIC) { - mac_msg->age_flag &= ~MAC_AGE_PEER; - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail); - ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag); + //TBD do we need to send delete notification to peer .? + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + mac_msg->op_type = MAC_SYNC_DEL; + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } } + else + mac_msg->pending_local_del = 0; } } + return; } /****************************************** @@ -837,6 +1101,7 @@ static void mlacp_resync_arp(struct CSM* csm) { arp_msg = (struct ARPMsg*)msg->buf; arp_msg->op_type = NEIGH_SYNC_ADD; + arp_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, sizeof(struct ARPMsg)) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); @@ -862,6 +1127,7 @@ static void mlacp_resync_ndisc(struct CSM *csm) { ndisc_msg = (struct NDISCMsg *)msg->buf; ndisc_msg->op_type = NEIGH_SYNC_ADD; + ndisc_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, sizeof(struct NDISCMsg)) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); @@ -1016,6 +1282,15 @@ static void mlacp_sync_receiver_handler(struct CSM* csm, struct Msg* msg) case TLV_T_MLACP_WARMBOOT_FLAG: mlacp_sync_recv_warmboot(csm, msg); break; + + case TLV_T_MLACP_IF_UP_ACK: + mlacp_fsm_recv_if_up_ack(csm, msg); + break; + + default: + ICCPD_LOG_ERR("ICCP_FSM", "Receive unsupported msg 0x%x from peer", + icc_param->type); + break; } /*ICCPD_LOG_DEBUG("mlacp_fsm", " [Sync Recv] %s... DONE", get_tlv_type_string(icc_param->type));*/ @@ -1238,7 +1513,13 @@ static void mlacp_exchange_handler(struct CSM* csm, struct Msg* msg) iccp_csm_send(csm, g_csm_buf, len); /* Destroy old interface*/ if (lif_purge != NULL) + { + /* Re-enable traffic distribution on MCLAG interface */ + if ((lif_purge->type == IF_T_PORT_CHANNEL) && lif_purge->is_traffic_disable) + mlacp_link_enable_traffic_distribution(lif_purge); + LIST_REMOVE(lif_purge, mlacp_purge_next); + } } /* Send mlag lif*/ @@ -1246,6 +1527,10 @@ static void mlacp_exchange_handler(struct CSM* csm, struct Msg* msg) { if (lif->type == IF_T_PORT_CHANNEL && lif->port_config_sync) { + /* Disable traffic distribution on LAG members if LAG is down */ + if (!lif->po_active) + mlacp_link_disable_traffic_distribution(lif); + /* Send port channel information*/ memset(g_csm_buf, 0, CSM_BUFFER_SIZE); len = mlacp_prepare_for_Aggport_config(csm, g_csm_buf, CSM_BUFFER_SIZE, lif, 0); @@ -1264,8 +1549,12 @@ static void mlacp_exchange_handler(struct CSM* csm, struct Msg* msg) /* Send port channel state information*/ memset(g_csm_buf, 0, CSM_BUFFER_SIZE); len = mlacp_prepare_for_Aggport_state(csm, g_csm_buf, CSM_BUFFER_SIZE, lif); - iccp_csm_send(csm, g_csm_buf, len); - lif->changed = 0; + //if po state send to peer is not successful, next time will try to + //send again, until then dont unmark lif->changed flag + if (iccp_csm_send(csm, g_csm_buf, len) > 0) + { + lif->changed = 0; + } } } @@ -1291,3 +1580,90 @@ static void mlacp_exchange_handler(struct CSM* csm, struct Msg* msg) return; } + +/***************************************** + * Interface up ACK + * + ****************************************/ +static void mlacp_fsm_send_if_up_ack( + struct CSM *csm, + uint8_t if_type, + uint16_t if_id, + uint8_t port_isolation_enable) +{ + struct System* sys = NULL; + int msg_len = 0; + int rc = -10; + + sys = system_get_instance(); + if (sys == NULL) + return; + + /* Interface up ACK is expected only after the interface is up */ + if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) + return; + + memset(g_csm_buf, 0, CSM_BUFFER_SIZE); + msg_len = mlacp_prepare_for_if_up_ack( + csm, g_csm_buf, CSM_BUFFER_SIZE, if_type, if_id, port_isolation_enable); + if (msg_len > 0) + rc = iccp_csm_send(csm, g_csm_buf, msg_len); + + if (rc <= 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "failed, interface type/id %d/%d, rc %d", + if_type, if_id, rc); + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__,"interface type/id %d/%d", if_type, if_id); + } +} + +/* MLACP ICCP mesage type to debug counter type conversion */ +ICCP_DBG_CNTR_MSG_e mlacp_fsm_iccp_to_dbg_msg_type(uint32_t tlv_type) +{ + switch (tlv_type) + { + case TLV_T_MLACP_SYSTEM_CONFIG: + return ICCP_DBG_CNTR_MSG_SYS_CONFIG; + + case TLV_T_MLACP_AGGREGATOR_CONFIG: + return ICCP_DBG_CNTR_MSG_AGGR_CONFIG; + + case TLV_T_MLACP_AGGREGATOR_STATE: + return ICCP_DBG_CNTR_MSG_AGGR_STATE; + + case TLV_T_MLACP_SYNC_REQUEST: + return ICCP_DBG_CNTR_MSG_SYNC_REQ; + + case TLV_T_MLACP_SYNC_DATA: + return ICCP_DBG_CNTR_MSG_SYNC_DATA; + + case TLV_T_MLACP_HEARTBEAT: + return ICCP_DBG_CNTR_MSG_HEART_BEAT; + + case TLV_T_MLACP_PORT_CHANNEL_INFO: + return ICCP_DBG_CNTR_MSG_PORTCHANNEL_INFO; + + case TLV_T_MLACP_PEERLINK_INFO: + return ICCP_DBG_CNTR_MSG_PEER_LINK_INFO; + + case TLV_T_MLACP_ARP_INFO: + return ICCP_DBG_CNTR_MSG_ARP_INFO; + + case TLV_T_MLACP_MAC_INFO: + return ICCP_DBG_CNTR_MSG_MAC_INFO; + + case TLV_T_MLACP_WARMBOOT_FLAG: + return ICCP_DBG_CNTR_MSG_WARM_BOOT; + + case TLV_T_MLACP_IF_UP_ACK: + return ICCP_DBG_CNTR_MSG_IF_UP_ACK; + + default: + ICCPD_LOG_DEBUG(__FUNCTION__, "No debug counter for TLV type %u", + tlv_type); + return ICCP_DBG_CNTR_MSG_MAX; + } +} diff --git a/src/iccpd/src/mlacp_link_handler.c b/src/iccpd/src/mlacp_link_handler.c index 8bc533e387bd..c0e561988e55 100644 --- a/src/iccpd/src/mlacp_link_handler.c +++ b/src/iccpd/src/mlacp_link_handler.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,14 @@ #include "../include/iccp_csm.h" #include "mclagdctl/mclagdctl.h" #include "../include/iccp_cmd_show.h" +#include "../include/iccp_cli.h" +#include "../include/iccp_cmd.h" +#include "../include/mlacp_link_handler.h" +#include "../include/mlacp_sync_prepare.h" #include "../include/iccp_netlink.h" +#include "../include/scheduler.h" +#include "../include/iccp_ifm.h" + /***************************************** * Enum * @@ -57,6 +65,17 @@ typedef enum route_manipulate_type * ***************************************/ char g_ipv4_str[INET_ADDRSTRLEN]; char g_ipv6_str[INET6_ADDRSTRLEN]; +char g_iccp_mlagsyncd_recv_buf[ICCP_MLAGSYNCD_RECV_MSG_BUFFER_SIZE] = { 0 }; +char g_iccp_mlagsyncd_send_buf[ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE] = { 0 }; + + +extern void mlacp_sync_mac(struct CSM* csm); + +#define SYNCD_SEND_RETRY_INTERVAL_USEC 50000 //50 mseconds +#define SYNCD_SEND_RETRY_MAX 5 + +#define SYNCD_RECV_RETRY_INTERVAL_USEC 50000 //50 mseconds +#define SYNCD_RECV_RETRY_MAX 5 /***************************************** * Tool : show ip string @@ -111,6 +130,7 @@ static int arp_set_handler(struct CSM* csm, struct Msg* msg = NULL; struct ARPMsg* arp_msg = NULL; char mac_str[18] = ""; + int err = 0; if (!csm || !lif) return 0; @@ -121,7 +141,7 @@ static int arp_set_handler(struct CSM* csm, goto del_arp; /* Process Add */ - add_arp: +add_arp: if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) return 0; @@ -141,13 +161,12 @@ static int arp_set_handler(struct CSM* csm, sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4], arp_msg->mac_addr[5]); - iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_msg->ipv4_addr, 1, arp_msg->mac_addr, arp_msg->ifname); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Add dynamic ARP to kernel [%s]", - show_ip_str(arp_msg->ipv4_addr));*/ + err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_msg->ipv4_addr, 1, arp_msg->mac_addr, arp_msg->ifname, 0, 4); + ICCPD_LOG_NOTICE(__FUNCTION__, "Add dynamic ARP to kernel [%s], status %d", show_ip_str(arp_msg->ipv4_addr), err); } goto done; - del_arp: +del_arp: /* Process Del */ TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail) { @@ -161,13 +180,12 @@ static int arp_set_handler(struct CSM* csm, if (arp_msg->op_type == NEIGH_SYNC_DEL) continue; - /* link broken, del all dynamic arp on the lif*/ - iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_msg->ipv4_addr, 0, arp_msg->mac_addr, arp_msg->ifname); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Del dynamic ARP [%s]", - show_ip_str(arp_msg->ipv4_addr));*/ + err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_msg->ipv4_addr, 0, arp_msg->mac_addr, arp_msg->ifname, 0, 5); + /* link broken, del all dynamic arp on the lif */ + ICCPD_LOG_NOTICE(__FUNCTION__, "Del dynamic ARP [%s], status %d", show_ip_str(arp_msg->ipv4_addr), err); } - done: +done: return 0; } @@ -176,6 +194,7 @@ static int ndisc_set_handler(struct CSM *csm, struct LocalInterface *lif, int ad struct Msg *msg = NULL; struct NDISCMsg *ndisc_msg = NULL; char mac_str[18] = ""; + int err = 0; if (!csm || !lif) return 0; @@ -206,8 +225,8 @@ static int ndisc_set_handler(struct CSM *csm, struct LocalInterface *lif, int ad sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", ndisc_msg->mac_addr[0], ndisc_msg->mac_addr[1], ndisc_msg->mac_addr[2], ndisc_msg->mac_addr[3], ndisc_msg->mac_addr[4], ndisc_msg->mac_addr[5]); - iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Add dynamic ND to kernel [%s]", show_ipv6_str((char *)ndisc_msg->ipv6_addr));*/ + err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname, 0, 6); + ICCPD_LOG_NOTICE(__FUNCTION__, "Add dynamic ND to kernel [%s], status %d", show_ipv6_str((char *)ndisc_msg->ipv6_addr), err); } goto done; @@ -225,9 +244,10 @@ static int ndisc_set_handler(struct CSM *csm, struct LocalInterface *lif, int ad if (ndisc_msg->op_type == NEIGH_SYNC_DEL) continue; + err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname, 0, 7); + /* link broken, del all dynamic ndisc on the lif */ - iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 0, ndisc_msg->mac_addr, ndisc_msg->ifname); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Del dynamic ND [%s]", show_ipv6_str((char *)ndisc_msg->ipv6_addr));*/ + ICCPD_LOG_NOTICE(__FUNCTION__, "Del dynamic ND [%s], status %d", show_ipv6_str((char *)ndisc_msg->ipv6_addr), err); } done: @@ -309,6 +329,7 @@ static void update_po_if_info(struct CSM *csm, { local_if->changed = 1; local_if->po_active = (po_state != 0); + /*printf("update po [%s=%d]\n",local_if->name, local_if->po_active);*/ } local_if->mlacp_state = MLACP(csm).current_state; @@ -375,47 +396,129 @@ static int peer_po_is_alive(struct CSM *csm, int po_ifindex) return pif_active; } +// return -1 if failed +ssize_t iccp_send_to_mclagsyncd(uint8_t msg_type, char *send_buff, uint16_t msg_len) +{ + struct System *sys; + ssize_t write = 0; + int num_retry = 0; + size_t pos = 0; + int send_len = 0; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } + + if (sys->sync_fd) + { + while (msg_len > 0) + { + send_len = send(sys->sync_fd, &send_buff[pos], msg_len, MSG_DONTWAIT); + + if (send_len == -1) + { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + ++num_retry; + if (num_retry > SYNCD_SEND_RETRY_MAX) + { + ICCPD_LOG_ERR("ICCP_FSM", "Send to mclagsyncd Non-blocking send() retry failed,msg_type: %d msg_len/send_len %d/%d", + msg_type, msg_len, send_len); + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_type, ICCP_DBG_CNTR_STS_ERR); + return MCLAG_ERROR; + } + else + { + usleep(SYNCD_SEND_RETRY_INTERVAL_USEC); + send_len = 0; + } + } + else + { + ICCPD_LOG_ERR("ICCP_FSM", "Send to mclagsyncd Non-blocking send() failed, msg_type: %d errno %d", + msg_type, errno); + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_type, ICCP_DBG_CNTR_STS_ERR); + return MCLAG_ERROR; + } + } + else if (send_len == 0) + { + ICCPD_LOG_ERR("ICCP_FSM", "Send to mclagsyncd Non-blocking send() failed socket closed msg_type: %d errno %d", + msg_type, errno); + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_type, ICCP_DBG_CNTR_STS_ERR); + return MCLAG_ERROR; + } + msg_len -= send_len; + pos += send_len; + } + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_type, ICCP_DBG_CNTR_STS_OK); + } + + return pos; + +} + +#if 0 static void mlacp_clean_fdb(void) { struct IccpSyncdHDr * msg_hdr; - char *msg_buf = g_csm_buf; - + char *msg_buf = g_iccp_mlagsyncd_send_buf; + ssize_t rc; struct System *sys; sys = system_get_instance(); if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; - memset(msg_buf, 0, CSM_BUFFER_SIZE); + } + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); msg_hdr = (struct IccpSyncdHDr *)msg_buf; - msg_hdr->ver = 1; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; msg_hdr->type = MCLAG_MSG_TYPE_FLUSH_FDB; msg_hdr->len = sizeof(struct IccpSyncdHDr); if (sys->sync_fd) - write(sys->sync_fd, msg_buf, msg_hdr->len); + { + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); - ICCPD_LOG_NOTICE(__FUNCTION__, "Notify mclagsyncd to clear FDB"); + if (rc <= 0) + { + ICCPD_LOG_WARN(__FUNCTION__, "Send to Mclagsyncd failed rc: %d",rc); + } + } + ICCPD_LOG_DEBUG(__FUNCTION__, "Notify mclagsyncd to clear FDB"); return; } +#endif void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable) { struct IccpSyncdHDr * msg_hdr; mclag_sub_option_hdr_t * sub_msg; - char *msg_buf = g_csm_buf; + char *msg_buf = g_iccp_mlagsyncd_send_buf; int msg_len; struct System *sys; + ssize_t rc; sys = system_get_instance(); if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; + } if (!lif) return; - memset(msg_buf, 0, CSM_BUFFER_SIZE); + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); msg_hdr = (struct IccpSyncdHDr *)msg_buf; - msg_hdr->ver = 1; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; msg_hdr->type = MCLAG_MSG_TYPE_PORT_MAC_LEARN_MODE; msg_hdr->len = sizeof(struct IccpSyncdHDr); @@ -433,201 +536,735 @@ void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable) msg_hdr->len += sizeof(mclag_sub_option_hdr_t); msg_hdr->len += sub_msg->op_len; - ICCPD_LOG_NOTICE(__FUNCTION__, "Send %s port MAC learn msg to mclagsyncd for %s", + ICCPD_LOG_DEBUG(__FUNCTION__, "Send %s port MAC learn msg to mclagsyncd for %s", sub_msg->op_type == MCLAG_SUB_OPTION_TYPE_MAC_LEARN_DISABLE ? "DISABLE":"ENABLE", lif->name); /*send msg*/ if (sys->sync_fd) - write(sys->sync_fd, msg_buf, msg_hdr->len); - + { + rc = write(sys->sync_fd,msg_buf, msg_hdr->len); + if ((rc <= 0) || (rc != msg_hdr->len)) + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_ERR); + ICCPD_LOG_ERR(__FUNCTION__, "Failed to write for %s, rc %d", + lif->name, rc); + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + } + } return; } -static void set_peerlink_mlag_port_kernel_forward( - struct CSM *csm, - struct LocalInterface *lif, - int enable) +/* Send request to Mclagsyncd to enable or disable traffic on + * MLAG interface + */ +static int mlacp_link_set_traffic_dist_mode( + char *po_name, + bool is_enable) { - if (!csm || !csm->peer_link_if || !lif) - return; + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + int msg_len; + struct System *sys; + ssize_t rc = 0; - char cmd[256] = { 0 }; + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } - sprintf(cmd, "ebtables %s FORWARD -i %s -o %s -j DROP", - "-D", csm->peer_link_if->name, lif->name); - ICCPD_LOG_NOTICE(__FUNCTION__, " ebtable cmd %s", cmd ); - system(cmd); + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = is_enable ? + MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_ENABLE : + MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_DISABLE; + msg_hdr->len = sizeof(struct IccpSyncdHDr); - sprintf(cmd, "ebtables %s FORWARD -i %s -o %s -j DROP", - (enable) ? "-A" : "-D", csm->peer_link_if->name, lif->name); - ICCPD_LOG_NOTICE(__FUNCTION__, " ebtable cmd %s", cmd ); - system(cmd); + /* Sub-message: port-channel name */ + sub_msg =(mclag_sub_option_hdr_t*) &msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_INTF_NAME; + sub_msg->op_len = strlen(po_name); + memcpy(sub_msg->data, po_name, sub_msg->op_len); - return; + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write traffic %s for %s, rc %d", + is_enable ? "enable" : "disable", po_name, rc); + return MCLAG_ERROR; + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__, "%s traffic dist for interface %s", + is_enable ? "Enable" : "Disable", po_name); + return 0; + } } -void update_peerlink_isolate_from_all_csm_lif( - struct CSM* csm) +/* Send request to Mclagsyncd to update ICCP state + * The message includes MLAG id and ICCP state + */ +int mlacp_link_set_iccp_state( + int mlag_id, + bool is_oper_up) { - struct LocalInterface *lif = NULL; - struct IccpSyncdHDr * msg_hdr; - mclag_sub_option_hdr_t * sub_msg; - char msg_buf[4096]; - struct System *sys; - - char mlag_po_buf[512]; - int src_len = 0, dst_len = 0; + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; sys = system_get_instance(); if (sys == NULL) - return; - - if (!csm || !csm->peer_link_if) - return; - - memset(msg_buf, 0, 4095); - memset(mlag_po_buf, 0, 511); - + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } + /* On startup, session down processing is triggered as part of + * peer link info setting before the socket to Mclagsyncd is setup. + * Check for valid socket to log a notification instead of an error + */ + if ((sys->sync_fd <= 0) && (!is_oper_up)) + { + ICCPD_LOG_NOTICE(__FUNCTION__, + "Unconnected socket to Mclagsyncd, skip mlag %d ICCP down update", + mlag_id); + return MCLAG_ERROR; + } + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); msg_hdr = (struct IccpSyncdHDr *)msg_buf; - msg_hdr->ver = 1; - msg_hdr->type = MCLAG_MSG_TYPE_PORT_ISOLATE; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_SET_ICCP_STATE; msg_hdr->len = sizeof(struct IccpSyncdHDr); - /*sub msg src*/ + /* Sub-message: mlag ID */ sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; - sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ISOLATE_SRC; - - if (csm->peer_link_if->type == IF_T_VXLAN) - { - /*TBD: vxlan tunnel port isolation will be supportted later*/ - return; -#if 0 - int begin_eth_port = 0; - - /*VTTNL0001;Ethernet0001,Ethernet0002*/ - /*src_len= strlen(csm->peer_link_if->name); */ - src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", csm->peer_link_if->name); - src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", ";"); - - /*traverse all ethernet port */ - LIST_FOREACH(lif, &(sys->lif_list), system_next) - { - if (lif->type != IF_T_PORT) - continue; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - /* need to isolate port, get it's name */ - if (begin_eth_port != 0) - { - src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", ","); - } + /* Sub-message: operational status */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_OPER_STATUS; + sub_msg->op_len = sizeof(is_oper_up); + memcpy(sub_msg->data, &is_oper_up, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", lif->name); - begin_eth_port = 1; - } - memcpy(sub_msg->data, src_buf, src_len); + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); - ICCPD_LOG_DEBUG(__FUNCTION__, "isolate src %s, data %s, len %d", src_buf, sub_msg->data, src_len); -#endif + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, ICCP status %s, rc %d", + mlag_id, is_oper_up ? "up" : "down", rc); + return MCLAG_ERROR; } else { - src_len = strlen(csm->peer_link_if->name); - memcpy(sub_msg->data, csm->peer_link_if->name, src_len); + ICCPD_LOG_DEBUG(__FUNCTION__, "Set mlag %d, ICCP status %s", + mlag_id, is_oper_up ? "up" : "down"); + return 0; } - sub_msg->op_len = src_len; +} - /*sub msg dst */ - msg_hdr->len += sub_msg->op_len; - msg_hdr->len += sizeof(mclag_sub_option_hdr_t); - sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; - sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ISOLATE_DST; +/* Send request to Mclagsyncd to update ICCP role + * The message includes MLAG id and ICCP active/standby role. System ID + * is also included for active role + */ +int mlacp_link_set_iccp_role( + int mlag_id, + bool is_active_role, + uint8_t *system_id) +{ + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; - /*traverse all portchannel member port and send msg to syncd */ - LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) + sys = system_get_instance(); + if (sys == NULL) { - if (lif->type != IF_T_PORT_CHANNEL) - continue; + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } - /* check pif port state and lif pochannel state */ - if (lif->isolate_to_peer_link == 1) - { - /* need to isolate port, get it's member name */ - if (strlen(mlag_po_buf) != 0) - dst_len += snprintf(mlag_po_buf + dst_len, sizeof(mlag_po_buf) - dst_len, "%s", ","); + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_SET_ICCP_ROLE; + msg_hdr->len = sizeof(struct IccpSyncdHDr); - dst_len += snprintf(mlag_po_buf + dst_len, sizeof(mlag_po_buf) - dst_len, "%s", lif->portchannel_member_buf); - } - } + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - sub_msg->op_len = dst_len; - msg_hdr->len += sizeof(mclag_sub_option_hdr_t); - msg_hdr->len += sub_msg->op_len; + /* Sub-message: active/standby role */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ICCP_ROLE; + sub_msg->op_len = sizeof(is_active_role); + memcpy(sub_msg->data, &is_active_role, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - if (dst_len) + /* Sub-message: system ID if it is active role */ + if (is_active_role) { - memcpy(sub_msg->data, mlag_po_buf, dst_len); - ICCPD_LOG_NOTICE(__FUNCTION__, "Send port isolate msg to mclagsyncd, src port %s, dst port %s", csm->peer_link_if->name, mlag_po_buf); + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_SYSTEM_ID; + sub_msg->op_len = ETHER_ADDR_LEN; + memcpy(sub_msg->data, system_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + } + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, ICCP role %s, rc %d", + mlag_id, is_active_role ? "active" : "standby", rc); + return MCLAG_ERROR; } else { - ICCPD_LOG_NOTICE(__FUNCTION__, "Send port isolate msg to mclagsyncd, src port %s, dst port is NULL", csm->peer_link_if->name); + ICCPD_LOG_DEBUG(__FUNCTION__, "Set mlag %d, ICCP role to %s", + mlag_id, is_active_role ? "active" : "standby"); + return 0; } - - /*send msg*/ - if (sys->sync_fd) - write(sys->sync_fd, msg_buf, msg_hdr->len); - - return; } -static void set_peerlink_mlag_port_isolate( - struct CSM *csm, - struct LocalInterface *lif, - int enable) +/* Send request to Mclagsyncd to update ICCP system ID + * The message includes MLAG id and system id + */ +int mlacp_link_set_iccp_system_id( + int mlag_id, + uint8_t *system_id) { - if (!lif) - return; + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; - lif->isolate_to_peer_link = enable; + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } - if (!csm || !csm->peer_link_if ) - return; + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_SET_ICCP_SYSTEM_ID; + msg_hdr->len = sizeof(struct IccpSyncdHDr); - if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) - return; + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - ICCPD_LOG_DEBUG(__FUNCTION__, "%s port-isolate from %s to %s", - enable ? "Enable" : "Disable", csm->peer_link_if->name, lif->name); - update_peerlink_isolate_from_all_csm_lif(csm); + /* Sub-message: system ID */ + sub_msg = (mclag_sub_option_hdr_t*)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_SYSTEM_ID; + sub_msg->op_len = ETHER_ADDR_LEN; + memcpy(sub_msg->data, system_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); - /* Kernel also needs to block traffic from peerlink to mlag-port*/ - set_peerlink_mlag_port_kernel_forward(csm, lif, enable); + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); - return; + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, ICCP system ID %s, rc %d", + mlag_id, mac_addr_to_str(system_id), rc); + return MCLAG_ERROR; + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__, + "Set mlag %d, ICCP system ID to %s", + mlag_id, mac_addr_to_str(system_id)); + return 0; + } } -void peerlink_port_isolate_cleanup(struct CSM* csm) +/* Send request to Mclagsyncd to remove MCLAG table entry. + * The message includes MLAG id + */ +int mlacp_link_del_iccp_info( + int mlag_id) { - struct LocalInterface *local_if = NULL; - - if (!csm) - return; + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; - /* Clean all port block*/ - LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) + sys = system_get_instance(); + if (sys == NULL) { - if (local_if->type == IF_T_PORT_CHANNEL) - { - set_peerlink_mlag_port_isolate(csm, local_if, 0); - } + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; } - return; -} + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_DEL_ICCP_INFO; + msg_hdr->len = sizeof(struct IccpSyncdHDr); -void update_peerlink_isolate_from_pif( - struct CSM *csm, - struct PeerInterface *pif, + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + if (sys->sync_fd) + rc = send(sys->sync_fd,msg_buf, msg_hdr->len, MSG_DONTWAIT); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d delete request, rc %d", mlag_id, rc); + return MCLAG_ERROR; + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + ICCPD_LOG_DEBUG("ICCP_FSM", "Delete mlag %d", mlag_id); + return 0; + } +} + + +/* Send request to Mclagsyncd to update remote interface state + * The message includes MLAG id, LAG interface name and operational status + */ +int mlacp_link_set_remote_if_state( + int mlag_id, + char *po_name, + bool is_oper_up) +{ + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } + + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_SET_REMOTE_IF_STATE; + msg_hdr->len = sizeof(struct IccpSyncdHDr); + + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + /* Sub-message: MLAG interface name */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_INTF_NAME; + sub_msg->op_len = strlen(po_name); + memcpy(sub_msg->data, po_name, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + /* Sub-message: operational status */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_OPER_STATUS; + sub_msg->op_len = sizeof(is_oper_up); + memcpy(sub_msg->data, &is_oper_up, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, remote if %s status %s, rc %d", + mlag_id, po_name, is_oper_up ? "up" : "down", rc); + return MCLAG_ERROR; + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + ICCPD_LOG_DEBUG("ICCP_FSM", "Set mlag %d, remote if %s status %s", + mlag_id, po_name, is_oper_up ? "up" : "down"); + return 0; + } +} + + +/* Send request to Mclagsyncd to remove remote interface table entry + * The message includes MLAG id and remote interface name + */ +int mlacp_link_del_remote_if_info( + int mlag_id, + char *po_name) +{ + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } + + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_DEL_REMOTE_IF_INFO; + msg_hdr->len = sizeof(struct IccpSyncdHDr); + + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + /* Sub-message: MLAG interface name */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_INTF_NAME; + sub_msg->op_len = strlen(po_name); + memcpy(sub_msg->data, po_name, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, del remote if %s, rc %d", + mlag_id, po_name, rc); + return MCLAG_ERROR; + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + ICCPD_LOG_DEBUG("ICCP_FSM", "Delete mlag %d, remote if %s", + mlag_id, po_name); + return 0; + } +} + +/* Send request to Mclagsyncd to update port isolation state + * The message includes LAG interface name and enable/disable state + */ +int mlacp_link_set_peerlink_port_isolation( + int mlag_id, + char *po_name, + bool is_isolation_enable) +{ + struct IccpSyncdHDr *msg_hdr; + mclag_sub_option_hdr_t *sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + ssize_t rc = 0; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return MCLAG_ERROR; + } + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_SET_PEER_LINK_ISOLATION; + msg_hdr->len = sizeof(struct IccpSyncdHDr); + + /* Sub-message: mlag ID */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_ID; + sub_msg->op_len = sizeof(mlag_id); + memcpy(sub_msg->data, &mlag_id, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + /* Sub-message: MLAG interface name */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_MCLAG_INTF_NAME; + sub_msg->op_len = strlen(po_name); + memcpy(sub_msg->data, po_name, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + /* Sub-message: isolation enable/disable */ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ISOLATION_STATE; + sub_msg->op_len = sizeof(is_isolation_enable); + memcpy(sub_msg->data, &is_isolation_enable, sub_msg->op_len); + msg_hdr->len += (sizeof(mclag_sub_option_hdr_t) + sub_msg->op_len); + + if (sys->sync_fd) + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + + if ((rc <= 0) || (rc != msg_hdr->len)) + { + ICCPD_LOG_ERR(__FUNCTION__, + "Failed to write mlag %d, %s port isolation %s, rc %d", + mlag_id, po_name, is_isolation_enable ? "enable" : "disable", rc); + return MCLAG_ERROR; + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + ICCPD_LOG_NOTICE("ICCP_FSM", "Set mlag %d, %s port isolation %s", + mlag_id, po_name, is_isolation_enable ? "enable" : "disable"); + return 0; + } +} + +static void set_peerlink_mlag_port_kernel_forward( + struct CSM *csm, + struct LocalInterface *lif, + int enable) +{ + if (!csm || !csm->peer_link_if || !lif) + return; + + char cmd[256] = { 0 }; + + sprintf(cmd, "ebtables %s FORWARD -i %s -o %s -j DROP", + "-D", csm->peer_link_if->name, lif->name); + ICCPD_LOG_DEBUG(__FUNCTION__, " ebtable cmd %s", cmd ); + system(cmd); + + sprintf(cmd, "ebtables %s FORWARD -i %s -o %s -j DROP", + (enable) ? "-I" : "-D", csm->peer_link_if->name, lif->name); + ICCPD_LOG_DEBUG(__FUNCTION__, " ebtable cmd %s", cmd ); + system(cmd); + + return; +} + +void update_peerlink_isolate_from_all_csm_lif( + struct CSM* csm) +{ + struct LocalInterface *lif = NULL; + struct IccpSyncdHDr * msg_hdr; + mclag_sub_option_hdr_t * sub_msg; + char *msg_buf = g_iccp_mlagsyncd_send_buf; + struct System *sys; + + char mlag_po_buf[512]; + int src_len = 0, dst_len = 0; + ssize_t rc; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return; + } + + if (!csm || !csm->peer_link_if) + return; + + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); + memset(mlag_po_buf, 0, 511); + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; + msg_hdr->type = MCLAG_MSG_TYPE_PORT_ISOLATE; + msg_hdr->len = sizeof(struct IccpSyncdHDr); + + /*sub msg src*/ + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ISOLATE_SRC; + + if (csm->peer_link_if->type == IF_T_VXLAN) + { + /*TBD: vxlan tunnel port isolation will be supportted later*/ + return; +#if 0 + int begin_eth_port = 0; + + /*VTTNL0001;Ethernet0001,Ethernet0002*/ + /*src_len= strlen(csm->peer_link_if->name); */ + src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", csm->peer_link_if->name); + src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", ";"); + + /*traverse all ethernet port */ + LIST_FOREACH(lif, &(sys->lif_list), system_next) + { + if (lif->type != IF_T_PORT) + continue; + + /* need to isolate port, get it's name */ + if (begin_eth_port != 0) + { + src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", ","); + } + + src_len += snprintf(src_buf + src_len, sizeof(src_buf) - src_len, "%s", lif->name); + begin_eth_port = 1; + } + memcpy(sub_msg->data, src_buf, src_len); + + ICCPD_LOG_DEBUG(__FUNCTION__, "isolate src %s, data %s, len %d", src_buf, sub_msg->data, src_len); +#endif + } + else + { + src_len = strlen(csm->peer_link_if->name); + memcpy(sub_msg->data, csm->peer_link_if->name, src_len); + } + sub_msg->op_len = src_len; + + /*sub msg dst */ + msg_hdr->len += sub_msg->op_len; + msg_hdr->len += sizeof(mclag_sub_option_hdr_t); + sub_msg = (mclag_sub_option_hdr_t *)&msg_buf[msg_hdr->len]; + sub_msg->op_type = MCLAG_SUB_OPTION_TYPE_ISOLATE_DST; + + /*traverse all portchannel member port and send msg to syncd */ + LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) + { + if (lif->type != IF_T_PORT_CHANNEL) + continue; + + /* check pif port state and lif pochannel state */ + if (lif->isolate_to_peer_link == 1) + { + /* need to isolate port, get it's member name */ + if (strlen(mlag_po_buf) != 0) + dst_len += snprintf(mlag_po_buf + dst_len, sizeof(mlag_po_buf) - dst_len, "%s", ","); + + dst_len += snprintf(mlag_po_buf + dst_len, sizeof(mlag_po_buf) - dst_len, "%s%s%s", + lif->name, lif->portchannel_member_buf[0] == 0 ? "" : ",", lif->portchannel_member_buf); + } + } + + sub_msg->op_len = dst_len; + msg_hdr->len += sizeof(mclag_sub_option_hdr_t); + msg_hdr->len += sub_msg->op_len; + + if (dst_len) + { + memcpy(sub_msg->data, mlag_po_buf, dst_len); + ICCPD_LOG_DEBUG(__FUNCTION__, "Send port isolate msg to mclagsyncd, src port %s, dst port %s", csm->peer_link_if->name, mlag_po_buf); + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Send port isolate msg to mclagsyncd, src port %s, dst port is NULL", csm->peer_link_if->name); + } + + /*send msg*/ + if (sys->sync_fd) + { + rc = write(sys->sync_fd,msg_buf, msg_hdr->len); + if ((rc <= 0) || (rc != msg_hdr->len)) + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_ERR); + ICCPD_LOG_ERR(__FUNCTION__, "Failed to write, rc %d", rc); + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER( + sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); + } + } + + return; +} + +static void set_peerlink_mlag_port_isolate( + struct CSM *csm, + struct LocalInterface *lif, + int enable, + bool is_unbind_pending) +{ + if (!lif) + return; + + lif->isolate_to_peer_link = enable; + + if (!csm || !csm->peer_link_if ) + return; + + if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) + return; + + ICCPD_LOG_DEBUG(__FUNCTION__, "%s port-isolate from %s to %s", + enable ? "Enable" : "Disable", csm->peer_link_if->name, lif->name); + ICCPD_LOG_DEBUG("ICCP_FSM", "Set port isolation %s: mlag_if %s, members %s", + enable ? "enable" : "disable", lif->name, lif->portchannel_member_buf); + + update_peerlink_isolate_from_all_csm_lif(csm); + + /* Kernel also needs to block traffic from peerlink to mlag-port*/ + set_peerlink_mlag_port_kernel_forward(csm, lif, enable); + + /* Do not need to send update to Mclagsyncd to update the local + * MLAG interface table in STATE_DB because Mclagsyncd will delete + * the entry + */ + if (!is_unbind_pending) + mlacp_link_set_peerlink_port_isolation(csm->mlag_id, lif->name, enable); +} + +void peerlink_port_isolate_cleanup(struct CSM* csm) +{ + struct LocalInterface *local_if = NULL; + + if (!csm) + return; + + /* Clean all port block*/ + LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) + { + if (local_if->type == IF_T_PORT_CHANNEL) + { + set_peerlink_mlag_port_isolate(csm, local_if, 0, false); + } + } + + return; +} + +void update_peerlink_isolate_from_pif( + struct CSM *csm, + struct PeerInterface *pif, int pif_po_state, int new_create) { @@ -667,16 +1304,16 @@ void update_peerlink_isolate_from_pif( if (pif_po_state == 1) { /* both peer-pair link up, enable port-isolate*/ - ICCPD_LOG_DEBUG(__FUNCTION__, "Enable port-isolate from %s to %s", - csm->peer_link_if->name, lif->name); - set_peerlink_mlag_port_isolate(csm, lif, 1); + ICCPD_LOG_DEBUG("ICCP_FSM", "Enable port-isolate: from peer_link %s to mlag_if %s", + csm->peer_link_if->name, lif->name); + set_peerlink_mlag_port_isolate(csm, lif, 1, false); } else { /* local link up, and peer link changes to down, disable port-isolate*/ - ICCPD_LOG_DEBUG(__FUNCTION__, "Disable port-isolate from %s to %s", - csm->peer_link_if->name, lif->name); - set_peerlink_mlag_port_isolate(csm, lif, 0); + ICCPD_LOG_DEBUG("ICCP_FSM", "Disable port-isolate: from peer_link %s to mlag_if %s", + csm->peer_link_if->name, lif->name); + set_peerlink_mlag_port_isolate(csm, lif, 0, false); } } else @@ -711,7 +1348,7 @@ static void update_peerlink_isolate_from_lif( break; } - ICCPD_LOG_DEBUG(__FUNCTION__, "From if %s local(%s) / peer(%s)", + ICCPD_LOG_DEBUG(__FUNCTION__, " from local %s local(%s) / peer(%s)", lif->name, (lif_po_state) ? "up" : "down", (pif_po_state) ? "up" : "down"); if (lif_po_state == 1) @@ -721,14 +1358,14 @@ static void update_peerlink_isolate_from_lif( /* both peer-pair link up, enable port-isolate*/ ICCPD_LOG_DEBUG(__FUNCTION__, "Enable port-isolate from %s to %s", csm->peer_link_if->name, lif->name); - set_peerlink_mlag_port_isolate(csm, lif, 1); + set_peerlink_mlag_port_isolate(csm, lif, 1, false); } else { /* peer link down, local link changes to up, disable port-isolate*/ ICCPD_LOG_DEBUG(__FUNCTION__, " Disable port-isolate from %s to %s", csm->peer_link_if->name, lif->name); - set_peerlink_mlag_port_isolate(csm, lif, 0); + set_peerlink_mlag_port_isolate(csm, lif, 0, false); } } else @@ -750,14 +1387,8 @@ static void update_l2_po_state(struct CSM *csm, if (!csm || !lif) return; - /*L2 po*/ - /*if (po_state != lif->po_active && po_state == 0) - { - mlacp_clean_fdb(); - }*/ - /*Is there any L3 vlan over L2 po?*/ - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) + RB_FOREACH (vlan, vlan_rb_tree, &(lif->vlan_tree)) { route_type = ROUTE_NONE; @@ -869,6 +1500,7 @@ void syn_arp_info_to_peer(struct CSM *csm, struct LocalInterface *local_if) arp_msg = (struct ARPMsg*)msg->buf; arp_msg->op_type = NEIGH_SYNC_ADD; + arp_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, sizeof(struct ARPMsg)) == 0) { @@ -878,7 +1510,7 @@ void syn_arp_info_to_peer(struct CSM *csm, struct LocalInterface *local_if) } else ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] for %s", - show_ip_str(arp_msg->ipv4_addr)); + show_ip_str(htonl(arp_msg->ipv4_addr))); } } @@ -905,19 +1537,21 @@ void syn_ndisc_info_to_peer(struct CSM *csm, struct LocalInterface *local_if) ndisc_msg = (struct NDISCMsg *)msg->buf; ndisc_msg->op_type = NEIGH_SYNC_ADD; + ndisc_msg->flag = 0; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, sizeof(struct NDISCMsg)) == 0) { TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ND[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr));*/ + ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ND[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } else - ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ND[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); + ICCPD_LOG_DEBUG(__FUNCTION__, "Failed to enqueue ND[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } } return; } + void update_stp_peer_link(struct CSM *csm, struct PeerInterface *pif, int po_state, int new_create) @@ -927,6 +1561,12 @@ void update_stp_peer_link(struct CSM *csm, if (!csm || !pif) return; + + ICCPD_LOG_DEBUG("ICCP_FSM", + "PEER_MLAG_IF %s %s: po_active %d, new_state %s, sync_state %s", + pif->name, new_create ? "add" : "update", + pif->po_active, po_state ? "up" : "down", mlacp_state(csm)); + if (new_create == 0 && po_state == pif->po_active) return; @@ -952,7 +1592,7 @@ void update_stp_peer_link(struct CSM *csm, } else { - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) + RB_FOREACH(vlan, vlan_rb_tree, &(lif->vlan_tree)) { if (!is_local_vlan_on(vlan)) continue; @@ -979,255 +1619,471 @@ void update_stp_peer_link(struct CSM *csm, break; } - return; } -void iccp_get_fdb_change_from_syncd( void) +void iccp_send_fdb_entry_to_syncd( struct MACMsg* mac_msg, uint8_t mac_type, uint8_t oper) { struct IccpSyncdHDr * msg_hdr; - char msg_buf[512]; + char *msg_buf = g_iccp_mlagsyncd_send_buf; struct System *sys; + struct mclag_fdb_info * mac_info; + ssize_t rc; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; sys = system_get_instance(); if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; + } - memset(msg_buf, 0, 512); - - msg_hdr = (struct IccpSyncdHDr *)msg_buf; - msg_hdr->ver = 1; - msg_hdr->type = MCLAG_MSG_TYPE_GET_FDB_CHANGES; - msg_hdr->len = sizeof(struct IccpSyncdHDr); - - ICCPD_LOG_DEBUG(__FUNCTION__, "Send get fdb change msg to mclagsyncd"); - - /*send msg*/ - if (sys->sync_fd > 0) - write(sys->sync_fd, msg_buf, msg_hdr->len); - - return; -} - -void iccp_send_fdb_entry_to_syncd( struct MACMsg* mac_msg, uint8_t mac_type) -{ - struct IccpSyncdHDr * msg_hdr; - char msg_buf[512]; - struct System *sys; - struct mclag_fdb_info * mac_info; - - sys = system_get_instance(); - if (sys == NULL) + if (memcmp(mac_msg->mac_addr, null_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address do not send to Syncd."); return; + } - memset(msg_buf, 0, 512); + memset(msg_buf, 0, ICCP_MLAGSYNCD_SEND_MSG_BUFFER_SIZE); msg_hdr = (struct IccpSyncdHDr *)msg_buf; - msg_hdr->ver = 1; + msg_hdr->ver = ICCPD_TO_MCLAGSYNCD_HDR_VERSION; msg_hdr->type = MCLAG_MSG_TYPE_SET_FDB; /*mac msg */ mac_info = (struct mclag_fdb_info *)&msg_buf[sizeof(struct IccpSyncdHDr)]; mac_info->vid = mac_msg->vid; memcpy(mac_info->port_name, mac_msg->ifname, MAX_L_PORT_NAME); - memcpy(mac_info->mac, mac_msg->mac_str, ETHER_ADDR_STR_LEN); + memcpy(mac_info->mac, mac_msg->mac_addr, ETHER_ADDR_LEN); mac_info->type = mac_type; - mac_info->op_type = mac_msg->op_type; + mac_info->op_type = oper; msg_hdr->len = sizeof(struct IccpSyncdHDr) + sizeof(struct mclag_fdb_info); - ICCPD_LOG_NOTICE(__FUNCTION__, "Send mac %s msg to mclagsyncd, vid %d ; ifname %s ; mac %s; type %s", - mac_info->op_type == MAC_SYNC_ADD ? "add" : "del", mac_info->vid, mac_info->port_name, mac_info->mac, mac_info->type == MAC_TYPE_STATIC ? "static" : "dynamic"); + ICCPD_LOG_DEBUG("ICCP_FDB", "Send fdb to syncd: write mac msg vid : %d ; ifname %s ; mac %s fdb type %d ; op type %s", + mac_info->vid, mac_info->port_name, mac_addr_to_str(mac_info->mac), mac_info->type, + oper == MAC_SYNC_ADD ? "add" : "del"); /*send msg*/ if (sys->sync_fd > 0 ) - write(sys->sync_fd, msg_buf, msg_hdr->len); + { + rc = iccp_send_to_mclagsyncd(msg_hdr->type, msg_buf, msg_hdr->len); + if (rc <= 0) + { + ICCPD_LOG_WARN(__FUNCTION__, "Send to Mclagsyncd failed rc: %d",rc); + } + } + else + { + SYSTEM_SET_SYNCD_TX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_ERR); + ICCPD_LOG_ERR(__FUNCTION__, "Invalid sync_fd Failed to write, fd %d", sys->sync_fd); + } + + if (oper == MAC_SYNC_DEL) + mac_msg->add_to_syncd = 0; + else + mac_msg->add_to_syncd = 1; return; } void add_mac_to_chip(struct MACMsg* mac_msg, uint8_t mac_type) { - mac_msg->op_type = MAC_SYNC_ADD; - iccp_send_fdb_entry_to_syncd( mac_msg, mac_type); + iccp_send_fdb_entry_to_syncd( mac_msg, mac_type, MAC_SYNC_ADD); return; } void del_mac_from_chip(struct MACMsg* mac_msg) { - mac_msg->op_type = MAC_SYNC_DEL; - iccp_send_fdb_entry_to_syncd( mac_msg, mac_msg->fdb_type); + iccp_send_fdb_entry_to_syncd( mac_msg, mac_msg->fdb_type, MAC_SYNC_DEL); return; } -uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg* mac_msg, uint8_t set ) +uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg* mac_msg, uint8_t set, uint8_t update_peer ) { uint8_t new_age_flag = 0; - struct Msg *msg = NULL; new_age_flag = mac_msg->age_flag; if (set == 0)/*remove age flag*/ { - new_age_flag &= ~MAC_AGE_LOCAL; + if (new_age_flag & MAC_AGE_LOCAL) + { + new_age_flag &= ~MAC_AGE_LOCAL; - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove local age flag: %d ifname %s, add %s vlan-id %d, age_flag %d", - new_age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag); + ICCPD_LOG_DEBUG("ICCP_FDB", "After Remove local age, flag: %d interface %s, " + "add %s vlan-id %d, old age_flag %d", new_age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); - /*send mac MAC_SYNC_ADD message to peer*/ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) - { - mac_msg->op_type = MAC_SYNC_ADD; - if (iccp_csm_init_msg(&msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + /*send mac MAC_SYNC_ADD message to peer*/ + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && update_peer) { - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg, tail); + mac_msg->op_type = MAC_SYNC_ADD; + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } /*ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, age_flag %d", mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag);*/ } - else + } + } + else/*set age flag*/ + { + if (!(new_age_flag & MAC_AGE_LOCAL)) + { + new_age_flag |= MAC_AGE_LOCAL; + + ICCPD_LOG_DEBUG("ICCP_FDB", "After local age set, flag: %d interface %s, " + "MAC %s vlan-id %d, old age_flag %d", new_age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + + /*send mac MAC_SYNC_DEL message to peer*/ + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && update_peer) { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue MAC-msg-list: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag); + mac_msg->op_type = MAC_SYNC_DEL; + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); } + + ICCPD_LOG_DEBUG("ICCP_FDB", "Set local age: MAC-msg-list enqueue interface: %s, oper: %s " + "MAC %s vlan-id %d, age_flag %d", mac_msg->ifname, + (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + } } } - else/*set age flag*/ + return new_age_flag; +} + +/*Deal with mac add,del,move when portchannel up or down*/ +static void update_l2_mac_state(struct CSM *csm, + struct LocalInterface *lif, + int po_state) +{ + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; + struct PeerInterface* pif = NULL; + pif = peer_if_find_by_name(csm, lif->name); + + if (!csm || !lif) + return; + + if (po_state == 0) + { + lif->po_down_time = time(NULL); + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, ifname: %s, po_down_time: %u", lif->name, lif->po_down_time); + } + else { - new_age_flag |= MAC_AGE_LOCAL; + lif->po_down_time = 0; + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf up, ifname: %s, clear po_down_time, time %u", lif->name, lif->po_down_time); + } + - ICCPD_LOG_DEBUG(__FUNCTION__, "Add local age flag: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag); + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) + { + /* find the MAC for this interface*/ + if (strcmp(lif->name, mac_msg->origin_ifname) != 0) + continue; - /*send mac MAC_SYNC_DEL message to peer*/ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + /*portchannel down*/ + if (po_state == 0) { - mac_msg->op_type = MAC_SYNC_DEL; - if (iccp_csm_init_msg(&msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + // MAC is locally learned do not delete MAC, Move to peer_link + if ((mac_msg->age_flag == MAC_AGE_PEER) && pif && (pif->state == PORT_STATE_UP)) { - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg, tail); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag);*/ + if ((strlen(csm->peer_itf_name) != 0) && csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) + { + memcpy(mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, MAC learn local only, age flag %d, " + "redirect MAC to peer-link: %s, MAC %s vlan-id %d", + mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + } + else + { + del_mac_from_chip(mac_msg); + memcpy(mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, MAC learn local only, age flag %d, " + "can not redirect, del MAC as peer-link %s not available or down, " + "MAC %s vlan-id %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + + mac_msg->pending_local_del = 1; + + continue; + } + + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 1); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, age flag %d, MAC %s, " + "vlan-id %d, Interface: %s", mac_msg->age_flag , + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + + if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) + { + /*send mac del message to mclagsyncd.*/ + if (mac_msg->fdb_type != MAC_TYPE_STATIC) + del_mac_from_chip(mac_msg); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, del MAC %s, vlan-id %d," + " Interface: %s,", mac_addr_to_str(mac_msg->mac_addr), + mac_msg->vid, mac_msg->ifname); + + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } } else { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue MAC-msg-list: %s, del %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag); + /*If local is aged but peer is not aged, redirect the mac to peer-link*/ + if (strlen(csm->peer_itf_name) != 0) + { + /*Send mac add message to mclagsyncd. fdb_type is not changed*/ + /*Is need to delete the old item before add?(Old item probably is static)*/ + if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) + { + memcpy(mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, age flag %d, " + "redirect MAC to peer-link: %s, MAC %s vlan-id %d", + mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + else + { + /*must redirect but peerlink is down, del mac from ASIC*/ + /*if peerlink change to up, mac will add back to ASIC*/ + del_mac_from_chip(mac_msg); + memcpy(mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, age flag %d, " + "can not redirect, del MAC as peer-link: %s down, " + "MAC %s vlan-id %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + } + else + { + /*peer-link is not configured, del mac from ASIC, mac still in mac_rb*/ + del_mac_from_chip(mac_msg); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf down, flag %d, peer-link: %s not available, " + "MAC %s vlan-id %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + } + } + else /*portchannel up*/ + { + /*the old item is redirect to peerlink for portchannel down*/ + /*when this portchannel up, recover the mac back*/ + if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf up, redirect MAC to Interface: %s," + " MAC %s vlan-id %d, age flag: %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + + if (mac_msg->pending_local_del) + mac_msg->pending_local_del = 0; + + /*Remove MAC_AGE_LOCAL flag*/ + // commenting this code to fix an issue, when interface comes back up dont delete age flag + // as the MAC is remote now, delete only if MAC learns again. + //mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0, 1); + + /*Reverse interface from peer-link to the original portchannel*/ + memcpy(mac_msg->ifname, mac_msg->origin_ifname, MAX_L_PORT_NAME); + + /*Send dynamic or static mac add message to mclagsyncd*/ + + if (mac_msg->age_flag == MAC_AGE_LOCAL) + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + else + add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC_LOCAL); + } + else + { + // Delete the MAC from HW so that it can be re-learned accordingly if traffic is still hitting local node. + if (mac_msg->pending_local_del) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf up, Clear pending MAC: interface: %s, mac %s vlan-id %d, age_flag %d", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + + del_mac_from_chip(mac_msg); + + // if static dont delete mac + if (mac_msg->fdb_type != MAC_TYPE_STATIC) + { + //TBD do we need to send delete notification to peer .? + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + mac_msg->op_type = MAC_SYNC_DEL; + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } + } + else + mac_msg->pending_local_del = 0; + } + +// Dont set local learn unless learned from MCLAGSYNCD. +// When interface is UP MAC addresses gets re-learned +#if 0 + /*this may be peerlink is not configured and portchannel is down*/ + /*when this portchannel up, add the mac back to ASIC*/ + ICCPD_LOG_DEBUG("ICCP_FDB", "Intf up, add MAC %s to ASIC," + " vlan-id %d Interface %s", mac_addr_to_str(mac_msg->mac_addr), + mac_msg->vid, mac_msg->ifname); + + /*Remove MAC_AGE_LOCAL flag*/ + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0, 1); + + + memcpy(mac_msg->ifname, mac_msg->origin_ifname, MAX_L_PORT_NAME); + + /*Send dynamic or static mac add message to mclagsyncd*/ + add_mac_to_chip(mac_msg, mac_msg->fdb_type); +#endif } } } - return new_age_flag; + return; } -/*Deal with mac add,del,move when portchannel up or down*/ -static void update_l2_mac_state(struct CSM *csm, - struct LocalInterface *lif, - int po_state) +void update_orphan_port_mac(struct CSM *csm, + struct LocalInterface *lif, + int state) +{ + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; + + if (!csm || !lif) + return; + + if (!state) + return; + + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) + { + if (strcmp(mac_msg->origin_ifname, lif->name ) != 0) + continue; + + ICCPD_LOG_DEBUG("ICCP_FDB", "Orphan port is UP sync MAC: interface %s, " + "MAC %s vlan-id %d, age flag: %d, exchange state :%d", mac_msg->origin_ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + mac_msg->age_flag, MLACP(csm).current_state); + + // sync local macs on orphan port , if any + if ((mac_msg->age_flag == MAC_AGE_PEER) && (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)) + { + mac_msg->op_type = MAC_SYNC_ADD; + + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } + } + } +} + +void mlacp_convert_remote_mac_to_local(struct CSM *csm, char *po_name) +{ + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; + struct LocalInterface* lif = NULL; + lif = local_if_find_by_name(po_name); + + if (!csm || !lif) + return; + + if (lif->state == PORT_STATE_DOWN) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Do not Convert remote mac as Local interface %s is down", po_name); + return; + } + + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) + { + if (strcmp(mac_msg->origin_ifname, po_name) != 0) + continue; + + // convert only remote macs. + if (mac_msg->age_flag == MAC_AGE_LOCAL) + { + mac_msg->age_flag = MAC_AGE_PEER; + ICCPD_LOG_DEBUG("ICCP_FDB", "Convert remote mac on Origin Interface as local: interface %s, " + "interface %s, MAC %s vlan-id %d age flag:%d", mac_msg->origin_ifname, + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->age_flag); + + /*Send mac add message to mclagsyncd with aging enabled*/ + add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC_LOCAL); + + mac_msg->op_type = MAC_SYNC_ADD; + + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } + } + } +} + +//update remote macs to point to peerlink, if peer link is configured +static void update_remote_macs_to_peerlink(struct CSM *csm, struct LocalInterface *lif) { - struct Msg* msg = NULL; - struct MACMsg* mac_msg = NULL; + struct MACMsg* mac_entry = NULL; if (!csm || !lif) return; - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + RB_FOREACH (mac_entry, mac_rb_tree, &MLACP(csm).mac_rb) { - mac_msg = (struct MACMsg*)msg->buf; - /* find the MAC for this interface*/ - if (strcmp(lif->name, mac_msg->origin_ifname) != 0) + if (strcmp(lif->name, mac_entry->origin_ifname) != 0) continue; - /*portchannel down*/ - if (po_state == 0) + //consider only remote mac; rest of MACs no need to handle + if(mac_entry->age_flag & MAC_AGE_PEER) { - ICCPD_LOG_NOTICE(__FUNCTION__, "Intf %s down, age local MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1); - - if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) - { - /*send mac del message to mclagsyncd.*/ - if (mac_msg->fdb_type != MAC_TYPE_STATIC) - del_mac_from_chip(mac_msg); + continue; + } - ICCPD_LOG_DEBUG(__FUNCTION__, "Intf %s down, del MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "Update remote macs to peer: age flag %d, MAC %s, " + "vlan-id %d, Interface: %s", mac_entry->age_flag , + mac_addr_to_str(mac_entry->mac_addr), mac_entry->vid, mac_entry->ifname); - /*If local and peer both aged, del the mac*/ - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); - } - else + //If local interface unbinded, redirect the mac to peer-link if peer + //link is configured + if (strlen(csm->peer_itf_name) != 0) + { + /*Send mac add message to mclagsyncd. fdb_type is not changed*/ + if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) { - /*If local is aged but peer is not aged, redirect the mac to peer-link*/ - if (strlen(csm->peer_itf_name) != 0) - { - /*Send mac add message to mclagsyncd. fdb_type is not changed*/ - /*Is need to delete the old item before add?(Old item probably is static)*/ - if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) - { - memcpy(mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); - add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC); - } - else - { - /*must redirect but peerlink is down, del mac from ASIC*/ - /*if peerlink change to up, mac will add back to ASIC*/ - del_mac_from_chip(mac_msg); - memcpy(mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); - } - - ICCPD_LOG_NOTICE(__FUNCTION__, "Intf %s down, redirect MAC %s vlan-id %d to peer-link %s", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, csm->peer_itf_name); - } - else + //if the mac is already pointing to peer interface, no need to + //change it + if (strcmp(mac_entry->ifname, csm->peer_itf_name) != 0) { - /*peer-link is not configured, del mac from ASIC, mac still in mac_list*/ - del_mac_from_chip(mac_msg); - - ICCPD_LOG_NOTICE(__FUNCTION__, "Intf %s down, peer-link is not configured: MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + memcpy(mac_entry->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + add_mac_to_chip(mac_entry, mac_entry->fdb_type); + ICCPD_LOG_DEBUG("ICCP_FDB", "Update remote macs to peer: age flag %d, " + "redirect MAC to peer-link: %s, MAC %s vlan-id %d", + mac_entry->age_flag, mac_entry->ifname, + mac_addr_to_str(mac_entry->mac_addr), mac_entry->vid); } } } - else /*portchannel up*/ - { - /*the old item is redirect to peerlink for portchannel down*/ - /*when this portchannel up, recover the mac back*/ - if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) - { - ICCPD_LOG_NOTICE(__FUNCTION__, "Intf %s up, redirect MAC %s vlan-id %d from peerlink to %s", - mac_msg->origin_ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->origin_ifname); - - /*Remove MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); - - /*Reverse interface from peer-link to the original portchannel*/ - memcpy(mac_msg->ifname, mac_msg->origin_ifname, MAX_L_PORT_NAME); - - /*Send dynamic or static mac add message to mclagsyncd*/ - add_mac_to_chip(mac_msg, mac_msg->fdb_type); - } - else - { - /*this may be peerlink is not configured and portchannel is down*/ - /*when this portchannel up, add the mac back to ASIC*/ - ICCPD_LOG_NOTICE(__FUNCTION__, "Intf %s up, add MAC %s vlan-id %d to ASIC", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - - /*Remove MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); - - /*Send dynamic or static mac add message to mclagsyncd*/ - add_mac_to_chip(mac_msg, mac_msg->fdb_type); - } - } } - return; } @@ -1237,6 +2093,13 @@ void mlacp_portchannel_state_handler(struct CSM* csm, { if (!csm || !local_if) return; + ICCPD_LOG_DEBUG("ICCP_FSM", + "MLAG_IF(%s) %s %s: state %s, po_active %d, traffic_dis %d, sync_state %s cfg_sync/changed %d/%d", + local_if_is_l3_mode(local_if) ? "L3" : "L2", + local_if->name, po_state ? "up" : "down", + (local_if->state == PORT_STATE_UP) ? "up" : "down", + local_if->po_active, local_if->is_traffic_disable, + mlacp_state(csm), local_if->port_config_sync, local_if->changed); update_peerlink_isolate_from_lif(csm, local_if, po_state); @@ -1249,60 +2112,94 @@ void mlacp_portchannel_state_handler(struct CSM* csm, update_po_if_info(csm, local_if, po_state); + /* Disable packet tx/rx on MLAG interface when it is down + * Traffic is re-enabled back after the interface is up and ack is + * received from peer + */ + if (po_state == 0) + mlacp_link_disable_traffic_distribution(local_if); + return; } -static void mlacp_conn_handler_fdb(struct CSM* csm) +void mlacp_mlag_intf_detach_handler(struct CSM* csm, struct LocalInterface* local_if) { - struct Msg* msg = NULL; - struct MACMsg* mac_msg = NULL; - struct Msg *msg_send = NULL; - - if (!csm) + if (!csm || !local_if) return; - if (!TAILQ_EMPTY(&(MLACP(csm).mac_list))) - { - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) - { - mac_msg = (struct MACMsg*)msg->buf; + ICCPD_LOG_DEBUG("ICCP_FSM", + "MLAG_IF(%s) %s Detach: state %s, po_active %d, traffic_dis %d, sync_state %s", + local_if_is_l3_mode(local_if) ? "L3" : "L2", + local_if->name, + (local_if->state == PORT_STATE_UP) ? "up" : "down", + local_if->po_active, local_if->is_traffic_disable, + mlacp_state(csm)); - /*Wait the ACK from peer?*/ - /*mac_msg->age_flag &= ~MAC_AGE_PEER;*/ + //set port isolate for lifpo + mlacp_mlag_link_del_handler(csm, local_if); - /*If MAC with local age flag, dont sync to peer. Such MAC only exist when peer is warm-reboot. - If peer is warm-reboot, peer age flag is not set when connection is lost. - When MAC is aged in local switch, this MAC is not deleted for no peer age flag. - After warm-reboot, this MAC must be learnt by peer and sync to local switch*/ - if (!(mac_msg->age_flag & MAC_AGE_LOCAL)) - { - /*Send mac add message to peer*/ - mac_msg->op_type = MAC_SYNC_ADD; - if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0) - { - mac_msg->age_flag &= ~MAC_AGE_PEER; - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail); - ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - } - } - else - { - /*If MAC with local age flag and is point to MCLAG enabled port, reomove local age flag*/ - if (strcmp(mac_msg->ifname, csm->peer_itf_name) != 0) - { - ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list not enqueue for local age flag: %s, mac %s vlan-id %d, remove local age flag", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - mac_msg->age_flag &= ~MAC_AGE_LOCAL; - } - } + //point remotely learnt macs to peer-link + update_remote_macs_to_peerlink(csm, local_if); + + //Handle Route/ARP changes as if portchannel is down + if (!local_if_is_l3_mode(local_if)) + update_l2_po_state(csm, local_if, 0); + else + update_l3_po_state(csm, local_if, 0); + + + //If the traffic is disabled due to interface flap; while coming up, if + //mclag interface is removed before receiving ack, it will be in + //blocked state; to address timing scenario unblock Tx/Rx of + //traffic on this portchannel if the traffic is blocked on this port + if(local_if->is_traffic_disable) + { + if ( !csm->peer_link_if || !(strcmp(csm->peer_link_if->name, local_if->name)) ) + { + mlacp_link_enable_traffic_distribution(local_if); } } return; } -static void mlacp_fix_bridge_mac(struct CSM* csm) +//Handler to handle when mclag interface is deleted on peer end +void mlacp_peer_mlag_intf_delete_handler(struct CSM* csm, char *mlag_if_name) +{ + struct LocalInterface *local_if = NULL; + if (!csm) + return; + + local_if = local_if_find_by_name(mlag_if_name); + + if (!local_if) + return; + + ICCPD_LOG_DEBUG("ICCP_FSM", + "MLAG_IF(%s) %s Peer IF Delete Event: state %s, po_active %d, traffic_dis %d, sync_state %s", + local_if_is_l3_mode(local_if) ? "L3" : "L2", + local_if->name, + (local_if->state == PORT_STATE_UP) ? "up" : "down", + local_if->po_active, local_if->is_traffic_disable, + mlacp_state(csm)); + + //if it is standby node change back the mac to its original system mac + recover_if_ipmac_on_standby(local_if, 2); + + return; +} + + +static void mlacp_conn_handler_fdb(struct CSM* csm) +{ + if (!csm) + return; + ICCPD_LOG_DEBUG(__FUNCTION__, " Sync MAC addresses to peer "); + mlacp_sync_mac(csm); + return; +} + +void mlacp_fix_bridge_mac(struct CSM* csm) { char syscmd[128]; int ret = 0; @@ -1320,7 +2217,7 @@ static void mlacp_fix_bridge_mac(struct CSM* csm) /*The Bridge mac can not be the same as peer system id, so fix the Bridge MAC address here.*/ sprintf(syscmd, "ip link set dev Bridge address %s > /dev/null 2>&1", macaddr); ret = system(syscmd); - ICCPD_LOG_NOTICE(__FUNCTION__, " %s ret = %d", syscmd, ret); + ICCPD_LOG_DEBUG(__FUNCTION__, " %s ret = %d", syscmd, ret); } return; @@ -1333,40 +2230,48 @@ static void mlacp_fix_bridge_mac(struct CSM* csm) void mlacp_peer_conn_handler(struct CSM* csm) { struct LocalInterface *lif = NULL; + struct PeerInterface* peer_if; static int once_connected = 0; struct System* sys = NULL; + struct If_info * cif = NULL; if (!csm) return; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; + } if (csm->warm_reboot_disconn_time != 0) { /*If peer reconnected, reset peer disconnect time*/ csm->warm_reboot_disconn_time = 0; - ICCPD_LOG_NOTICE(__FUNCTION__, "Peer warm reboot and reconnect, reset peer disconnect time!"); + ICCPD_LOG_DEBUG(__FUNCTION__, "Peer warm reboot and reconnect, reset warm disconnect time!"); } if (csm->peer_link_if) { set_peerlink_mlag_port_learn(csm->peer_link_if, 0); + set_peerlink_learn_kernel(csm, 0, 7); } + ICCPD_LOG_NOTICE("ICCP_FSM", "ICCP session up: warm reboot %s, role %s", + (sys->warmboot_start == WARM_REBOOT) ? "yes" : "no", + (csm->role_type == STP_ROLE_STANDBY) ? "standby" : "active"); + /*If peer connect again, don't flush FDB*/ if (once_connected == 0) { once_connected = 1; mlacp_fix_bridge_mac(csm); - /*If warm reboot, don't flush FDB*/ - if (sys->warmboot_start != WARM_REBOOT) - mlacp_clean_fdb(); + // do not required to flush FDB + //if (sys->warmboot_start != WARM_REBOOT) + // mlacp_clean_fdb(); } - iccp_get_fdb_change_from_syncd(); sys->csm_trans_time = time(NULL); - mlacp_conn_handler_fdb(csm); LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) @@ -1377,77 +2282,184 @@ void mlacp_peer_conn_handler(struct CSM* csm) } } + /* Send ICCP up update to Mclagsyncd */ + mlacp_link_set_iccp_state(csm->mlag_id, true); + + /* Send remote interface status update to Mclagsyncd */ + LIST_FOREACH(peer_if, &(MLACP(csm).pif_list), mlacp_next) + { + mlacp_link_set_remote_if_state( + csm->mlag_id, peer_if->name, + (peer_if->state == PORT_STATE_UP)? true : false); + } + /* Port isolation is cleaned up when session goes down via + * peerlink_port_isolate_cleanup(). MlagOrch blocks all traffic from + * ISL to all MLAG interfaces to avoid packet duplicate and transient + * loop to cover the case where peer link is still up when ICCP goes + * down. On session up, update port isolation group based on the + * latest remote interface state. This is needed to cover the case + * where all remote MLAG interfaces are down after ICCP comes back up + */ + update_peerlink_isolate_from_all_csm_lif(csm); + + if (csm->peer_link_if) + { + update_vlan_if_mac_on_iccp_up(csm->peer_link_if, 1, NULL); + } + + sync_unique_ip(); return; } -extern void recover_if_ipmac_on_standby(struct LocalInterface* lif_po); +void mlacp_peer_disconn_fdb_handler(struct CSM* csm) +{ + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; + + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "ICCP session down: existing flag %d interface %s, MAC %s vlan-id %d," + " pending_del %s", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + (mac_msg->pending_local_del) ? "true":"false"); + + if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) + { + mac_msg->age_flag |= MAC_AGE_PEER; + + /* local and peer both aged, to be deleted*/ + // delete peer-link check, delete all remote macs which are aged local and remote. + if ((mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) || mac_msg->pending_local_del) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "ICCP session down: del MAC pointing to peer_link for %s, " + "MAC %s vlan-id %d", mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + + /*Send mac del message to mclagsyncd, may be already deleted*/ + del_mac_from_chip(mac_msg); + + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } + } + } + else + { + if (!mac_msg->age_flag) + { + // MAC learned on both nodes convert to local not update to ASIC required. + mac_msg->age_flag = MAC_AGE_PEER; + ICCPD_LOG_DEBUG("ICCP_FDB", "ICCP session down: MAC learned on both nodes update to local only" + " flag %d interface %s, MAC %s vlan-id %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + else if (mac_msg->age_flag == MAC_AGE_LOCAL) + { + // MAC is remote pointing to MCLAG PO convert to local + add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC_LOCAL); + mac_msg->age_flag = MAC_AGE_PEER; + ICCPD_LOG_DEBUG("ICCP_FDB", "ICCP session down: MAC is remote convert to local" + " flag %d interface %s, MAC %s vlan-id %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + //else MAC is local (mac_msg->age_flag == MAC_AGE_PEER) no changes required + } + } +} + void mlacp_peer_disconn_handler(struct CSM* csm) { uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct LocalInterface* lif = NULL; + struct LocalInterface* peer_link_if = NULL; + struct PeerInterface* peer_if; struct Msg* msg = NULL; - struct MACMsg* mac_msg = NULL; + struct MACMsg* mac_msg = NULL, *mac_temp = NULL; struct System* sys = NULL; + uint8_t remote_system_mac[ETHER_ADDR_LEN]; if (!csm) return; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; - + } + if (MLACP(csm).current_state != MLACP_STATE_INIT) + { + ICCPD_LOG_NOTICE("ICCP_FSM", + "ICCP session down: warm reboot %s, role %s, sync_state %s", + (sys->warmboot_exit == WARM_REBOOT) ? "yes" : "no", + (csm->role_type == STP_ROLE_STANDBY) ? "standby" : "active", + mlacp_state(csm)); + } /*If warm reboot, don't change FDB and MAC address*/ if (sys->warmboot_exit == WARM_REBOOT) return; - /*If peer is warm reboot, don't change FDB*/ if (csm->peer_warm_reboot_time != 0) { /*If peer disconnected, recover peer to normal reboot for next time*/ csm->peer_warm_reboot_time = 0; /*peer connection must be establised again within 90s - from last disconnection for peer warm reboot*/ + from last disconnection for peer warm reboot*/ time(&csm->warm_reboot_disconn_time); - ICCPD_LOG_NOTICE(__FUNCTION__, "Peer warm reboot and disconnect, recover to normal reboot for next time!"); + ICCPD_LOG_DEBUG(__FUNCTION__, "Peer warm reboot and disconnect, recover to normal reboot for next time!"); return; } - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) - { - mac_msg = (struct MACMsg*)msg->buf; - - mac_msg->age_flag |= MAC_AGE_PEER; - ICCPD_LOG_DEBUG(__FUNCTION__, "Add peer age flag: %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - - /* find the MAC that the port is peer-link or local and peer both aged, to be deleted*/ - if (strcmp(mac_msg->ifname, csm->peer_itf_name) != 0 && mac_msg->age_flag != (MAC_AGE_LOCAL | MAC_AGE_PEER)) - continue; - - ICCPD_LOG_NOTICE(__FUNCTION__, "Peer disconnect, del MAC for peer-link: %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - - /*Send mac del message to mclagsyncd, may be already deleted*/ - del_mac_from_chip(mac_msg); + mlacp_peer_disconn_fdb_handler(csm); - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); - } + /* Send ICCP down update to Mclagsyncd before clearing all port isolation + * so that mclagsync can differentiate between session down and all remote + * MLAG interface down + */ + mlacp_link_set_iccp_state(csm->mlag_id, false); /* Clean all port block*/ peerlink_port_isolate_cleanup(csm); + memset(remote_system_mac, 0, ETHER_ADDR_LEN); + memcpy(remote_system_mac, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); memcpy(MLACP(csm).remote_system.system_id, null_mac, ETHER_ADDR_LEN); /*If peer is disconnected, recover the MAC address.*/ - if (csm->role_type == STP_ROLE_STANDBY) + LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) { - LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) + if (csm->role_type == STP_ROLE_STANDBY) + recover_if_ipmac_on_standby(lif, 3); + + /* Re-enable traffic tx/rx for MLAG interface regardless of its state + */ + if (lif->is_traffic_disable) { - recover_if_ipmac_on_standby(lif); + mlacp_link_enable_traffic_distribution(lif); } } + if (csm->peer_link_if) + { + update_vlan_if_mac_on_iccp_up(csm->peer_link_if, 0, remote_system_mac); + } + + ICCPD_LOG_DEBUG(__FUNCTION__, "Peer disconnect %u times", + SYSTEM_GET_SESSION_DOWN_COUNTER(sys)); + SYSTEM_INCR_SESSION_DOWN_COUNTER(sys); + + /* On standby, system ID is reverted back to its local system ID. + * Update Mclagsyncd + * */ + if (csm->role_type == STP_ROLE_STANDBY) + mlacp_link_set_iccp_system_id(csm->mlag_id, MLACP(csm).system_id); + + /* Delete remote interface info */ + LIST_FOREACH(peer_if, &(MLACP(csm).pif_list), mlacp_next) + { + mlacp_link_del_remote_if_info(csm->mlag_id, peer_if->name); + } return; } @@ -1459,20 +2471,21 @@ void mlacp_peerlink_up_handler(struct CSM* csm) if (!csm) return; + ICCPD_LOG_DEBUG("ICCP_FSM", "PEER_LINK %s up: sync_state %s", + csm->peer_itf_name, mlacp_state(csm)); + /*If peer link up, set all the mac that point to the peer-link in ASIC*/ - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + RB_FOREACH (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb) { - mac_msg = (struct MACMsg*)msg->buf; - /* Find the MAC that the port is peer-link to be added*/ if (strcmp(mac_msg->ifname, csm->peer_itf_name) != 0) continue; - ICCPD_LOG_NOTICE(__FUNCTION__, "Peer link up, add MAC to ASIC for peer-link: %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "Peer link up, add MAC to ASIC for peer-link: %s, " + "MAC %s vlan-id %d", mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); /*Send mac add message to mclagsyncd, local age flag is already set*/ - add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC); + add_mac_to_chip(mac_msg, mac_msg->fdb_type); } return; @@ -1480,42 +2493,51 @@ void mlacp_peerlink_up_handler(struct CSM* csm) void mlacp_peerlink_down_handler(struct CSM* csm) { - struct Msg* msg = NULL; + struct MACMsg* mac_temp = NULL; struct MACMsg* mac_msg = NULL; if (!csm) return; + ICCPD_LOG_DEBUG("ICCP_FSM", "PEER_LINK %s down: sync_state %s", + csm->peer_itf_name, mlacp_state(csm)); + /*If peer link down, remove all the mac that point to the peer-link*/ - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + RB_FOREACH_SAFE (mac_msg, mac_rb_tree, &MLACP(csm).mac_rb, mac_temp) { - mac_msg = (struct MACMsg*)msg->buf; - /* Find the MAC that the port is peer-link to be deleted*/ if (strcmp(mac_msg->ifname, csm->peer_itf_name) != 0) continue; - ICCPD_LOG_NOTICE(__FUNCTION__, "Peer link down, del MAC for peer-link: %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + if (!mac_msg->pending_local_del) + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 1); - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1); + ICCPD_LOG_DEBUG("ICCP_FDB", "Peer link down, del MAC for peer-link: %s," + " MAC %s vlan-id %d", mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); /*Send mac del message to mclagsyncd*/ del_mac_from_chip(mac_msg); - /*If peer is not age, keep the MAC in mac_list, but ASIC is deleted*/ + /*If peer is not age, keep the MAC in mac_rb, but ASIC is deleted*/ if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) { /*If local and peer both aged, del the mac*/ - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } } } + SYSTEM_INCR_PEER_LINK_DOWN_COUNTER(system_get_instance()); return; } + /***************************************** * Po add/remove handler * @@ -1527,7 +2549,22 @@ void mlacp_mlag_link_add_handler(struct CSM *csm, struct LocalInterface *lif) if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) return; - set_peerlink_mlag_port_isolate(csm, lif, 1); + //enable peerlink isolation only if the both mclag interfaces are up + update_peerlink_isolate_from_lif(csm, lif, lif->po_active); + + //if it is standby node and peer interface is configured, update + //standby node mac to active's mac for this lif + if (csm->role_type == STP_ROLE_STANDBY) + { + struct PeerInterface* pif=NULL; + pif = peer_if_find_by_name(csm, lif->name); + + if (pif) + { + update_if_ipmac_on_standby(lif, 4); + mlacp_link_set_iccp_system_id(csm->mlag_id, lif->mac_addr); + } + } return; } @@ -1540,7 +2577,7 @@ void mlacp_mlag_link_del_handler(struct CSM *csm, struct LocalInterface *lif) if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) return; - set_peerlink_mlag_port_isolate(csm, lif, 0); + set_peerlink_mlag_port_isolate(csm, lif, 0, true); return; } @@ -1555,8 +2592,10 @@ int iccp_connect_syncd() struct epoll_event event; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); goto conn_fail; - + } if (sys->sync_fd >= 0) return 0; @@ -1565,7 +2604,6 @@ int iccp_connect_syncd() { count = 0; } - fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -1602,7 +2640,7 @@ int iccp_connect_syncd() count = 0; return 0; - conn_fail: +conn_fail: if (count == 0) ICCPD_LOG_DEBUG(__FUNCTION__, "Mclag syncd socket connect fail"); @@ -1616,7 +2654,10 @@ void syncd_info_close() struct System* sys = NULL; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; + } if (sys->sync_fd > 0) { @@ -1633,22 +2674,33 @@ int iccp_get_receive_fdb_sock_fd(struct System *sys) } /*When received MAC add and del packets from mclagsyncd, update mac information*/ -void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, char *ifname, uint8_t fdb_type, uint8_t op_type) +void do_mac_update_from_syncd(uint8_t mac_addr[ETHER_ADDR_LEN], uint16_t vid, char *ifname, uint8_t fdb_type, uint8_t op_type) { struct System *sys = NULL; struct CSM *csm = NULL; struct Msg *msg = NULL; - struct MACMsg *mac_msg = NULL, *mac_info = NULL; + struct MACMsg *mac_msg = NULL, *mac_info = NULL, *new_mac_msg = NULL; + struct MACMsg mac_find; uint8_t mac_exist = 0; char buf[MAX_BUFSIZE]; size_t msg_len = 0; uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/ struct CSM *first_csm = NULL; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct LocalInterface *lif_po = NULL, *mac_lif = NULL; if (!(sys = system_get_instance())) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return; + } + + if (memcmp(mac_addr, null_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address from syncd do not add."); return; + } /* create MAC msg*/ memset(buf, 0, MAX_BUFSIZE); @@ -1656,12 +2708,24 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch mac_msg = (struct MACMsg*)buf; mac_msg->op_type = op_type; mac_msg->fdb_type = fdb_type; - sprintf(mac_msg->mac_str, "%s", mac_str); + memcpy(mac_msg->mac_addr, mac_addr, ETHER_ADDR_LEN); mac_msg->vid = vid; mac_msg->age_flag = 0; - - ICCPD_LOG_NOTICE(__FUNCTION__, "Recv MAC msg from mclagsyncd, vid %d mac %s port %s optype %s ", vid, mac_str, ifname, op_type == MAC_SYNC_ADD ? "add" : "del"); + mac_msg->pending_local_del = 0; + + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: vid %d mac %s port %s type: %d optype %s ", + vid, mac_addr_to_str(mac_addr), ifname, fdb_type, op_type == MAC_SYNC_ADD ? "add" : "del"); + /*Debug*/ + #if 0 + /* dump receive MAC info*/ + fprintf(stderr, "\n======== MAC Update==========\n"); + fprintf(stderr, " MAC = %s \n", mac_addr_to_str(mac_addr)); + fprintf(stderr, " vlan id = %d\n", vid); + fprintf(stderr, " fdb type = %s\n", fdb_type == MAC_TYPE_STATIC ? "static" : "dynamic"); + fprintf(stderr, " op type = %s\n", op_type == MAC_SYNC_ADD ? "add" : "del"); + fprintf(stderr, "==============================\n"); + #endif /* Find MLACP itf, may be mclag enabled port-channel*/ LIST_FOREACH(csm, &(sys->csm_list), next) @@ -1695,20 +2759,23 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch if (!first_csm) return; - /*If support multiple CSM, the MAC list of orphan port must be moved to sys->mac_list*/ + /*If support multiple CSM, the MAC list of orphan port must be moved to sys->mac_rb*/ csm = first_csm; - /* find lif MAC+vid*/ - TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) - { - mac_info = (struct MACMsg*)msg->buf; + struct PeerInterface* pif = NULL; + pif = peer_if_find_by_name(csm, ifname); - /*MAC and vid are equal*/ - if (strcmp(mac_info->mac_str, mac_str) == 0 && mac_info->vid == vid) - { - mac_exist = 1; - break; - } + memset(&mac_find, 0, sizeof(struct MACMsg)); + mac_find.vid = vid; + memcpy(mac_find.mac_addr,mac_addr, ETHER_ADDR_LEN); + + mac_info = RB_FIND(mac_rb_tree, &MLACP(csm).mac_rb ,&mac_find); + if(mac_info) + { + mac_exist = 1; + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: RB_FIND success for the MAC entry : %s, " + " vid: %d , ifname %s, type: %d, age flag: %d", mac_addr_to_str(mac_info->mac_addr), + mac_info->vid, mac_info->ifname, mac_info->fdb_type, mac_info->age_flag ); } /*handle mac add*/ @@ -1716,25 +2783,70 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch { /* Find local itf*/ if (!(mac_lif = local_if_find_by_name(ifname))) + { + ICCPD_LOG_ERR(__FUNCTION__, " interface %s not present failed " + "to add MAC %s vlan %d", ifname, mac_addr_to_str(mac_addr), vid); return; + } sprintf(mac_msg->ifname, "%s", ifname); sprintf(mac_msg->origin_ifname, "%s", ifname); + /*If the recv mac port is peer-link, no need to handle*/ + if (strcmp(csm->peer_itf_name, mac_msg->ifname) == 0) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC learn received on peer_link %s ignore MAC %s vlan %d", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + return; + } + /*same MAC exist*/ if (mac_exist) { - /*If the recv mac port is peer-link, that is add from iccpd, no need to handle*/ - if (strcmp(csm->peer_itf_name, mac_msg->ifname) == 0) - { - return; - } - /*If the current mac port is peer-link, it will handle by port up event*/ /*if(strcmp(csm->peer_itf_name, mac_info->ifname) == 0) { return; }*/ + if (mac_lif->state == PORT_STATE_DOWN) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC add received, " + "MAC exists interface %s down, MAC %s vlan %d, is mclag interface : %s ", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + from_mclag_intf ? "true":"false" ); + + // if from mclag intf update mac to point to peer_link. + //else ignore mac. + if (from_mclag_intf && pif && (pif->state == PORT_STATE_UP)) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC add received, " + "MAC exists interface %s down, point to peer link MAC %s, vlan %d, is pending local del : %s ", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + mac_info->pending_local_del ? "true":"false" ); + + mac_info->pending_local_del = 1; + mac_info->fdb_type = mac_msg->fdb_type; + memcpy(&mac_info->origin_ifname, mac_msg->ifname, MAX_L_PORT_NAME); + + //existing mac must be pointing to peer_link, else update if info and send to syncd + if (strcmp(mac_info->ifname, csm->peer_itf_name) == 0) + { + add_mac_to_chip(mac_info, mac_msg->fdb_type); + } + else + { + // this for the case of MAC move , existing mac may point to different interface. + // need to update the ifname and update to syncd. + memcpy(&mac_info->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + add_mac_to_chip(mac_info, mac_msg->fdb_type); + } + + return; + } + + //else + //Update the MAC + } /* update MAC*/ if (mac_info->fdb_type != mac_msg->fdb_type @@ -1746,16 +2858,35 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch sprintf(mac_info->origin_ifname, "%s", mac_msg->ifname); /*Remove MAC_AGE_LOCAL flag*/ - mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 0); + mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 0, 1); - ICCPD_LOG_DEBUG(__FUNCTION__, "Update MAC for %s, ifname %s", mac_msg->mac_str, mac_msg->ifname); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Update MAC %s, vlan %d ifname %s", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + // MAC is local now Del entry from MCLAG_FDB_TABLE if peer not aged. + if (!(mac_msg->age_flag & MAC_AGE_PEER)) + { + ICCPD_LOG_DEBUG("ICCP_FDB", " MAC update from mclagsyncd: MAC move Update MAC remote to local %s, vlan %d" + " ifname %s, del entry from MCLAG_FDB_TABLE", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + mac_info->age_flag = MAC_AGE_PEER; + del_mac_from_chip(mac_msg); + } } else { /*All info are the same, Remove MAC_AGE_LOCAL flag, then return*/ /*In theory, this will be happened that mac age and then learn*/ - mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 0); - + mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 0, 1); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Duplicate update MAC %s, vlan %d ifname %s", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + // MAC is local now Del entry from MCLAG_FDB_TABLE if peer not aged. + if (!(mac_msg->age_flag & MAC_AGE_PEER)) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Update MAC remote to local %s, vlan %d" + " ifname %s, del entry from MCLAG_FDB_TABLE", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + del_mac_from_chip(mac_msg); + } return; } } @@ -1763,48 +2894,72 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch { /*If the port the mac learn is change to down before the mac sync to iccp, this mac must be deleted */ - if (mac_lif->state == PORT_STATE_DOWN) +#if 0 + if ((mac_lif->state == PORT_STATE_DOWN)) { - del_mac_from_chip(mac_msg); + if ((!from_mclag_intf) && (mac_msg->fdb_type != MAC_TYPE_STATIC)) + { + //ignore mac add + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: mclag interface %s down, MAC %s," + " vlan %d ignore mac add.", ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + return; + } + } +#endif + // If both local and remote MCLAG interfaces are down, ignore MAC and send delete to HW. + if (from_mclag_intf && (mac_lif->state == PORT_STATE_DOWN) && pif && (pif->state == PORT_STATE_DOWN)) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: mclag interface %s down on local and remote ignore MAC %s," + " vlan %d ", ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + del_mac_from_chip(mac_msg); return; } - /*set MAC_AGE_PEER flag before send this item to peer*/ mac_msg->age_flag |= MAC_AGE_PEER; - /*ICCPD_LOG_DEBUG(__FUNCTION__, "Add peer age flag: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag);*/ + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Add peer age flag, age %d interface %s, " + "MAC %s vlan-id %d ", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); mac_msg->op_type = MAC_SYNC_ADD; - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + /*enqueue mac to mac-list*/ + if (iccp_csm_init_mac_msg(&new_mac_msg, (char*)mac_msg, msg_len) == 0) { - struct Msg *msg_send = NULL; - if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, msg_len) == 0) - { - mac_msg->age_flag &= ~MAC_AGE_PEER; - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail); + RB_INSERT(mac_rb_tree, &MLACP(csm).mac_rb, new_mac_msg); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, age_flag %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->age_flag);*/ - } - else + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC-list enqueue interface %s, " + "MAC %s vlan-id %d", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + + //if port is down do not sync the MAC. + // For MAC learned on MCLAG interface point to peer_link. + // MAC learned on orphan port save MAC, when Orphan port is UP sync MAC + if (mac_lif->state == PORT_STATE_DOWN) { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue MAC-msg-list: %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + if (from_mclag_intf && pif && (pif->state == PORT_STATE_UP)) + { + mac_msg->pending_local_del = 1; + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: mclag interface %s down, MAC %s," + " vlan %d point to peer link %s", ifname, mac_addr_to_str(mac_msg->mac_addr), + mac_msg->vid, mac_msg->ifname); + } + return; } - } - /*enqueue mac to mac-list*/ - if (iccp_csm_init_msg(&msg, (char*)mac_msg, msg_len) == 0) - { - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_list), msg, tail); + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE)) + { + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), new_mac_msg, tail); - /*ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-list enqueue: %s, add %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid);*/ + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC-msg-list enqueue interface %s, " + "MAC %s vlan-id %d, age_flag %d", new_mac_msg->ifname, + mac_addr_to_str(new_mac_msg->mac_addr), new_mac_msg->vid, new_mac_msg->age_flag); + } } else - ICCPD_LOG_DEBUG(__FUNCTION__, "Failed to enqueue MAC %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Failed to enqueue interface %s, MAC %s vlan-id %d", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); } } else/*handle mac del*/ @@ -1815,63 +2970,94 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch /*orphan port mac or origin from_mclag_intf but state is down*/ if (strcmp(mac_info->ifname, csm->peer_itf_name) == 0) { + if (mac_info->pending_local_del) + { + //do not delete the MAC. + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: do not del pending MAC on %s(peer-link), " + "MAC %s vlan-id %d", mac_info->ifname, + mac_addr_to_str(mac_info->mac_addr), mac_info->vid); + return; + } /*Set MAC_AGE_LOCAL flag*/ - mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1); + mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1, 1); if (mac_info->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) { - ICCPD_LOG_DEBUG(__FUNCTION__, "Recv MAC del msg: %s(peer-link), del %s vlan-id %d", - mac_info->ifname, mac_info->mac_str, mac_info->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(peer-link), " + "MAC %s vlan-id %d", mac_info->ifname, + mac_addr_to_str(mac_info->mac_addr), mac_info->vid); + + if (mac_info->add_to_syncd) + { + del_mac_from_chip(mac_info); + } /*If peer link is down, del the mac*/ - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_info); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_info, tail)) + { + free(mac_info); + } } else if (csm->peer_link_if && csm->peer_link_if->state != PORT_STATE_DOWN) { /*peer-link learn mac is control by iccpd, ignore the chip del info*/ - add_mac_to_chip(mac_info, MAC_TYPE_DYNAMIC); + add_mac_to_chip(mac_info, mac_info->fdb_type); - ICCPD_LOG_NOTICE(__FUNCTION__, "Recv MAC del msg: %s(peer-link is up), add back %s vlan-id %d", - mac_info->ifname, mac_info->mac_str, mac_info->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(peer-link is up), " + "add back MAC %s vlan-id %d", mac_info->ifname, + mac_addr_to_str(mac_info->mac_addr), mac_info->vid); } return; } /*Add MAC_AGE_LOCAL flag*/ - mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1); + mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1, 1); if (mac_info->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) { - ICCPD_LOG_DEBUG(__FUNCTION__, "Recv MAC del msg: %s, del %s vlan-id %d", - mac_info->ifname, mac_info->mac_str, mac_info->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s, " + "MAC %s vlan-id %d", mac_info->ifname, + mac_addr_to_str(mac_info->mac_addr), mac_info->vid); + //before removing the MAC send del to syncd if added before. + if (mac_info->add_to_syncd) + { + del_mac_from_chip(mac_info); + } /*If local and peer both aged, del the mac (local orphan mac is here)*/ - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_info); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_info, tail)) + { + free(mac_info); + } } else { - ICCPD_LOG_NOTICE(__FUNCTION__, "Recv MAC del msg: %s, del %s vlan-id %d, peer is not age, add back to chip", - mac_info->ifname, mac_info->mac_str, mac_info->vid); - - mac_info->fdb_type = MAC_TYPE_DYNAMIC; + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s, " + "MAC %s vlan-id %d, peer is not age, add back to chip", + mac_info->ifname, mac_addr_to_str(mac_info->mac_addr), mac_info->vid); if (from_mclag_intf && lif_po && lif_po->state == PORT_STATE_DOWN) { /*If local if is down, redirect the mac to peer-link*/ if (strlen(csm->peer_itf_name) != 0) { - memcpy(&mac_info->ifname, csm->peer_itf_name, IFNAMSIZ); + memcpy(&mac_info->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) { - add_mac_to_chip(mac_info, MAC_TYPE_DYNAMIC); - ICCPD_LOG_NOTICE(__FUNCTION__, "Recv MAC del msg: %s(down), del %s vlan-id %d, redirect to peer-link", - mac_info->ifname, mac_info->mac_str, mac_info->vid); + add_mac_to_chip(mac_info, mac_info->fdb_type); + ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(down), " + "MAC %s vlan-id %d, redirect to peer-link", + mac_info->ifname, mac_addr_to_str(mac_info->mac_addr), mac_info->vid); } } @@ -1884,7 +3070,7 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch if (!(mac_lif = local_if_find_by_name(mac_info->ifname))) return; if (mac_lif->state == PORT_STATE_UP) - add_mac_to_chip(mac_info, MAC_TYPE_DYNAMIC); + add_mac_to_chip(mac_info, mac_info->fdb_type); } } } @@ -1892,53 +3078,588 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch return; } -int iccp_receive_fdb_handler_from_syncd(struct System *sys) +int iccp_mclagsyncd_mclag_domain_cfg_handler(struct System *sys, char *msg_buf) +{ + struct IccpSyncdHDr * msg_hdr; + struct mclag_domain_cfg_info* cfg_info; + int count, i = 0; + char system_mac_str[ETHER_ADDR_STR_LEN]; + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + + count = (msg_hdr->len- sizeof(struct IccpSyncdHDr ))/sizeof(struct mclag_domain_cfg_info); + ICCPD_LOG_DEBUG(__FUNCTION__, "recv domain cfg msg ; count %d ",count); + + for (i = 0; i < count; i++) + { + cfg_info = (struct mclag_domain_cfg_info *)((char *)(msg_buf) + sizeof(struct IccpSyncdHDr) + i * sizeof(struct mclag_domain_cfg_info)); + + memcpy(system_mac_str, mac_addr_to_str(cfg_info->system_mac), sizeof(system_mac_str)); + + ICCPD_LOG_NOTICE(__FUNCTION__, "recv cfg msg ; domain_id:%d op_type:%d attr_bmap:0x%x local_ip:%s peer_ip:%s peer_ifname:%s system_mac:%s session_timeout:%d keepalive_time:%d",cfg_info->domain_id, cfg_info->op_type, cfg_info->attr_bmap, cfg_info->local_ip, cfg_info->peer_ip, cfg_info->peer_ifname, system_mac_str, cfg_info->session_timeout, cfg_info->keepalive_time); + + if (cfg_info->op_type == MCLAG_CFG_OPER_ADD || cfg_info->op_type == MCLAG_CFG_OPER_UPDATE) //mclag domain create/update + { + if (cfg_info->op_type == MCLAG_CFG_OPER_ADD) + { + set_mc_lag_by_id(cfg_info->domain_id); + set_local_system_id(system_mac_str); + } + + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_SRC_ADDR) + { + set_local_address(cfg_info->domain_id, cfg_info->local_ip); + } + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_PEER_ADDR) + { + set_peer_address(cfg_info->domain_id, cfg_info->peer_ip); + } + + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_PEER_LINK) + { + set_peer_link(cfg_info->domain_id, cfg_info->peer_ifname); + } + + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_KEEPALIVE_INTERVAL) + { + if (cfg_info->keepalive_time != -1) + { + set_keepalive_time(cfg_info->domain_id, cfg_info->keepalive_time); + } + else + { + set_keepalive_time(cfg_info->domain_id, CONNECT_INTERVAL_SEC); + } + } + + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_SESSION_TIMEOUT) + { + if (cfg_info->session_timeout != -1) + { + set_session_timeout(cfg_info->domain_id, cfg_info->session_timeout); + } + else + { + set_session_timeout(cfg_info->domain_id, HEARTBEAT_TIMEOUT_SEC); + } + } + } //MCLAG Domain create/update End + else if (cfg_info->op_type == MCLAG_CFG_OPER_DEL) //mclag domain delete + { + unset_mc_lag_by_id(cfg_info->domain_id); + } //MCLAG Domain delete End + else if (cfg_info->op_type == MCLAG_CFG_OPER_ATTR_DEL) //mclag domain attribute delete + { + if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_PEER_LINK) + { + unset_peer_link(cfg_info->domain_id); + } + else if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_KEEPALIVE_INTERVAL) + { + //reset to default + set_keepalive_time(cfg_info->domain_id, CONNECT_INTERVAL_SEC); + } + else if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_SESSION_TIMEOUT) + { + //reset to default + set_session_timeout(cfg_info->domain_id, HEARTBEAT_TIMEOUT_SEC); + } + else if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_SRC_ADDR) + { + unset_local_address(cfg_info->domain_id); + } + else if(cfg_info->attr_bmap & MCLAG_CFG_ATTR_PEER_ADDR) + { + unset_peer_address(cfg_info->domain_id); + } + } //MCLAG Domain Attribute delete End + } + + return 0; +} + +int iccp_mclagsyncd_mclag_iface_cfg_handler(struct System *sys, char *msg_buf) +{ + struct IccpSyncdHDr * msg_hdr; + struct mclag_iface_cfg_info* cfg_info; + int count, i = 0; + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + + count = (msg_hdr->len- sizeof(struct IccpSyncdHDr))/sizeof(struct mclag_iface_cfg_info); + ICCPD_LOG_DEBUG(__FUNCTION__, "recv domain cfg msg ; count %d ",count); + + for (i =0; idomain_id, cfg_info->op_type, cfg_info->mclag_iface); + + if (cfg_info->op_type == MCLAG_CFG_OPER_ADD) + { + iccp_cli_attach_mclag_domain_to_port_channel(cfg_info->domain_id, cfg_info->mclag_iface); + } + else if (cfg_info->op_type == MCLAG_CFG_OPER_DEL) + { + iccp_cli_detach_mclag_domain_to_port_channel(cfg_info->mclag_iface); + } + } + return 0; +} + +int iccp_mclagsyncd_mclag_unique_ip_cfg_handler(struct System *sys, char *msg_buf) { - char *msg_buf = g_csm_buf; struct IccpSyncdHDr *msg_hdr; - struct mclag_fdb_info * mac_info; - size_t pos = 0; + struct mclag_unique_ip_cfg_info *cfg_info; + struct LocalInterface *lif = NULL; + int count = 0, i = 0; + int sync_add = 0, is_v4 = 0, is_v6 = 0; + struct Unq_ip_If_info* unq_ip_if = NULL; + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + + count = (msg_hdr->len- sizeof(struct IccpSyncdHDr))/sizeof(struct mclag_unique_ip_cfg_info); + ICCPD_LOG_DEBUG(__FUNCTION__, "recv domain cfg msg, count %d ",count); + + for (i =0; iop_type, cfg_info->mclag_unique_ip_ifname); + + if (cfg_info->op_type == MCLAG_CFG_OPER_ADD) + { + LIST_FOREACH(unq_ip_if, &(sys->unq_ip_if_list), if_next) + { + if (strcmp(unq_ip_if->name, cfg_info->mclag_unique_ip_ifname) == 0) + { + break; + } + } + + if (!unq_ip_if) + { + unq_ip_if = (struct Unq_ip_If_info *)malloc(sizeof(struct Unq_ip_If_info)); + if (!unq_ip_if) + return -1; + + snprintf(unq_ip_if->name, MAX_L_PORT_NAME, "%s", cfg_info->mclag_unique_ip_ifname); + ICCPD_LOG_DEBUG(__FUNCTION__, "Add mclag_unique_ip_ifname %s", unq_ip_if->name); + LIST_INSERT_HEAD(&(sys->unq_ip_if_list), unq_ip_if, if_next); + } + + } + else if (cfg_info->op_type == MCLAG_CFG_OPER_DEL) + { + LIST_FOREACH(unq_ip_if, &(sys->unq_ip_if_list), if_next) + { + if (strcmp(unq_ip_if->name, cfg_info->mclag_unique_ip_ifname) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Del mclag_unique_ip_ifname %s", unq_ip_if->name); + LIST_REMOVE(unq_ip_if, if_next); + free(unq_ip_if); + break; + } + } + } + + lif = local_if_find_by_name(cfg_info->mclag_unique_ip_ifname); + if (lif) + { + if (cfg_info->op_type == MCLAG_CFG_OPER_ADD) + { + lif->is_l3_proto_enabled = true; + sync_add = 1; + if (lif->ipv4_addr) + { + is_v4 = 1; + } + + if (lif->prefixlen_v6) + { + is_v6 = 1; + } + } + else if (cfg_info->op_type == MCLAG_CFG_OPER_DEL) + { + lif->is_l3_proto_enabled = false; + sync_add = 0; + if (lif->ipv4_addr) + { + is_v4 = 1; + } + + if (lif->prefixlen_v6) + { + is_v6 = 1; + } + } + + ICCPD_LOG_DEBUG(__FUNCTION__,"add %d, v4 %d, v6 %d, l3_mode %d, is_l3 %d", + sync_add, is_v4, is_v6, lif->l3_mode, local_if_is_l3_mode(lif)); + + if (local_if_is_l3_mode(lif)) + { + if (sync_add) { + update_vlan_if_mac_on_standby(lif, 6); + } + + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, 1, 1, 0, 1); + } else { + if (!sync_add) { + recover_vlan_if_mac_on_standby(lif, 6, NULL); + syn_local_neigh_mac_info_to_peer(lif, sync_add, is_v4, is_v6, 1, 1, 0, 1); + } + } + } + } + return 0; +} + +int iccp_mclagsyncd_vlan_mbr_update_handler(struct System *sys, char *msg_buf) +{ + struct IccpSyncdHDr * msg_hdr; + struct mclag_vlan_mbr_info* vlan_mbr_info; + int count, i = 0; + int add_count = 0; + int del_count = 0; + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + + count = (msg_hdr->len- sizeof(struct IccpSyncdHDr))/sizeof(struct mclag_vlan_mbr_info); + + for (i =0; iop_type, vlan_mbr_info->vid, vlan_mbr_info->mclag_iface); + + if (vlan_mbr_info->op_type == MCLAG_CFG_OPER_ADD) + { + vlan_mbrship_change_handler(vlan_mbr_info->vid, vlan_mbr_info->mclag_iface, 1 /*add */); + add_count++; + } + else if (vlan_mbr_info->op_type == MCLAG_CFG_OPER_DEL) + { + vlan_mbrship_change_handler(vlan_mbr_info->vid, vlan_mbr_info->mclag_iface, 0 /* del */); + del_count++; + } + } + ICCPD_LOG_NOTICE(__FUNCTION__, "Rx vlan member update count %d add/delete count: %d/%d", count, add_count, del_count); + + return 0; +} + +int iccp_receive_fdb_handler_from_syncd(struct System *sys, char *msg_buf) +{ int count = 0; int i = 0; - int n = 0; + struct IccpSyncdHDr * msg_hdr; + struct mclag_fdb_info * mac_info; + + msg_hdr = (struct IccpSyncdHDr *)msg_buf; + + count = (msg_hdr->len- sizeof(struct IccpSyncdHDr))/sizeof(struct mclag_fdb_info); + ICCPD_LOG_DEBUG(__FUNCTION__, "recv msg fdb count %d ",count ); + + for (i =0; imac, mac_info->vid, mac_info->port_name, mac_info->type, mac_info->op_type); + } + return 0; +} + +int iccp_mclagsyncd_msg_handler(struct System *sys) +{ + int num_bytes_rxed = 0; + char *msg_buf = g_iccp_mlagsyncd_recv_buf; + struct IccpSyncdHDr * msg_hdr; + int pos = 0; + int recv_len = 0; + int num_retry = 0; + errno = 0; if (sys == NULL) return MCLAG_ERROR; + memset(msg_buf, 0, ICCP_MLAGSYNCD_RECV_MSG_BUFFER_SIZE); - memset(msg_buf, 0, CSM_BUFFER_SIZE); + /* read (max_size - msg_size) so that we have space to + accomodate anything remaining in the last message */ + num_bytes_rxed = recv(sys->sync_fd, msg_buf, + ICCP_MLAGSYNCD_RECV_MSG_BUFFER_SIZE - MCLAG_MAX_MSG_LEN, MSG_DONTWAIT ); - n = read(sys->sync_fd, msg_buf, CSM_BUFFER_SIZE); - if (n <= 0) + if (num_bytes_rxed <= 0) { - ICCPD_LOG_ERR(__FUNCTION__, "read msg error!!!" ); - return MCLAG_ERROR; + // if received count is 0 socket is closed. + if (num_bytes_rxed == 0) + { + ICCPD_LOG_WARN("ICCP_FSM", "Recv fom Mclagsyncd read erro:%d ", num_bytes_rxed); + SYSTEM_INCR_RX_READ_SOCK_ZERO_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + + while( num_bytes_rxed < 0 ) + { + recv_len = recv(sys->sync_fd, msg_buf, + ICCP_MLAGSYNCD_RECV_MSG_BUFFER_SIZE - MCLAG_MAX_MSG_LEN, MSG_DONTWAIT ); + + if (recv_len == -1) + { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + ICCPD_LOG_NOTICE( + "ICCP_FSM", "Recv fom Mclagsyncd Non-blocking recv errno %d, num_retry %d", + errno, num_retry); + ++num_retry; + if (num_retry > SYNCD_RECV_RETRY_MAX) + { + ICCPD_LOG_NOTICE( + "ICCP_FSM", "Recv fom Mclagsyncd retry failed recv_len: %d", recv_len); + SYSTEM_INCR_RX_RETRY_FAIL_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + else + { + usleep(SYNCD_RECV_RETRY_INTERVAL_USEC); + recv_len = 0; + } + } + else + { + ICCPD_LOG_NOTICE("ICCP_FSM", "Recv fom Mclagsyncd retry failed recv_len: %d", recv_len); + SYSTEM_INCR_HDR_READ_SOCK_ERR_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + } + else if (recv_len == 0) + { + ICCPD_LOG_NOTICE("ICCP_FSM", "Recv fom Mclagsyncd error %d connection closed ", recv_len ); + SYSTEM_INCR_HDR_READ_SOCK_ZERO_LEN_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + + num_bytes_rxed += recv_len; + } } - while (pos < n) + num_retry = 0; + while (pos < num_bytes_rxed) //iterate through all msgs { - msg_hdr = (struct IccpSyncdHDr *)&msg_buf[pos]; - if (msg_hdr->ver != 1 || msg_hdr->type != MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION ) + if ((num_bytes_rxed - pos) < sizeof(struct IccpSyncdHDr)) + { + int recv_len = 0, len = 0; + int pending_len = sizeof(struct IccpSyncdHDr) - (num_bytes_rxed - pos); + + ICCPD_LOG_NOTICE(__FUNCTION__, "Recv fom Mclagsync header less than expected, trying to retrieve %d bytes more ", pending_len); + + while (recv_len < pending_len) + { + int remaining_len = pending_len-recv_len; + len = recv(sys->sync_fd, msg_buf+num_bytes_rxed+recv_len, remaining_len, MSG_DONTWAIT); + if (len <= 0) + { + if (len == 0) + { + ICCPD_LOG_WARN("ICCP_FSM", "Recv fom Mclagsync header less than expected data read error; recv_len:%d pending_len:%d ", recv_len, pending_len); + SYSTEM_INCR_HDR_READ_SOCK_ZERO_LEN_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + + if (len == -1) + { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + ICCPD_LOG_NOTICE( + "ICCP_FSM", "Recv fom Mclagsync header less than expected Non-blocking recv errno %d, num_retry %d", + errno, num_retry); + ++num_retry; + if (num_retry > SYNCD_RECV_RETRY_MAX) + { + ICCPD_LOG_ERR( + "ICCP_FSM", "Recv fom Mclagsync header less than expected Non-blocking recv() retry failed, len: %d, errno: %d", len, errno); + SYSTEM_INCR_RX_RETRY_FAIL_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + else + { + usleep(SYNCD_RECV_RETRY_INTERVAL_USEC); + len = 0; + } + } + else + { + ICCPD_LOG_WARN("ICCP_FSM", "Recv fom Mclagsyncd header less than expected error; recv_len:%d errno %d", + recv_len, errno); + SYSTEM_INCR_HDR_READ_SOCK_ERR_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + } + } + ICCPD_LOG_NOTICE("ICCP_FSM", "received %d pending bytes", len); + recv_len += len; + } + } + + msg_hdr = (struct IccpSyncdHDr *)(&msg_buf[pos]); + ICCPD_LOG_DEBUG(__FUNCTION__, "rcv msg version %d type %d len %d pos:%d num_bytes_rxed:%d ", + msg_hdr->ver , msg_hdr->type, msg_hdr->len, pos, num_bytes_rxed); + + if (!msg_hdr->len) + { + ICCPD_LOG_ERR(__FUNCTION__, "msg length zero!!!!! "); + return MCLAG_ERROR; + } + if (msg_hdr->ver != 1) + { + ICCPD_LOG_ERR(__FUNCTION__, "msg version %d wrong!!!!! ", msg_hdr->ver); + pos += msg_hdr->len; + continue; + } + if ((pos + msg_hdr->len) > num_bytes_rxed) + { + int recv_len = 0, len = 0; + int pending_len = pos + msg_hdr->len - num_bytes_rxed; + + ICCPD_LOG_NOTICE(__FUNCTION__, "Recv fom Mclagsyncd msg less than expected, trying to retrieve %d bytes more ", + pending_len); + + while (recv_len < pending_len) + { + int remaining_len = pending_len-recv_len; + len = recv(sys->sync_fd, msg_buf+num_bytes_rxed+recv_len, remaining_len, MSG_DONTWAIT); + if (len <= 0) + { + if (len == 0) + { + ICCPD_LOG_WARN("ICCP_FSM", "Recv fom Mclagsyncd msg less than expected read error; len:%d ",len); + SYSTEM_INCR_TLV_READ_SOCK_ZERO_LEN_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + + if (len == -1) + { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + ICCPD_LOG_NOTICE( + "ICCP_FSM", "Recv fom Mclagsyncd msg less than expected Non-blocking recv errno %d, num_retry %d", + errno, num_retry); + ++num_retry; + if (num_retry > SYNCD_RECV_RETRY_MAX) + { + ICCPD_LOG_ERR("ICCP_FSM", "Recv fom Mclagsyncd msg less than expected Non-blocking recv() retry failed len %d",len); + SYSTEM_INCR_RX_RETRY_FAIL_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + else + { + usleep(SYNCD_RECV_RETRY_INTERVAL_USEC); + len = 0; + } + } + else + { + ICCPD_LOG_WARN("ICCP_FSM", "Recv fom Mclagsyncd msg less than expectedread retry error len:%d , errno %d", + len, errno); + SYSTEM_INCR_TLV_READ_SOCK_ERR_COUNTER(system_get_instance()); + return MCLAG_ERROR; + } + } + + } + ICCPD_LOG_NOTICE(__FUNCTION__, "received %d pending bytes", len); + recv_len += len; + } + } + + if (msg_hdr->type == MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION) + { + iccp_receive_fdb_handler_from_syncd(sys, &msg_buf[pos]); + } + else if (msg_hdr->type == MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_DOMAIN) + { + iccp_mclagsyncd_mclag_domain_cfg_handler(sys, &msg_buf[pos]); + } + else if (msg_hdr->type == MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_IFACE) + { + iccp_mclagsyncd_mclag_iface_cfg_handler(sys, &msg_buf[pos]); + } + else if (msg_hdr->type == MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_UNIQUE_IP) + { + iccp_mclagsyncd_mclag_unique_ip_cfg_handler(sys, &msg_buf[pos]); + } + else if (msg_hdr->type == MCLAG_SYNCD_MSG_TYPE_VLAN_MBR_UPDATES) { - ICCPD_LOG_ERR(__FUNCTION__, "msg version or type wrong!!!!! "); - return MCLAG_ERROR; + iccp_mclagsyncd_vlan_mbr_update_handler(sys, &msg_buf[pos]); } - - count = ( msg_hdr->len - sizeof(struct IccpSyncdHDr )) / sizeof(struct mclag_fdb_info); - ICCPD_LOG_DEBUG(__FUNCTION__, "recv msg fdb count %d ", count); - - for (i = 0; i < count; i++) + else { - mac_info = (struct mclag_fdb_info *)&msg_buf[pos + sizeof(struct IccpSyncdHDr ) + i * sizeof(struct mclag_fdb_info)]; - /*ICCPD_LOG_DEBUG(__FUNCTION__, "recv msg fdb count %d vid %d mac %s port %s optype %s ", i, mac_info->vid, mac_info->mac, mac_info->port_name, mac_info->op_type == MAC_SYNC_ADD ? "add" : "del");*/ - do_mac_update_from_syncd(mac_info->mac, mac_info->vid, mac_info->port_name, mac_info->type, mac_info->op_type); + ICCPD_LOG_ERR(__FUNCTION__, "recv unknown msg type %d ", msg_hdr->type); + pos += msg_hdr->len; + continue; } - pos += msg_hdr->len; + SYSTEM_SET_SYNCD_RX_DBG_COUNTER(sys, msg_hdr->type, ICCP_DBG_CNTR_STS_OK); } - return 0; } + + /* + * Send request to Mclagsyncd to disable traffic for MLAG interface + */ + void mlacp_link_disable_traffic_distribution(struct LocalInterface *lif) + { + int rc; + + /* Update traffic distribution only if local interface is still bound to MLAG */ + if (!lif || !lif->csm) + return; + + /* Expecting ACK from peer only after reaching EXCHANGE state */ + if (MLACP(lif->csm).current_state != MLACP_STATE_EXCHANGE) + return; + + /* Disable traffic distribution for all LAG member ports when LAG goes down. + * If MLAG interface goes down again while waiting for i/f up ack, + * do not need to update hardware again + */ + if ((lif->type == IF_T_PORT_CHANNEL) && (!lif->po_active) && + (!lif->is_traffic_disable)) + { + rc = mlacp_link_set_traffic_dist_mode(lif->name, false); + ICCPD_LOG_DEBUG("ICCP_FSM", "MLAG_IF %s: set traffic disable, rc %d", + lif->name, rc); + if (rc == 0) + lif->is_traffic_disable = true; + } + } + + /* + * Send request to Mclagsyncd to enable traffic for MLAG interface + * Note: + * 1. Caller should check for LAG up before calling this API in normal case. + * 2. For the ICCP session down case or LAG interface is no longer MLAG + * interface, this API is called regardless of the LAG state + */ + void mlacp_link_enable_traffic_distribution(struct LocalInterface *lif) + { + int rc; + + /* Update traffic distribution only if local interface is still bound to MLAG */ + if (!lif || !lif->csm) + return; + + if ((lif->type == IF_T_PORT_CHANNEL) && lif->is_traffic_disable) + { + rc = mlacp_link_set_traffic_dist_mode(lif->name, true); + ICCPD_LOG_DEBUG("ICCP_FSM", "MLAG_IF %s: set traffic enable, rc %d", + lif->name, rc); + if (rc == 0) + lif->is_traffic_disable = false; + } +} + char * mclagd_ctl_cmd_str(int req_type) { switch (req_type) @@ -1961,8 +3682,15 @@ char * mclagd_ctl_cmd_str(int req_type) case INFO_TYPE_DUMP_PEER_PORTLIST: return "dump peer portlist"; + case INFO_TYPE_DUMP_DBG_COUNTERS: + return "dump debug counters"; + + case INFO_TYPE_DUMP_UNIQUE_IP: + return "dump unique_ip"; + case INFO_TYPE_CONFIG_LOGLEVEL: return "config loglevel"; + default: break; } @@ -1979,7 +3707,10 @@ int mclagd_ctl_sock_create() int ret = 0; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return MCLAG_ERROR; + } if (sys->sync_ctrl_fd > 0) return sys->sync_ctrl_fd; @@ -2259,7 +3990,7 @@ void mclagd_ctl_handle_dump_local_portlist(int client_fd, int mclag_id) { char * Pbuf = NULL; char buf[512] = { 0 }; - int lif_num = 0;; + int lif_num = 0; int ret = 0; struct mclagd_reply_hdr *hd = NULL; int len_tmp = 0; @@ -2335,6 +4066,83 @@ void mclagd_ctl_handle_dump_peer_portlist(int client_fd, int mclag_id) return; } +void mclagd_ctl_handle_dump_dbg_counters(int client_fd, int mclag_id) +{ + char * Pbuf = NULL; + char buf[512] = {0}; + int data_len = 0; + int ret = 0; + struct mclagd_reply_hdr *hd = NULL; + int len_tmp = 0; + + ret = iccp_cmd_dbg_counter_dump(&Pbuf, &data_len, mclag_id); + if (ret != EXEC_TYPE_SUCCESS) + { + len_tmp = sizeof(struct mclagd_reply_hdr); + memcpy(buf, &len_tmp, sizeof(int)); + hd = (struct mclagd_reply_hdr *)(buf + sizeof(int)); + hd->exec_result = ret; + hd->info_type = INFO_TYPE_DUMP_DBG_COUNTERS; + hd->data_len = 0; + mclagd_ctl_sock_write(client_fd, buf, MCLAGD_REPLY_INFO_HDR); + + if (Pbuf) + free(Pbuf); + return; + } + + hd = (struct mclagd_reply_hdr *)(Pbuf + sizeof(int)); + hd->exec_result = EXEC_TYPE_SUCCESS; + hd->info_type = INFO_TYPE_DUMP_DBG_COUNTERS; + hd->data_len = data_len; + len_tmp = (hd->data_len + sizeof(struct mclagd_reply_hdr)); + memcpy(Pbuf, &len_tmp, sizeof(int)); + mclagd_ctl_sock_write(client_fd, Pbuf, MCLAGD_REPLY_INFO_HDR + hd->data_len); + + if (Pbuf) + free(Pbuf); +} + +void mclagd_ctl_handle_dump_unique_ip(int client_fd, int mclag_id) +{ + char *Pbuf = NULL; + char buf[512] = { 0 }; + int lif_num = 0; + int ret = 0; + struct mclagd_reply_hdr *hd = NULL; + int len_tmp = 0; + + ret = iccp_unique_ip_if_dump(&Pbuf, &lif_num, mclag_id); + if (ret != EXEC_TYPE_SUCCESS) + { + len_tmp = sizeof(struct mclagd_reply_hdr); + memcpy(buf, &len_tmp, sizeof(int)); + hd = (struct mclagd_reply_hdr *)(buf + sizeof(int)); + hd->exec_result = ret; + hd->info_type = INFO_TYPE_DUMP_LOCAL_PORTLIST; + hd->data_len = 0; + mclagd_ctl_sock_write(client_fd, buf, MCLAGD_REPLY_INFO_HDR); + + if (Pbuf) + free(Pbuf); + + return; + } + + hd = (struct mclagd_reply_hdr *)(Pbuf + sizeof(int)); + hd->exec_result = EXEC_TYPE_SUCCESS; + hd->info_type = INFO_TYPE_DUMP_UNIQUE_IP; + hd->data_len = lif_num * sizeof(struct mclagd_unique_ip_if); + len_tmp = (hd->data_len + sizeof(struct mclagd_reply_hdr)); + memcpy(Pbuf, &len_tmp, sizeof(int)); + mclagd_ctl_sock_write(client_fd, Pbuf, MCLAGD_REPLY_INFO_HDR + hd->data_len); + + if (Pbuf) + free(Pbuf); + + return; +} + void mclagd_ctl_handle_config_loglevel(int client_fd, int log_level) { char buf[sizeof(struct mclagd_reply_hdr)+sizeof(int)]; @@ -2389,7 +4197,7 @@ int mclagd_ctl_interactive_process(int client_fd) case INFO_TYPE_DUMP_MAC: mclagd_ctl_handle_dump_mac(client_fd, req->mclag_id); - break; + break; case INFO_TYPE_DUMP_LOCAL_PORTLIST: mclagd_ctl_handle_dump_local_portlist(client_fd, req->mclag_id); @@ -2399,6 +4207,14 @@ int mclagd_ctl_interactive_process(int client_fd) mclagd_ctl_handle_dump_peer_portlist(client_fd, req->mclag_id); break; + case INFO_TYPE_DUMP_DBG_COUNTERS: + mclagd_ctl_handle_dump_dbg_counters(client_fd, req->mclag_id); + break; + + case INFO_TYPE_DUMP_UNIQUE_IP: + mclagd_ctl_handle_dump_unique_ip(client_fd, req->mclag_id); + break; + case INFO_TYPE_CONFIG_LOGLEVEL: mclagd_ctl_handle_config_loglevel(client_fd, req->mclag_id); break; @@ -2410,4 +4226,339 @@ int mclagd_ctl_interactive_process(int client_fd) return 0; } +int syn_local_mac_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int is_sag) +{ + struct MACMsg mac_msg = {0}; + int msg_len = 0, rc = MCLAG_ERROR; + int vid = 0; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (!csm || !local_if) { + ICCPD_LOG_DEBUG(__FUNCTION__,"invalid parameters"); + return MCLAG_ERROR; + } + + if (memcmp(MLACP(csm).system_id, null_mac, ETHER_ADDR_LEN) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__,"invalid system id"); + return MCLAG_ERROR; + } + + if (sync_add) { + mac_msg.op_type = MAC_SYNC_ADD; + } else { + mac_msg.op_type = MAC_SYNC_DEL; + } + + if (is_sag) { + sscanf (local_if->name,"sag%d.256",&vid); + } else { + sscanf (local_if->name,"Vlan%d",&vid); + } + + mac_msg.vid = vid; + mac_msg.fdb_type = MAC_TYPE_STATIC; + memcpy(mac_msg.origin_ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + memcpy(mac_msg.mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN); + + ICCPD_LOG_DEBUG(__FUNCTION__,"add %d, mac name %s, vid %d", sync_add, mac_msg.origin_ifname, mac_msg.vid); + ICCPD_LOG_DEBUG(__FUNCTION__,"mac [%02X:%02X:%02X:%02X:%02X:%02X]", + mac_msg.mac_addr[0], mac_msg.mac_addr[1], mac_msg.mac_addr[2], mac_msg.mac_addr[3], mac_msg.mac_addr[4], mac_msg.mac_addr[5]); + + memset(g_csm_buf, 0, CSM_BUFFER_SIZE); + msg_len = mlacp_prepare_for_mac_info_to_peer(csm, g_csm_buf, CSM_BUFFER_SIZE, &mac_msg, 0); + if (msg_len > 0) + rc = iccp_csm_send(csm, g_csm_buf, msg_len); + + if (rc <= 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "failed rc %d, msg_len %d", rc, msg_len); + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__,"success"); + } + return rc; +} + +int syn_local_arp_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int ack) +{ + struct ARPMsg arp_msg = {0}; + int msg_len = 0, rc = MCLAG_ERROR; + + if (!csm || !local_if) { + ICCPD_LOG_DEBUG(__FUNCTION__,"invalid parameters"); + return MCLAG_ERROR; + } + + if (sync_add) { + arp_msg.op_type = NEIGH_SYNC_ADD; + if (ack) { + arp_msg.flag |= NEIGH_SYNC_FLAG_ACK; + } + } else { + arp_msg.op_type = NEIGH_SYNC_DEL; + } + + arp_msg.ipv4_addr = local_if->ipv4_addr; + arp_msg.flag |= NEIGH_SYNC_FLAG_SELF_IP; + memcpy(arp_msg.ifname, local_if->name, MAX_L_PORT_NAME); + memcpy(arp_msg.mac_addr, local_if->mac_addr, ETHER_ADDR_LEN); + + ICCPD_LOG_DEBUG(__FUNCTION__," add %d ack %d ifname %s, ip %s", sync_add, ack, arp_msg.ifname, show_ip_str(arp_msg.ipv4_addr)); + ICCPD_LOG_DEBUG(__FUNCTION__," mac [%02X:%02X:%02X:%02X:%02X:%02X]", + arp_msg.mac_addr[0], arp_msg.mac_addr[1], arp_msg.mac_addr[2], arp_msg.mac_addr[3], arp_msg.mac_addr[4], arp_msg.mac_addr[5]); + + memset(g_csm_buf, 0, CSM_BUFFER_SIZE); + msg_len = mlacp_prepare_for_arp_info(csm, g_csm_buf, CSM_BUFFER_SIZE, &arp_msg, 0, NEIGH_SYNC_SELF_IP); + if (msg_len > 0) + rc = iccp_csm_send(csm, g_csm_buf, msg_len); + + if (rc <= 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "failed rc %d, msg_len %d", rc, msg_len); + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__,"success"); + } + + return rc; +} + +int syn_local_nd_info_to_peer(struct CSM* csm, struct LocalInterface *local_if, int sync_add, int ack, int is_ipv6_ll, int dir) +{ + struct NDISCMsg nd_msg = {0}; + int msg_len = 0, rc = MCLAG_ERROR; + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (!csm || !local_if) { + ICCPD_LOG_DEBUG(__FUNCTION__,"invalid parameters"); + return MCLAG_ERROR; + } + + if (sync_add) { + nd_msg.op_type = NEIGH_SYNC_ADD; + if (ack) { + nd_msg.flag |= NEIGH_SYNC_FLAG_ACK; + } + } else { + nd_msg.op_type = NEIGH_SYNC_DEL; + } + + if (is_ipv6_ll) { + if (local_if->ll_prefixlen_v6 == 0) { + ICCPD_LOG_NOTICE(__FUNCTION__, " Link Local Address not configured."); + return MCLAG_ERROR; + } + nd_msg.flag |= NEIGH_SYNC_FLAG_SELF_LL; + memcpy(nd_msg.ipv6_addr, local_if->ipv6_ll_addr, 16); + if (memcmp(MLACP(csm).system_id, null_mac, ETHER_ADDR_LEN) == 0){ + ICCPD_LOG_NOTICE(__FUNCTION__, " system_id not initialised."); + return MCLAG_ERROR; + } + memcpy(nd_msg.mac_addr, MLACP(csm).system_id, ETHER_ADDR_LEN); + } else { + nd_msg.flag |= NEIGH_SYNC_FLAG_SELF_IP; + memcpy(nd_msg.ipv6_addr, local_if->ipv6_addr, 16); + memcpy(nd_msg.mac_addr, local_if->mac_addr, ETHER_ADDR_LEN); + } + memcpy(nd_msg.ifname, local_if->name, MAX_L_PORT_NAME); + + ICCPD_LOG_DEBUG(__FUNCTION__,"add %d, ack %d, flag %x, is_ll %d, dir %d, ifname %s, ip %s", sync_add, ack, + nd_msg.flag, is_ipv6_ll, dir, nd_msg.ifname, show_ipv6_str((char *)nd_msg.ipv6_addr)); + ICCPD_LOG_DEBUG(__FUNCTION__,"mac [%02X:%02X:%02X:%02X:%02X:%02X]", + nd_msg.mac_addr[0], nd_msg.mac_addr[1], nd_msg.mac_addr[2], nd_msg.mac_addr[3], nd_msg.mac_addr[4], nd_msg.mac_addr[5]); + + memset(g_csm_buf, 0, CSM_BUFFER_SIZE); + msg_len = mlacp_prepare_for_ndisc_info(csm, g_csm_buf, CSM_BUFFER_SIZE, &nd_msg, 0, NEIGH_SYNC_SELF_IP); + if (msg_len > 0) + rc = iccp_csm_send(csm, g_csm_buf, msg_len); + + if (rc <= 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "failed rc %d, msg_len %d", rc, msg_len); + } + else + { + ICCPD_LOG_DEBUG(__FUNCTION__,"success"); + } + + return rc; +} + +int syn_local_neigh_mac_info_to_peer(struct LocalInterface *local_if, + int sync_add, int is_v4, int is_v6, int sync_mac, int ack, int is_ipv6_ll, int dir) +{ + struct System* sys = NULL; + struct CSM* csm = NULL; + + if ((sys = system_get_instance()) == NULL) { + ICCPD_LOG_DEBUG(__FUNCTION__,"system instance not present, skip sync"); + return MCLAG_ERROR; + } + + while (!LIST_EMPTY(&(sys->csm_list))) + { + csm = LIST_FIRST(&(sys->csm_list)); + break; + } + + if (!csm) { + ICCPD_LOG_DEBUG(__FUNCTION__,"csm not present, skip sync"); + return MCLAG_ERROR; + } + + if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) { + ICCPD_LOG_DEBUG(__FUNCTION__,"Session not up, skip sync"); + return MCLAG_ERROR; + } + + if (local_if->type != IF_T_VLAN) { + ICCPD_LOG_DEBUG(__FUNCTION__,"invalid if type %d", local_if->type); + return MCLAG_ERROR; + } + + ICCPD_LOG_DEBUG(__FUNCTION__,"add %d, v4 %d, v6 %d, mac %d ack %d, is_ipv6_ll %d, dir %d", + sync_add, is_v4, is_v6, sync_mac, ack, is_ipv6_ll, dir); + + if (csm->peer_link_if) + { + set_peerlink_learn_kernel(csm, 0, 9); + } + if (sync_mac) { + syn_local_mac_info_to_peer(csm, local_if, sync_add, is_ipv6_ll); + } + + if (is_v4) { + syn_local_arp_info_to_peer(csm, local_if, sync_add, ack); + } + + if (is_v6) { + syn_local_nd_info_to_peer(csm, local_if, sync_add, ack, is_ipv6_ll, 1); + } + + return 0; +} + +int syn_ack_local_neigh_mac_info_to_peer(char *ifname, int is_ipv6_ll) +{ + struct LocalInterface *lif = NULL; + int sync_add = 0, is_v4 = 0, is_v6 = 0; + + if (!ifname) + return -1; + + lif = local_if_find_by_name(ifname); + if (lif) + { + if (is_ipv6_ll) { + syn_local_neigh_mac_info_to_peer(lif, 1, 0, 1, 1, 0, 1, 2); + return 0; + } + + if (lif->ipv4_addr) + { + is_v4 = 1; + } + + if (lif->prefixlen_v6) + { + is_v6 = 1; + } + ICCPD_LOG_DEBUG(__FUNCTION__," v4 %d, v6 %d, l3_mode %d, proto %d", is_v4, is_v6, lif->l3_mode, lif->is_l3_proto_enabled); + if (lif->l3_mode && lif->is_l3_proto_enabled) { + syn_local_neigh_mac_info_to_peer(lif, 1, is_v4, is_v6, 1, 0, 0, 3); + } + } + return 0; +} + +int is_unique_ip_configured(char *ifname) +{ + struct System* sys = NULL; + struct Unq_ip_If_info* unq_ip_if = NULL; + + if (!(sys = system_get_instance())) + return 0; + + LIST_FOREACH(unq_ip_if, &(sys->unq_ip_if_list), if_next) + { + if (strcmp(unq_ip_if->name, ifname) == 0) + { + return 1; + } + } + + return 0; +} + +int sync_unique_ip() +{ + struct System* sys = NULL; + struct Unq_ip_If_info* unq_ip_if = NULL; + struct LocalInterface* local_if = NULL; + + if (!(sys = system_get_instance())) + return 0; + + LIST_FOREACH(unq_ip_if, &(sys->unq_ip_if_list), if_next) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "unq_ip_if name %s", unq_ip_if->name); + syn_ack_local_neigh_mac_info_to_peer(unq_ip_if->name, 0); + } + + return 0; +} + +void set_peer_mac_in_kernel(char *mac, int vlan, int add) +{ + char cmd[256] = { 0 }; + int ret = 0; + + ICCPD_LOG_DEBUG(__FUNCTION__,"mac %s, vlan %d, add %d", mac, vlan, add); + + if (add) { + sprintf(cmd, "bridge fdb replace %s dev Bridge vlan %d local", mac, vlan); + } else { + sprintf(cmd, "bridge fdb del %s dev Bridge vlan %d local", mac, vlan); + } + + ret = system(cmd); + ICCPD_LOG_DEBUG(__FUNCTION__, " cmd %s ret = %d", cmd, ret); + + return; +} + +void set_peerlink_learn_kernel( + struct CSM* csm, + int enable, int dir) +{ + struct LocalInterface *lif = NULL; + if (!csm || !csm->peer_link_if) + return; + + lif = csm->peer_link_if; + + ICCPD_LOG_DEBUG(__FUNCTION__,"ifname %s, enable %d, dir %d", lif->name, enable, dir); + char cmd[256] = { 0 }; + int ret = 0; + if (enable == 0) { + sprintf(cmd, "bridge link set dev %s learning off", lif->name); + } else { + sprintf(cmd, "bridge link set dev %s learning on", lif->name); + } + + ret = system(cmd); + ICCPD_LOG_DEBUG(__FUNCTION__, " cmd %s ret = %d", cmd, ret); + + if (ret != 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, " cmd %s ret = %d", cmd, ret); + csm->peer_link_learning_enable = enable; + csm->peer_link_learning_retry_time = time(NULL); + } else { + csm->peer_link_learning_retry_time = 0; + } + return; +} diff --git a/src/iccpd/src/mlacp_sync_prepare.c b/src/iccpd/src/mlacp_sync_prepare.c index ef1cd244a90a..a28a43e2b842 100644 --- a/src/iccpd/src/mlacp_sync_prepare.c +++ b/src/iccpd/src/mlacp_sync_prepare.c @@ -91,6 +91,10 @@ int mlacp_prepare_for_sync_request_tlv(struct CSM* csm, char* buf, size_t max_bu tlv->port_num_agg_id = 0; tlv->actor_key = 0; + ICCPD_LOG_DEBUG("ICCP_FSM", "TX sync_request: role %s, sync_state %s", + (csm->role_type == STP_ROLE_STANDBY) ? "standby" : "active", + mlacp_state(csm)); + return msg_len; } @@ -138,6 +142,7 @@ int mlacp_prepare_for_sync_data_tlv(struct CSM* csm, char* buf, size_t max_buf_s else tlv->flags = htons(0x01); + ICCPD_LOG_DEBUG("ICCP_CSM", "TX sync %s", end ? "end" : "start"); return msg_len; } @@ -182,6 +187,10 @@ int mlacp_prepare_for_sys_config(struct CSM* csm, char* buf, size_t max_buf_size memcpy(tlv->sys_id, MLACP(csm).system_id, ETHER_ADDR_LEN); tlv->sys_priority = htons(MLACP(csm).system_priority); tlv->node_id = MLACP(csm).node_id; + + ICCPD_LOG_DEBUG("ICCP_FSM", "TX sys_config: systemID %s, priority %u, nodeID %u", + mac_addr_to_str(MLACP(csm).system_id), MLACP(csm).system_priority, + MLACP(csm).node_id); return msg_len; } @@ -232,6 +241,8 @@ int mlacp_prepare_for_Aggport_state(struct CSM* csm, char* buf, size_t max_buf_s tlv->actor_key = 0; tlv->agg_state = local_if->state; + ICCPD_LOG_DEBUG("ICCP_FSM", "TX aggrport_state: %s is %s", + local_if->name, (local_if->state == PORT_STATE_UP) ? "up" : "down"); return msg_len; } @@ -280,6 +291,8 @@ int mlacp_prepare_for_Aggport_config(struct CSM* csm, memcpy(tlv->agg_name, lif->name, MAX_L_PORT_NAME); memcpy(tlv->mac_addr, lif->mac_addr, ETHER_ADDR_LEN); + ICCPD_LOG_DEBUG("ICCP_FSM", "TX aggrport_config: %s, purge_flag %d, mac %s", + lif->name, purge_flag, mac_addr_to_str(lif->mac_addr)); return msg_len; } @@ -322,12 +335,13 @@ int mlacp_prepare_for_mac_info_to_peer(struct CSM* csm, char* buf, size_t max_bu MacData = (struct mLACPMACData *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPMACInfoTLV) + sizeof(struct mLACPMACData) * count]; MacData->type = mac_msg->op_type; - sprintf(MacData->mac_str, "%s", mac_msg->mac_str); + MacData->mac_type = mac_msg->fdb_type; + memcpy(MacData->mac_addr, mac_msg->mac_addr,ETHER_ADDR_LEN); sprintf(MacData->ifname, "%s", mac_msg->origin_ifname); MacData->vid = htons(mac_msg->vid); - ICCPD_LOG_NOTICE(__FUNCTION__, "Send MAC messge to peer, port %s mac = %s, vid = %d, type = %s count %d ", mac_msg->origin_ifname, - mac_msg->mac_str, mac_msg->vid, mac_msg->op_type == MAC_SYNC_ADD ? "add" : "del", count); + ICCPD_LOG_DEBUG("ICCP_FDB", "Send MAC messge to peer, port %s mac = %s, vid = %d, type = %s count %d ", mac_msg->origin_ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type == MAC_SYNC_ADD ? "add" : "del", count); return msg_len; } @@ -336,7 +350,7 @@ int mlacp_prepare_for_mac_info_to_peer(struct CSM* csm, char* buf, size_t max_bu * Preprare Sync ARP-Info TLV * * ***************************************/ -int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count) +int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count, int dir) { struct mLACPARPInfoTLV* tlv = NULL; size_t msg_len = 0; @@ -373,13 +387,15 @@ int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, ArpData = (struct ARPMsg *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPARPInfoTLV) + sizeof(struct ARPMsg) * count]; ArpData->op_type = arp_msg->op_type; + ArpData->flag = arp_msg->flag; sprintf(ArpData->ifname, "%s", arp_msg->ifname); ArpData->ipv4_addr = arp_msg->ipv4_addr; memcpy(ArpData->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN); - ICCPD_LOG_NOTICE(__FUNCTION__, "Send ARP messge to peer, if name %s mac %02x:%02x:%02x:%02x:%02x:%02x IP %s", ArpData->ifname, ArpData->mac_addr[0], ArpData->mac_addr[1], ArpData->mac_addr[2], - ArpData->mac_addr[3], ArpData->mac_addr[4], ArpData->mac_addr[5], show_ip_str(ArpData->ipv4_addr)); - + ICCPD_LOG_DEBUG(__FUNCTION__, "Send ARP messge to peer, dir %d, flag %d, if name %s mac %02x:%02x:%02x:%02x:%02x:%02x IP %s", + dir, ArpData->flag, ArpData->ifname, + ArpData->mac_addr[0], ArpData->mac_addr[1], ArpData->mac_addr[2], ArpData->mac_addr[3], ArpData->mac_addr[4], + ArpData->mac_addr[5], show_ip_str(ArpData->ipv4_addr)); return msg_len; } @@ -387,14 +403,13 @@ int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, * Preprare Sync NDISC-Info TLV * * ***************************************/ -int mlacp_prepare_for_ndisc_info(struct CSM *csm, char *buf, size_t max_buf_size, struct NDISCMsg *ndisc_msg, int count) +int mlacp_prepare_for_ndisc_info(struct CSM *csm, char *buf, size_t max_buf_size, struct NDISCMsg *ndisc_msg, int count, int dir) { - struct mLACPNDISCInfoTLV *tlv = NULL; size_t msg_len = 0; size_t tlv_len = 0; ICCHdr *icc_hdr = NULL; - struct NDISCMsg *NdiscData; + struct NDISCMsg *NdiscData = NULL; if (!csm) return -1; @@ -422,14 +437,16 @@ int mlacp_prepare_for_ndisc_info(struct CSM *csm, char *buf, size_t max_buf_size tlv->icc_parameter.type = htons(TLV_T_MLACP_NDISC_INFO); } - NdiscData = (struct mLACPMACData *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPNDISCInfoTLV) + sizeof(struct NDISCMsg) * count]; + NdiscData = (struct NDISCMsg *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPNDISCInfoTLV) + sizeof(struct NDISCMsg) * count]; NdiscData->op_type = ndisc_msg->op_type; + NdiscData->flag = ndisc_msg->flag; sprintf(NdiscData->ifname, "%s", ndisc_msg->ifname); - memcpy(NdiscData->ipv6_addr, ndisc_msg->ipv6_addr, 32); + memcpy(NdiscData->ipv6_addr, ndisc_msg->ipv6_addr, 16); memcpy(NdiscData->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN); - ICCPD_LOG_NOTICE(__FUNCTION__, "Send ND messge to peer, if name %s mac =%02x:%02x:%02x:%02x:%02x:%02x IPv6 %s", NdiscData->ifname, + ICCPD_LOG_DEBUG(__FUNCTION__, "Send ND messge to peer, dir %d, flag %d, if name %s mac =%02x:%02x:%02x:%02x:%02x:%02x IPv6 %s", + dir, NdiscData->flag, NdiscData->ifname, NdiscData->mac_addr[0], NdiscData->mac_addr[1], NdiscData->mac_addr[2], NdiscData->mac_addr[3], NdiscData->mac_addr[4], NdiscData->mac_addr[5], show_ipv6_str((char *)NdiscData->ipv6_addr)); @@ -465,9 +482,9 @@ int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf, return MCLAG_ERROR; /* Calculate VLAN ID Length */ - LIST_FOREACH(vlan_id, &(port_channel->vlan_list), port_next) - if (vlan_id != NULL) - num_of_vlan_id++; + RB_FOREACH(vlan_id, vlan_rb_tree, &(port_channel->vlan_tree)) + if (vlan_id != NULL) + num_of_vlan_id++; tlv_len = sizeof(struct mLACPPortChannelInfoTLV) + sizeof(struct mLACPVLANData) * num_of_vlan_id; @@ -500,7 +517,7 @@ int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf, tlv->num_of_vlan_id = htons(num_of_vlan_id); num_of_vlan_id = 0; - LIST_FOREACH(vlan_id, &(port_channel->vlan_list), port_next) + RB_FOREACH(vlan_id, vlan_rb_tree, &(port_channel->vlan_tree)) { if (vlan_id != NULL ) { @@ -512,7 +529,7 @@ int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf, } ICCPD_LOG_DEBUG(__FUNCTION__, "PortChannel%d: ipv4 addr = %s l3 mode %d", port_channel->po_id, show_ip_str( tlv->ipv4_addr), tlv->l3_mode); - + ICCPD_LOG_DEBUG("ICCP_FSM", "TX po_info: %s has %d vlans", port_channel->name, num_of_vlan_id); return msg_len; } @@ -562,8 +579,8 @@ int mlacp_prepare_for_port_peerlink_info(struct CSM* csm, char* buf, memcpy(tlv->if_name, peerlink_port->name, MAX_L_PORT_NAME); tlv->port_type = peerlink_port->type; - ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port is %s, type = %d", tlv->if_name, tlv->port_type); - + ICCPD_LOG_DEBUG("ICCP_FSM", "TX peerlink_info: name %s, type %d", + peerlink_port->name, peerlink_port->type); return msg_len; } @@ -649,8 +666,60 @@ int mlacp_prepare_for_warm_reboot(struct CSM* csm, char* buf, size_t max_buf_siz tlv->icc_parameter.len = htons(sizeof(struct mLACPWarmbootTLV) - sizeof(ICCParameter)); tlv->warmboot = 0x1; + ICCPD_LOG_DEBUG("ICCP_FSM", "TX start warm reboot"); + return msg_len; +} + +/***************************************** +* Prepare interface up ACK message +* +* ***************************************/ +int mlacp_prepare_for_if_up_ack( + struct CSM *csm, + char *buf, + size_t max_buf_size, + uint8_t if_type, + uint16_t if_id, + uint8_t port_isolation_state) +{ + struct System* sys = NULL; + ICCHdr* icc_hdr = (ICCHdr*) buf; + struct mLACPIfUpAckTLV* tlv = (struct mLACPIfUpAckTLV*) &buf[sizeof(ICCHdr)]; + size_t msg_len = sizeof(ICCHdr) + sizeof(struct mLACPIfUpAckTLV); + + if(csm == NULL) + return -1; + + if(buf == NULL) + return -1; + + if(msg_len > max_buf_size) + return -1; + + if((sys = system_get_instance()) == NULL) + return -1; + + /* Prepare for sync request */ + memset(buf, 0, max_buf_size); + + icc_hdr = (ICCHdr*) buf; + tlv = (struct mLACPIfUpAckTLV*) &buf[sizeof(ICCHdr)]; + + /* ICC header */ + mlacp_fill_icc_header(csm, icc_hdr, msg_len); + + /* If up ack TLV */ + tlv->icc_parameter.u_bit = 0; + tlv->icc_parameter.f_bit = 0; + tlv->icc_parameter.type = htons(TLV_T_MLACP_IF_UP_ACK); + + tlv->icc_parameter.len = htons(sizeof(struct mLACPIfUpAckTLV) - sizeof(ICCParameter)); + tlv->if_type = if_type; + tlv->if_id = htons(if_id); + tlv->port_isolation_state = port_isolation_state; - ICCPD_LOG_NOTICE(__FUNCTION__, "Send warm reboot notification to peer!"); + ICCPD_LOG_DEBUG("ICCP_FSM", "TX if_up_ack: PortChannel%d, isolation_set %d", + if_id, port_isolation_state); return msg_len; } diff --git a/src/iccpd/src/mlacp_sync_update.c b/src/iccpd/src/mlacp_sync_update.c index b82fc1c16cb9..be2c75d12e5d 100644 --- a/src/iccpd/src/mlacp_sync_update.c +++ b/src/iccpd/src/mlacp_sync_update.c @@ -31,37 +31,48 @@ #include "../include/mlacp_tlv.h" #include "../include/iccp_csm.h" #include "../include/mlacp_link_handler.h" +#include "../include/iccp_netlink.h" #include "../include/iccp_consistency_check.h" #include "../include/port.h" -#include "../include/iccp_netlink.h" +#include "../include/openbsd_tree.h" + /***************************************** * Port-Conf Update * * ***************************************/ -extern void update_if_ipmac_on_standby(struct LocalInterface* lif_po); + int mlacp_fsm_update_system_conf(struct CSM* csm, mLACPSysConfigTLV*sysconf) { struct LocalInterface* lif = NULL; + uint8_t old_remote_system_id[ETHER_ADDR_LEN]; + + ICCPD_LOG_NOTICE("ICCP_FSM", "RX system_conf: systemID %s, priority %d, remote nodeID %d, nodeID %d", + mac_addr_to_str(MLACP(csm).remote_system.system_id), + MLACP(csm).remote_system.system_priority, + MLACP(csm).remote_system.node_id, + MLACP(csm).node_id); /*NOTE a little tricky, we change the NodeID local side if collision happened first time*/ if (sysconf->node_id == MLACP(csm).node_id) MLACP(csm).node_id++; + memcpy(old_remote_system_id, MLACP(csm).remote_system.system_id, ETHER_ADDR_LEN); + memcpy(MLACP(csm).remote_system.system_id, sysconf->sys_id, ETHER_ADDR_LEN); MLACP(csm).remote_system.system_priority = ntohs(sysconf->sys_priority); MLACP(csm).remote_system.node_id = sysconf->node_id; - ICCPD_LOG_DEBUG(__FUNCTION__, "SystemID [%02X:%02X:%02X:%02X:%02X:%02X], SystemPriority [%d], Remote NodeID [%d], NodeID [%d]", - MLACP(csm).remote_system.system_id[0], MLACP(csm).remote_system.system_id[1], MLACP(csm).remote_system.system_id[2], - MLACP(csm).remote_system.system_id[3], MLACP(csm).remote_system.system_id[4], MLACP(csm).remote_system.system_id[5], - MLACP(csm).remote_system.system_priority, - MLACP(csm).remote_system.node_id, - MLACP(csm).node_id); - LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) { - update_if_ipmac_on_standby(lif); + update_if_ipmac_on_standby(lif, 2); + } + + /* On standby, update system ID upon receiving change from active */ + if ((csm->role_type == STP_ROLE_STANDBY) && + (memcmp(old_remote_system_id, sysconf->sys_id, ETHER_ADDR_LEN) != 0)) + { + mlacp_link_set_iccp_system_id(csm->mlag_id, sysconf->sys_id); } return 0; @@ -76,10 +87,14 @@ int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf) struct PeerInterface* pif = NULL; uint8_t po_active; uint8_t new_create = 0; + struct LocalInterface *lif; + + if (!csm) + return MCLAG_ERROR; - ICCPD_LOG_DEBUG(__FUNCTION__, "Port name %s, po id %d flag %d MAC[%02x:%02x:%02x:%02x:%02x:%02x] ", - portconf->agg_name, ntohs(portconf->agg_id), portconf->flags, portconf->mac_addr[0], portconf->mac_addr[1], portconf->mac_addr[2], - portconf->mac_addr[3], portconf->mac_addr[4], portconf->mac_addr[5] ); + ICCPD_LOG_DEBUG("ICCP_FSM", "RX aggrport_config: name %s, po_id %d, flag 0x%x, MAC %s", + portconf->agg_name, ntohs(portconf->agg_id), portconf->flags, + mac_addr_to_str(portconf->mac_addr)); /* Looking for the peer port instance, is any peer if exist?*/ pif = peer_if_find_by_name(csm, portconf->agg_name); @@ -89,7 +104,16 @@ int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf) { /*Purge*/ if (pif != NULL ) + { + //This handler would take of handling mlacp changes based on peer + //mclag interface delete; recover back mac of po to original + //on standby etc + mlacp_peer_mlag_intf_delete_handler(csm, pif->name); + + /* Delete remote interface info from STATE_DB */ + mlacp_link_del_remote_if_info(csm->mlag_id, pif->name); peer_if_destroy(pif); + } else MLACP(csm).need_to_sync = 1; /*ICCPD_LOG_INFO("mlacp_fsm", @@ -116,6 +140,21 @@ int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf) update_peerlink_isolate_from_pif(csm, pif, po_active, new_create); pif->po_active = po_active; + /* When peer MLAG interface does not exist on active, standby does not set + * its MLAG interface MAC address to the active system MAC address. + * Peer MLAG interface is added now, update the standby MLAG interface + * MAC address + */ + if (new_create) + { + mlacp_link_set_remote_if_state(csm->mlag_id, pif->name, (po_active)? true : false); + if ((csm->role_type == STP_ROLE_STANDBY)) + { + lif = local_if_find_by_name(portconf->agg_name); + if (lif) + update_if_ipmac_on_standby(lif, 3); + } + } return 0; } @@ -130,7 +169,10 @@ int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv) if (csm == NULL || tlv == NULL) return MCLAG_ERROR; - ICCPD_LOG_DEBUG(__FUNCTION__, "Portchannel id %d state %d", ntohs(tlv->agg_id), tlv->agg_state); + + ICCPD_LOG_DEBUG("ICCP_FSM", "RX aggrport_state: po_id %d, state %s, sync_state %s", + ntohs(tlv->agg_id), (tlv->agg_state == PORT_STATE_UP) ? "up" : "down", + mlacp_state(csm)); po_active = (tlv->agg_state == PORT_STATE_UP); @@ -150,6 +192,18 @@ int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv) peer_if->po_active = po_active; ICCPD_LOG_DEBUG(__FUNCTION__, "Update peer interface %s to state %s", peer_if->name, tlv->agg_state ? "down" : "up"); + /* Update remote interface state if ICCP reaches EXCHANGE state. + * Otherwise, it is updated after the session comes up + */ + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + { + if (tlv->agg_state == PORT_STATE_DOWN) + mlacp_convert_remote_mac_to_local(csm, peer_if->name); + + mlacp_link_set_remote_if_state( + csm->mlag_id, peer_if->name, + (tlv->agg_state == PORT_STATE_UP)? true : false); + } break; } @@ -161,15 +215,26 @@ int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv) * ***************************************/ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData *MacData) { - struct Msg* msg = NULL; - struct MACMsg *mac_msg = NULL, mac_data; + struct MACMsg *mac_msg = NULL, *new_mac_msg = NULL; + struct MACMsg mac_data, mac_find; struct LocalInterface* local_if = NULL; uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/ + memset(&mac_data, 0, sizeof(struct MACMsg)); + memset(&mac_find, 0, sizeof(struct MACMsg)); + uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + ICCPD_LOG_INFO("ICCP_FDB", + "Received MAC Info, interface=[%s] vid[%d] MAC[%s] OperType[%s] MacType[%d] ", + MacData->ifname, ntohs(MacData->vid), mac_addr_to_str(MacData->mac_addr), + MacData->type == MAC_SYNC_ADD ? "add" : "del", MacData->mac_type); + + if (memcmp(MacData->mac_addr, null_mac, ETHER_ADDR_LEN) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address from peer do not add."); + return 0; + } - ICCPD_LOG_NOTICE(__FUNCTION__, - "Received MAC Info, port[%s] vid[%d] MAC[%s] type[%s]", - MacData->ifname, ntohs(MacData->vid), MacData->mac_str, MacData->type == MAC_SYNC_ADD ? "add" : "del"); /*Find the interface in MCLAG interface list*/ LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) @@ -181,104 +246,214 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * } } - /* update MAC list*/ - TAILQ_FOREACH(msg, &(MLACP(csm).mac_list), tail) + mac_find.vid = ntohs(MacData->vid); + memcpy(&mac_find.mac_addr, MacData->mac_addr, ETHER_ADDR_LEN); + mac_msg = RB_FIND(mac_rb_tree, &MLACP(csm).mac_rb ,&mac_find); + + /*Same MAC is exist in local switch, this may be mac move*/ + //if (strcmp(mac_msg->mac_str, MacData->mac_str) == 0 && mac_msg->vid == ntohs(MacData->vid)) + if (mac_msg) { - mac_msg = (struct MACMsg*)msg->buf; + ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC update from peer RB_FIND success, existing MAC age flag:%d interface %s, " + "MAC %s vlan-id %d, fdb_type: %d, op_type %s", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->fdb_type, + (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del"); - /*Same MAC is exist in local switch, this may be mac move*/ - if (strcmp(mac_msg->mac_str, MacData->mac_str) == 0 && mac_msg->vid == ntohs(MacData->vid)) + if (MacData->type == MAC_SYNC_ADD) { - if (MacData->type == MAC_SYNC_ADD) + mac_msg->age_flag &= ~MAC_AGE_PEER; + + if (from_mclag_intf && mac_msg->pending_local_del) { - mac_msg->age_flag &= ~MAC_AGE_PEER; - ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ADD, Remove peer age flag:%d ifname %s, MAC %s vlan-id %d", - mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + mac_msg->pending_local_del = 0; + + mac_msg->age_flag = MAC_AGE_LOCAL; - /*mac_msg->fdb_type = tlv->fdb_type;*/ - /*The port ifname is different to the local item*/ - if (from_mclag_intf == 0 || strcmp(mac_msg->ifname, MacData->ifname) != 0 || strcmp(mac_msg->origin_ifname, MacData->ifname) != 0) + // AS MAC was learned locally and in pending state due to IF is down, + // send del to peer when MAC add received from peer + mac_msg->op_type = MAC_SYNC_DEL; + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) { - if (mac_msg->fdb_type != MAC_TYPE_STATIC) - { - /*Update local item*/ - memcpy(&mac_msg->origin_ifname, MacData->ifname, MAX_L_PORT_NAME); - } + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail); + } + } + + ICCPD_LOG_DEBUG("ICCP_FDB", "Recv ADD, Remove peer age flag:%d interface %s, " + "MAC %s vlan-id %d, op_type %s, from_mclag_intf: %d ", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del", from_mclag_intf); - /*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/ - if (from_mclag_intf == 0 || (local_if->state == PORT_STATE_DOWN && strcmp(mac_msg->ifname, csm->peer_itf_name) != 0)) + /*mac_msg->fdb_type = tlv->fdb_type;*/ + /*The port ifname is different to the local item*/ + if (strcmp(mac_msg->ifname, MacData->ifname) != 0 || strcmp(mac_msg->origin_ifname, MacData->ifname) != 0) + { + if (mac_msg->fdb_type != MAC_TYPE_STATIC) + { + /*Update local item*/ + memcpy(&mac_msg->origin_ifname, MacData->ifname, MAX_L_PORT_NAME); + } + else + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Ignore Recv MAC ADD, Local static present," + " interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + //set back the peer age flag + mac_msg->age_flag |= MAC_AGE_PEER; + return 0; + } + + /*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/ + if (from_mclag_intf == 0 || local_if->state == PORT_STATE_DOWN ) + { + /*Set MAC_AGE_LOCAL flag*/ + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 1); + + if (strlen(csm->peer_itf_name) != 0) { - /*Set MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1); + if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) + { + /*This MAC is already point to peer-link*/ + ICCPD_LOG_NOTICE("ICCP_FDB", "Remote MAC ADD local IF down, MAC already points to Peer_link done processing " + " interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + return 0; + } - if (strlen(csm->peer_itf_name) != 0) + if (csm->peer_link_if && (csm->peer_link_if->state == PORT_STATE_UP)) { - if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) - { - /* This MAC is already point to peer-link */ - return 0; - } + /*Redirect the mac to peer-link*/ + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); - if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) - { - /*Redirect the mac to peer-link*/ - memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); + /*Send mac add message to mclagsyncd*/ + add_mac_to_chip(mac_msg, mac_msg->fdb_type); - /*Send mac add message to mclagsyncd*/ - add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC); - } - else - { - /*must redirect but peerlink is down, del mac from ASIC*/ - /*if peerlink change to up, mac will add back to ASIC*/ - del_mac_from_chip(mac_msg); + ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD , local mac exist move to peer link up " + " interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); - /*Redirect the mac to peer-link*/ - memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); - } } else { - /*must redirect but no peerlink, del mac from ASIC*/ - del_mac_from_chip(mac_msg); + /*Redirect the mac to peer-link, if peerlink is down FdbOrch deletes MAC*/ + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); - /*Update local item*/ - memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME); + add_mac_to_chip(mac_msg, mac_msg->fdb_type); - /*if orphan port mac but no peerlink, don't keep this mac*/ - if (from_mclag_intf == 0) - { - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); - return 0; - } + ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD , local mac exist move to peer link down " + " interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); } } else { - /*Remove MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); + /*must redirect but no peerlink, del mac from ASIC*/ + del_mac_from_chip(mac_msg); /*Update local item*/ memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME); - /*from MCLAG port and the local port is up, add mac to ASIC to update port*/ - add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC); + /*if orphan port mac but no peerlink, don't keep this mac*/ + if (from_mclag_intf == 0) + { + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } + + ICCPD_LOG_ERR(__FUNCTION__, "Ignore Recv MAC ADD " + "MAC %s vlan %d interface %s peer link not available ", + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname); + return 0; + } } } + else + { + /*Update local item*/ + memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME); + + /*from MCLAG port and the local port is up, add mac to ASIC to update port*/ + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + } } + else if(!from_mclag_intf && (strcmp(mac_msg->ifname, MacData->ifname) == 0)) + { + // local to remote MAC move on Orphan port. + if (strlen(csm->peer_itf_name) != 0) + { + if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) + { + /*This MAC is already point to peer-link*/ + ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,MAC already points to Peer_link" + " interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + return 0; + } - break; + if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) + { + /*Redirect the mac to peer-link*/ + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,point MAC address to Peer_link" + "interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + /*Send mac add message to mclagsyncd*/ + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + } + else + { + /*Redirect the mac to peer-link*/ + /*must redirect but if peerlink is down FdbOrch will delete MAC */ + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); + add_mac_to_chip(mac_msg, mac_msg->fdb_type); + + ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,point MAC address to Peer_link" + " peer link is down, delete the MAC, interface %s, MAC %s vlan-id %d ", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid); + } + } + } + + // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed. + #if 0 + mac_msg->op_type = MAC_SYNC_ACK; + if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + { + /*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/ + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail); + ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ADD, MAC-msg-list enqueue: %s, " + "add %s vlan-id %d, op_type %d", mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type); + } + #endif } + // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed. + #if 0 + else if (tlv->type == MAC_SYNC_ACK) + { + /*Clean the MAC_AGE_PEER flag*/ + mac_msg->age_flag &= ~MAC_AGE_PEER; + ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ACK, Remove peer age flag:%d ifname %s, " + "add %s vlan-id %d, op_type %d", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type); + } + #endif + } /* delete/add MAC list*/ - if (msg && MacData->type == MAC_SYNC_DEL) + if (mac_msg && (MacData->type == MAC_SYNC_DEL)) { mac_msg->age_flag |= MAC_AGE_PEER; - ICCPD_LOG_DEBUG(__FUNCTION__, "Recv DEL, Add peer age flag: %d ifname %s, MAC %s vlan-id %d", - mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC DEL from peer: Add peer age flag: %d interface %s, " + "MAC %s vlan %d, op_type %s", mac_msg->age_flag, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, + (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del"); if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER)) { @@ -286,59 +461,67 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * del_mac_from_chip(mac_msg); /*If local and peer both aged, del the mac*/ - TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail); - free(msg->buf); - free(msg); + MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg); + + // free only if not in change list to be send to peer node, + // else free is taken care after sending the update to peer + if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail)) + { + free(mac_msg); + } } else { return 0; } } - else if (!msg && MacData->type == MAC_SYNC_ADD) + else if (!mac_msg && (MacData->type == MAC_SYNC_ADD)) { mac_msg = (struct MACMsg*)&mac_data; - mac_msg->fdb_type = MAC_TYPE_DYNAMIC; + mac_msg->fdb_type = MacData->mac_type; mac_msg->vid = ntohs(MacData->vid); - sprintf(mac_msg->mac_str, "%s", MacData->mac_str); + memcpy(mac_msg->mac_addr, MacData->mac_addr, ETHER_ADDR_LEN); sprintf(mac_msg->ifname, "%s", MacData->ifname); sprintf(mac_msg->origin_ifname, "%s", MacData->ifname); mac_msg->age_flag = 0; + /*Set MAC_AGE_LOCAL flag*/ + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 0); + /*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/ if (from_mclag_intf == 0 || local_if->state == PORT_STATE_DOWN) { - /*Set MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1); if (strlen(csm->peer_itf_name) == 0) { - ICCPD_LOG_NOTICE(__FUNCTION__, "From orphan port or portchannel is down, but peer-link is not configured: ifname %s, MAC %s vlan-id %d", - mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); - /*if orphan port mac but no peerlink, don't keep this mac*/ + //MAC to be saved and program when peer_link is configured..? TBD if (from_mclag_intf == 0) + { + ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC ADD from peer: Ignore MAC learn on orphan port " + "peer-link is not configured interface %s, MAC %s vlan-id %d, " + " op_type %d", from_mclag_intf, mac_msg->ifname, + mac_addr_to_str(mac_msg->mac_addr), + mac_msg->vid, mac_msg->op_type); return 0; + } } else { /*Redirect the mac to peer-link*/ - memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); + memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME); - ICCPD_LOG_NOTICE(__FUNCTION__, "Redirect to peerlink for orphan port or portchannel is down, Add local age flag: %d ifname %s, MAC %s vlan-id %d", - mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid); + ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC ADD from peer: Redirect to peerlink for orphan port or portchannel is down," + " age flag: %d interface %s, MAC %s vlan %d, op_type %d", + mac_msg->age_flag, mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), + mac_msg->vid, mac_msg->op_type); } } - else - { - /*Remove MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); - } - if (iccp_csm_init_msg(&msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + if (iccp_csm_init_mac_msg(&new_mac_msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0) { - TAILQ_INSERT_TAIL(&(MLACP(csm).mac_list), msg, tail); /*ICCPD_LOG_INFO(__FUNCTION__, "add mac queue successfully");*/ + RB_INSERT(mac_rb_tree, &MLACP(csm).mac_rb, new_mac_msg); /*If the mac is from orphan port, or from MCLAG port but the local port is down*/ if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) @@ -347,11 +530,22 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) add_mac_to_chip(mac_msg, mac_msg->fdb_type); } - else + else if(local_if->state != PORT_STATE_DOWN) { /*from MCLAG port and the local port is up*/ add_mac_to_chip(mac_msg, mac_msg->fdb_type); } + // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed. + #if 0 + mac_msg->op_type = MAC_SYNC_ACK; + if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0) + { + /*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/ + TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail); + ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, op_type %d", + mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type); + } + #endif } } @@ -366,7 +560,7 @@ int mlacp_fsm_update_mac_info_from_peer(struct CSM* csm, struct mLACPMACInfoTLV* if (!csm || !tlv) return MCLAG_ERROR; count = ntohs(tlv->num_of_entry); - ICCPD_LOG_INFO(__FUNCTION__, "Received MAC Info count %d", count ); + ICCPD_LOG_INFO(__FUNCTION__, "Received MAC Info count %d ", count ); for (i = 0; i < count; i++) { @@ -433,51 +627,102 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) { struct Msg* msg = NULL; struct ARPMsg *arp_msg = NULL, arp_data; - struct LocalInterface* local_if; + struct LocalInterface *local_if = NULL; + struct LocalInterface *vlan_if = NULL; struct LocalInterface *peer_link_if = NULL; + struct LocalInterface *local_vlan_if = NULL; struct VLAN_ID *vlan_id_list = NULL; int set_arp_flag = 0; + int my_ip_arp_flag = 0; + int vlan_count = 0; char mac_str[18] = ""; + int err = 0, ln = 0; + int permanent_neigh = 0; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; + int vid_intf_present = 0; if (!csm || !arp_entry) return MCLAG_ERROR; - sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2], - arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]); - - ICCPD_LOG_NOTICE(__FUNCTION__, + #if 0 + ICCPD_LOG_INFO(__FUNCTION__, "Received ARP Info, intf[%s] IP[%s], MAC[%02x:%02x:%02x:%02x:%02x:%02x]", arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2], arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]); + #endif - if (strncmp(arp_entry->ifname, "Vlan", 4) == 0) + sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2], + arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]); + + ICCPD_LOG_DEBUG(__FUNCTION__, "Received ARP Info, Flag %x, intf[%s] IP[%s], MAC[%s]", arp_entry->flag, arp_entry->ifname, + show_ip_str(arp_entry->ipv4_addr), mac_str); + + if (strncmp(arp_entry->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0) { + sscanf (arp_entry->ifname, "Vlan%hu", &vlan_id); + } + + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + peer_link_if = local_if_find_by_name(csm->peer_itf_name); if (peer_link_if && !local_if_is_l3_mode(peer_link_if)) { + ln = __LINE__; /* Is peer-linlk itf belong to a vlan the same as peer?*/ - LIST_FOREACH(vlan_id_list, &(peer_link_if->vlan_list), port_next) + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list) { - if (!vlan_id_list->vlan_itf) - continue; - if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) != 0) - continue; - if (!local_if_is_l3_mode(vlan_id_list->vlan_itf)) - continue; + vlan_count++; + if (vlan_id_list->vlan_itf) { + if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) == 0) { + ln = __LINE__; + vid_intf_present = 1; + } + + if (vid_intf_present && local_if_is_l3_mode(vlan_id_list->vlan_itf)) { + if (arp_entry->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) { + my_ip_arp_flag = 1; + } + } - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from intf %s, peer-link %s is the member of this vlan", - vlan_id_list->vlan_itf->name, peer_link_if->name); + ICCPD_LOG_DEBUG(__FUNCTION__, + "ARP is learnt from intf %s, peer-link %s is the member of this vlan", + vlan_id_list->vlan_itf->name, peer_link_if->name); - /* Peer-link belong to L3 vlan is alive, set the ARP info*/ - set_arp_flag = 1; + /* Peer-link belong to L3 vlan is alive, set the ARP info*/ + set_arp_flag = 1; + } + } - break; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP Received ln %d, vlan_count %d, set_arp_flag %d, my_ip %d", + ln, vlan_count, set_arp_flag, my_ip_arp_flag); + + if (vlan_count == 0) + { + vlan_if = local_if_find_by_name(arp_entry->ifname); + if (vlan_if && vlan_if->is_l3_proto_enabled) + { + if (arp_entry->ipv4_addr == vlan_if->ipv4_addr) { + my_ip_arp_flag = 1; + } + set_arp_flag = 1; + } } } } + if(my_ip_arp_flag) + { + ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ARP sync for self ip %s ", show_ip_str(arp_entry->ipv4_addr)); + return 0; + } + if (set_arp_flag == 0) { LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) @@ -487,20 +732,21 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) if (!local_if_is_l3_mode(local_if)) { /* Is the L2 MLAG itf belong to a vlan the same as peer?*/ - LIST_FOREACH(vlan_id_list, &(local_if->vlan_list), port_next) - { - if (!vlan_id_list->vlan_itf) - continue; - if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) != 0) - continue; - if (!local_if_is_l3_mode(vlan_id_list->vlan_itf)) - continue; - - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from intf %s, mclag %s is the member of this vlan", - vlan_id_list->vlan_itf->name, local_if->name); - break; + if (vlan_id) { + vlan_id_list = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), &vlan_key); + if (vlan_id_list && vlan_id_list->vlan_itf) { + if (arp_entry->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) { + my_ip_arp_flag = 1; + } + + ICCPD_LOG_DEBUG(__FUNCTION__, + "ARP is learnt from intf %s, mclag %s is the member of this vlan", + vlan_id_list->vlan_itf->name, local_if->name); + } } + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received PO %s, active %d, my_ip %d, ln %d", + local_if->name, local_if->po_active, my_ip_arp_flag, ln); if (vlan_id_list && local_if->po_active == 1) { /* Any po of L3 vlan is alive, set the ARP info*/ @@ -513,7 +759,9 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) /* Is the ARP belong to a L3 mode MLAG itf?*/ if (strcmp(local_if->name, arp_entry->ifname) == 0) { - ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from mclag L3 intf %s", local_if->name); + ICCPD_LOG_DEBUG(__FUNCTION__, + "ARP is learnt from mclag L3 intf %s, active %d", + local_if->name, local_if->po_active); if (local_if->po_active == 1) { /* po is alive, set the ARP info*/ @@ -523,6 +771,7 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) } else { + ln = __LINE__; continue; } } @@ -530,35 +779,65 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) } } + if(my_ip_arp_flag) + { + ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ARP sync for self ip %s ", show_ip_str(arp_entry->ipv4_addr)); + return 0; + } + /* set dynamic ARP*/ if (set_arp_flag == 1) { + if (arp_entry->flag & NEIGH_SYNC_FLAG_SELF_IP) + { + permanent_neigh = 1; + } + if (arp_entry->op_type == NEIGH_SYNC_ADD) { - if (iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 1, arp_entry->mac_addr, arp_entry->ifname) < 0) + err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 1, arp_entry->mac_addr, arp_entry->ifname, permanent_neigh, 8); + if (err < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "ARP add failure for %s %s %s", - arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str); - return MCLAG_ERROR; + if (err != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_ERR(__FUNCTION__, "ARP add failure for %s %s %s, status %d", + arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str, err); + return MCLAG_ERROR; + } } + + if (arp_entry->flag & NEIGH_SYNC_FLAG_ACK) + { + ICCPD_LOG_DEBUG(__FUNCTION__,"Sync ARP on ACK "); + syn_ack_local_neigh_mac_info_to_peer(arp_entry->ifname, 0); + } } else { - if (iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 0, arp_entry->mac_addr, arp_entry->ifname) < 0) + err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 0, arp_entry->mac_addr, arp_entry->ifname, permanent_neigh, 9); + if (err < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "ARP delete failure for %s %s %s", - arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str); - return MCLAG_ERROR; + if (err != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_ERR(__FUNCTION__, "ARP delete failure for %s %s %s, status %d", + arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str, err); + return MCLAG_ERROR; + } } } - /*ICCPD_LOG_DEBUG(__FUNCTION__, "%s: ARP update for %s %s %s", - __FUNCTION__, arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str);*/ + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP update for %s %s %s", + arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str); } else { - ICCPD_LOG_NOTICE(__FUNCTION__, "Failure: port-channel is not alive"); + ICCPD_LOG_NOTICE(__FUNCTION__, "Failure: port-channel is not alive, ln %d", ln); /*TODO Set static route through peer-link or just skip it?*/ + local_vlan_if = local_if_find_by_name(arp_entry->ifname); + if (local_vlan_if) { + if (arp_entry->ipv4_addr == local_vlan_if->ipv4_addr) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ignore my ip %s", show_ip_str(arp_entry->ipv4_addr)); + return 0; + } + } } /* update ARP list*/ @@ -588,6 +867,8 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) sprintf(arp_msg->ifname, "%s", arp_entry->ifname); arp_msg->ipv4_addr = arp_entry->ipv4_addr; arp_msg->op_type = arp_entry->op_type; + arp_msg->flag = 0; + arp_msg->learn_flag = NEIGH_REMOTE; memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN); if (iccp_csm_init_msg(&msg, (char*)arp_msg, sizeof(struct ARPMsg)) == 0) { @@ -629,7 +910,7 @@ int mlacp_fsm_update_arp_info(struct CSM* csm, struct mLACPARPInfoTLV* tlv) if (!csm || !tlv) return MCLAG_ERROR; count = ntohs(tlv->num_of_entry); - ICCPD_LOG_INFO(__FUNCTION__, "Received ARP Info count %d ", count ); + ICCPD_LOG_DEBUG(__FUNCTION__, "Received ARP Info count %d ", count ); for (i = 0; i < count; i++) { @@ -645,10 +926,21 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) struct Msg *msg = NULL; struct NDISCMsg *ndisc_msg = NULL, ndisc_data; struct LocalInterface *local_if; + struct LocalInterface *vlan_if = NULL; struct LocalInterface *peer_link_if = NULL; + struct LocalInterface *local_vlan_if = NULL; struct VLAN_ID *vlan_id_list = NULL; int set_ndisc_flag = 0; char mac_str[18] = ""; + int my_ip_nd_flag = 0; + int vlan_count = 0; + int err = 0, ln = 0; + int permanent_neigh = 0; + int is_ack_ll = 0; + int is_link_local = 0; + uint16_t vlan_id = 0; + struct VLAN_ID vlan_key = { 0 }; + int vid_intf_present = 0; if (!csm || !ndisc_entry) return MCLAG_ERROR; @@ -656,37 +948,98 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", ndisc_entry->mac_addr[0], ndisc_entry->mac_addr[1], ndisc_entry->mac_addr[2], ndisc_entry->mac_addr[3], ndisc_entry->mac_addr[4], ndisc_entry->mac_addr[5]); - ICCPD_LOG_NOTICE(__FUNCTION__, - "Received ND Info, intf[%s] IP[%s], MAC[%s]", ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); + ICCPD_LOG_DEBUG(__FUNCTION__, + "Received ND Info, intf[%s] Flag %x, IP[%s], MAC[%s]", + ndisc_entry->ifname, ndisc_entry->flag, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); + + if (strncmp(ndisc_entry->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0) { + sscanf (ndisc_entry->ifname, "Vlan%hu", &vlan_id); + } + + if ((memcmp(show_ipv6_str((char *)ndisc_entry->ipv6_addr), "FE80", 4) == 0) + || (memcmp(show_ipv6_str((char *)ndisc_entry->ipv6_addr), "fe80", 4) == 0)) + { + is_link_local = 1; + } - if (strncmp(ndisc_entry->ifname, "Vlan", 4) == 0) + if (vlan_id) { + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + peer_link_if = local_if_find_by_name(csm->peer_itf_name); if (peer_link_if && !local_if_is_l3_mode(peer_link_if)) { + ln = __LINE__; /* Is peer-linlk itf belong to a vlan the same as peer? */ - LIST_FOREACH(vlan_id_list, &(peer_link_if->vlan_list), port_next) + vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key); + + if (vlan_id_list) { - if (!vlan_id_list->vlan_itf) - continue; - if (strcmp(vlan_id_list->vlan_itf->name, ndisc_entry->ifname) != 0) - continue; - if (!local_if_is_l3_mode(vlan_id_list->vlan_itf)) - continue; + vlan_count++; + if (vlan_id_list->vlan_itf) { + if (strcmp(vlan_id_list->vlan_itf->name, ndisc_entry->ifname) == 0) { + ln = __LINE__; + vid_intf_present = 1; + } - ICCPD_LOG_DEBUG(__FUNCTION__, - "ND is learnt from intf %s, peer-link %s is the member of this vlan", - vlan_id_list->vlan_itf->name, peer_link_if->name); + if (vid_intf_present && local_if_is_l3_mode(vlan_id_list->vlan_itf)) { + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0) + { + my_ip_nd_flag = 1; + } - /* Peer-link belong to L3 vlan is alive, set the NDISC info */ - set_ndisc_flag = 1; + if ((my_ip_nd_flag == 0) && is_link_local) + { + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_ll_addr, 16) == 0) + { + my_ip_nd_flag = 1; + } + } + } - break; + ICCPD_LOG_DEBUG(__FUNCTION__, + "ND is learnt from intf %s, peer-link %s is the member of this vlan", + vlan_id_list->vlan_itf->name, peer_link_if->name); + + /* Peer-link belong to L3 vlan is alive, set the NDISC info */ + set_ndisc_flag = 1; + } + } + + ICCPD_LOG_DEBUG(__FUNCTION__, "ND Received ln %d, vlan_count %d, set_ndisc_flag %d, my_ip %d", + ln, vlan_count, set_ndisc_flag, my_ip_nd_flag); + + if (vlan_count == 0) + { + vlan_if = local_if_find_by_name(ndisc_entry->ifname); + if (vlan_if && vlan_if->is_l3_proto_enabled) + { + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_if->ipv6_addr, 16) == 0) + { + my_ip_nd_flag = 1; + } + + if ((my_ip_nd_flag == 0) && is_link_local) + { + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_if->ipv6_ll_addr, 16) == 0) + { + my_ip_nd_flag = 1; + } + } + set_ndisc_flag = 1; + } } } } + if(my_ip_nd_flag) + { + ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ND sync for self ipv6 %s ", show_ipv6_str((char *)ndisc_entry->ipv6_addr)); + return 0; + } + if (set_ndisc_flag == 0) { LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) @@ -695,21 +1048,24 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) { if (!local_if_is_l3_mode(local_if)) { + ln = __LINE__; /* Is the L2 MLAG itf belong to a vlan the same as peer? */ - LIST_FOREACH(vlan_id_list, &(local_if->vlan_list), port_next) - { - if (!vlan_id_list->vlan_itf) - continue; - if (strcmp(vlan_id_list->vlan_itf->name, ndisc_entry->ifname) != 0) - continue; - if (!local_if_is_l3_mode(vlan_id_list->vlan_itf)) - continue; + if (vlan_id) { + vlan_id_list = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), &vlan_key); + if (vlan_id_list && vlan_id_list->vlan_itf) { - ICCPD_LOG_DEBUG(__FUNCTION__, - "ND is learnt from intf %s, %s is the member of this vlan", vlan_id_list->vlan_itf->name, local_if->name); - break; + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0) + { + my_ip_nd_flag = 1; + } + + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is learnt from intf %s, %s is the member of this vlan, my_ip %d", + vlan_id_list->vlan_itf->name, local_if->name, my_ip_nd_flag); + } } + ICCPD_LOG_DEBUG(__FUNCTION__, "ND received PO %s, active %d, ln %d", + local_if->name, local_if->po_active, ln); if (vlan_id_list && local_if->po_active == 1) { /* Any po of L3 vlan is alive, set the NDISC info */ @@ -722,7 +1078,8 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) /* Is the ARP belong to a L3 mode MLAG itf? */ if (strcmp(local_if->name, ndisc_entry->ifname) == 0) { - ICCPD_LOG_DEBUG(__FUNCTION__, "ND is learnt from mclag L3 intf %s", local_if->name); + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is learnt from mclag L3 intf %s, active %d", + local_if->name, local_if->po_active); if (local_if->po_active == 1) { /* po is alive, set the NDISC info */ @@ -732,6 +1089,7 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) } else { + ln = __LINE__; continue; } } @@ -739,36 +1097,69 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) } } + if(my_ip_nd_flag) + { + ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ND sync for self ipv6 %s ", show_ipv6_str((char *)ndisc_entry->ipv6_addr)); + return 0; + } /* set dynamic Ndisc */ if (set_ndisc_flag == 1) { + if (ndisc_entry->flag & NEIGH_SYNC_FLAG_SELF_LL) + { + permanent_neigh = 1; + is_ack_ll = 1; + } + + if (ndisc_entry->flag & NEIGH_SYNC_FLAG_SELF_IP) + { + permanent_neigh = 1; + } + if (ndisc_entry->op_type == NEIGH_SYNC_ADD) { - if (iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 1, ndisc_entry->mac_addr, ndisc_entry->ifname) < 0) + err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 1, ndisc_entry->mac_addr, ndisc_entry->ifname, permanent_neigh, 10); + if (err < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to add nd entry(%s %s %s) to kernel", - ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); - return MCLAG_ERROR; + if (err != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to add nd entry(%s %s %s) to kernel, status %d", + ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str, err); + return MCLAG_ERROR; + } } + if (ndisc_entry->flag & NEIGH_SYNC_FLAG_ACK) + { + ICCPD_LOG_DEBUG(__FUNCTION__,"Sync ND on ACK "); + syn_ack_local_neigh_mac_info_to_peer(ndisc_entry->ifname, is_ack_ll); + } } else { - if (iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 0, ndisc_entry->mac_addr, ndisc_entry->ifname) < 0) + err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 0, ndisc_entry->mac_addr, ndisc_entry->ifname, permanent_neigh, 11); + if (err < 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Failed to delete nd entry(%s %s %s) from kernel", - ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); - return MCLAG_ERROR; + if (err != ICCP_NLE_SEQ_MISMATCH) { + ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to delete nd entry(%s %s %s) from kernel status %d", + ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str, err); + return MCLAG_ERROR; + } } - } - /* ICCPD_LOG_DEBUG(__FUNCTION__, "NDISC update for %s %s %s", ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); */ + ICCPD_LOG_DEBUG(__FUNCTION__, "NDISC update for %s %s %s", ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str); } else { - ICCPD_LOG_DEBUG(__FUNCTION__, "Failure: port-channel is not alive"); + ICCPD_LOG_NOTICE(__FUNCTION__, "Failure: port-channel is not alive, ln %d", ln); /* TODO Set static route through peer-link or just skip it? */ + local_vlan_if = local_if_find_by_name(ndisc_entry->ifname); + if (local_vlan_if) { + if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)local_vlan_if->ipv6_addr, 16) == 0) { + ICCPD_LOG_DEBUG(__FUNCTION__, "ignore my ip %s", show_ipv6_str((char *)ndisc_entry->ipv6_addr)); + return 0; + } + } } /* update NDISC list */ @@ -798,6 +1189,8 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) sprintf(ndisc_msg->ifname, "%s", ndisc_entry->ifname); memcpy((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16); ndisc_msg->op_type = ndisc_entry->op_type; + ndisc_msg->flag = 0; + ndisc_msg->learn_flag = NEIGH_REMOTE; memcpy(ndisc_msg->mac_addr, ndisc_entry->mac_addr, ETHER_ADDR_LEN); if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, sizeof(struct NDISCMsg)) == 0) { @@ -868,7 +1261,7 @@ int mlacp_fsm_update_port_channel_info(struct CSM* csm, if (peer_if->po_id != ntohs(tlv->agg_id)) continue; - LIST_FOREACH(peer_vlan_id, &(peer_if->vlan_list), port_next) + RB_FOREACH(peer_vlan_id, vlan_rb_tree, &(peer_if->vlan_tree)) { peer_vlan_id->vlan_removed = 1; } @@ -886,7 +1279,8 @@ int mlacp_fsm_update_port_channel_info(struct CSM* csm, iccp_consistency_check(peer_if->name); - ICCPD_LOG_DEBUG(__FUNCTION__, "Peer intf %s info: ipv4 addr %s l3 mode %d", peer_if->name, show_ip_str( tlv->ipv4_addr), peer_if->l3_mode); + ICCPD_LOG_DEBUG("ICCP_FSM", "RX Peer po_info: %s ipv4 addr %s l3 mode %d", + peer_if->name, show_ip_str( tlv->ipv4_addr), peer_if->l3_mode); break; } @@ -909,10 +1303,10 @@ int mlacp_fsm_update_peerlink_info(struct CSM* csm, } if (csm->peer_link_if->type != tlv->port_type) - ICCPD_LOG_NOTICE(__FUNCTION__, "Peerlink port type of peer %d is not same with local %d !", tlv->port_type, csm->peer_link_if->type); + ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port type of peer %d is not same with local %d !", tlv->port_type, csm->peer_link_if->type); if (tlv->port_type == IF_T_VXLAN && strncmp(csm->peer_itf_name, tlv->if_name, strlen(csm->peer_itf_name))) - ICCPD_LOG_NOTICE(__FUNCTION__, "Peerlink port is vxlan port, but peerlink port of peer %s is not same with local %s !", tlv->if_name, csm->peer_itf_name); + ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port is vxlan port, but peerlink port of peer %s is not same with local %s !", tlv->if_name, csm->peer_itf_name); return 0; } @@ -939,8 +1333,7 @@ int mlacp_fsm_update_warmboot(struct CSM* csm, struct mLACPWarmbootTLV* tlv) return MCLAG_ERROR; time(&csm->peer_warm_reboot_time); - ICCPD_LOG_NOTICE(__FUNCTION__, "Receive warm reboot notification from peer!"); - + ICCPD_LOG_DEBUG("ICCP_FSM", "RX peer warm reboot: start, sync_state %s", + mlacp_state(csm)); return 0; } - diff --git a/src/iccpd/src/openbsd_tree.c b/src/iccpd/src/openbsd_tree.c new file mode 100644 index 000000000000..b9d8202df049 --- /dev/null +++ b/src/iccpd/src/openbsd_tree.c @@ -0,0 +1,618 @@ +/* $OpenBSD: subr_tree.c,v 1.9 2017/06/08 03:30:52 dlg Exp $ */ + +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2016 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include <../include/openbsd_tree.h> + +static inline struct rb_entry *rb_n2e(const struct rb_type *t, void *node) +{ + unsigned long addr = (unsigned long)node; + + return ((struct rb_entry *)(addr + t->t_offset)); +} + +static inline void *rb_e2n(const struct rb_type *t, struct rb_entry *rbe) +{ + unsigned long addr = (unsigned long)rbe; + + return ((void *)(addr - t->t_offset)); +} + +#define RBE_LEFT(_rbe) (_rbe)->rbt_left +#define RBE_RIGHT(_rbe) (_rbe)->rbt_right +#define RBE_PARENT(_rbe) (_rbe)->rbt_parent +#define RBE_COLOR(_rbe) (_rbe)->rbt_color + +#define RBH_ROOT(_rbt) (_rbt)->rbt_root + +static inline void rbe_set(struct rb_entry *rbe, struct rb_entry *parent) +{ + RBE_PARENT(rbe) = parent; + RBE_LEFT(rbe) = RBE_RIGHT(rbe) = NULL; + RBE_COLOR(rbe) = RB_RED; +} + +static inline void rbe_set_blackred(struct rb_entry *black, + struct rb_entry *red) +{ + RBE_COLOR(black) = RB_BLACK; + RBE_COLOR(red) = RB_RED; +} + +static inline void rbe_augment(const struct rb_type *t, struct rb_entry *rbe) +{ + (*t->t_augment)(rb_e2n(t, rbe)); +} + +static inline void rbe_if_augment(const struct rb_type *t, struct rb_entry *rbe) +{ + if (t->t_augment != NULL) + rbe_augment(t, rbe); +} + +static inline void rbe_rotate_left(const struct rb_type *t, + struct rbt_tree *rbt, struct rb_entry *rbe) +{ + struct rb_entry *parent; + struct rb_entry *tmp; + + tmp = RBE_RIGHT(rbe); + RBE_RIGHT(rbe) = RBE_LEFT(tmp); + if (RBE_RIGHT(rbe) != NULL) + RBE_PARENT(RBE_LEFT(tmp)) = rbe; + + parent = RBE_PARENT(rbe); + RBE_PARENT(tmp) = parent; + if (parent != NULL) { + if (rbe == RBE_LEFT(parent)) + RBE_LEFT(parent) = tmp; + else + RBE_RIGHT(parent) = tmp; + } else + RBH_ROOT(rbt) = tmp; + + RBE_LEFT(tmp) = rbe; + RBE_PARENT(rbe) = tmp; + + if (t->t_augment != NULL) { + rbe_augment(t, rbe); + rbe_augment(t, tmp); + parent = RBE_PARENT(tmp); + if (parent != NULL) + rbe_augment(t, parent); + } +} + +static inline void rbe_rotate_right(const struct rb_type *t, + struct rbt_tree *rbt, struct rb_entry *rbe) +{ + struct rb_entry *parent; + struct rb_entry *tmp; + + tmp = RBE_LEFT(rbe); + RBE_LEFT(rbe) = RBE_RIGHT(tmp); + if (RBE_LEFT(rbe) != NULL) + RBE_PARENT(RBE_RIGHT(tmp)) = rbe; + + parent = RBE_PARENT(rbe); + RBE_PARENT(tmp) = parent; + if (parent != NULL) { + if (rbe == RBE_LEFT(parent)) + RBE_LEFT(parent) = tmp; + else + RBE_RIGHT(parent) = tmp; + } else + RBH_ROOT(rbt) = tmp; + + RBE_RIGHT(tmp) = rbe; + RBE_PARENT(rbe) = tmp; + + if (t->t_augment != NULL) { + rbe_augment(t, rbe); + rbe_augment(t, tmp); + parent = RBE_PARENT(tmp); + if (parent != NULL) + rbe_augment(t, parent); + } +} + +static inline void rbe_insert_color(const struct rb_type *t, + struct rbt_tree *rbt, struct rb_entry *rbe) +{ + struct rb_entry *parent, *gparent, *tmp; + + while ((parent = RBE_PARENT(rbe)) != NULL + && RBE_COLOR(parent) == RB_RED) { + gparent = RBE_PARENT(parent); + + if (parent == RBE_LEFT(gparent)) { + tmp = RBE_RIGHT(gparent); + if (tmp != NULL && RBE_COLOR(tmp) == RB_RED) { + RBE_COLOR(tmp) = RB_BLACK; + rbe_set_blackred(parent, gparent); + rbe = gparent; + continue; + } + + if (RBE_RIGHT(parent) == rbe) { + rbe_rotate_left(t, rbt, parent); + tmp = parent; + parent = rbe; + rbe = tmp; + } + + rbe_set_blackred(parent, gparent); + rbe_rotate_right(t, rbt, gparent); + } else { + tmp = RBE_LEFT(gparent); + if (tmp != NULL && RBE_COLOR(tmp) == RB_RED) { + RBE_COLOR(tmp) = RB_BLACK; + rbe_set_blackred(parent, gparent); + rbe = gparent; + continue; + } + + if (RBE_LEFT(parent) == rbe) { + rbe_rotate_right(t, rbt, parent); + tmp = parent; + parent = rbe; + rbe = tmp; + } + + rbe_set_blackred(parent, gparent); + rbe_rotate_left(t, rbt, gparent); + } + } + + RBE_COLOR(RBH_ROOT(rbt)) = RB_BLACK; +} + +static inline void rbe_remove_color(const struct rb_type *t, + struct rbt_tree *rbt, + struct rb_entry *parent, + struct rb_entry *rbe) +{ + struct rb_entry *tmp; + + while ((rbe == NULL || RBE_COLOR(rbe) == RB_BLACK) + && rbe != RBH_ROOT(rbt) && parent) { + if (RBE_LEFT(parent) == rbe) { + tmp = RBE_RIGHT(parent); + if (RBE_COLOR(tmp) == RB_RED) { + rbe_set_blackred(tmp, parent); + rbe_rotate_left(t, rbt, parent); + tmp = RBE_RIGHT(parent); + } + if ((RBE_LEFT(tmp) == NULL + || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK) + && (RBE_RIGHT(tmp) == NULL + || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK)) { + RBE_COLOR(tmp) = RB_RED; + rbe = parent; + parent = RBE_PARENT(rbe); + } else { + if (RBE_RIGHT(tmp) == NULL + || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK) { + struct rb_entry *oleft; + + oleft = RBE_LEFT(tmp); + if (oleft != NULL) + RBE_COLOR(oleft) = RB_BLACK; + + RBE_COLOR(tmp) = RB_RED; + rbe_rotate_right(t, rbt, tmp); + tmp = RBE_RIGHT(parent); + } + + RBE_COLOR(tmp) = RBE_COLOR(parent); + RBE_COLOR(parent) = RB_BLACK; + if (RBE_RIGHT(tmp)) + RBE_COLOR(RBE_RIGHT(tmp)) = RB_BLACK; + + rbe_rotate_left(t, rbt, parent); + rbe = RBH_ROOT(rbt); + break; + } + } else { + tmp = RBE_LEFT(parent); + if (RBE_COLOR(tmp) == RB_RED) { + rbe_set_blackred(tmp, parent); + rbe_rotate_right(t, rbt, parent); + tmp = RBE_LEFT(parent); + } + + if ((RBE_LEFT(tmp) == NULL + || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK) + && (RBE_RIGHT(tmp) == NULL + || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK)) { + RBE_COLOR(tmp) = RB_RED; + rbe = parent; + parent = RBE_PARENT(rbe); + } else { + if (RBE_LEFT(tmp) == NULL + || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK) { + struct rb_entry *oright; + + oright = RBE_RIGHT(tmp); + if (oright != NULL) + RBE_COLOR(oright) = RB_BLACK; + + RBE_COLOR(tmp) = RB_RED; + rbe_rotate_left(t, rbt, tmp); + tmp = RBE_LEFT(parent); + } + + RBE_COLOR(tmp) = RBE_COLOR(parent); + RBE_COLOR(parent) = RB_BLACK; + if (RBE_LEFT(tmp) != NULL) + RBE_COLOR(RBE_LEFT(tmp)) = RB_BLACK; + + rbe_rotate_right(t, rbt, parent); + rbe = RBH_ROOT(rbt); + break; + } + } + } + + if (rbe != NULL) + RBE_COLOR(rbe) = RB_BLACK; +} + +static inline struct rb_entry * +rbe_remove(const struct rb_type *t, struct rbt_tree *rbt, struct rb_entry *rbe) +{ + struct rb_entry *child, *parent, *old = rbe; + unsigned int color; + + if (RBE_LEFT(rbe) == NULL) + child = RBE_RIGHT(rbe); + else if (RBE_RIGHT(rbe) == NULL) + child = RBE_LEFT(rbe); + else { + struct rb_entry *tmp; + + rbe = RBE_RIGHT(rbe); + while ((tmp = RBE_LEFT(rbe)) != NULL) + rbe = tmp; + + child = RBE_RIGHT(rbe); + parent = RBE_PARENT(rbe); + color = RBE_COLOR(rbe); + if (child != NULL) + RBE_PARENT(child) = parent; + if (parent != NULL) { + if (RBE_LEFT(parent) == rbe) + RBE_LEFT(parent) = child; + else + RBE_RIGHT(parent) = child; + + rbe_if_augment(t, parent); + } else + RBH_ROOT(rbt) = child; + if (RBE_PARENT(rbe) == old) + parent = rbe; + *rbe = *old; + + tmp = RBE_PARENT(old); + if (tmp != NULL) { + if (RBE_LEFT(tmp) == old) + RBE_LEFT(tmp) = rbe; + else + RBE_RIGHT(tmp) = rbe; + + rbe_if_augment(t, tmp); + } else + RBH_ROOT(rbt) = rbe; + + RBE_PARENT(RBE_LEFT(old)) = rbe; + if (RBE_RIGHT(old)) + RBE_PARENT(RBE_RIGHT(old)) = rbe; + + if (t->t_augment != NULL && parent != NULL) { + tmp = parent; + do { + rbe_augment(t, tmp); + tmp = RBE_PARENT(tmp); + } while (tmp != NULL); + } + + goto color; + } + + parent = RBE_PARENT(rbe); + color = RBE_COLOR(rbe); + + if (child != NULL) + RBE_PARENT(child) = parent; + if (parent != NULL) { + if (RBE_LEFT(parent) == rbe) + RBE_LEFT(parent) = child; + else + RBE_RIGHT(parent) = child; + + rbe_if_augment(t, parent); + } else + RBH_ROOT(rbt) = child; +color: + if (color == RB_BLACK) + rbe_remove_color(t, rbt, parent, child); + + return (old); +} + +void *_rb_remove(const struct rb_type *t, struct rbt_tree *rbt, void *elm) +{ + struct rb_entry *rbe = rb_n2e(t, elm); + struct rb_entry *old; + + old = rbe_remove(t, rbt, rbe); + + return (old == NULL ? NULL : rb_e2n(t, old)); +} + +void *_rb_insert(const struct rb_type *t, struct rbt_tree *rbt, void *elm) +{ + struct rb_entry *rbe = rb_n2e(t, elm); + struct rb_entry *tmp; + struct rb_entry *parent = NULL; + void *node; + int comp = 0; + + tmp = RBH_ROOT(rbt); + while (tmp != NULL) { + parent = tmp; + + node = rb_e2n(t, tmp); + comp = (*t->t_compare)(elm, node); + if (comp < 0) + tmp = RBE_LEFT(tmp); + else if (comp > 0) + tmp = RBE_RIGHT(tmp); + else + return (node); + } + + rbe_set(rbe, parent); + + if (parent != NULL) { + if (comp < 0) + RBE_LEFT(parent) = rbe; + else + RBE_RIGHT(parent) = rbe; + + rbe_if_augment(t, parent); + } else + RBH_ROOT(rbt) = rbe; + + rbe_insert_color(t, rbt, rbe); + + return (NULL); +} + +/* Finds the node with the same key as elm */ +void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key) +{ + struct rb_entry *tmp = RBH_ROOT(rbt); + void *node; + int comp; + + while (tmp != NULL) { + node = rb_e2n(t, tmp); + comp = (*t->t_compare)(key, node); + if (comp < 0) + tmp = RBE_LEFT(tmp); + else if (comp > 0) + tmp = RBE_RIGHT(tmp); + else + return (node); + } + + return (NULL); +} + +/* Finds the first node greater than or equal to the search key */ +void *_rb_nfind(const struct rb_type *t, struct rbt_tree *rbt, const void *key) +{ + struct rb_entry *tmp = RBH_ROOT(rbt); + void *node; + void *res = NULL; + int comp; + + while (tmp != NULL) { + node = rb_e2n(t, tmp); + comp = (*t->t_compare)(key, node); + if (comp < 0) { + res = node; + tmp = RBE_LEFT(tmp); + } else if (comp > 0) + tmp = RBE_RIGHT(tmp); + else + return (node); + } + + return (res); +} + +void *_rb_next(const struct rb_type *t, void *elm) +{ + struct rb_entry *rbe = rb_n2e(t, elm); + + if (RBE_RIGHT(rbe) != NULL) { + rbe = RBE_RIGHT(rbe); + while (RBE_LEFT(rbe) != NULL) + rbe = RBE_LEFT(rbe); + } else { + if (RBE_PARENT(rbe) && (rbe == RBE_LEFT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + else { + while (RBE_PARENT(rbe) + && (rbe == RBE_RIGHT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + rbe = RBE_PARENT(rbe); + } + } + + return (rbe == NULL ? NULL : rb_e2n(t, rbe)); +} + +void *_rb_prev(const struct rb_type *t, void *elm) +{ + struct rb_entry *rbe = rb_n2e(t, elm); + + if (RBE_LEFT(rbe)) { + rbe = RBE_LEFT(rbe); + while (RBE_RIGHT(rbe)) + rbe = RBE_RIGHT(rbe); + } else { + if (RBE_PARENT(rbe) && (rbe == RBE_RIGHT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + else { + while (RBE_PARENT(rbe) + && (rbe == RBE_LEFT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + rbe = RBE_PARENT(rbe); + } + } + + return (rbe == NULL ? NULL : rb_e2n(t, rbe)); +} + +void *_rb_root(const struct rb_type *t, struct rbt_tree *rbt) +{ + struct rb_entry *rbe = RBH_ROOT(rbt); + + return (rbe == NULL ? rbe : rb_e2n(t, rbe)); +} + +void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt) +{ + struct rb_entry *rbe = RBH_ROOT(rbt); + struct rb_entry *parent = NULL; + + while (rbe != NULL) { + parent = rbe; + rbe = RBE_LEFT(rbe); + } + + return (parent == NULL ? NULL : rb_e2n(t, parent)); +} + +void *_rb_max(const struct rb_type *t, struct rbt_tree *rbt) +{ + struct rb_entry *rbe = RBH_ROOT(rbt); + struct rb_entry *parent = NULL; + + while (rbe != NULL) { + parent = rbe; + rbe = RBE_RIGHT(rbe); + } + + return (parent == NULL ? NULL : rb_e2n(t, parent)); +} + +void *_rb_left(const struct rb_type *t, void *node) +{ + struct rb_entry *rbe = rb_n2e(t, node); + rbe = RBE_LEFT(rbe); + return (rbe == NULL ? NULL : rb_e2n(t, rbe)); +} + +void *_rb_right(const struct rb_type *t, void *node) +{ + struct rb_entry *rbe = rb_n2e(t, node); + rbe = RBE_RIGHT(rbe); + return (rbe == NULL ? NULL : rb_e2n(t, rbe)); +} + +void *_rb_parent(const struct rb_type *t, void *node) +{ + struct rb_entry *rbe = rb_n2e(t, node); + rbe = RBE_PARENT(rbe); + return (rbe == NULL ? NULL : rb_e2n(t, rbe)); +} + +void _rb_set_left(const struct rb_type *t, void *node, void *left) +{ + struct rb_entry *rbe = rb_n2e(t, node); + struct rb_entry *rbl = (left == NULL) ? NULL : rb_n2e(t, left); + + RBE_LEFT(rbe) = rbl; +} + +void _rb_set_right(const struct rb_type *t, void *node, void *right) +{ + struct rb_entry *rbe = rb_n2e(t, node); + struct rb_entry *rbr = (right == NULL) ? NULL : rb_n2e(t, right); + + RBE_RIGHT(rbe) = rbr; +} + +void _rb_set_parent(const struct rb_type *t, void *node, void *parent) +{ + struct rb_entry *rbe = rb_n2e(t, node); + struct rb_entry *rbp = (parent == NULL) ? NULL : rb_n2e(t, parent); + + RBE_PARENT(rbe) = rbp; +} + +void _rb_poison(const struct rb_type *t, void *node, unsigned long poison) +{ + struct rb_entry *rbe = rb_n2e(t, node); + + RBE_PARENT(rbe) = RBE_LEFT(rbe) = RBE_RIGHT(rbe) = + (struct rb_entry *)poison; +} + +int _rb_check(const struct rb_type *t, void *node, unsigned long poison) +{ + struct rb_entry *rbe = rb_n2e(t, node); + + return ((unsigned long)RBE_PARENT(rbe) == poison + && (unsigned long)RBE_LEFT(rbe) == poison + && (unsigned long)RBE_RIGHT(rbe) == poison); +} diff --git a/src/iccpd/src/port.c b/src/iccpd/src/port.c index e63429a77c2e..7e233a7c20bd 100644 --- a/src/iccpd/src/port.c +++ b/src/iccpd/src/port.c @@ -28,8 +28,23 @@ #include "../include/port.h" #include "../include/system.h" #include "../include/iccp_csm.h" -#include "../include/iccp_netlink.h" +#include "../include/mlacp_link_handler.h" #include "../include/scheduler.h" +#include "../include/iccp_netlink.h" +#include "../include/iccp_ifm.h" + + +static int vlan_node_compare(const struct VLAN_ID *p_vlan_node1, const struct VLAN_ID *p_vlan_node2) +{ + if (p_vlan_node1->vid < p_vlan_node2->vid) + return -1; + + if (p_vlan_node1->vid > p_vlan_node2->vid) + return 1; + + return 0; +} +RB_GENERATE(vlan_rb_tree, VLAN_ID, vlan_entry, vlan_node_compare); void local_if_init(struct LocalInterface* local_if) { @@ -46,11 +61,14 @@ void local_if_init(struct LocalInterface* local_if) local_if->is_peer_link = 0; local_if->is_arp_accept = 0; local_if->l3_mode = 0; + local_if->master_ifindex = 0; local_if->state = PORT_STATE_DOWN; local_if->prefixlen = 32; local_if->csm = NULL; local_if->isolate_to_peer_link = 0; - LIST_INIT(&local_if->vlan_list); + local_if->is_l3_proto_enabled = false; + local_if->vlan_count = 0; + RB_INIT(vlan_rb_tree, &local_if->vlan_tree); return; } @@ -64,7 +82,7 @@ void vlan_info_init(struct VLAN_ID* vlan) return; } -struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) +struct LocalInterface* local_if_create(int ifindex, char* ifname, int type, uint8_t state) { struct System* sys = NULL; struct LocalInterface* local_if = NULL; @@ -77,11 +95,10 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) if (!(sys = system_get_instance())) return NULL; - if (ifindex < 0) - return NULL; - - if ((local_if = local_if_find_by_ifindex(ifindex))) - return local_if; + if (ifindex > 0) { + if ((local_if = local_if_find_by_ifindex(ifindex))) + return local_if; + } if (!(local_if = (struct LocalInterface*)malloc(sizeof(struct LocalInterface)))) { @@ -91,7 +108,10 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) local_if_init(local_if); local_if->ifindex = ifindex; - local_if->type = type; + local_if->type = type; + local_if->state = state; + + local_if->po_down_time = 0; if (local_if->type == IF_T_PORT_CHANNEL) { @@ -107,6 +127,7 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) return NULL; local_if->po_id = atoi(&ifname[i]); + local_if->po_active = (state == PORT_STATE_UP) ? 1 : 0; } if (ifname) @@ -121,7 +142,10 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) break; case IF_T_VLAN: - /* do nothing currently. */ + if(is_unique_ip_configured(local_if->name)) + { + local_if->is_l3_proto_enabled = true; + } break; case IF_T_VXLAN: @@ -142,6 +166,9 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) LIST_INSERT_HEAD(&(sys->lif_list), local_if, system_next); + //if there is pending vlan membership for this interface move to system lif + move_pending_vlan_mbr_to_lif(sys, local_if); + /*Check the intf is peer-link? Only support PortChannel and Ethernet currently*/ /*When set peer-link, the local-if is probably not created*/ LIST_FOREACH(csm, &(sys->csm_list), next) @@ -150,6 +177,7 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) { local_if->is_peer_link = 1; csm->peer_link_if = local_if; + set_peerlink_learn_kernel(csm, 0, 3); break; } /*check the intf is bind with csm*/ @@ -217,24 +245,40 @@ struct LocalInterface* local_if_find_by_po_id(int po_id) return NULL; } -static void local_if_vlan_remove(struct LocalInterface *lif_vlan) + void local_if_vlan_remove(struct LocalInterface *lif_vlan) { struct System *sys = NULL; struct LocalInterface *lif = NULL; struct VLAN_ID *vlan = NULL; + int vid = 0; + struct VLAN_ID vlan_key = { 0 }; + + if (!lif_vlan || lif_vlan->type != IF_T_VLAN) + { + return; + } + + sscanf(lif_vlan->name, "Vlan%d", &vid); + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + if ((sys = system_get_instance()) != NULL) { LIST_FOREACH(lif, &(sys->lif_list), system_next) { - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) + if (lif->type == IF_T_VLAN) + continue; + + //delink this vlan (lif_vlan) interface from all associated lifs + //in scenario where vlan membership delete comes later when compared + //to vlan interface delete from kernel + vlan = RB_FIND(vlan_rb_tree, &(lif->vlan_tree), &vlan_key); + if (vlan) { - if (lif_vlan != vlan->vlan_itf) - continue; - vlan->vlan_itf = NULL; } - } + } } return; @@ -279,6 +323,7 @@ void local_if_destroy(char *ifname) { struct LocalInterface* lif = NULL; struct CSM *csm = NULL; + struct CSM *peer_ifname_csm = NULL; struct System *sys = NULL; if (!(sys = system_get_instance())) @@ -297,21 +342,27 @@ void local_if_destroy(char *ifname) else local_if_remove(lif); - csm = lif->csm; - if (csm && csm->peer_link_if && strcmp(csm->peer_link_if->name, ifname) == 0) + //handle peer_link del case + if ( (peer_ifname_csm = system_get_csm_by_peer_ifname(ifname)) != NULL ) { /*if the peerlink interface is not created, peer connection can not establish*/ - scheduler_session_disconnect_handler(csm); + scheduler_session_disconnect_handler(peer_ifname_csm); + + // The function above calls iccp_csm_status_reset, which sets csm->Peer_link_if to NULL, + // accessing the peer_link_if cause crash due to null pointer access. +#if 0 csm->peer_link_if->is_peer_link = 0; csm->peer_link_if = NULL; +#endif } + csm = lif->csm; if (csm && MLACP(csm).current_state == MLACP_STATE_EXCHANGE) goto to_mlacp_purge; else goto to_sys_purge; - to_sys_purge: +to_sys_purge: /* sys purge */ LIST_REMOVE(lif, system_next); if (lif->csm) @@ -319,7 +370,7 @@ void local_if_destroy(char *ifname) LIST_INSERT_HEAD(&(sys->lif_purge_list), lif, system_purge_next); return; - to_mlacp_purge: +to_mlacp_purge: /* sys & mlacp purge */ LIST_REMOVE(lif, system_next); LIST_REMOVE(lif, mlacp_next); @@ -336,8 +387,11 @@ int local_if_is_l3_mode(struct LocalInterface* local_if) if (local_if == NULL) return 0; - if (local_if->ipv4_addr != 0 || memcmp(local_if->ipv6_addr, addr_null, 16) != 0) + if ((local_if->ipv4_addr != 0) + || (memcmp(local_if->ipv6_addr, addr_null, 16) != 0) + || (local_if->master_ifindex != 0)) { ret = 1; + } return ret; } @@ -361,6 +415,25 @@ void local_if_change_flag_clear(void) return; } + +static void local_if_mlacp_purge_del(struct LocalInterface* lif) +{ + struct CSM* csm; + struct LocalInterface *lif_purge; + + if (lif && lif->csm) + { + LIST_FOREACH(lif_purge, &(MLACP(lif->csm).lif_purge_list), mlacp_purge_next) + { + if (lif_purge == lif) + { + LIST_REMOVE(lif, mlacp_purge_next); + break; + } + } + } +} + void local_if_purge_clear(void) { struct System* sys = NULL; @@ -375,8 +448,7 @@ void local_if_purge_clear(void) lif = LIST_FIRST(&(sys->lif_purge_list)); ICCPD_LOG_DEBUG(__FUNCTION__, "Purge %s", lif->name); LIST_REMOVE(lif, system_purge_next); - if (lif->mlacp_purge_next.le_next != 0 && lif->mlacp_purge_next.le_prev != 0) - LIST_REMOVE(lif, mlacp_purge_next); + local_if_mlacp_purge_del(lif); local_if_del_all_vlan(lif); free(lif); } @@ -470,17 +542,15 @@ struct PeerInterface* peer_if_find_by_name(struct CSM* csm, char* name) void peer_if_del_all_vlan(struct PeerInterface* pif) { - struct VLAN_ID *pvlan = NULL; + struct VLAN_ID *vlan = NULL; + struct VLAN_ID* vlan_temp = NULL; - while (!LIST_EMPTY(&(pif->vlan_list))) + ICCPD_LOG_NOTICE(__FUNCTION__, "Remove all VLANs from peer intf %s", pif->name); + RB_FOREACH_SAFE(vlan, vlan_rb_tree, &(pif->vlan_tree), vlan_temp) { - pvlan = LIST_FIRST(&(pif->vlan_list)); - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove peer intf %s from VLAN %d", - pif->name, pvlan->vid); - LIST_REMOVE(pvlan, port_next); - free(pvlan); + VLAN_RB_REMOVE(vlan_rb_tree, &(pif->vlan_tree), vlan); + free(vlan); } - return; } @@ -497,73 +567,86 @@ void peer_if_destroy(struct PeerInterface* pif) return; } -int local_if_add_vlan(struct LocalInterface* local_if, uint16_t vid) +int local_if_add_vlan(struct LocalInterface* local_if, uint16_t vid) { struct VLAN_ID *vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; char vlan_name[16] = ""; sprintf(vlan_name, "Vlan%d", vid); - /* traverse 1 time */ - LIST_FOREACH(vlan, &(local_if->vlan_list), port_next) - { - if (vlan->vid == vid) - break; - } + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + vlan = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), &vlan_key); + if (!vlan) { vlan = (struct VLAN_ID*)malloc(sizeof(struct VLAN_ID)); if (!vlan) return MCLAG_ERROR; - ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s to VLAN %d", local_if->name, vid); + vlan_info_init(vlan); + vlan->vid = vid; + vlan->vlan_itf = local_if_find_by_name(vlan_name); + + if (vlan->vlan_itf == NULL) { + ICCPD_LOG_DEBUG(__FUNCTION__, "vlan_itf %s not present", vlan_name); + } + local_if->vlan_count +=1; + ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s to VLAN %d vlan count %d", local_if->name, vid, local_if->vlan_count); local_if->port_config_sync = 1; - LIST_INSERT_HEAD(&(local_if->vlan_list), vlan, port_next); + RB_INSERT(vlan_rb_tree, &(local_if->vlan_tree), vlan); } - vlan_info_init(vlan); - vlan->vid = vid; vlan->vlan_removed = 0; - vlan->vlan_itf = local_if_find_by_name(vlan_name); - - update_if_ipmac_on_standby(local_if); +// update_if_ipmac_on_standby(local_if, 5); + if (vlan->vlan_itf) + { + if (local_if->is_peer_link) + { + update_vlan_if_mac_on_standby(vlan->vlan_itf, 1); + } + } + else + { + ICCPD_LOG_WARN(__FUNCTION__, "skip VLAN MAC update for vlan %d interface %s ", vid, local_if->name); + } return 0; } void local_if_del_vlan(struct LocalInterface* local_if, uint16_t vid) { struct VLAN_ID *vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; - /* traverse 1 time */ - LIST_FOREACH(vlan, &(local_if->vlan_list), port_next) - { - if (vlan->vid == vid) - break; - } + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vid; + vlan = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), &vlan_key); + if (vlan != NULL) { - LIST_REMOVE(vlan, port_next); + VLAN_RB_REMOVE(vlan_rb_tree, &(local_if->vlan_tree), vlan); free(vlan); local_if->port_config_sync = 1; + local_if->vlan_count -=1; + ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d, count %d", local_if->name, vid, local_if->vlan_count); } - - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", local_if->name, vid); - return; } void local_if_del_all_vlan(struct LocalInterface* lif) { struct VLAN_ID* vlan = NULL; + struct VLAN_ID* vlan_temp = NULL; - while (!LIST_EMPTY(&(lif->vlan_list))) + ICCPD_LOG_NOTICE(__FUNCTION__, "Remove all VLANs from %s", lif->name); + RB_FOREACH_SAFE(vlan, vlan_rb_tree, &(lif->vlan_tree), vlan_temp) { - vlan = LIST_FIRST(&(lif->vlan_list)); - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", lif->name, vlan->vid); - LIST_REMOVE(vlan, port_next); + VLAN_RB_REMOVE(vlan_rb_tree, &(lif->vlan_tree), vlan); + lif->vlan_count -=1; free(vlan); } @@ -574,34 +657,30 @@ void local_if_del_all_vlan(struct LocalInterface* lif) int peer_if_add_vlan(struct PeerInterface* peer_if, uint16_t vlan_id) { struct VLAN_ID *peer_vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; char vlan_name[16] = ""; sprintf(vlan_name, "Vlan%d", vlan_id); - /* traverse 1 time */ - LIST_FOREACH(peer_vlan, &(peer_if->vlan_list), port_next) - { - if (peer_vlan->vid == vlan_id) - { - ICCPD_LOG_DEBUG(__FUNCTION__, "Update VLAN ID %d for peer intf %s", peer_vlan->vid, peer_if->name); - break; - } - } + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = vlan_id; + peer_vlan = RB_FIND(vlan_rb_tree, &(peer_if->vlan_tree), &vlan_key); + if (!peer_vlan) { peer_vlan = (struct VLAN_ID*)malloc(sizeof(struct VLAN_ID)); if (!peer_vlan) return MCLAG_ERROR; - ICCPD_LOG_DEBUG(__FUNCTION__, "Add peer intf %s to VLAN %d", peer_if->name, vlan_id); - LIST_INSERT_HEAD(&(peer_if->vlan_list), peer_vlan, port_next); + vlan_info_init(peer_vlan); + peer_vlan->vid = vlan_id; + + ICCPD_LOG_DEBUG(__FUNCTION__, "add VLAN ID = %d from peer's %s", vlan_id, peer_if->name); + RB_INSERT(vlan_rb_tree, &(peer_if->vlan_tree), peer_vlan); } - vlan_info_init(peer_vlan); - peer_vlan->vid = vlan_id; peer_vlan->vlan_removed = 0; - return 0; } @@ -610,14 +689,15 @@ int peer_if_clean_unused_vlan(struct PeerInterface* peer_if) { struct VLAN_ID *peer_vlan = NULL; struct VLAN_ID *peer_vlan_next = NULL; + struct VLAN_ID *vlan_temp = NULL; /* traverse 1 time */ - LIST_FOREACH(peer_vlan_next, &(peer_if->vlan_list), port_next) + RB_FOREACH_SAFE(peer_vlan_next, vlan_rb_tree, &(peer_if->vlan_tree), vlan_temp) { if (peer_vlan != NULL) { ICCPD_LOG_DEBUG(__FUNCTION__, "Remove peer intf %s from VLAN %d", peer_if->name, peer_vlan->vid); - LIST_REMOVE(peer_vlan, port_next); + VLAN_RB_REMOVE(vlan_rb_tree, &(peer_if->vlan_tree), peer_vlan); free(peer_vlan); peer_vlan = NULL; @@ -629,7 +709,7 @@ int peer_if_clean_unused_vlan(struct PeerInterface* peer_if) if (peer_vlan != NULL) { ICCPD_LOG_DEBUG(__FUNCTION__, "Remove peer intf %s from VLAN %d", peer_if->name, peer_vlan->vid); - LIST_REMOVE(peer_vlan, port_next); + VLAN_RB_REMOVE(vlan_rb_tree, &(peer_if->vlan_tree), peer_vlan); free(peer_vlan); } @@ -660,9 +740,32 @@ int set_sys_arp_accept_flag(char* ifname, int flag) memset(cmd, 0, 64); snprintf(cmd, 63, "echo %d > /proc/sys/net/ipv4/conf/%s/arp_accept", flag, ifname); if (system(cmd)) - ICCPD_LOG_WARN(__func__, "Failed to execute cmd = %s", flag, cmd); + ICCPD_LOG_WARN(__func__, "Failed to execute cmd = %s", cmd); } fclose(file_ptr); return result; } + +int local_if_l3_proto_enabled(const char* ifname) +{ + struct System* sys = NULL; + struct LocalInterface* local_if = NULL; + + if (!ifname) + return 0; + + if (!(sys = system_get_instance())) + return 0; + + LIST_FOREACH(local_if, &(sys->lif_list), system_next) + { + if (strcmp(local_if->name, ifname) == 0) + { + if (local_if->is_l3_proto_enabled) + return 1; + } + } + + return 0; +} diff --git a/src/iccpd/src/scheduler.c b/src/iccpd/src/scheduler.c index 0ff9d4f5e083..865f79b0da6b 100644 --- a/src/iccpd/src/scheduler.c +++ b/src/iccpd/src/scheduler.c @@ -48,6 +48,14 @@ * ******************************************************/ +//this needs to be fine tuned +#define PEER_SOCK_SND_BUF_LEN (6 * 1024 * 1024) +#define PEER_SOCK_RCV_BUF_LEN (6 * 1024 * 1024) +#define RECV_RETRY_INTERVAL_USEC 100000 +#define RECV_RETRY_MAX 10 + +extern int mlacp_prepare_for_warm_reboot(struct CSM* csm, char* buf, size_t max_buf_size); + static int session_conn_thread_lock(pthread_mutex_t *conn_mutex) { return 1; /*pthread_mutex_lock(conn_mutex);*/ @@ -71,10 +79,10 @@ static void heartbeat_check(struct CSM *csm) return; } - if ( (time(NULL) - csm->heartbeat_update_time) > HEARTBEAT_TIMEOUT_SEC) + if ( (time(NULL) - csm->heartbeat_update_time) > csm->session_timeout) { /* hearbeat timeout*/ - ICCPD_LOG_WARN(__FUNCTION__, "iccpd connection timeout (heartbeat)"); + ICCPD_LOG_WARN("ICCP_FSM", "iccpd connection timeout (heartbeat)"); scheduler_session_disconnect_handler(csm); } @@ -106,15 +114,13 @@ static int scheduler_transit_fsm() iccp_csm_transit(csm); app_csm_transit(csm); mlacp_fsm_transit(csm); - - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && (time(NULL) - sys->csm_trans_time) >= 60) - { - iccp_get_fdb_change_from_syncd(); - sys->csm_trans_time = time(NULL); - } } - local_if_change_flag_clear(); + //lif->changed flag is marked for state change for lif, for active node when + //it is in STAGE2 where it receiving cfg sync from peer if there is any po + //state change that change is not sent and this clear clears the marking and + //thus remote state is not updated; so commenting this out + //local_if_change_flag_clear(); local_if_purge_clear(); return 1; @@ -131,6 +137,9 @@ int scheduler_csm_read_callback(struct CSM* csm) size_t data_len = 0; size_t pos = 0; int recv_len = 0, len = 0, retval; + int num_retry = 0; + int total_retry_time = 0; + int total_data_len = 0; if (csm->sock_fd <= 0) return MCLAG_ERROR; @@ -138,6 +147,7 @@ int scheduler_csm_read_callback(struct CSM* csm) memset(peer_msg, 0, CSM_BUFFER_SIZE); recv_len = 0; + errno = 0; while (recv_len != sizeof(LDPHdr)) { @@ -145,38 +155,92 @@ int scheduler_csm_read_callback(struct CSM* csm) if (len == -1) { perror("recv(). Error"); + ICCPD_LOG_WARN("ICCP_FSM", "Peer disconnect for header read error[%s] len = -1 till now received len = %d ", strerror(errno), recv_len); + SYSTEM_INCR_HDR_READ_SOCK_ERR_COUNTER(system_get_instance()); goto recv_err; } else if (len == 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Peer disconnect for receive error"); + ICCPD_LOG_WARN("ICCP_FSM", "Peer disconnect for header read error[%s] len = 0, till now received len = %d ",strerror(errno), recv_len); + SYSTEM_INCR_HDR_READ_SOCK_ZERO_LEN_COUNTER(system_get_instance()); goto recv_err; } recv_len += len; /*usleep(100);*/ } - data_len = ntohs(ldp_hdr->msg_len) - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS; + if (ntohs(ldp_hdr->msg_len) >= MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS) + { + data_len = ntohs(ldp_hdr->msg_len) - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS; + } + else + { + ICCPD_LOG_ERR("ICCP_FSM", "Peer disconnect for invalid data error; length[%d] msg_type[0x%x] ", ntohs(ldp_hdr->msg_len), ntohs(ldp_hdr->msg_type)); + SYSTEM_INCR_INVALID_PEER_MSG_COUNTER(system_get_instance()); + goto recv_err; + } + total_data_len = data_len; pos = 0; while (data_len > 0) { - recv_len = recv(csm->sock_fd, &data[pos], data_len, 0); + /* When consecutive CCP session flaps happen, recv() call got stuck. + * Change recv() to non-blocking with retry mechanism. If max + * retry reaches, attempt one more retry after waiting for one KA + * interval before bringing down the session. + */ + recv_len = recv(csm->sock_fd, &data[pos], data_len, MSG_DONTWAIT); if (recv_len == -1) { - perror("continue recv(). Error"); - goto recv_err; + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + ICCPD_LOG_NOTICE( + "ICCP_FSM", "Non-blocking recv total/pending len %d/%d, errno %d, num_retry %d", + total_data_len, data_len, errno, num_retry); + ++num_retry; + if (num_retry > RECV_RETRY_MAX) + { + ICCPD_LOG_ERR( + "ICCP_FSM", "Non-blocking recv() retry failed, total/pending len %d/%d", + total_data_len, data_len); + SYSTEM_INCR_RX_RETRY_FAIL_COUNTER(system_get_instance()); + goto recv_err; + } + else + { + if (num_retry == RECV_RETRY_MAX) + usleep((csm->session_timeout * 1000000) - total_retry_time); + else + { + total_retry_time += (num_retry * RECV_RETRY_INTERVAL_USEC); + usleep(num_retry * RECV_RETRY_INTERVAL_USEC); + } + recv_len = 0; + } + } + else + { + perror("continue recv() Error"); + ICCPD_LOG_WARN("ICCP_FSM", "Peer data read error; recv_len:%d data_len:%d, errno %d", + recv_len, data_len, errno); + SYSTEM_INCR_TLV_READ_SOCK_ERR_COUNTER(system_get_instance()); + goto recv_err; + } } else if (recv_len == 0) { - ICCPD_LOG_WARN(__FUNCTION__, "Peer disconnect for read error"); + ICCPD_LOG_WARN("ICCP_FSM", "Peer disconnect for data read error; recv_len:%d data_len:%d ", recv_len, data_len); + SYSTEM_INCR_TLV_READ_SOCK_ZERO_LEN_COUNTER(system_get_instance()); goto recv_err; } data_len -= recv_len; pos += recv_len; /*usleep(100);*/ } - + if (num_retry > 0) + { + SYSTEM_SET_RETRY_COUNTER(system_get_instance(), num_retry); + } retval = iccp_csm_init_msg(&msg, peer_msg, ntohs(ldp_hdr->msg_len) + MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS); if (retval == 0) { @@ -224,21 +288,21 @@ int scheduler_server_accept() if (!csm) { /* can't find csm with peer ip*/ - ICCPD_LOG_INFO(__FUNCTION__, "csm null with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); + ICCPD_LOG_NOTICE("ICCP_FSM", "csm null with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); goto reject_client; } if (csm->sock_fd > 0) { /* peer already connected*/ - ICCPD_LOG_INFO(__FUNCTION__, "csm sock is connected with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); + ICCPD_LOG_NOTICE("ICCP_FSM", "csm sock is connected with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); goto reject_client; } if ((ret = scheduler_check_csm_config(csm)) < 0) { /* csm config error*/ - ICCPD_LOG_INFO(__FUNCTION__, "csm config error with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); + ICCPD_LOG_NOTICE("ICCP_FSM", "csm config error with peer ip [%s]", inet_ntoa(client_addr.sin_addr)); goto reject_client; } } @@ -257,6 +321,8 @@ int scheduler_server_accept() struct epoll_event event; int err; + int send_buf_len = PEER_SOCK_SND_BUF_LEN; + int recv_buf_len = PEER_SOCK_RCV_BUF_LEN; event.data.fd = new_fd; event.events = EPOLLIN; err = epoll_ctl(sys->epoll_fd, EPOLL_CTL_ADD, new_fd, &event); @@ -267,6 +333,14 @@ int scheduler_server_accept() } csm->sock_fd = new_fd; + if (setsockopt(csm->sock_fd, SOL_SOCKET, SO_SNDBUF, &send_buf_len, sizeof(send_buf_len)) == -1) + { + ICCPD_LOG_ERR(__FUNCTION__, "Set socket send buf option failed. Error"); + } + if (setsockopt(csm->sock_fd, SOL_SOCKET, SO_RCVBUF, &recv_buf_len, sizeof(recv_buf_len)) == -1) + { + ICCPD_LOG_ERR(__FUNCTION__, "Set socket recv buf option failed. Error"); + } csm->current_state = ICCP_NONEXISTENT; FD_SET(new_fd, &(sys->readfd)); sys->readfd_count++; @@ -293,6 +367,8 @@ void iccp_get_start_type(struct System* sys) if (strstr(g_csm_buf, "SONIC_BOOT_TYPE=warm")) sys->warmboot_start = WARM_REBOOT; + ICCPD_LOG_DEBUG("ICCP_FSM", "Start ICCP: warm reboot %s", + (sys->warmboot_start == WARM_REBOOT)? "yes" : "no"); return; } @@ -309,8 +385,10 @@ void scheduler_init() iccp_sys_local_if_list_get_init(); iccp_sys_local_if_list_get_addr(); /*Interfaces must be created before this func called*/ + //no need to create iccpd config from startup file, it will be done through + //cli iccp_config_from_file(sys->config_file_path); - + /*Get kernel ARP info */ iccp_neigh_get_init(); @@ -331,7 +409,6 @@ void scheduler_init() return; } -extern int mlacp_prepare_for_warm_reboot(struct CSM* csm, char* buf, size_t max_buf_size); void mlacp_sync_send_warmboot_flag() { struct System* sys = NULL; @@ -350,7 +427,7 @@ void mlacp_sync_send_warmboot_flag() iccp_csm_send(csm, g_csm_buf, msg_len); } } - + ICCPD_LOG_DEBUG("ICCP_FSM", "Send warmboot flag to peer. Start warmboot"); return; } @@ -542,12 +619,23 @@ void session_client_conn_handler(struct CSM *csm) /* Conn OK*/ struct epoll_event event; int err; + int send_buf_len = PEER_SOCK_SND_BUF_LEN; + int recv_buf_len = PEER_SOCK_RCV_BUF_LEN; event.data.fd = connFd; event.events = EPOLLIN; err = epoll_ctl(sys->epoll_fd, EPOLL_CTL_ADD, connFd, &event); if (err) goto conn_fail; csm->sock_fd = connFd; + if (setsockopt(csm->sock_fd, SOL_SOCKET, SO_SNDBUF, &send_buf_len, sizeof(send_buf_len)) == -1) + { + ICCPD_LOG_ERR(__FUNCTION__, "Set socket send buf option failed. Error"); + } + if (setsockopt(csm->sock_fd, SOL_SOCKET, SO_RCVBUF, &recv_buf_len, sizeof(recv_buf_len)) == -1) + { + ICCPD_LOG_ERR(__FUNCTION__, "Set socket recv buf option failed. Error"); + } + FD_SET(connFd, &(sys->readfd)); sys->readfd_count++; ICCPD_LOG_INFO(__FUNCTION__, "Connect to server %s sucess .", csm->peer_ip); @@ -707,6 +795,7 @@ int scheduler_check_csm_config(struct CSM* csm) { lif->is_peer_link = 1; csm->peer_link_if = lif; + set_peerlink_learn_kernel(csm, 0, 2); } } @@ -742,32 +831,66 @@ int scheduler_unregister_sock_read_event_callback(struct CSM* csm) void scheduler_session_disconnect_handler(struct CSM* csm) { struct System* sys = NULL; + struct If_info * cif = NULL; if ((sys = system_get_instance()) == NULL ) return; - struct epoll_event event; - if (csm == NULL) return; + ICCPD_LOG_NOTICE("ICCP_FSM", "scheduler session disconnect handler"); + session_conn_thread_lock(&csm->conn_mutex); scheduler_unregister_sock_read_event_callback(csm); if (csm->sock_fd > 0) { - event.data.fd = csm->sock_fd; - event.events = EPOLLIN; - epoll_ctl(sys->epoll_fd, EPOLL_CTL_DEL, csm->sock_fd, &event); - - close(csm->sock_fd); - csm->sock_fd = -1; + scheduler_csm_socket_cleanup(csm, 1); } mlacp_peer_disconn_handler(csm); MLACP(csm).current_state = MLACP_STATE_INIT; iccp_csm_status_reset(csm, 0); + time(&csm->connTimePrev); session_conn_thread_unlock(&csm->conn_mutex); return; } + +void scheduler_csm_socket_cleanup(struct CSM* csm, int location) +{ + struct System* sys; + struct epoll_event event; + + sys = system_get_instance(); + if (sys == NULL) + return; + + if (csm == NULL) + return; + + if (csm->sock_fd <= 0) + return + + event.data.fd = csm->sock_fd; + event.events = EPOLLIN; + if (epoll_ctl(sys->epoll_fd, EPOLL_CTL_DEL, csm->sock_fd, &event) != 0) + { + ICCPD_LOG_ERR("ICCP_FSM", "CSM socket %d epoll del error %d, location %d", + csm->sock_fd, errno, location); + } + if (close(csm->sock_fd) != 0) + { + ICCPD_LOG_ERR("ICCP_FSM", "CSM socket %d close error %d, location %d", + csm->sock_fd, errno, location); + SYSTEM_INCR_SOCKET_CLOSE_ERR_COUNTER(system_get_instance()); + } + else + { + ICCPD_LOG_NOTICE("ICCP_FSM", "CSM socket %d close, location %d", + csm->sock_fd, location); + } + csm->sock_fd = -1; +} + diff --git a/src/iccpd/src/system.c b/src/iccpd/src/system.c index 33aca67f8079..293a2329af6f 100644 --- a/src/iccpd/src/system.c +++ b/src/iccpd/src/system.c @@ -22,11 +22,17 @@ */ #include +#include #include "../include/iccp_csm.h" #include "../include/logger.h" #include "../include/iccp_netlink.h" #include "../include/scheduler.h" +#include "../include/mlacp_link_handler.h" +#include "../include/iccp_ifm.h" + +#define ETHER_ADDR_LEN 6 +char mac_print_str[ETHER_ADDR_STR_LEN]; /* Singleton */ struct System* system_get_instance() @@ -53,6 +59,7 @@ void system_init(struct System* sys) if (sys == NULL ) return; + memset(sys, 0, sizeof(struct System)); sys->server_fd = -1; sys->sync_fd = -1; sys->sync_ctrl_fd = -1; @@ -65,6 +72,8 @@ void system_init(struct System* sys) LIST_INIT(&(sys->csm_list)); LIST_INIT(&(sys->lif_list)); LIST_INIT(&(sys->lif_purge_list)); + LIST_INIT(&(sys->unq_ip_if_list)); + LIST_INIT(&(sys->pending_vlan_mbr_if_list)); sys->log_file_path = strdup("/var/log/iccpd.log"); sys->cmd_file_path = strdup("/var/run/iccpd/iccpd.vty"); @@ -88,15 +97,21 @@ void system_finalize() struct System* sys = NULL; struct CSM* csm = NULL; struct LocalInterface* local_if = NULL; + struct Unq_ip_If_info* unq_ip_if = NULL; if ((sys = system_get_instance()) == NULL ) return; - ICCPD_LOG_INFO(__FUNCTION__, "System resource pool is destructing."); + ICCPD_LOG_NOTICE(__FUNCTION__, + "System resource pool is destructing. Warmboot exit (%d)", + sys->warmboot_exit); while (!LIST_EMPTY(&(sys->csm_list))) { csm = LIST_FIRST(&(sys->csm_list)); + /* Remove ICCP info from STATE_DB if it is not warm reboot */ + if (sys->warmboot_exit != WARM_REBOOT) + mlacp_link_del_iccp_info(csm->mlag_id); iccp_csm_finalize(csm); } @@ -115,6 +130,16 @@ void system_finalize() local_if_finalize(local_if); } + //remove all pending vlan membership entries + del_all_pending_vlan_mbr_ifs(sys); + + while (!LIST_EMPTY(&(sys->unq_ip_if_list))) + { + unq_ip_if = LIST_FIRST(&(sys->unq_ip_if_list)); + LIST_REMOVE(unq_ip_if, if_next); + free(unq_ip_if); + } + iccp_system_dinit_netlink_socket(); if (sys->log_file_path != NULL ) @@ -185,6 +210,34 @@ struct CSM* system_get_csm_by_peer_ip(const char* peer_ip) return NULL; } +//function to get CSM by peer interface name +struct CSM* system_get_csm_by_peer_ifname(char *ifname) +{ + struct CSM *csm = NULL; + struct System* sys = NULL; + + if (!ifname) + { + return NULL; + } + + if ((sys = system_get_instance()) == NULL) + { + return NULL; + } + + /* traverse all CSM and find matching csm with peer ifname */ + LIST_FOREACH(csm, &(sys->csm_list), next) + { + //return matching csm + if (strcmp(ifname, csm->peer_itf_name) == 0) + { + return csm; + } + } + return NULL; +} + struct CSM* system_get_csm_by_mlacp_id(int id) { struct System* sys = NULL; @@ -201,3 +254,146 @@ struct CSM* system_get_csm_by_mlacp_id(int id) return NULL; } + +struct CSM* system_get_first_csm() +{ + struct System* sys = NULL; + struct CSM* csm = NULL; + + if ((sys = system_get_instance()) == NULL ) + return NULL; + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + return csm; + } + + return NULL; +} + +SYNCD_TX_DBG_CNTR_MSG_e system_syncdtx_to_dbg_msg_type(uint32_t msg_type) +{ + switch(msg_type) + { + case MCLAG_MSG_TYPE_PORT_ISOLATE: + return SYNCD_TX_DBG_CNTR_MSG_PORT_ISOLATE; + + case MCLAG_MSG_TYPE_PORT_MAC_LEARN_MODE: + return SYNCD_TX_DBG_CNTR_MSG_PORT_MAC_LEARN_MODE; + + case MCLAG_MSG_TYPE_FLUSH_FDB: + return SYNCD_TX_DBG_CNTR_MSG_FLUSH_FDB; + + case MCLAG_MSG_TYPE_SET_MAC: + return SYNCD_TX_DBG_CNTR_MSG_SET_IF_MAC; + + case MCLAG_MSG_TYPE_SET_FDB: + return SYNCD_TX_DBG_CNTR_MSG_SET_FDB; + + case MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_ENABLE: + return SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_ENABLE; + + case MCLAG_MSG_TYPE_SET_TRAFFIC_DIST_DISABLE: + return SYNCD_TX_DBG_CNTR_MSG_SET_TRAFFIC_DIST_DISABLE; + + case MCLAG_MSG_TYPE_SET_ICCP_STATE: + return SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_STATE; + + case MCLAG_MSG_TYPE_SET_ICCP_ROLE: + return SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_ROLE; + + case MCLAG_MSG_TYPE_SET_ICCP_SYSTEM_ID: + return SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_SYSTEM_ID; + + case MCLAG_MSG_TYPE_SET_REMOTE_IF_STATE: + return SYNCD_TX_DBG_CNTR_MSG_SET_REMOTE_IF_STATE; + + case MCLAG_MSG_TYPE_DEL_ICCP_INFO: + return SYNCD_TX_DBG_CNTR_MSG_DEL_ICCP_INFO; + + case MCLAG_MSG_TYPE_DEL_REMOTE_IF_INFO: + return SYNCD_TX_DBG_CNTR_MSG_DEL_REMOTE_IF_INFO; + + case MCLAG_MSG_TYPE_SET_PEER_LINK_ISOLATION: + return SYNCD_TX_DBG_CNTR_MSG_PEER_LINK_ISOLATION; + + case MCLAG_MSG_TYPE_SET_ICCP_PEER_SYSTEM_ID: + return SYNCD_TX_DBG_CNTR_MSG_SET_ICCP_PEER_SYSTEM_ID; + + default: + return SYNCD_TX_DBG_CNTR_MSG_MAX; + } +} + +SYNCD_RX_DBG_CNTR_MSG_e system_syncdrx_to_dbg_msg_type(uint32_t msg_type) +{ + switch(msg_type) + { + case MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION: + return SYNCD_RX_DBG_CNTR_MSG_MAC; + case MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_DOMAIN: + return SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_DOMAIN; + case MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_IFACE: + return SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_IFACE; + case MCLAG_SYNCD_MSG_TYPE_CFG_MCLAG_UNIQUE_IP: + return SYNCD_RX_DBG_CNTR_MSG_CFG_MCLAG_UNIQUE_IP; + case MCLAG_SYNCD_MSG_TYPE_VLAN_MBR_UPDATES: + return SYNCD_RX_DBG_CNTR_MSG_VLAN_MBR_UPDATES; + default: + return SYNCD_RX_DBG_CNTR_MSG_MAX; + } +} + +char *mac_addr_to_str(uint8_t mac_addr[ETHER_ADDR_LEN]) +{ + memset(mac_print_str, 0, sizeof(mac_print_str)); + snprintf(mac_print_str, sizeof(mac_print_str), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + return mac_print_str; +} + +void system_update_netlink_counters( + uint16_t netlink_msg_type, + struct nlmsghdr *nlh) +{ + struct System *sys; + struct ndmsg *ndm = NLMSG_DATA(nlh); + + sys = system_get_instance(); + if (!sys) + return; + + switch (netlink_msg_type) + { + case RTM_NEWLINK: + ++sys->dbg_counters.newlink_count; + break; + case RTM_DELLINK: + ++sys->dbg_counters.dellink_count; + break; + case RTM_NEWNEIGH: + ++sys->dbg_counters.newnbr_count; + if (ndm->ndm_family == AF_BRIDGE) + ++sys->dbg_counters.newmac_count; + break; + case RTM_DELNEIGH: + ++sys->dbg_counters.delnbr_count; + if (ndm->ndm_family == AF_BRIDGE) + ++sys->dbg_counters.delmac_count; + break; + case RTM_NEWADDR: + ++sys->dbg_counters.newaddr_count; + break; + case RTM_DELADDR: + ++sys->dbg_counters.deladdr_count; + break; + default: + ++sys->dbg_counters.unknown_type_count; + if (sys->dbg_counters.unknown_type_count < 5) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "NETLINK_COUNTER: Unknown type %d", netlink_msg_type); + } + break; + } +}