From 83f09299aecfd9c2b2fcb9e1dc2ae7277dd31f54 Mon Sep 17 00:00:00 2001 From: dongjianjun Date: Tue, 1 Jun 2021 14:16:42 +0800 Subject: [PATCH] [MCLAG] Improve performance and fix some bugs --- src/iccpd/include/iccp_ifm.h | 3 + src/iccpd/include/mlacp_link_handler.h | 2 +- src/iccpd/include/mlacp_tlv.h | 11 +- src/iccpd/include/openbsd_tree.h | 571 +++++++++++++++++++++++ src/iccpd/include/port.h | 43 +- src/iccpd/include/system.h | 12 +- src/iccpd/src/Makefile.am | 3 +- src/iccpd/src/app_csm.c | 6 +- src/iccpd/src/iccp_cmd.c | 7 +- src/iccpd/src/iccp_cmd_show.c | 44 +- src/iccpd/src/iccp_consistency_check.c | 17 +- src/iccpd/src/iccp_csm.c | 10 +- src/iccpd/src/iccp_ifm.c | 292 ++++++++++-- src/iccpd/src/iccp_netlink.c | 151 ++++-- src/iccpd/src/mclagdctl/mclagdctl.c | 78 +++- src/iccpd/src/mclagdctl/mclagdctl.h | 67 ++- src/iccpd/src/mlacp_fsm.c | 12 +- src/iccpd/src/mlacp_link_handler.c | 175 +++++-- src/iccpd/src/mlacp_sync_prepare.c | 8 +- src/iccpd/src/mlacp_sync_update.c | 61 ++- src/iccpd/src/openbsd_tree.c | 618 +++++++++++++++++++++++++ src/iccpd/src/port.c | 306 ++++++++---- src/iccpd/src/scheduler.c | 1 + src/iccpd/src/system.c | 9 +- 24 files changed, 2215 insertions(+), 292 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_ifm.h b/src/iccpd/include/iccp_ifm.h index bbb1af67ee90..63fdb01b69f0 100644 --- a/src/iccpd/include/iccp_ifm.h +++ b/src/iccpd/include/iccp_ifm.h @@ -38,5 +38,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 iccp_get_if_vlan_info_from_netlink(); + #endif // LACP_IFM_H diff --git a/src/iccpd/include/mlacp_link_handler.h b/src/iccpd/include/mlacp_link_handler.h index 624b4111a7ee..617139d0d992 100644 --- a/src/iccpd/include/mlacp_link_handler.h +++ b/src/iccpd/include/mlacp_link_handler.h @@ -44,7 +44,7 @@ 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); +void add_mac_to_chip(struct CSM *csm, 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); diff --git a/src/iccpd/include/mlacp_tlv.h b/src/iccpd/include/mlacp_tlv.h index 7d3a4e18e4e2..79d80d72c33a 100644 --- a/src/iccpd/include/mlacp_tlv.h +++ b/src/iccpd/include/mlacp_tlv.h @@ -33,6 +33,7 @@ #define MLACP_SYSCONF_NODEID_NODEID_MASK 0x70 #define MLACP_SYSCONF_NODEID_FREE_MASK 0x0F +#define NEIGH_SYNC_TIME 240 /* * RFC 7275 * 7.2.3. mLACP System Config TLV @@ -369,17 +370,19 @@ struct mLACPMACInfoTLV struct ARPMsg { uint8_t op_type; - char ifname[MAX_L_PORT_NAME]; + char ifname[MAX_L_PORT_NAME]; uint32_t ipv4_addr; uint8_t mac_addr[ETHER_ADDR_LEN]; + time_t sync_time; }; struct NDISCMsg { - uint8_t op_type; - char ifname[MAX_L_PORT_NAME]; + uint8_t op_type; + char ifname[MAX_L_PORT_NAME]; uint32_t ipv6_addr[4]; - uint8_t mac_addr[ETHER_ADDR_LEN]; + uint8_t mac_addr[ETHER_ADDR_LEN]; + time_t sync_time; }; /* 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..ca0f1ab80582 100644 --- a/src/iccpd/include/port.h +++ b/src/iccpd/include/port.h @@ -28,8 +28,11 @@ #include #include +#include "../include/openbsd_tree.h" + #define ETHER_ADDR_LEN 6 #define ETHER_ADDR_STR_LEN 18 + /* * RFC 7275 * 7.2.4. mLACP Port Config TLV @@ -47,9 +50,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; @@ -67,9 +71,19 @@ 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_entry, vlan_node_compare); + +#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 +102,13 @@ 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 PortChannel_member +{ + char name[MAX_L_PORT_NAME]; + LIST_ENTRY(PortChannel_member) member_next; }; struct LocalInterface @@ -108,7 +128,6 @@ struct LocalInterface uint8_t l3_mode; uint8_t l3_mac_addr[ETHER_ADDR_LEN]; uint8_t is_peer_link; - char portchannel_member_buf[512]; uint8_t is_arp_accept; int po_id; /* Port Channel ID */ uint8_t po_active; /* Port Channel is in active status? */ @@ -120,9 +139,12 @@ struct LocalInterface uint8_t changed; uint8_t port_config_sync; - LIST_HEAD(local_vlan_list, VLAN_ID) vlan_list; + struct vlan_rb_tree vlan_tree; + + LIST_HEAD(member_list, PortChannel_member) member_list; + int portchannel_member_count; - LIST_ENTRY(LocalInterface) system_next; + RB_ENTRY(LocalInterface) lif_entry; LIST_ENTRY(LocalInterface) system_purge_next; LIST_ENTRY(LocalInterface) mlacp_next; LIST_ENTRY(LocalInterface) mlacp_purge_next; @@ -131,9 +153,9 @@ struct LocalInterface struct LocalInterface* local_if_create(int ifindex, char* ifname, int type); 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); +/*struct LocalInterface* local_if_find_by_po_id(int po_id);*/ -void local_if_destroy(char *ifname); +void local_if_destroy(struct LocalInterface *lif); void local_if_change_flag_clear(void); void local_if_purge_clear(void); int local_if_is_l3_mode(struct LocalInterface* local_if); @@ -152,6 +174,7 @@ int peer_if_clean_unused_vlan(struct PeerInterface* peer_if); int local_if_add_vlan(struct LocalInterface* local_if, uint16_t vid); void local_if_del_vlan(struct LocalInterface* local_if, uint16_t vid); void local_if_del_all_vlan(struct LocalInterface* lif); +void local_if_del_all_portchannel_member(struct LocalInterface* lif); /* ARP manipulation */ int set_sys_arp_accept_flag(char* ifname, int flag); diff --git a/src/iccpd/include/system.h b/src/iccpd/include/system.h index 3ee314d253aa..12cfe7e8d318 100644 --- a/src/iccpd/include/system.h +++ b/src/iccpd/include/system.h @@ -52,6 +52,16 @@ struct CSM; #define MAX_BUFSIZE 4096 #endif +RB_HEAD(lif_rb_tree, LocalInterface); +RB_PROTOTYPE(lif_rb_tree, LocalInterface, lif_entry, lif_node_compare); + +#define LIF_RB_REMOVE(name, head, elm) do { \ + RB_REMOVE(name, head, elm); \ + (elm)->lif_entry.rbt_parent = NULL; \ + (elm)->lif_entry.rbt_left = NULL; \ + (elm)->lif_entry.rbt_right = NULL; \ +} while (0) + struct System { int server_fd;/* Peer-Link Socket*/ @@ -76,7 +86,7 @@ struct System /* Info List*/ LIST_HEAD(csm_list, CSM) csm_list; - LIST_HEAD(lif_all_list, LocalInterface) lif_list; + struct lif_rb_tree lif_tree; LIST_HEAD(lif_purge_all_list, LocalInterface) lif_purge_list; /* Settings */ diff --git a/src/iccpd/src/Makefile.am b/src/iccpd/src/Makefile.am index 9d19dbb5285c..0f3c9690d1a5 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..74bb4a79062b 100644 --- a/src/iccpd/src/app_csm.c +++ b/src/iccpd/src/app_csm.c @@ -238,13 +238,13 @@ 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*/ + /*if join a po member, may swss restart, reset portchannel ip mac to mclagsyncd*/ update_if_ipmac_on_standby(lif_po); return 0; } } - if (lif_po == NULL) + /*if (lif_po == NULL) { lif_po = local_if_find_by_po_id(lif->po_id); if (lif_po == NULL) @@ -257,7 +257,7 @@ int mlacp_bind_local_if(struct CSM* csm, struct LocalInterface* lif) LIST_INSERT_HEAD(&(MLACP(csm).lif_list), lif_po, mlacp_next); lif_po->port_config_sync = 1; ICCPD_LOG_INFO(__FUNCTION__, "Add port_channel %d into local_if_list in CSM %p.", lif->po_id, csm); - } + }*/ return 0; } diff --git a/src/iccpd/src/iccp_cmd.c b/src/iccpd/src/iccp_cmd.c index 50025a8e3810..4ba2930db1ee 100644 --- a/src/iccpd/src/iccp_cmd.c +++ b/src/iccpd/src/iccp_cmd.c @@ -32,6 +32,7 @@ #include "../include/iccp_cmd_show.h" #include "../include/iccp_cli.h" #include "../include/logger.h" +#include "mclagdctl/mclagdctl.h" int set_mc_lag_by_id(uint16_t mid) { @@ -55,8 +56,6 @@ int set_mc_lag_by_id(uint16_t mid) return ret; } -#define CONFIG_LINE_LEN 512 - int iccp_config_from_command(char * line) { char *cp, *start; @@ -150,13 +149,13 @@ int iccp_config_from_file(char *config_default_dir) { FILE *confp = NULL; - char command_buf[CONFIG_LINE_LEN]; + char command_buf[CONFIG_MCLAG_ENABLE_INTF_LEN]; confp = fopen(config_default_dir, "r"); if (confp == NULL) return (1); - while (fgets(command_buf, CONFIG_LINE_LEN, confp)) + while (fgets(command_buf, CONFIG_MCLAG_ENABLE_INTF_LEN, confp)) { iccp_config_from_command(command_buf); } diff --git a/src/iccpd/src/iccp_cmd_show.c b/src/iccpd/src/iccp_cmd_show.c index 18b2e5bded8e..13f8a3a0808a 100644 --- a/src/iccpd/src/iccp_cmd_show.c +++ b/src/iccpd/src/iccp_cmd_show.c @@ -75,7 +75,7 @@ int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id) continue; } - peer_link_if = local_if_find_by_name(csm->peer_itf_name); + peer_link_if = csm->peer_link_if; if (csm->mlag_id <= 0) state_info.mclag_id = -1; @@ -98,7 +98,7 @@ int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id) state_info.role = csm->role_type; - str_size = MCLAGDCTL_PORT_MEMBER_BUF_LEN; + str_size = CONFIG_MCLAG_ENABLE_INTF_LEN; len = 0; LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next) @@ -339,20 +339,18 @@ int iccp_mac_dump(char * *buf, int *num, int mclag_id) return EXEC_TYPE_SUCCESS; } -int iccp_local_if_dump(char * *buf, int *num, int mclag_id) +int iccp_local_if_dump(char * *buf, int *data_len, int mclag_id) { struct System *sys = NULL; struct CSM *csm = NULL; struct LocalInterface *lif_po = NULL; struct mclagd_local_if mclagd_lif; struct VLAN_ID* vlan_id = NULL; - char * str_buf = NULL; - int str_size = MCLAGDCTL_PARA3_LEN - 1; - int len = 0; - int lif_num = 0; int id_exist = 0; int lif_buf_size = MCLAGDCTL_CMD_SIZE; + int lif_buf_base = MCLAGD_REPLY_INFO_HDR; char * lif_buf = NULL; + struct PortChannel_member *member = NULL; if (!(sys = system_get_instance())) { @@ -405,7 +403,7 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) mclagd_lif.is_peer_link = lif_po->is_peer_link; - memcpy(mclagd_lif.portchannel_member_buf, lif_po->portchannel_member_buf, 512); + mclagd_lif.portchannel_member_count = lif_po->portchannel_member_count; mclagd_lif.po_id = lif_po->po_id; mclagd_lif.po_active = lif_po->po_active; @@ -423,36 +421,36 @@ int iccp_local_if_dump(char * *buf, int *num, int mclag_id) mclagd_lif.isolate_to_peer_link = lif_po->isolate_to_peer_link; - str_buf = mclagd_lif.vlanlist; - - len = 0; - LIST_FOREACH(vlan_id, &(lif_po->vlan_list), port_next) + RB_FOREACH (vlan_id, vlan_rb_tree, &(lif_po->vlan_tree)) { - if (vlan_id != NULL ) + if (vlan_id == NULL ) { - if (str_size - len < 4) - break; - len += snprintf(str_buf + len, str_size - len, "%d ", vlan_id->vid); + continue; } + BMAP_ADD(mclagd_lif.vlan_map, vlan_id->vid); } - 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)) + if ((lif_buf_base + sizeof(struct mclagd_local_if) + lif_po->portchannel_member_count*MAX_L_PORT_NAME) > lif_buf_size) { lif_buf_size += MCLAGDCTL_CMD_SIZE; lif_buf = (char*)realloc(lif_buf, lif_buf_size); if (!lif_buf) return EXEC_TYPE_FAILED; } + + memcpy(lif_buf + lif_buf_base, &mclagd_lif, sizeof(struct mclagd_local_if)); + lif_buf_base += sizeof(struct mclagd_local_if); + + LIST_FOREACH(member, &(lif_po->member_list), member_next) + { + memcpy(lif_buf + lif_buf_base, &member->name, MAX_L_PORT_NAME); + lif_buf_base += MAX_L_PORT_NAME; + } } } *buf = lif_buf; - *num = lif_num; + *data_len = lif_buf_base; if (mclag_id > 0 && !id_exist) return EXEC_TYPE_NO_EXIST_MCLAGID; 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..22926ee46339 100644 --- a/src/iccpd/src/iccp_csm.c +++ b/src/iccpd/src/iccp_csm.c @@ -219,6 +219,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; @@ -236,7 +238,13 @@ 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)) + { + 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)); + } + return (rc); } /* Connection State Machine Transition */ diff --git a/src/iccpd/src/iccp_ifm.c b/src/iccpd/src/iccp_ifm.c index 258c661e03a4..e6835738d66b 100644 --- a/src/iccpd/src/iccp_ifm.c +++ b/src/iccpd/src/iccp_ifm.c @@ -144,7 +144,7 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int if (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; + /*arp_msg->ipv4_addr = arp_msg->ipv4_addr;*/ ICCPD_LOG_NOTICE(__FUNCTION__, "ARP type %s, state (%04X)(%d) ifindex [%d] (%s) ip %s, mac [%02X:%02X:%02X:%02X:%02X:%02X]", msgtype == RTM_NEWNEIGH ? "New":"Del", ndm->ndm_state, fwd_neigh_state_valid(ndm->ndm_state), @@ -161,10 +161,10 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int if (lif_po->type != IF_T_PORT_CHANNEL) continue; - if (!local_if_is_l3_mode(lif_po)) + if (!local_if_is_l3_mode(lif_po) && strncmp(arp_lif->name, "Vlan", 4) == 0) { /* Is the L2 MLAG itf belong to a vlan?*/ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(lif_po->vlan_tree)) { if ( !(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex)) @@ -175,6 +175,9 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int if (!vlan_id_list) continue; + if (vlan_id_list->vlan_itf && !local_if_is_l3_mode(vlan_id_list->vlan_itf)) + continue; + ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %s", vlan_id_list->vlan_itf->name); } @@ -220,13 +223,11 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int else { /* update ARP*/ - if (arp_info->op_type != arp_msg->op_type - || strcmp(arp_info->ifname, arp_msg->ifname) != 0 + if (strcmp(arp_info->ifname, arp_msg->ifname) != 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; sprintf(arp_info->ifname, "%s", arp_msg->ifname); memcpy(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN); ICCPD_LOG_DEBUG(__FUNCTION__, "Update ARP for %s", show_ip_str(arp_msg->ipv4_addr)); @@ -255,12 +256,16 @@ static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr)); } + arp_info = (struct ARPMsg*)msg->buf; + /* enqueue iccp_msg (add)*/ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && + (arp_update == 1 || (time(NULL) - arp_info->sync_time) >= NEIGH_SYNC_TIME)) { arp_msg->op_type = NEIGH_SYNC_ADD; if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0) { + time(&arp_info->sync_time); TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] message for %s", show_ip_str(arp_msg->ipv4_addr));*/ @@ -343,10 +348,10 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i if (lif_po->type != IF_T_PORT_CHANNEL) continue; - if (!local_if_is_l3_mode(lif_po)) + if (!local_if_is_l3_mode(lif_po) && strncmp(ndisc_lif->name, "Vlan", 4) == 0) { /* Is the L2 MLAG itf belong to a vlan? */ - LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(lif_po->vlan_tree)) { if (!(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex)) continue; @@ -356,6 +361,9 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i if (!vlan_id_list) continue; + if (vlan_id_list->vlan_itf && !local_if_is_l3_mode(vlan_id_list->vlan_itf)) + continue; + ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from mclag enabled member port of vlan %s", vlan_id_list->vlan_itf->name); } else @@ -401,12 +409,10 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i else { /* 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) + if (strcmp(ndisc_info->ifname, ndisc_msg->ifname) != 0 + || memcmp(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN) != 0) { neigh_update = 1; - 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 neighbor for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); @@ -434,12 +440,16 @@ static void do_ndisc_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], i ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } + ndisc_info = (struct NDISCMsg *)msg->buf; + /* enqueue iccp_msg (add) */ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && + (neigh_update == 1 || (time(NULL) - ndisc_info->sync_time) >= NEIGH_SYNC_TIME)) { ndisc_msg->op_type = NEIGH_SYNC_ADD; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0) { + time(&ndisc_info->sync_time); TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail); /* ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue Ndisc[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); */ } @@ -622,6 +632,7 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui struct LocalInterface *lif_po = NULL, *arp_lif = NULL; int verify_arp = 0; + bool sync_to_peer = false; if (!(sys = system_get_instance())) return; @@ -656,7 +667,7 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui 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) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(lif_po->vlan_tree)) { if ( !(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ifindex)) @@ -706,14 +717,13 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui continue; /* update ARP*/ - if (arp_info->op_type != arp_msg->op_type - || strcmp(arp_info->ifname, arp_msg->ifname) != 0 + if (strcmp(arp_info->ifname, arp_msg->ifname) != 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); + sync_to_peer = true; 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]); @@ -736,12 +746,16 @@ void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, ui arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr)); } + arp_info = (struct ARPMsg*)msg->buf; + /* enqueue iccp_msg (add)*/ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && + (sync_to_peer == true || (time(NULL) - arp_info->sync_time) >= NEIGH_SYNC_TIME)) { arp_msg->op_type = NEIGH_SYNC_ADD; if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0) { + time(&arp_info->sync_time); TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail); /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] for %s", show_ip_str(arp_msg->ipv4_addr));*/ @@ -767,6 +781,7 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui char buf[MAX_BUFSIZE]; size_t msg_len = 0; + bool sync_to_peer = false; struct LocalInterface *lif_po = NULL, *ndisc_lif = NULL; @@ -804,7 +819,7 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui 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) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(lif_po->vlan_tree)) { if (!(vlan_id_list->vlan_itf && vlan_id_list->vlan_itf->ifindex == ifindex)) continue; @@ -861,13 +876,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 + if (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); + sync_to_peer = true; ICCPD_LOG_DEBUG(__FUNCTION__, "Update ND for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); } break; @@ -892,6 +906,7 @@ 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 ND request is not sent by this switch, linux kernel don't learn this ND reply, install the ND item to kernel*/ if (iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname) < 0) { ICCPD_LOG_WARN(__FUNCTION__, "Failed to add ND entry(%s, %s, %s) to kernel", @@ -899,12 +914,16 @@ void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, ui return; } + ndisc_info = (struct NDISCMsg *)msg->buf; + /* enqueue iccp_msg (add) */ - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) + if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && + (sync_to_peer == true || (time(NULL) - ndisc_info->sync_time) >= NEIGH_SYNC_TIME)) { ndisc_msg->op_type = NEIGH_SYNC_ADD; if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0) { + time(&ndisc_info->sync_time); 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)); */ } @@ -914,7 +933,8 @@ 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) + +void iccp_from_netlink_port_state_handler(char * ifname, int state) { struct CSM *csm = NULL; struct LocalInterface *lif_po = NULL; @@ -955,10 +975,195 @@ void iccp_from_netlink_port_state_handler( char * ifname, int state) return; } +#define BUF_LEN 10000000 +void iccp_get_if_vlan_info_from_netlink() +{ + struct LocalInterface *lif = NULL; + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + /* Attribute has to be NLMSG aligned */ + struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); + __u32 ext_filter_mask; + }req; + + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char *buf = malloc(BUF_LEN); + struct nl_sock *sk; + int fd; + uint16_t vid_range_start = 0; + uint16_t vid_range_flags = -1; + + struct System *sys; + + if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_WARN(__FUNCTION__, "Failed to obtain System instance."); + free(buf); + return; + } + fd = nl_socket_get_fd(sys->route_sock); + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = RTM_GETLINK; + req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq =0; + req.ifm.ifi_family = PF_BRIDGE; + + req.ext_req.rta_type = IFLA_EXT_MASK; + req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); + req.ext_filter_mask = RTEXT_FILTER_BRVLAN; + + send(fd, (void*)&req, sizeof(req), 0); + + iov.iov_base = buf; + while (1) + { + int status; + int msglen = 0; + + iov.iov_len = BUF_LEN; + + status = recvmsg(fd, &msg, 0); + + if (status < 0 || status == 0) + { + ICCPD_LOG_WARN(__FUNCTION__, "netlink receive error (%d) status %d", fd, status); + free(buf); + return; + } + + struct nlmsghdr *n = (struct nlmsghdr *)buf; + + msglen = status; + + while (NLMSG_OK(n, msglen)) + { + struct ifinfomsg *ifm = NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr *tb[IFLA_MAX+1] = {0}; + + if (n->nlmsg_type != RTM_NEWLINK) + { + free(buf); + return; + } + + len -= NLMSG_LENGTH(sizeof(*ifm)); + if (len < 0) + { + ICCPD_LOG_WARN(__FUNCTION__, "BUG: wrong nlmsg len %d", len); + free(buf); + return; + } + + if (ifm->ifi_family != AF_BRIDGE) + { + free(buf); + return; + } + + if (lif = local_if_find_by_ifindex(ifm->ifi_index)) + { + 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; + struct VLAN_ID *vlan_temp = NULL; + + /*set vlan flag is removed*/ + RB_FOREACH (vlan, vlan_rb_tree, &(lif->vlan_tree)) + { + vlan->vlan_removed = 1; + } + + for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) + { + struct bridge_vlan_info *vinfo; + + if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) + continue; + + vinfo = RTA_DATA(i); + ICCPD_LOG_NOTICE(__FUNCTION__, "%s: add vlan .", lif->name); + + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + { + vid_range_start = vinfo->vid; + vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN); + continue; + } + + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) + { + /* sanity check the range flags */ + if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) + { + ICCPD_LOG_ERR(__FUNCTION__, "VLAN range flags differ; can not handle it .The %s of VLAN %d", lif->name, vinfo->vid); + return; + } + } + else + { + vid_range_start = vinfo->vid; + } + + for (; vid_range_start <= vinfo->vid; vid_range_start++) + { + local_if_add_vlan(lif, vid_range_start); + ICCPD_LOG_NOTICE(__FUNCTION__, "add %s to VLAN %d success", lif->name, vid_range_start); + } + vid_range_flags = -1; + } + + /*After update vlan list, remove unused item*/ + RB_FOREACH_SAFE (vlan, vlan_rb_tree, &(lif->vlan_tree), vlan_temp) + { + if (vlan->vlan_removed == 1) + { + local_if_del_vlan(lif, vlan->vid); + + ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", lif->name, vlan->vid); + + VLAN_RB_REMOVE(vlan_rb_tree, &(lif->vlan_tree), vlan); + free(vlan); + } + } + } + } + + n = NLMSG_NEXT(n, msglen); + } + } + + free(buf); + return; +} + void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n) { struct LocalInterface *lif = NULL; int msglen = 0; + uint16_t vid_range_start = 0; + uint16_t vid_range_flags = -1; msglen = n->nlmsg_len; @@ -1000,9 +1205,10 @@ void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n) struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); struct VLAN_ID *vlan = NULL; + struct VLAN_ID *vlan_temp = NULL; /*set vlan flag is removed*/ - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) + RB_FOREACH (vlan, vlan_rb_tree, &(lif->vlan_tree)) { vlan->vlan_removed = 1; } @@ -1016,17 +1222,45 @@ void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n) vinfo = RTA_DATA(i); - local_if_add_vlan(lif, vinfo->vid); + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + { + vid_range_start = vinfo->vid; + vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN); + continue; + } + + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) + { + /* sanity check the range flags */ + if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) + { + ICCPD_LOG_ERR(__FUNCTION__, "VLAN range flags differ; can not handle it .The %s of VLAN %d", lif->name, vinfo->vid); + return; + } + } + else + { + vid_range_start = vinfo->vid; + } + + for (; vid_range_start <= vinfo->vid; vid_range_start++) + { + local_if_add_vlan(lif, vid_range_start); + ICCPD_LOG_NOTICE(__FUNCTION__, "Add %s to VLAN %d success", lif->name, vid_range_start); + } + vid_range_flags = -1; } /*After update vlan list, remove unused item*/ - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) + RB_FOREACH_SAFE (vlan, vlan_rb_tree, &(lif->vlan_tree), vlan_temp) { if (vlan->vlan_removed == 1) { + local_if_del_vlan(lif, vlan->vid); + 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); free(vlan); } } diff --git a/src/iccpd/src/iccp_netlink.c b/src/iccpd/src/iccp_netlink.c index 002c254ae9c1..e57533b57ef9 100644 --- a/src/iccpd/src/iccp_netlink.c +++ b/src/iccpd/src/iccp_netlink.c @@ -57,6 +57,7 @@ #include "../include/mlacp_link_handler.h" #include "../include/msg_format.h" #include "../include/iccp_netlink.h" +#include "mclagdctl/mclagdctl.h" /** * SECTION: Netlink helpers @@ -159,8 +160,9 @@ int iccp_get_portchannel_member_list_handler(struct nl_msg *msg, void * arg) uint32_t ifindex = 0; struct System* sys = NULL; struct LocalInterface* local_if = NULL; - char temp_buf[512]; int len = 0; + struct PortChannel_member *member = NULL; + bool update_member = false; sys = system_get_instance(); if (sys == NULL) @@ -215,38 +217,54 @@ int iccp_get_portchannel_member_list_handler(struct nl_msg *msg, void * arg) if (port_attrs[TEAM_ATTR_PORT_REMOVED] && local_if_member->po_id != -1) { + if (local_if_member->type == IF_T_PORT && local_if_member->po_id == local_if->po_id) + { + LIST_FOREACH(member, &(local_if->member_list), member_next) + { + if (strcmp(member->name, local_if_member->name) == 0) + { + LIST_REMOVE(member, member_next); + --local_if->portchannel_member_count; + update_member = true; + free(member); + break; + } + } + } local_if_member->po_id = -1; mlacp_unbind_local_if(local_if_member); } else if ( local_if_member->po_id == -1) { local_if_member->po_id = local_if->po_id; - mlacp_bind_local_if(local_if->csm, local_if_member); - } - } - memset(temp_buf, 0, 512); - LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next) - { - if (lif->type == IF_T_PORT && lif->po_id == local_if->po_id) - { - if (strlen(temp_buf) != 0) - len += snprintf(temp_buf + len, 512 - len, "%s", ","); - - len += snprintf(temp_buf + len, 512 - len, "%s", lif->name); + if (local_if_member->type == IF_T_PORT) + { + LIST_FOREACH(member, &(local_if->member_list), member_next) + { + if (strcmp(member->name, local_if_member->name) == 0) + { + break; + } + } + if(NULL == member) + { + struct PortChannel_member *new = (struct PortChannel_member*)malloc(sizeof(struct PortChannel_member)); + memcpy(new->name, local_if_member->name, MAX_L_PORT_NAME); + LIST_INSERT_HEAD(&(local_if->member_list), new, member_next); + ++local_if->portchannel_member_count; + update_member = true; + } + } + mlacp_bind_local_if(local_if->csm, local_if_member); } } - if (strcmp(temp_buf, local_if->portchannel_member_buf)) + if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && update_member) { - memset(local_if->portchannel_member_buf, 0, 512); - memcpy(local_if->portchannel_member_buf, temp_buf, sizeof(local_if->portchannel_member_buf) - 1); - - if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) - { - /* portchannel member changed, update port isolate attribute*/ - update_peerlink_isolate_from_all_csm_lif(csm); - } + /* portchannel member changed, update port isolate attribute*/ + update_peerlink_isolate_from_all_csm_lif(csm); + update_member = false; } } else /*peerlink portchannel */ @@ -292,6 +310,19 @@ int iccp_get_portchannel_member_list_handler(struct nl_msg *msg, void * arg) if (port_attrs[TEAM_ATTR_PORT_REMOVED] && local_if_member->po_id != -1) { + if (local_if_member->type == IF_T_PORT && local_if_member->po_id == local_if->po_id) + { + LIST_FOREACH(member, &(local_if->member_list), member_next) + { + if (strcmp(member->name, local_if_member->name) == 0) + { + LIST_REMOVE(member, member_next); + --local_if->portchannel_member_count; + free(member); + break; + } + } + } local_if_member->po_id = -1; if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { @@ -304,6 +335,23 @@ int iccp_get_portchannel_member_list_handler(struct nl_msg *msg, void * arg) else if ( local_if_member->po_id == -1) { local_if_member->po_id = local_if->po_id; + if (local_if_member->type == IF_T_PORT) + { + LIST_FOREACH(member, &(local_if->member_list), member_next) + { + if (strcmp(member->name, local_if_member->name) == 0) + { + break; + } + } + if(NULL == member) + { + struct PortChannel_member *new = (struct PortChannel_member*)malloc(sizeof(struct PortChannel_member)); + memcpy(new->name, local_if_member->name, MAX_L_PORT_NAME); + LIST_INSERT_HEAD(&(local_if->member_list), new, member_next); + ++local_if->portchannel_member_count; + } + } if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE) { @@ -312,24 +360,6 @@ int iccp_get_portchannel_member_list_handler(struct nl_msg *msg, void * arg) } } } - - memset(temp_buf, 0, 512); - LIST_FOREACH(lif, &(sys->lif_list), system_next) - { - if (lif->type == IF_T_PORT && lif->po_id == local_if->po_id) - { - if (strlen(temp_buf) != 0) - len += snprintf(temp_buf + len, 512 - len, "%s", ","); - - len += snprintf(temp_buf + len, 512 - len, "%s", lif->name); - } - } - - if (strcmp(temp_buf, local_if->portchannel_member_buf)) - { - memset(local_if->portchannel_member_buf, 0, 512); - memcpy(local_if->portchannel_member_buf, temp_buf, sizeof(local_if->portchannel_member_buf) - 1); - } } } @@ -608,7 +638,7 @@ void update_if_ipmac_on_standby(struct LocalInterface* lif_po) } 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; @@ -689,7 +719,7 @@ void recover_if_ipmac_on_standby(struct LocalInterface* lif_po) } 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; @@ -917,7 +947,39 @@ void iccp_event_handler_obj_input_dellink(struct nl_object *obj, void *arg) ifindex = rtnl_link_get_ifindex(link); if ((lif = local_if_find_by_ifindex(ifindex)) != NULL) - local_if_destroy(lif->name); + local_if_destroy(lif); + + return; +} + +void iccp_set_vlan_ipadd_mac_by_portchannel(char *vlan_name) +{ + struct CSM* csm; + struct System *sys = NULL; + struct LocalInterface* lifp = NULL; + struct VLAN_ID *vlan = NULL; + + if (!(sys = system_get_instance())) + return; + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + LIST_FOREACH(lifp, &(MLACP(csm).lif_list), mlacp_next) + { + if (lifp->type == IF_T_PORT_CHANNEL) + { + RB_FOREACH(vlan, vlan_rb_tree, &(lifp->vlan_tree)) + { + if (vlan->vlan_itf && strcmp(vlan_name, vlan->vlan_itf->name) == 0) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Mclag interface %s is member of %s", lifp->name, vlan_name); + update_if_ipmac_on_standby(lifp); + return; + } + } + } + } + } return; } @@ -1310,6 +1372,7 @@ int iccp_system_init_netlink_socket() sys->route_sock = nl_socket_alloc(); if (!sys->route_sock) goto err_route_sock_alloc; + nl_socket_disable_seq_check(sys->route_sock); err = nl_connect(sys->route_sock, NETLINK_ROUTE); if (err) goto err_route_sock_connect; @@ -1651,7 +1714,7 @@ void iccp_netlink_sync_again() { sys->need_sync_team_again = 0; - LIST_FOREACH(lif, &(sys->lif_list), system_next) + RB_FOREACH (lif, lif_rb_tree, &(sys->lif_tree)) { if (lif->type == IF_T_PORT_CHANNEL) { diff --git a/src/iccpd/src/mclagdctl/mclagdctl.c b/src/iccpd/src/mclagdctl/mclagdctl.c index 630e333be6ed..100e1b932db7 100644 --- a/src/iccpd/src/mclagdctl/mclagdctl.c +++ b/src/iccpd/src/mclagdctl/mclagdctl.c @@ -30,6 +30,7 @@ #include #include #include "mclagdctl.h" +#include "../../include/port.h" static int mclagdctl_sock_fd = -1; char *mclagdctl_sock_path = "/var/run/iccpd/mclagdctl.sock"; @@ -470,15 +471,19 @@ int mclagdctl_enca_dump_local_portlist(char *msg, int mclag_id, int argc, char * int mclagdctl_parse_dump_local_portlist(char *msg, int data_len) { struct mclagd_local_if * lif_info = NULL; - int len = 0; - int count = 0; int pos = 0; + int vid; + int vid_range_start = 0, vid_range_end = 0; + int lif_info_base = 0; + int i = 0; + char member_name[MAX_L_PORT_NAME]; - len = sizeof(struct mclagd_local_if); - - for (; data_len >= len; data_len -= len, count++) + while (lif_info_base < data_len) { - lif_info = (struct mclagd_local_if*)(msg + len * count); + lif_info = (struct mclagd_local_if*)(msg + lif_info_base); + lif_info_base += sizeof(struct mclagd_local_if); + vid_range_start = 0; + vid_range_end = 0; for (pos = 0; pos < 60; ++pos) fprintf(stdout, "-"); @@ -496,17 +501,64 @@ int mclagdctl_parse_dump_local_portlist(char *msg, int data_len) lif_info->mac_addr[2], lif_info->mac_addr[3], lif_info->mac_addr[4], lif_info->mac_addr[5]); - fprintf(stdout, "%s: %s\n", "IPv4Address", lif_info->ipv4_addr); - fprintf(stdout, "%s: %d\n", "Prefixlen", lif_info->prefixlen); + /*fprintf(stdout, "%s: %s\n", "IPv4Address", lif_info->ipv4_addr); + fprintf(stdout, "%s: %d\n", "Prefixlen", lif_info->prefixlen);*/ fprintf(stdout, "%s: %s\n", "State", lif_info->state); 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" ,"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", "VlanList", lif_info->vlanlist); + fprintf(stdout, "%s: ", "VlanList"); + FOREACH_BIT_IN_BMP(lif_info->vlan_map, vid, MCLAGDCTL_VLAN_MAX) + { + if (vid_range_start == 0) + { + goto initvars; + } + else if ((vid - vid_range_end) == 1) + { + vid_range_end = vid; + continue; + } + if (vid_range_start == vid_range_end) + { + fprintf(stdout, "%d ", vid_range_start); + } + else + { + fprintf(stdout, "%d-%d ", vid_range_start, vid_range_end); + } +initvars: + vid_range_start = vid; + vid_range_end = vid; + } + if (vid_range_start != 0) + { + if(vid_range_start == vid_range_end) + { + fprintf(stdout, "%d ", vid_range_start); + } + else + { + fprintf(stdout, "%d-%d ", vid_range_start, vid_range_end); + } + } + fprintf(stdout, "\n"); + + fprintf(stdout, "%s: ", "MemberPorts"); + for (i = 0; i < lif_info->portchannel_member_count; i++) + { + memcpy(member_name, msg + lif_info_base, MAX_L_PORT_NAME); + fprintf(stdout, "%s", member_name); + if(i != (lif_info->portchannel_member_count-1)) + { + fprintf(stdout, ","); + } + lif_info_base += MAX_L_PORT_NAME; + } + fprintf(stdout, "\n"); } else { @@ -932,7 +984,7 @@ int main(int argc, char **argv) ret = EXIT_SUCCESS; - mclagdctl_disconnect: +mclagdctl_disconnect: mclagdctl_sock_close(); if (rcv_buf) diff --git a/src/iccpd/src/mclagdctl/mclagdctl.h b/src/iccpd/src/mclagdctl/mclagdctl.h index 91155ecb7321..34cbf48e4b18 100644 --- a/src/iccpd/src/mclagdctl/mclagdctl.h +++ b/src/iccpd/src/mclagdctl/mclagdctl.h @@ -18,10 +18,14 @@ * Maintainer: Jim Jiang from nephos */ +#define CONFIG_MCLAG_ENABLE_INTF_LEN 8320 /*max number of mclag enable portchannel is 520*/ + #define MCLAGDCTL_PARA1_LEN 16 #define MCLAGDCTL_PARA2_LEN 32 #define MCLAGDCTL_PARA3_LEN 64 -#define MCLAGDCTL_CMD_SIZE 4096 +#define MCLAGDCTL_CMD_SIZE CONFIG_MCLAG_ENABLE_INTF_LEN + 4096 +#define MCLAGDCTL_VLAN_BMP_MAX 128 +#define MCLAGDCTL_VLAN_MAX 4095 #define MCLAGDCTL_MAX_L_PORT_NANE 32 #define MCLAGDCTL_INET_ADDR_LEN 32 @@ -30,6 +34,61 @@ #define MCLAGDCTL_PORT_MEMBER_BUF_LEN 512 #define ETHER_ADDR_STR_LEN 18 +#define BMAP_ADD(bmap, id) \ + (bmap)[(id)>>5] |= (1<<((id)%32)) + +#define BMAP_DEL(bmap, id) \ + (bmap)[(id)>>5] & = ~(1<<((id)%32)) + +#define BMAP_MEMBER(bmap, id) \ + (((bmap)[(id)>>5] & (1<<((id)%32))) != 0) + +#define BMAP_CLEAR(bmap, len) \ + bmap_clr((bmap), (len)) + +#define FORECH_BMAP_FROM_LOW(bmap_all, id, max_id) \ + for((id)=0;(id)<=max_id;(id)++) \ + if(BMAP_MEMBER(bmap_all,id)) + +static unsigned int get_next_bit(unsigned int bitmap[], int bit, unsigned int max_bit) +{ + bit++; + while (bit < max_bit && bitmap[bit>>5]>>(bit%32)==0) + { + /*All of the rest bits of this array element are 0, + jump to the start bit of next bitmap array element*/ + bit = ((bit>>5) + 1)*32; + if (bit >= max_bit) + { + bit = max_bit; + return bit; + } + } + + if (bit >= max_bit) + { + bit = max_bit; + } + else + { + /*Traverses each bit of the current array element, + if not zero, return this bit*/ + int bit_end = ((bit>>5) + 1)*32; + for (; bit < bit_end; bit++) + { + if (bitmap[bit>>5] & (1<<(bit%32))) + { + return bit; + } + } + } + + return bit; +} +#define get_first_bit(bitmap, max_bit) get_next_bit(bitmap,-1, max_bit) +#define FOREACH_BIT_IN_BMP(bitmap, bit, max_bit)\ + for (bit = get_first_bit(bitmap, max_bit); bit < max_bit; bit = get_next_bit(bitmap, bit, max_bit)) + typedef int (*call_enca_msg_fun)(char *msg, int mclag_id, int argc, char **argv); typedef int (*call_parse_msg_fun)(char *msg, int data_len); @@ -127,7 +186,7 @@ struct mclagd_state 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]; + char enabled_po[CONFIG_MCLAG_ENABLE_INTF_LEN]; char loglevel[MCLAGDCTL_PARA1_LEN]; }; @@ -173,13 +232,13 @@ struct mclagd_local_if unsigned char l3_mode; unsigned char is_peer_link; - char portchannel_member_buf[MCLAGDCTL_PORT_MEMBER_BUF_LEN]; int po_id; /* Port Channel ID */ unsigned char po_active; char mlacp_state[MCLAGDCTL_PARA1_LEN]; unsigned char isolate_to_peer_link; - char vlanlist[MCLAGDCTL_PARA3_LEN]; + unsigned int vlan_map[MCLAGDCTL_VLAN_BMP_MAX]; + int portchannel_member_count; }; struct mclagd_peer_if diff --git a/src/iccpd/src/mlacp_fsm.c b/src/iccpd/src/mlacp_fsm.c index c56eb9051736..bed10d252044 100644 --- a/src/iccpd/src/mlacp_fsm.c +++ b/src/iccpd/src/mlacp_fsm.c @@ -76,7 +76,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); \ } \ @@ -301,6 +301,7 @@ static void mlacp_sync_send_syncNdiscInfo(struct CSM *csm) return; } + static void mlacp_sync_send_syncPortChannelInfo(struct CSM* csm) { struct System* sys = NULL; @@ -518,6 +519,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*/ @@ -1264,8 +1266,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; + } } } diff --git a/src/iccpd/src/mlacp_link_handler.c b/src/iccpd/src/mlacp_link_handler.c index 8bc533e387bd..dc5c4297f147 100644 --- a/src/iccpd/src/mlacp_link_handler.c +++ b/src/iccpd/src/mlacp_link_handler.c @@ -406,10 +406,14 @@ void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable) char *msg_buf = g_csm_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; @@ -438,8 +442,14 @@ void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable) /*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)) + { + ICCPD_LOG_ERR(__FUNCTION__, "Failed to write for %s, rc %d", + lif->name, rc); + } + } return; } @@ -472,21 +482,26 @@ void update_peerlink_isolate_from_all_csm_lif( struct LocalInterface *lif = NULL; struct IccpSyncdHDr * msg_hdr; mclag_sub_option_hdr_t * sub_msg; - char msg_buf[4096]; + char msg_buf[MCLAGDCTL_CMD_SIZE]; struct System *sys; + struct PortChannel_member *member = NULL; - char mlag_po_buf[512]; + char mlag_po_buf[CONFIG_MCLAG_ENABLE_INTF_LEN]; 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, 4095); - memset(mlag_po_buf, 0, 511); + memset(msg_buf, 0, MCLAGDCTL_CMD_SIZE); + memset(mlag_po_buf, 0, CONFIG_MCLAG_ENABLE_INTF_LEN); msg_hdr = (struct IccpSyncdHDr *)msg_buf; msg_hdr->ver = 1; @@ -552,10 +567,12 @@ void update_peerlink_isolate_from_all_csm_lif( 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", lif->portchannel_member_buf); + LIST_FOREACH(member, &(lif->member_list), member_next) + { + 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", member->name); + } } } @@ -575,7 +592,13 @@ void update_peerlink_isolate_from_all_csm_lif( /*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)) + { + ICCPD_LOG_ERR(__FUNCTION__, "Failed to write, rc %d", rc); + } + } return; } @@ -757,7 +780,7 @@ static void update_l2_po_state(struct CSM *csm, }*/ /*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; @@ -918,6 +941,7 @@ void syn_ndisc_info_to_peer(struct CSM *csm, struct LocalInterface *local_if) return; } + void update_stp_peer_link(struct CSM *csm, struct PeerInterface *pif, int po_state, int new_create) @@ -952,7 +976,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; @@ -1009,16 +1033,27 @@ void iccp_get_fdb_change_from_syncd( void) return; } -void iccp_send_fdb_entry_to_syncd( struct MACMsg* mac_msg, uint8_t mac_type) +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; + ssize_t rc; + char null_mac[ETHER_ADDR_STR_LEN] = "00:00:00:00:00:00"; sys = system_get_instance(); if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return; + } + + if (strcmp(mac_msg->mac_str, null_mac) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address, do not send to Syncd."); return; + } memset(msg_buf, 0, 512); @@ -1040,15 +1075,52 @@ void iccp_send_fdb_entry_to_syncd( struct MACMsg* mac_msg, uint8_t mac_type) /*send msg*/ if (sys->sync_fd > 0 ) - 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)) + { + ICCPD_LOG_ERR(__FUNCTION__, "Failed to write, rc %d", rc); + } + } + else + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid sync_fd, failed to write, fd %d", sys->sync_fd); + } return; } -void add_mac_to_chip(struct MACMsg* mac_msg, uint8_t mac_type) +void add_mac_to_chip(struct CSM *csm, struct MACMsg* mac_msg, uint8_t mac_type) { + /*If this MAC is redirected to peer-link, peer-link must be up and in the same vlan with MAC*/ + if (strlen(csm->peer_itf_name) != 0 && strcmp(mac_msg->ifname, csm->peer_itf_name) == 0) + { + struct VLAN_ID *vlan = NULL; + struct VLAN_ID vlan_key = { 0 }; + + /*Peer-link must be exist and up*/ + if (!csm->peer_link_if || csm->peer_link_if->state != PORT_STATE_UP) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s vlan-id %d to peer-link, but peer-link does not exist or not up.", + mac_msg->mac_str, mac_msg->vid); + return; + } + + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = mac_msg->vid; + + /*MAC and peer-link must be in the same vlan*/ + vlan = RB_FIND(vlan_rb_tree, &(csm->peer_link_if->vlan_tree), &vlan_key); + if (!vlan) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s vlan-id %d to peer-link, but peer-link is not in the same vlan.", + mac_msg->mac_str, mac_msg->vid); + return; + } + } + 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); return; } @@ -1056,7 +1128,7 @@ void add_mac_to_chip(struct MACMsg* mac_msg, uint8_t mac_type) 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); return; } @@ -1089,7 +1161,7 @@ uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg* mac_msg, uint8_t { 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); - } + } } } else/*set age flag*/ @@ -1171,7 +1243,7 @@ static void update_l2_mac_state(struct CSM *csm, 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); + add_mac_to_chip(csm, mac_msg, MAC_TYPE_DYNAMIC); } else { @@ -1210,7 +1282,7 @@ static void update_l2_mac_state(struct CSM *csm, 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); + add_mac_to_chip(csm, mac_msg, mac_msg->fdb_type); } else { @@ -1223,7 +1295,7 @@ static void update_l2_mac_state(struct CSM *csm, 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); + add_mac_to_chip(csm, mac_msg, mac_msg->fdb_type); } } } @@ -1340,7 +1412,10 @@ void mlacp_peer_conn_handler(struct CSM* csm) return; if ((sys = system_get_instance()) == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); return; + } if (csm->warm_reboot_disconn_time != 0) { @@ -1364,6 +1439,8 @@ void mlacp_peer_conn_handler(struct CSM* csm) mlacp_clean_fdb(); } + sleep(1); + iccp_get_fdb_change_from_syncd(); sys->csm_trans_time = time(NULL); @@ -1392,6 +1469,11 @@ void mlacp_peer_disconn_handler(struct CSM* csm) if (!csm) return; + if (MLACP(csm).current_state != MLACP_STATE_EXCHANGE) + { + return; + } + if ((sys = system_get_instance()) == NULL) return; @@ -1472,7 +1554,7 @@ void mlacp_peerlink_up_handler(struct CSM* csm) mac_msg->ifname, mac_msg->mac_str, 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(csm, mac_msg, MAC_TYPE_DYNAMIC); } return; @@ -1616,7 +1698,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) { @@ -1644,11 +1729,21 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch size_t msg_len = 0; uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/ struct CSM *first_csm = NULL; + char null_mac[ETHER_ADDR_STR_LEN] = "00:00:00:00:00:00"; struct LocalInterface *lif_po = NULL, *mac_lif = NULL; if (!(sys = system_get_instance())) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance"); + return; + } + + if (strcmp(mac_str, null_mac) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address from syncd, do not add."); return; + } /* create MAC msg*/ memset(buf, 0, MAX_BUFSIZE); @@ -1716,7 +1811,11 @@ 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_str, vid); return; + } sprintf(mac_msg->ifname, "%s", ifname); sprintf(mac_msg->origin_ifname, "%s", ifname); @@ -1763,13 +1862,22 @@ 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 (mac_lif->state == PORT_STATE_DOWN && mac_msg->fdb_type != MAC_TYPE_STATIC) { del_mac_from_chip(mac_msg); return; } + /*If the recv mac port is peer-link, that must be added by iccpd, delete it*/ + if (strcmp(csm->peer_itf_name, mac_msg->ifname) == 0) + { + ICCPD_LOG_NOTICE(__FUNCTION__, "MAC learnt from peerlink, vid %d mac %s, delete it.", vid, mac_str); + 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", @@ -1831,7 +1939,7 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch 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(csm, mac_info, MAC_TYPE_DYNAMIC); 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); @@ -1869,7 +1977,7 @@ void do_mac_update_from_syncd(char mac_str[ETHER_ADDR_STR_LEN], uint16_t vid, ch if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) { - add_mac_to_chip(mac_info, MAC_TYPE_DYNAMIC); + add_mac_to_chip(csm, 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); } @@ -1884,7 +1992,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(csm, mac_info, MAC_TYPE_DYNAMIC); } } } @@ -1979,7 +2087,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,12 +2370,12 @@ 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 data_len = 0; int ret = 0; struct mclagd_reply_hdr *hd = NULL; int len_tmp = 0; - ret = iccp_local_if_dump(&Pbuf, &lif_num, mclag_id); + ret = iccp_local_if_dump(&Pbuf, &data_len, mclag_id); if (ret != EXEC_TYPE_SUCCESS) { len_tmp = sizeof(struct mclagd_reply_hdr); @@ -2284,10 +2395,10 @@ void mclagd_ctl_handle_dump_local_portlist(int client_fd, int mclag_id) hd = (struct mclagd_reply_hdr *)(Pbuf + sizeof(int)); hd->exec_result = EXEC_TYPE_SUCCESS; hd->info_type = INFO_TYPE_DUMP_LOCAL_PORTLIST; - hd->data_len = lif_num * sizeof(struct mclagd_local_if); - len_tmp = (hd->data_len + sizeof(struct mclagd_reply_hdr)); + hd->data_len = data_len - MCLAGD_REPLY_INFO_HDR; + 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); + mclagd_ctl_sock_write(client_fd, Pbuf, data_len); if (Pbuf) free(Pbuf); diff --git a/src/iccpd/src/mlacp_sync_prepare.c b/src/iccpd/src/mlacp_sync_prepare.c index ef1cd244a90a..c5ca70149576 100644 --- a/src/iccpd/src/mlacp_sync_prepare.c +++ b/src/iccpd/src/mlacp_sync_prepare.c @@ -465,9 +465,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 +500,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 ) { diff --git a/src/iccpd/src/mlacp_sync_update.c b/src/iccpd/src/mlacp_sync_update.c index b82fc1c16cb9..6a4c72544d46 100644 --- a/src/iccpd/src/mlacp_sync_update.c +++ b/src/iccpd/src/mlacp_sync_update.c @@ -34,6 +34,7 @@ #include "../include/iccp_consistency_check.h" #include "../include/port.h" #include "../include/iccp_netlink.h" +#include "../include/openbsd_tree.h" /***************************************** * Port-Conf Update * @@ -166,11 +167,18 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * struct MACMsg *mac_msg = NULL, mac_data; struct LocalInterface* local_if = NULL; uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/ + char null_mac[ETHER_ADDR_STR_LEN] = "00:00:00:00:00:00"; 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"); + if (strcmp(MacData->mac_str, null_mac) == 0) + { + ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address from peer, do not add."); + return 0; + } + /*Find the interface in MCLAG interface list*/ LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next) { @@ -225,7 +233,7 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ); /*Send mac add message to mclagsyncd*/ - add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC); + add_mac_to_chip(csm, mac_msg, MAC_TYPE_DYNAMIC); } else { @@ -255,16 +263,19 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * } } } - else + else /*From mclag enable intf*/ { - /*Remove MAC_AGE_LOCAL flag*/ - mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); + if (local_if->state == PORT_STATE_UP) + { + /*Remove MAC_AGE_LOCAL flag*/ + mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0); - /*Update local item*/ - memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME); + /*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); + /*from MCLAG port and the local port is up, add mac to ASIC to update port*/ + add_mac_to_chip(csm, mac_msg, MAC_TYPE_DYNAMIC); + } } } } @@ -345,12 +356,12 @@ int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData * { /*Send mac add message to mclagsyncd*/ if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP) - add_mac_to_chip(mac_msg, mac_msg->fdb_type); + add_mac_to_chip(csm, mac_msg, mac_msg->fdb_type); } else { /*from MCLAG port and the local port is up*/ - add_mac_to_chip(mac_msg, mac_msg->fdb_type); + add_mac_to_chip(csm, mac_msg, mac_msg->fdb_type); } } } @@ -453,12 +464,12 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) if (strncmp(arp_entry->ifname, "Vlan", 4) == 0) { - peer_link_if = local_if_find_by_name(csm->peer_itf_name); + peer_link_if = csm->peer_link_if; if (peer_link_if && !local_if_is_l3_mode(peer_link_if)) { /* Is peer-linlk itf belong to a vlan the same as peer?*/ - LIST_FOREACH(vlan_id_list, &(peer_link_if->vlan_list), port_next) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(peer_link_if->vlan_tree)) { if (!vlan_id_list->vlan_itf) continue; @@ -487,7 +498,7 @@ 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) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(local_if->vlan_tree)) { if (!vlan_id_list->vlan_itf) continue; @@ -542,7 +553,7 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) return MCLAG_ERROR; } } - else + else if (arp_entry->op_type == NEIGH_SYNC_DEL) { if (iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 0, arp_entry->mac_addr, arp_entry->ifname) < 0) { @@ -551,6 +562,11 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) return MCLAG_ERROR; } } + else + { + ICCPD_LOG_ERR(__FUNCTION__, "ARP op type %d is invalid", arp_entry->op_type); + 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);*/ @@ -589,6 +605,7 @@ int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry) arp_msg->ipv4_addr = arp_entry->ipv4_addr; arp_msg->op_type = arp_entry->op_type; memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN); + time(&arp_msg->sync_time); if (iccp_csm_init_msg(&msg, (char*)arp_msg, sizeof(struct ARPMsg)) == 0) { mlacp_enqueue_arp(csm, msg); @@ -661,12 +678,12 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) if (strncmp(ndisc_entry->ifname, "Vlan", 4) == 0) { - peer_link_if = local_if_find_by_name(csm->peer_itf_name); + peer_link_if = csm->peer_link_if; if (peer_link_if && !local_if_is_l3_mode(peer_link_if)) { /* Is peer-linlk itf belong to a vlan the same as peer? */ - LIST_FOREACH(vlan_id_list, &(peer_link_if->vlan_list), port_next) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(peer_link_if->vlan_tree)) { if (!vlan_id_list->vlan_itf) continue; @@ -696,7 +713,7 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_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) + RB_FOREACH(vlan_id_list, vlan_rb_tree, &(local_if->vlan_tree)) { if (!vlan_id_list->vlan_itf) continue; @@ -752,7 +769,7 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) } } - else + else if (ndisc_entry->op_type == NEIGH_SYNC_DEL) { if (iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 0, ndisc_entry->mac_addr, ndisc_entry->ifname) < 0) { @@ -762,6 +779,11 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) } } + else + { + ICCPD_LOG_ERR(__FUNCTION__, "ND op type %d is invalid", ndisc_entry->op_type); + 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); */ } @@ -799,6 +821,7 @@ int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry) memcpy((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16); ndisc_msg->op_type = ndisc_entry->op_type; memcpy(ndisc_msg->mac_addr, ndisc_entry->mac_addr, ETHER_ADDR_LEN); + time(&ndisc_msg->sync_time); if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, sizeof(struct NDISCMsg)) == 0) { mlacp_enqueue_ndisc(csm, msg); @@ -868,7 +891,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; } 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..fb189d90df9f 100644 --- a/src/iccpd/src/port.c +++ b/src/iccpd/src/port.c @@ -30,6 +30,31 @@ #include "../include/iccp_csm.h" #include "../include/iccp_netlink.h" #include "../include/scheduler.h" +#include "../include/mlacp_link_handler.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); + +static int lif_node_compare(const struct LocalInterface *p_lif_node1, const struct LocalInterface *p_lif_node2) +{ + if (p_lif_node1->ifindex < p_lif_node2->ifindex) + return -1; + + if (p_lif_node1->ifindex > p_lif_node2->ifindex) + return 1; + + return 0; +} +RB_GENERATE(lif_rb_tree, LocalInterface, lif_entry, lif_node_compare); void local_if_init(struct LocalInterface* local_if) { @@ -50,7 +75,9 @@ void local_if_init(struct LocalInterface* local_if) local_if->prefixlen = 32; local_if->csm = NULL; local_if->isolate_to_peer_link = 0; - LIST_INIT(&local_if->vlan_list); + local_if->portchannel_member_count = 0; + LIST_INIT(&local_if->member_list); + RB_INIT(vlan_rb_tree, &local_if->vlan_tree); return; } @@ -140,7 +167,7 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) ifname, local_if->ifindex, local_if->mac_addr[0], local_if->mac_addr[1], local_if->mac_addr[2], local_if->mac_addr[3], local_if->mac_addr[4], local_if->mac_addr[5], local_if->state ? "down" : "up"); - LIST_INSERT_HEAD(&(sys->lif_list), local_if, system_next); + RB_INSERT(lif_rb_tree, &(sys->lif_tree), 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*/ @@ -156,51 +183,63 @@ struct LocalInterface* local_if_create(int ifindex, char* ifname, int type) LIST_FOREACH(cif, &(csm->if_bind_list), csm_next) { if (strcmp(ifname, cif->name) == 0) + { mlacp_bind_port_channel_to_csm(csm, ifname); + } } } return local_if; } +#define IFINDEX_STR_LEN 32 struct LocalInterface* local_if_find_by_name(const char* ifname) { - struct System* sys = NULL; struct LocalInterface* local_if = NULL; + FILE *fp = NULL; + char ifindex[IFINDEX_STR_LEN] = {0}; + char file_name[128] = "/sys/class/net/"; + char end_prefix[10] = "/ifindex"; if (!ifname) return NULL; - if (!(sys = system_get_instance())) - return NULL; + strcat(file_name, ifname); + strcat(file_name, end_prefix); - LIST_FOREACH(local_if, &(sys->lif_list), system_next) + fp = fopen(file_name, "r"); + if (fp == NULL) { - if (strcmp(local_if->name, ifname) == 0) - return local_if; + ICCPD_LOG_WARN(__FUNCTION__, "Can not get ifindex of local interface (%s)", ifname); + return NULL; } - return NULL; + fread(ifindex, IFINDEX_STR_LEN, 1, fp); + (void)fclose(fp); + + local_if = local_if_find_by_ifindex(atoi(ifindex)); + + return local_if; } struct LocalInterface* local_if_find_by_ifindex(int ifindex) { struct System* sys = NULL; struct LocalInterface* local_if = NULL; + struct LocalInterface lif_key = { 0 }; + + memset(&lif_key, 0, sizeof(struct LocalInterface)); + lif_key.ifindex = ifindex; if ((sys = system_get_instance()) == NULL) return NULL; - LIST_FOREACH(local_if, &(sys->lif_list), system_next) - { - if (local_if->ifindex == ifindex) - return local_if; - } + local_if = RB_FIND(lif_rb_tree, &(sys->lif_tree), &lif_key); - return NULL; + return local_if; } -struct LocalInterface* local_if_find_by_po_id(int po_id) +/*struct LocalInterface* local_if_find_by_po_id(int po_id) { struct System* sys = NULL; struct LocalInterface* local_if = NULL; @@ -215,23 +254,46 @@ struct LocalInterface* local_if_find_by_po_id(int po_id) } return NULL; -} +}*/ static 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 }; + char ifname[MAX_L_PORT_NAME]; + int i; + int len; + + if (lif_vlan->type != IF_T_VLAN) + return; + + /* Get vlan id from vlan name*/ + sprintf(ifname, "%s", lif_vlan->name); + len = strlen(ifname); + + for (i = 0; i < len; ++i) + if (ifname[i] >= '0' && ifname[i] <= '9') + break; + if (i >= len) + return; + + memset(&vlan_key, 0, sizeof(struct VLAN_ID)); + vlan_key.vid = atoi(&ifname[i]); if ((sys = system_get_instance()) != NULL) { - LIST_FOREACH(lif, &(sys->lif_list), system_next) + RB_FOREACH (lif, lif_rb_tree, &(sys->lif_tree)) { - LIST_FOREACH(vlan, &(lif->vlan_list), port_next) - { - if (lif_vlan != vlan->vlan_itf) - continue; + if (lif->type == IF_T_VLAN) + continue; + vlan = RB_FIND(vlan_rb_tree, &(lif->vlan_tree), &vlan_key); + if (vlan) + { + ICCPD_LOG_DEBUG(__FUNCTION__, "%s is member of Vlan (%d)", lif_vlan->name, vlan->vid); vlan->vlan_itf = NULL; } } @@ -246,6 +308,9 @@ static void local_if_po_remove(struct LocalInterface *lif_po) struct CSM *csm = NULL; struct LocalInterface *lif = NULL; + if (lif_po->type != IF_T_PORT_CHANNEL) + return; + /* remove all po member*/ if ((sys = system_get_instance()) != NULL) { @@ -275,19 +340,14 @@ static void local_if_remove(struct LocalInterface *lif) return; } -void local_if_destroy(char *ifname) +void local_if_destroy(struct LocalInterface *lif) { - struct LocalInterface* lif = NULL; struct CSM *csm = NULL; struct System *sys = NULL; if (!(sys = system_get_instance())) return; - lif = local_if_find_by_name(ifname); - if (!lif) - return; - ICCPD_LOG_WARN(__FUNCTION__, "Destroy interface %s, %d\n", lif->name, lif->ifindex); if (lif->type == IF_T_VLAN) @@ -298,7 +358,7 @@ void local_if_destroy(char *ifname) local_if_remove(lif); csm = lif->csm; - if (csm && csm->peer_link_if && strcmp(csm->peer_link_if->name, ifname) == 0) + if (csm && csm->peer_link_if && strcmp(csm->peer_link_if->name, lif->name) == 0) { /*if the peerlink interface is not created, peer connection can not establish*/ scheduler_session_disconnect_handler(csm); @@ -313,7 +373,7 @@ void local_if_destroy(char *ifname) to_sys_purge: /* sys purge */ - LIST_REMOVE(lif, system_next); + LIF_RB_REMOVE(lif_rb_tree, &(sys->lif_tree), lif); if (lif->csm) LIST_REMOVE(lif, mlacp_next); LIST_INSERT_HEAD(&(sys->lif_purge_list), lif, system_purge_next); @@ -321,7 +381,7 @@ void local_if_destroy(char *ifname) to_mlacp_purge: /* sys & mlacp purge */ - LIST_REMOVE(lif, system_next); + LIF_RB_REMOVE(lif_rb_tree, &(sys->lif_tree), lif); LIST_REMOVE(lif, mlacp_next); LIST_INSERT_HEAD(&(sys->lif_purge_list), lif, system_purge_next); LIST_INSERT_HEAD(&(MLACP(csm).lif_purge_list), lif, mlacp_purge_next); @@ -350,7 +410,7 @@ void local_if_change_flag_clear(void) if ((sys = system_get_instance()) == NULL) return; - LIST_FOREACH(lif, &(sys->lif_list), system_next) + RB_FOREACH (lif, lif_rb_tree, &(sys->lif_tree)) { if (lif->changed == 1) { @@ -378,6 +438,7 @@ void local_if_purge_clear(void) if (lif->mlacp_purge_next.le_next != 0 && lif->mlacp_purge_next.le_prev != 0) LIST_REMOVE(lif, mlacp_purge_next); local_if_del_all_vlan(lif); + local_if_del_all_portchannel_member(lif); free(lif); } @@ -392,6 +453,7 @@ void local_if_finalize(struct LocalInterface* lif) return; local_if_del_all_vlan(lif); + local_if_del_all_portchannel_member(lif); free(lif); @@ -470,15 +532,14 @@ 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; @@ -500,32 +561,75 @@ void peer_if_destroy(struct PeerInterface* pif) 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; + vlan_info_init(vlan); + vlan->vid = vid; + vlan->vlan_itf = local_if_find_by_name(vlan_name); + ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s to VLAN %d", local_if->name, vid); 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); + + /* If peer-link add to vlan, check the MAC list that redirected to the peer-link */ + if (local_if->is_peer_link) + { + struct CSM* csm; + struct System* sys = NULL; + struct Msg* msg = NULL; + struct MACMsg* mac_msg = NULL; + + sys = system_get_instance(); + if (sys == NULL) + { + ICCPD_LOG_ERR(__FUNCTION__, "Sys get failure"); + return 0; + } + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + if (csm->peer_link_if == local_if) + { + break; + } + } + + if (csm != NULL) + { + /* Check the MAC list that redirected to the peer-link, if the vlan of MAC is */ + /* the same as the vlan currently added, install the MAC to ASIC*/ + TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + { + mac_msg = (struct MACMsg*)msg->buf; + + if (strlen(csm->peer_itf_name) != 0 && strcmp(mac_msg->ifname, csm->peer_itf_name) == 0 + && mac_msg->vid == vid) + { + add_mac_to_chip(csm, mac_msg, MAC_TYPE_DYNAMIC); + } + } + } + else + { + ICCPD_LOG_ERR(__FUNCTION__, "CSM get failure for add %s to VLAN %d", local_if->name, vid); + } + } } - 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); @@ -534,36 +638,82 @@ int local_if_add_vlan(struct LocalInterface* local_if, uint16_t vid) void local_if_del_vlan(struct LocalInterface* local_if, uint16_t vid) { - struct VLAN_ID *vlan = NULL; - - /* traverse 1 time */ - LIST_FOREACH(vlan, &(local_if->vlan_list), port_next) + if (local_if == NULL) { - if (vlan->vid == vid) - break; + return; } - if (vlan != NULL) + /* If peer-link remove from vlan, check the MAC list that redirected to the peer-link */ + if (local_if->is_peer_link) { - LIST_REMOVE(vlan, port_next); - free(vlan); - local_if->port_config_sync = 1; + struct CSM* csm; + struct System* sys = NULL; + struct Msg* msg = NULL; + struct MACMsg* mac_msg = NULL; + + sys = system_get_instance(); + if (sys == NULL) + { + return; + } + + LIST_FOREACH(csm, &(sys->csm_list), next) + { + if (csm->peer_link_if == local_if ) + { + break; + } + } + + if (csm == NULL) + { + return; + } + + /* Check the MAC list that redirected to the peer-link, if the vlan of MAC is */ + /* the same as the vlan currently added, delete the MAC from ASIC*/ + TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail) + { + mac_msg = (struct MACMsg*)msg->buf; + + if (strlen(csm->peer_itf_name) != 0 && strcmp(mac_msg->ifname, csm->peer_itf_name) == 0 + && mac_msg->vid == vid) + { + del_mac_from_chip(mac_msg); + } + } } - ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", local_if->name, vid); + local_if->port_config_sync = 1; return; } +void local_if_del_all_portchannel_member(struct LocalInterface* lif) +{ + struct PortChannel_member *member = NULL; + + ICCPD_LOG_NOTICE(__FUNCTION__, "Remove all portchannel_member from %s", lif->name); + while (!LIST_EMPTY(&(lif->member_list))) + { + member = LIST_FIRST(&(lif->member_list)); + LIST_REMOVE(member, member_next); + free(member); + } + + LIST_INIT(&(lif->member_list)); + 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); free(vlan); } @@ -574,19 +724,15 @@ 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) { @@ -594,12 +740,13 @@ int peer_if_add_vlan(struct PeerInterface* peer_if, uint16_t vlan_id) if (!peer_vlan) return MCLAG_ERROR; + vlan_info_init(peer_vlan); + peer_vlan->vid = vlan_id; + 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); + 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 +757,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 +777,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); } diff --git a/src/iccpd/src/scheduler.c b/src/iccpd/src/scheduler.c index 0ff9d4f5e083..32b982a19cdd 100644 --- a/src/iccpd/src/scheduler.c +++ b/src/iccpd/src/scheduler.c @@ -308,6 +308,7 @@ void scheduler_init() /*Get kernel interface and port */ iccp_sys_local_if_list_get_init(); iccp_sys_local_if_list_get_addr(); + iccp_get_if_vlan_info_from_netlink(); /*Interfaces must be created before this func called*/ iccp_config_from_file(sys->config_file_path); diff --git a/src/iccpd/src/system.c b/src/iccpd/src/system.c index 33aca67f8079..5afa1f96d511 100644 --- a/src/iccpd/src/system.c +++ b/src/iccpd/src/system.c @@ -53,6 +53,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; @@ -63,7 +64,7 @@ void system_init(struct System* sys) sys->warmboot_start = 0; sys->warmboot_exit = 0; LIST_INIT(&(sys->csm_list)); - LIST_INIT(&(sys->lif_list)); + RB_INIT(lif_rb_tree, &sys->lif_tree); LIST_INIT(&(sys->lif_purge_list)); sys->log_file_path = strdup("/var/log/iccpd.log"); @@ -88,6 +89,7 @@ void system_finalize() struct System* sys = NULL; struct CSM* csm = NULL; struct LocalInterface* local_if = NULL; + struct LocalInterface* lif_temp = NULL; if ((sys = system_get_instance()) == NULL ) return; @@ -101,10 +103,9 @@ void system_finalize() } /* Release all port objects */ - while (!LIST_EMPTY(&(sys->lif_list))) + RB_FOREACH_SAFE(local_if, lif_rb_tree, &(sys->lif_tree), lif_temp) { - local_if = LIST_FIRST(&(sys->lif_list)); - LIST_REMOVE(local_if, system_next); + LIF_RB_REMOVE(lif_rb_tree, &(sys->lif_tree), local_if); local_if_finalize(local_if); }