MCLAG feature for SONIC (#2514)
* MCLAG feature for sonic * MCLAG feature for sonic * remove binary file * remove unused dockerfile update docker-iccpd to stretch-based container Signed-off-by: shine.chen <shine.chen@nephosinc.com> * minor fix for isolation port setting Signed-off-by: shine.chen <shine.chen@nephosinc.com> * iccpd docker would start on demand Signed-off-by: shine.chen <shine.chen@nephosinc.com> * Add x attribute on mclagdctl file Signed-off-by: shine.chen <shine.chen@nephosinc.com> * add warm-reboot support for MCLAG Signed-off-by: shine.chen <shine.chen@nephosinc.com> * merge to master branch and reformat iccpd file Signed-off-by: shine.chen <shine.chen@nephosinc.com> * fix some bugs and make peer-link configuration optional Signed-off-by: shine.chen <shine.chen@nephosinc.com> * refactor code per Brcm review Signed-off-by: shine.chen <shine.chen@nephosinc.com> * correct a typo Signed-off-by: shine.chen <shine.chen@nephosinc.com> * * optimize iccpd arp/mac sync process * refine code according to brcm opinoin * unify function return value Signed-off-by: shine.chen <shine.chen@nephosinc.com> * * optimize warm-reboot process * estabish iccpd connection with configurated src-ip Signed-off-by: shine.chen <shine.chen@nephosinc.com> * fix a typo Signed-off-by: shine.chen <shine.chen@nephosinc.com> * optimize some code * add some debug info * optimize bridge mac setting * fix vlan mac sync issue on standby node Signed-off-by: shine.chen <shine.chen@mediatek.com> * optimize some code Signed-off-by: shine.chen <shine.chen@mediatek.com> * fix some bugs for warm-reboot Signed-off-by: shine.chen <shine.chen@mediatek.com> * refine log level Signed-off-by: shine.chen <shine.chen@mediatek.com> * refine iccpd syslog & skip arp packet whose src ip is local ip Signed-off-by: shine.chen <shine.chen@mediatek.com> * remove iccpd dependency with teamd Signed-off-by: shine.chen <shine.chen@mediatek.com> * print log level when dump mclag status Signed-off-by: shine.chen <shine.chen@mediatek.com> * revise per community review Signed-off-by: shine.chen <shine.chen@mediatek.com> Co-authored-by: shine.chen <shine.chen@nephosinc.com> Co-authored-by: shine.chen <shine.chen@mediatek.com>
This commit is contained in:
parent
abbd871d55
commit
524cf9e56a
47
dockers/docker-iccpd/Dockerfile.j2
Normal file
47
dockers/docker-iccpd/Dockerfile.j2
Normal file
@ -0,0 +1,47 @@
|
||||
{% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files %}
|
||||
FROM docker-config-engine-stretch
|
||||
|
||||
ARG docker_container_name
|
||||
RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf
|
||||
|
||||
## Make apt-get non-interactive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -f -y \
|
||||
libdbus-1-3 \
|
||||
libdaemon0 \
|
||||
libpython2.7 \
|
||||
# Install redis-tools dependencies
|
||||
# TODO: implicitly install dependencies
|
||||
libatomic1 \
|
||||
libjemalloc1 \
|
||||
liblua5.1-0 \
|
||||
lua-bitop \
|
||||
lua-cjson
|
||||
|
||||
RUN apt-get -y install ebtables
|
||||
RUN apt-get -y install -f kmod
|
||||
|
||||
COPY \
|
||||
{% for deb in docker_iccpd_debs.split(' ') -%}
|
||||
debs/{{ deb }}{{' '}}
|
||||
{%- endfor -%}
|
||||
debs/
|
||||
|
||||
RUN dpkg -i \
|
||||
{% for deb in docker_iccpd_debs.split(' ') -%}
|
||||
debs/{{ deb }}{{' '}}
|
||||
{%- endfor %}
|
||||
|
||||
COPY ["start.sh", "iccpd.sh", "/usr/bin/"]
|
||||
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
|
||||
COPY ["iccpd.j2", "/usr/share/sonic/templates/"]
|
||||
|
||||
RUN chmod +x /usr/bin/start.sh /usr/bin/iccpd.sh
|
||||
RUN apt-get clean -y && \
|
||||
apt-get autoclean -y && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /debs
|
||||
|
||||
ENTRYPOINT ["/usr/bin/supervisord"]
|
10
dockers/docker-iccpd/base_image_files/mclagdctl
Executable file
10
dockers/docker-iccpd/base_image_files/mclagdctl
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
DOCKER_EXEC_FLAGS="i"
|
||||
|
||||
# Determine whether stdout is on a terminal
|
||||
if [ -t 1 ] ; then
|
||||
DOCKER_EXEC_FLAGS+="t"
|
||||
fi
|
||||
|
||||
docker exec -$DOCKER_EXEC_FLAGS iccpd mclagdctl "$@"
|
11
dockers/docker-iccpd/iccpd.j2
Normal file
11
dockers/docker-iccpd/iccpd.j2
Normal file
@ -0,0 +1,11 @@
|
||||
{% for mclag_id in MC_LAG %}
|
||||
mclag_id:{{mclag_id}}
|
||||
local_ip:{{MC_LAG[mclag_id]['local_ip']}}
|
||||
peer_ip:{{MC_LAG[mclag_id]['peer_ip']}}
|
||||
{% if MC_LAG[mclag_id].has_key('peer_link') %}
|
||||
peer_link:{{MC_LAG[mclag_id]['peer_link']}}
|
||||
{% endif %}
|
||||
mclag_interface:{{MC_LAG[mclag_id]['mclag_interface']}}
|
||||
{% endfor %}
|
||||
system_mac:{{DEVICE_METADATA['localhost']['mac']}}
|
||||
|
17
dockers/docker-iccpd/iccpd.sh
Normal file
17
dockers/docker-iccpd/iccpd.sh
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function start_app {
|
||||
rm -f /var/run/iccpd/*
|
||||
mclagsyncd &
|
||||
iccpd
|
||||
}
|
||||
|
||||
function clean_up {
|
||||
pkill -9 mclagsyncd
|
||||
pkill -9 iccpd
|
||||
exit
|
||||
}
|
||||
|
||||
trap clean_up SIGTERM SIGKILL
|
||||
start_app
|
||||
read
|
18
dockers/docker-iccpd/start.sh
Normal file
18
dockers/docker-iccpd/start.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
ICCPD_CONF_PATH=/etc/iccpd
|
||||
|
||||
rm -rf $ICCPD_CONF_PATH
|
||||
mkdir -p $ICCPD_CONF_PATH
|
||||
|
||||
sonic-cfggen -d -t /usr/share/sonic/templates/iccpd.j2 > $ICCPD_CONF_PATH/iccpd.conf
|
||||
|
||||
mkdir -p /var/sonic
|
||||
echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status
|
||||
|
||||
rm -f /var/run/rsyslogd.pid
|
||||
|
||||
supervisorctl start rsyslogd
|
||||
|
||||
supervisorctl start iccpd
|
29
dockers/docker-iccpd/supervisord.conf
Normal file
29
dockers/docker-iccpd/supervisord.conf
Normal file
@ -0,0 +1,29 @@
|
||||
[supervisord]
|
||||
logfile_maxbytes=1MB
|
||||
logfile_backups=2
|
||||
nodaemon=true
|
||||
|
||||
[program:start.sh]
|
||||
command=/usr/bin/start.sh
|
||||
priority=1
|
||||
autostart=true
|
||||
autorestart=false
|
||||
stdout_logfile=syslog
|
||||
stderr_logfile=syslog
|
||||
|
||||
[program:rsyslogd]
|
||||
command=/usr/sbin/rsyslogd -n
|
||||
priority=2
|
||||
autostart=false
|
||||
autorestart=false
|
||||
stdout_logfile=syslog
|
||||
stderr_logfile=syslog
|
||||
|
||||
[program:iccpd]
|
||||
command=/usr/bin/iccpd.sh
|
||||
priority=3
|
||||
autostart=false
|
||||
autorestart=false
|
||||
stdout_logfile=syslog
|
||||
stderr_logfile=syslog
|
||||
|
@ -231,6 +231,9 @@ start() {
|
||||
{%- if docker_container_name != "database" %}
|
||||
-v /usr/share/sonic/device/$PLATFORM/$HWSKU/$DEV:/usr/share/sonic/hwsku:ro \
|
||||
{%- endif %}
|
||||
{%- if docker_container_name == "iccpd" %}
|
||||
-v /lib/modules:/lib/modules:ro \
|
||||
{%- endif %}
|
||||
{%- if sonic_asic_platform != "mellanox" %}
|
||||
--tmpfs /tmp \
|
||||
{%- endif %}
|
||||
|
13
files/build_templates/iccpd.service.j2
Normal file
13
files/build_templates/iccpd.service.j2
Normal file
@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=ICCPD container
|
||||
Requires=updategraph.service swss.service
|
||||
After=updategraph.service swss.service
|
||||
|
||||
[Service]
|
||||
User={{ sonicadmin_user }}
|
||||
ExecStartPre=/usr/bin/{{docker_container_name}}.sh start
|
||||
ExecStart=/usr/bin/{{docker_container_name}}.sh wait
|
||||
ExecStop=/usr/bin/{{docker_container_name}}.sh stop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target swss.service
|
@ -427,6 +427,9 @@ if [ -f {{service}} ]; then
|
||||
echo "{{service}}" | sudo tee -a $GENERATED_SERVICE_FILE
|
||||
fi
|
||||
{% endfor %}
|
||||
if [ -f iccpd.service ]; then
|
||||
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable iccpd.service
|
||||
fi
|
||||
sudo LANG=C chroot $FILESYSTEM_ROOT fuser -km /sys || true
|
||||
sudo LANG=C chroot $FILESYSTEM_ROOT umount -lf /sys
|
||||
{% endif %}
|
||||
|
@ -115,6 +115,10 @@ SONIC_DPKG_CACHE_SOURCE ?= /var/cache/sonic/artifacts
|
||||
# Default VS build memory preparation
|
||||
DEFAULT_VS_PREPARE_MEM = yes
|
||||
|
||||
|
||||
# ENABLE_ICCPD - build docker-iccpd for mclag support
|
||||
ENABLE_ICCPD = y
|
||||
|
||||
# ENABLE_SYSTEM_SFLOW - build docker-sonic-sflow for sFlow support
|
||||
ENABLE_SFLOW = y
|
||||
|
||||
@ -126,3 +130,4 @@ ENABLE_RESTAPI = n
|
||||
|
||||
# ENABLE_NAT - build docker-sonic-nat for nat support
|
||||
ENABLE_NAT = y
|
||||
|
||||
|
18
rules/docker-iccpd.mk
Normal file
18
rules/docker-iccpd.mk
Normal file
@ -0,0 +1,18 @@
|
||||
# docker image for iccpd agent
|
||||
|
||||
DOCKER_ICCPD = docker-iccpd.gz
|
||||
$(DOCKER_ICCPD)_PATH = $(DOCKERS_PATH)/docker-iccpd
|
||||
$(DOCKER_ICCPD)_DEPENDS += $(SWSS) $(REDIS_TOOLS) $(ICCPD)
|
||||
$(DOCKER_ICCPD)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH)
|
||||
|
||||
ifeq ($(ENABLE_ICCPD), y)
|
||||
SONIC_DOCKER_IMAGES += $(DOCKER_ICCPD)
|
||||
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_ICCPD)
|
||||
SONIC_STRETCH_DOCKERS += $(DOCKER_ICCPD)
|
||||
endif
|
||||
|
||||
$(DOCKER_ICCPD)_CONTAINER_NAME = iccpd
|
||||
$(DOCKER_ICCPD)_RUN_OPT += --privileged -t
|
||||
$(DOCKER_ICCPD)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
|
||||
|
||||
$(DOCKER_ICCPD)_BASE_IMAGE_FILES += mclagdctl:/usr/bin/mclagdctl
|
14
rules/iccpd.mk
Normal file
14
rules/iccpd.mk
Normal file
@ -0,0 +1,14 @@
|
||||
# iccpd package
|
||||
|
||||
ICCPD_VERSION = 0.0.5
|
||||
|
||||
ICCPD = iccpd_$(ICCPD_VERSION)_amd64.deb
|
||||
$(ICCPD)_DEPENDS += $(LIBNL_GENL3_DEV) $(LIBNL_CLI_DEV)
|
||||
$(ICCPD)_RDEPENDS += $(LIBNL_GENL3) $(LIBNL_CLI)
|
||||
$(ICCPD)_SRC_PATH = $(SRC_PATH)/iccpd
|
||||
SONIC_MAKE_DEBS += $(ICCPD)
|
||||
# SONIC_STRETCH_DEBS += $(ICCPD)
|
||||
|
||||
# Export these variables so they can be used in a sub-make
|
||||
export ICCPD_VERSION
|
||||
export ICCPD
|
35
src/iccpd/Makefile
Normal file
35
src/iccpd/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
.ONESHELL:
|
||||
SHELL = /bin/bash
|
||||
.SHELLFLAGS += -e
|
||||
|
||||
MAIN_TARGET = iccpd_$(ICCPD_VERSION)_amd64.deb
|
||||
DEB_PATH = debian
|
||||
|
||||
all: iccpd-build mclagdctl-build
|
||||
|
||||
iccpd-build:
|
||||
make -C src
|
||||
|
||||
mclagdctl-build:
|
||||
make -C src/mclagdctl
|
||||
|
||||
$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||
make all
|
||||
if [ ! -d $(DEB_PATH)/usr/bin ]; then
|
||||
mkdir -p $(DEB_PATH)/usr/bin
|
||||
fi
|
||||
cp iccpd $(DEB_PATH)/usr/bin/iccpd
|
||||
cp src/mclagdctl/mclagdctl $(DEB_PATH)/usr/bin/mclagdctl
|
||||
chmod +x $(DEB_PATH)/usr/bin/iccpd
|
||||
chmod +x $(DEB_PATH)/usr/bin/mclagdctl
|
||||
md5sum $(DEB_PATH)/usr/bin/iccpd > $(DEB_PATH)/DEBIAN/md5sums
|
||||
md5sum $(DEB_PATH)/usr/bin/mclagdctl >> $(DEB_PATH)/DEBIAN/md5sums
|
||||
dpkg-deb -b $(DEB_PATH) $(DEST)/$(MAIN_TARGET)
|
||||
|
||||
clean: iccpd-clean mclagdctl-clean
|
||||
|
||||
iccpd-clean:
|
||||
make -C src clean
|
||||
|
||||
mclagdctl-clean:
|
||||
make -C src/mclagdctl clean
|
12
src/iccpd/debian/DEBIAN/control
Normal file
12
src/iccpd/debian/DEBIAN/control
Normal file
@ -0,0 +1,12 @@
|
||||
Package: iccpd-0.0.5-amd64
|
||||
Source: nps
|
||||
Version: 0.0.5
|
||||
Architecture: amd64
|
||||
Maintainer: Simon Ji <Simon.Ji@nephosinc.com>
|
||||
Installed-Size: 1508
|
||||
Depends:
|
||||
Section: main
|
||||
Priority: extra
|
||||
Homepage: https://github.com/NephosInc/SONiC
|
||||
Description:
|
||||
|
73
src/iccpd/include/app_csm.h
Normal file
73
src/iccpd/include/app_csm.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* app_csm.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef APP_CSM_H_
|
||||
#define APP_CSM_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "../include/mlacp_fsm.h"
|
||||
|
||||
struct CSM;
|
||||
|
||||
enum APP_CONNECTION_STATE
|
||||
{
|
||||
APP_NONEXISTENT,
|
||||
APP_RESET,
|
||||
APP_CONNSENT,
|
||||
APP_CONNREC,
|
||||
APP_CONNECTING,
|
||||
APP_OPERATIONAL
|
||||
};
|
||||
|
||||
typedef enum APP_CONNECTION_STATE APP_CONNECTION_STATE_E;
|
||||
|
||||
struct AppCSM
|
||||
{
|
||||
struct mLACP mlacp;
|
||||
APP_CONNECTION_STATE_E current_state;
|
||||
|
||||
uint32_t rx_connect_msg_id;
|
||||
uint32_t tx_connect_msg_id;
|
||||
uint32_t invalid_msg_id;
|
||||
|
||||
TAILQ_HEAD(app_msg_list, Msg) app_msg_list;
|
||||
|
||||
uint8_t invalid_msg : 1;
|
||||
uint8_t nak_msg : 1;
|
||||
};
|
||||
|
||||
void app_csm_init(struct CSM*, int all);
|
||||
void app_csm_finalize(struct CSM*);
|
||||
void app_csm_transit(struct CSM*);
|
||||
int app_csm_prepare_iccp_msg(struct CSM*, char*, size_t);
|
||||
void app_csm_enqueue_msg(struct CSM*, struct Msg*);
|
||||
struct Msg* app_csm_dequeue_msg(struct CSM*);
|
||||
void app_csm_correspond_from_msg(struct CSM*, struct Msg*);
|
||||
void app_csm_correspond_from_connect_msg(struct CSM*, struct Msg*);
|
||||
void app_csm_correspond_from_connect_ack_msg(struct CSM*, struct Msg*);
|
||||
int app_csm_prepare_nak_msg(struct CSM*, char*, size_t);
|
||||
int app_csm_prepare_connect_msg(struct CSM*, char*, size_t);
|
||||
int app_csm_prepare_connect_ack_msg(struct CSM*, char*, size_t);
|
||||
|
||||
#endif /* APP_CSM_H_ */
|
84
src/iccpd/include/cmd_option.h
Normal file
84
src/iccpd/include/cmd_option.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* cmd_option.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef CMD_OPTION_H_
|
||||
#define CMD_OPTION_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define OPTION_MAX_LEN 256
|
||||
#define MSG_LEN 81
|
||||
|
||||
#define CMD_OPTION_PARSER_INIT_VALUE \
|
||||
{ \
|
||||
.log_file_path = "/var/log/iccpd.log", \
|
||||
.pid_file_path = "/var/run/iccpd/iccpd.pid", \
|
||||
.cmd_file_path = "/var/run/iccpd/iccpd.vty", \
|
||||
.config_file_path = "/etc/iccpd/iccpd.conf", \
|
||||
.mclagdctl_file_path = "/var/run/iccpd/mclagdctl.sock", \
|
||||
.console_log = 0, \
|
||||
.telnet_port = 2015, \
|
||||
.init = cmd_option_parser_init, \
|
||||
.finalize = cmd_option_parser_finalize, \
|
||||
.dump_usage = cmd_option_parser_dump_usage, \
|
||||
.parse = cmd_option_parser_parse, \
|
||||
}
|
||||
|
||||
struct CmdOption
|
||||
{
|
||||
char* desc;
|
||||
char* option;
|
||||
char* parameter;
|
||||
LIST_ENTRY(CmdOption) next;
|
||||
};
|
||||
|
||||
struct CmdOptionParser
|
||||
{
|
||||
char* log_file_path;
|
||||
char* pid_file_path;
|
||||
char* cmd_file_path;
|
||||
char* config_file_path;
|
||||
char *mclagdctl_file_path;
|
||||
uint8_t console_log;
|
||||
uint16_t telnet_port;
|
||||
LIST_HEAD(option_list, CmdOption) option_list;
|
||||
int (*parse)(struct CmdOptionParser*, int, char*[]);
|
||||
void (*init)(struct CmdOptionParser*);
|
||||
void (*finalize)(struct CmdOptionParser*);
|
||||
void (*dump_usage)(struct CmdOptionParser*, char*);
|
||||
};
|
||||
|
||||
int cmd_option_parser_parse(struct CmdOptionParser*, int, char*[]);
|
||||
struct CmdOption* cmd_option_add(struct CmdOptionParser*, char*);
|
||||
struct CmdOption* cmd_option_find(struct CmdOptionParser*, char*);
|
||||
void cmd_option_delete(struct CmdOption*);
|
||||
void cmd_option_parser_init(struct CmdOptionParser*);
|
||||
void cmd_option_parser_finalize(struct CmdOptionParser*);
|
||||
void cmd_option_parser_dump_usage(struct CmdOptionParser*, char*);
|
||||
|
||||
#endif /* CMD_OPTION_H_ */
|
67
src/iccpd/include/iccp_cli.h
Normal file
67
src/iccpd/include/iccp_cli.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* iccp_cli.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef _ICCP_CLI_H
|
||||
#define _ICCP_CLI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct CSM;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
QU_TYPE_NONE,
|
||||
QU_TYPE_MLAG_ADD_PO
|
||||
} cli_queue_type_et;
|
||||
|
||||
typedef struct cli_param_queue
|
||||
{
|
||||
char ifname[16];
|
||||
cli_queue_type_et type;
|
||||
int param;
|
||||
int itf_add;
|
||||
LIST_ENTRY(cli_param_queue) cli_queue_next;
|
||||
} cli_param_queue_st;
|
||||
|
||||
#define MCLAG_ID_STR "mclag_id"
|
||||
#define LOCAL_IP_STR "local_ip"
|
||||
#define PEER_IP_STR "peer_ip"
|
||||
#define PEER_LINK_STR "peer_link"
|
||||
#define MCLAG_INTF_STR "mclag_interface"
|
||||
#define SYSTEM_MAC_STR "system_mac"
|
||||
|
||||
int set_mc_lag_id(struct CSM* csm, uint16_t domain);
|
||||
int set_peer_link(int mid, const char* ifname);
|
||||
int set_local_address(int mid, const char* addr);
|
||||
int set_peer_address(int mid, const char* addr);
|
||||
int unset_mc_lag_id(struct CSM* csm, uint16_t domain);
|
||||
int unset_peer_link(int mid);
|
||||
int unset_local_address(int mid);
|
||||
int unset_peer_address(int mid);
|
||||
|
||||
int iccp_cli_attach_mclag_domain_to_port_channel(int domain, const char* ifname);
|
||||
int iccp_cli_detach_mclag_domain_to_port_channel(const char* ifname);
|
||||
int set_local_system_id(const char* mac);
|
||||
int unset_local_system_id( );
|
||||
|
||||
#endif
|
29
src/iccpd/include/iccp_cmd.h
Normal file
29
src/iccpd/include/iccp_cmd.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* iccp_cmd.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef ICCP_CMD_H_
|
||||
#define ICCP_CMD_H_
|
||||
|
||||
int iccp_config_from_file(char *config_default_dir);
|
||||
|
||||
#endif /* ICCP_CMD_H_ */
|
35
src/iccpd/include/iccp_cmd_show.h
Normal file
35
src/iccpd/include/iccp_cmd_show.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* iccp_cmd_show.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef _ICCP_CMD_SHOW_H
|
||||
#define _ICCP_CMD_SHOW_H
|
||||
|
||||
#define ICCP_MAX_PORT_NAME 20
|
||||
#define ICCP_MAX_IP_STR_LEN 16
|
||||
|
||||
extern int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id);
|
||||
extern int iccp_arp_dump(char * *buf, int *num, int mclag_id);
|
||||
extern int iccp_mac_dump(char * *buf, int *num, int mclag_id);
|
||||
extern int iccp_local_if_dump(char * *buf, int *num, int mclag_id);
|
||||
extern int iccp_peer_if_dump(char * *buf, int *num, int mclag_id);
|
||||
#endif
|
43
src/iccpd/include/iccp_consistency_check.h
Normal file
43
src/iccpd/include/iccp_consistency_check.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* iccp_consistency_check.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ICCP_CONSISTENCY_CHECK_H
|
||||
#define _ICCP_CONSISTENCY_CHECK_H
|
||||
|
||||
|
||||
enum Reason_ID
|
||||
{
|
||||
REASON_NONE = 0,
|
||||
REASON_INTERRFACE_MODE_IS_ASYNC,
|
||||
REASON_PEER_IF_IP_IS_ASYNC,
|
||||
REASON_PEER_IF_VLAN_IS_ASYNC,
|
||||
REASON_MAX_ARRAY_SIZE
|
||||
};
|
||||
|
||||
extern const char *reasons[];
|
||||
|
||||
enum Reason_ID iccp_consistency_check(char* ifname);
|
||||
|
||||
|
||||
#endif
|
165
src/iccpd/include/iccp_csm.h
Normal file
165
src/iccpd/include/iccp_csm.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* iccp_csm.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef ICCP_CSM_H_
|
||||
#define ICCP_CSM_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../include/app_csm.h"
|
||||
#include "../include/msg_format.h"
|
||||
#include "../include/port.h"
|
||||
|
||||
#define CSM_BUFFER_SIZE 65536
|
||||
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif /*IFNAMSIZ*/
|
||||
|
||||
#ifndef INET_ADDRSTRLEN
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#endif /* INET_ADDRSTRLEN */
|
||||
|
||||
/* For socket binding */
|
||||
#define ICCP_TCP_PORT 8888
|
||||
#define MAX_ACCEPT_CONNETIONS 20
|
||||
|
||||
/* LDP message ID */
|
||||
extern uint32_t ICCP_MSG_ID;
|
||||
|
||||
/* Global Buffer */
|
||||
extern char g_csm_buf[CSM_BUFFER_SIZE];
|
||||
|
||||
struct IccpInfo
|
||||
{
|
||||
uint32_t icc_rg_id;
|
||||
char sender_name[MAX_L_ICC_SENDER_NAME];
|
||||
uint32_t status_code;
|
||||
uint8_t peer_capability_flag : 1;
|
||||
uint8_t peer_rg_connect_flag : 1;
|
||||
uint8_t sender_capability_flag : 1;
|
||||
uint8_t sender_rg_connect_flag : 1;
|
||||
uint32_t rejected_msg_id;
|
||||
};
|
||||
|
||||
/* Receive message node */
|
||||
struct Msg
|
||||
{
|
||||
char* buf;
|
||||
size_t len;
|
||||
TAILQ_ENTRY(Msg) tail;
|
||||
};
|
||||
|
||||
/* Connection state */
|
||||
enum ICCP_CONNECTION_STATE
|
||||
{
|
||||
ICCP_NONEXISTENT,
|
||||
ICCP_INITIALIZED,
|
||||
ICCP_CAPSENT,
|
||||
ICCP_CAPREC,
|
||||
ICCP_CONNECTING,
|
||||
ICCP_OPERATIONAL
|
||||
};
|
||||
|
||||
typedef enum ICCP_CONNECTION_STATE ICCP_CONNECTION_STATE_E;
|
||||
|
||||
typedef enum stp_role_type_e
|
||||
{
|
||||
STP_ROLE_NONE, /* mstp do nothing*/
|
||||
STP_ROLE_ACTIVE, /* mstp report port state*/
|
||||
STP_ROLE_STANDBY /* mstp fwd bpdu & set port state*/
|
||||
} stp_role_type_et;
|
||||
|
||||
/* Connection state machine instance */
|
||||
struct CSM
|
||||
{
|
||||
int mlag_id;
|
||||
|
||||
/* Socket info */
|
||||
int sock_fd;
|
||||
pthread_mutex_t conn_mutex;
|
||||
time_t connTimePrev;
|
||||
time_t heartbeat_send_time;
|
||||
time_t heartbeat_update_time;
|
||||
time_t peer_warm_reboot_time;
|
||||
time_t warm_reboot_disconn_time;
|
||||
char peer_itf_name[IFNAMSIZ];
|
||||
char peer_ip[INET_ADDRSTRLEN];
|
||||
char sender_ip[INET_ADDRSTRLEN];
|
||||
void* sock_read_event_ptr;
|
||||
|
||||
/* Msg queue */
|
||||
TAILQ_HEAD(msg_list, Msg) msg_list;
|
||||
|
||||
/* STP role */
|
||||
stp_role_type_et role_type;
|
||||
|
||||
/* Peers msg */
|
||||
struct LocalInterface* peer_link_if;
|
||||
struct IccpInfo iccp_info;
|
||||
struct AppCSM app_csm;
|
||||
ICCP_CONNECTION_STATE_E current_state;
|
||||
|
||||
/* Statistic info */
|
||||
uint64_t icc_msg_in_count; /* ICC message input count */
|
||||
uint64_t icc_msg_out_count; /* ICC message Output count */
|
||||
uint64_t u_msg_in_count; /* Unknown message Input count */
|
||||
uint64_t i_msg_in_count; /* Illegal message Input count */
|
||||
|
||||
/* Log */
|
||||
struct MsgLog msg_log;
|
||||
|
||||
LIST_ENTRY(CSM) next;
|
||||
LIST_HEAD(csm_if_list, If_info) if_bind_list;
|
||||
};
|
||||
int iccp_csm_send(struct CSM*, char*, int);
|
||||
int iccp_csm_init_msg(struct Msg**, char*, int);
|
||||
int iccp_csm_prepare_nak_msg(struct CSM*, char*, size_t);
|
||||
int iccp_csm_prepare_iccp_msg(struct CSM*, char*, size_t);
|
||||
int iccp_csm_prepare_capability_msg(struct CSM*, char*, size_t);
|
||||
int iccp_csm_prepare_rg_connect_msg(struct CSM*, char*, size_t);
|
||||
int iccp_csm_prepare_rg_disconnect_msg(struct CSM*, char*, size_t);
|
||||
struct Msg* iccp_csm_dequeue_msg(struct CSM*);
|
||||
void *iccp_get_csm();
|
||||
void iccp_csm_init(struct CSM*);
|
||||
void iccp_csm_transit(struct CSM*);
|
||||
void iccp_csm_finalize(struct CSM*);
|
||||
void iccp_csm_status_reset(struct CSM*, int);
|
||||
void iccp_csm_stp_role_count(struct CSM *csm);
|
||||
void iccp_csm_msg_list_finalize(struct CSM*);
|
||||
void iccp_csm_enqueue_msg(struct CSM*, struct Msg*);
|
||||
void iccp_csm_fill_icc_rg_id_tlv(struct CSM*, ICCHdr*);
|
||||
void iccp_csm_correspond_from_msg(struct CSM*, struct Msg*);
|
||||
void iccp_csm_correspond_from_capability_msg(struct CSM*, struct Msg*);
|
||||
void iccp_csm_correspond_from_rg_connect_msg(struct CSM*, struct Msg*);
|
||||
void iccp_csm_correspond_from_rg_disconnect_msg(struct CSM*, struct Msg*);
|
||||
|
||||
int mlacp_bind_port_channel_to_csm(struct CSM* csm, const char *ifname);
|
||||
|
||||
#endif /* ICCP_CSM_H_ */
|
41
src/iccpd/include/iccp_ifm.h
Normal file
41
src/iccpd/include/iccp_ifm.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* iccp_ifm.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef ICCP_IFM_H
|
||||
#define ICCP_IFM_H
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
|
||||
int iccp_sys_local_if_list_get_init();
|
||||
|
||||
int iccp_arp_get_init();
|
||||
|
||||
void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, uint8_t mac_addr[ETHER_ADDR_LEN]);
|
||||
|
||||
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);
|
||||
#endif // LACP_IFM_H
|
||||
|
47
src/iccpd/include/iccp_netlink.h
Normal file
47
src/iccpd/include/iccp_netlink.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef ICCP_NETLINK_H
|
||||
#define ICCP_NETLINK_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <netlink/netlink.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../include/system.h"
|
||||
#include "../include/port.h"
|
||||
|
||||
int iccp_get_port_member_list(struct LocalInterface* lif);
|
||||
void iccp_event_handler_obj_input_newlink(struct nl_object *obj, void *arg);
|
||||
void iccp_event_handler_obj_input_dellink(struct nl_object *obj, void *arg);
|
||||
int iccp_system_init_netlink_socket();
|
||||
void iccp_system_dinit_netlink_socket();
|
||||
int iccp_init_netlink_event_fd(struct System *sys);
|
||||
int iccp_handle_events(struct System * sys);
|
||||
void update_if_ipmac_on_standby(struct LocalInterface* lif_po);
|
||||
int iccp_sys_local_if_list_get_addr();
|
||||
int iccp_check_if_addr_from_netlink(int family, uint8_t *addr, struct LocalInterface *lif);
|
||||
|
||||
#endif
|
||||
|
70
src/iccpd/include/logger.h
Normal file
70
src/iccpd/include/logger.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* logger.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_H_
|
||||
#define LOGGER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "../include/cmd_option.h"
|
||||
|
||||
typedef enum _iccpd_log_level_t
|
||||
{
|
||||
CRITICAL_LOG_LEVEL = 0,
|
||||
ERR_LOG_LEVEL = 1,
|
||||
WARN_LOG_LEVEL = 2,
|
||||
NOTICE_LOG_LEVEL = 3,
|
||||
INFO_LOG_LEVEL = 4,
|
||||
DEBUG_LOG_LEVEL = 5
|
||||
} _iccpd_log_level_t;
|
||||
|
||||
|
||||
#define LOGBUF_SIZE 1024
|
||||
#define ICCPD_UTILS_SYSLOG (syslog)
|
||||
|
||||
#define ICCPD_LOG_CRITICAL(tag, format, args ...) write_log(CRITICAL_LOG_LEVEL, tag, format, ## args)
|
||||
#define ICCPD_LOG_ERR(tag, format, args ...) write_log(ERR_LOG_LEVEL, tag, format, ## args)
|
||||
#define ICCPD_LOG_WARN(tag, format, args ...) write_log(WARN_LOG_LEVEL, tag, format, ## args)
|
||||
#define ICCPD_LOG_NOTICE(tag, format, args ...) write_log(NOTICE_LOG_LEVEL, tag, format, ## args)
|
||||
#define ICCPD_LOG_INFO(tag, format, args ...) write_log(INFO_LOG_LEVEL, tag, format, ## args)
|
||||
#define ICCPD_LOG_DEBUG(tag, format, args ...) write_log(DEBUG_LOG_LEVEL, tag, format, ## args)
|
||||
|
||||
struct LoggerConfig
|
||||
{
|
||||
uint8_t console_log_enabled;
|
||||
uint8_t log_level;
|
||||
uint8_t init;
|
||||
};
|
||||
|
||||
struct LoggerConfig* logger_get_configuration();
|
||||
void logger_set_configuration(int log_level);
|
||||
char* log_level_to_string(int level);
|
||||
void log_setup(char* progname, char* path);
|
||||
void log_finalize();
|
||||
void log_init(struct CmdOptionParser* parser);
|
||||
void write_log(const int level, const char* tag, const char *format, ...);
|
||||
|
||||
#endif /* LOGGER_H_ */
|
||||
|
||||
|
106
src/iccpd/include/mlacp_fsm.h
Normal file
106
src/iccpd/include/mlacp_fsm.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* mlacp_fsm.h
|
||||
* mLACP finite state machine handler.
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef _MLACP_FSM_H
|
||||
#define _MLACP_FSM_H
|
||||
|
||||
#include "../include/port.h"
|
||||
|
||||
#define MLCAP_SYNC_PHY_DEV_SEC 1 /*every 1 sec*/
|
||||
|
||||
#define MLACP(csm_ptr) (csm_ptr->app_csm.mlacp)
|
||||
|
||||
struct CSM;
|
||||
|
||||
enum MLACP_APP_STATE
|
||||
{
|
||||
MLACP_STATE_INIT,
|
||||
MLACP_STATE_STAGE1,
|
||||
MLACP_STATE_STAGE2,
|
||||
MLACP_STATE_EXCHANGE,
|
||||
MLACP_STATE_ERROR,
|
||||
};
|
||||
|
||||
typedef enum MLACP_APP_STATE MLACP_APP_STATE_E;
|
||||
|
||||
/* for sender only*/
|
||||
enum MLACP_SYNC_STATE
|
||||
{
|
||||
MLACP_SYNC_SYSCONF=0,
|
||||
MLACP_SYNC_AGGCONF,
|
||||
MLACP_SYNC_AGGSTATE,
|
||||
MLACP_SYNC_AGGINFO,
|
||||
MLACP_SYNC_PEERLINKINFO,
|
||||
MLACP_SYNC_ARP_INFO,
|
||||
MLACP_SYNC_DONE,
|
||||
};
|
||||
|
||||
typedef enum MLACP_SYNC_STATE MLACP_SYNC_STATE_E;
|
||||
|
||||
struct Remote_System
|
||||
{
|
||||
uint8_t system_id[ETHER_ADDR_LEN];
|
||||
uint16_t system_priority;
|
||||
uint32_t node_id;
|
||||
};
|
||||
|
||||
struct mLACP
|
||||
{
|
||||
int id;
|
||||
int sync_req_num;
|
||||
|
||||
MLACP_APP_STATE_E current_state;
|
||||
MLACP_SYNC_STATE_E sync_state;
|
||||
|
||||
uint8_t wait_for_sync_data;
|
||||
uint8_t need_to_sync;
|
||||
uint8_t node_id;
|
||||
uint8_t system_id[ETHER_ADDR_LEN];
|
||||
uint16_t system_priority;
|
||||
uint8_t system_config_changed;
|
||||
|
||||
struct Remote_System remote_system;
|
||||
const char* error_msg;
|
||||
TAILQ_HEAD(mlacp_msg_list, Msg) mlacp_msg_list;
|
||||
TAILQ_HEAD(arp_msg_list, Msg) arp_msg_list;
|
||||
TAILQ_HEAD(arp_info_list, Msg) arp_list;
|
||||
TAILQ_HEAD(mac_msg_list, Msg) mac_msg_list;
|
||||
TAILQ_HEAD(mac_info_list, Msg) mac_list;
|
||||
|
||||
LIST_HEAD(lif_list, LocalInterface) lif_list;
|
||||
LIST_HEAD(lif_purge_list, LocalInterface) lif_purge_list;
|
||||
LIST_HEAD(pif_list, PeerInterface) pif_list;
|
||||
};
|
||||
|
||||
void mlacp_init(struct CSM* csm, int all);
|
||||
void mlacp_finalize(struct CSM* csm);
|
||||
void mlacp_fsm_transit(struct CSM* csm);
|
||||
void mlacp_enqueue_msg(struct CSM*, struct Msg*);
|
||||
struct Msg* mlacp_dequeue_msg(struct CSM*);
|
||||
|
||||
/* from app_csm*/
|
||||
extern int mlacp_bind_local_if(struct CSM* csm, struct LocalInterface* local_if);
|
||||
extern int mlacp_unbind_local_if(struct LocalInterface* local_if);
|
||||
|
||||
#endif /* _MLACP_HANDLER_H */
|
60
src/iccpd/include/mlacp_link_handler.h
Normal file
60
src/iccpd/include/mlacp_link_handler.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* mlacp_link_handler.h
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef __MLACP_LINK_HANDLER__
|
||||
#define __MLACP_LINK_HANDLER__
|
||||
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/mlacp_tlv.h"
|
||||
|
||||
/*****************************************
|
||||
* Link Handler
|
||||
*
|
||||
* ***************************************/
|
||||
void mlacp_portchannel_state_handler(struct CSM* csm, struct LocalInterface* local_if, int po_state);
|
||||
void mlacp_peer_conn_handler(struct CSM* csm);
|
||||
void mlacp_peer_disconn_handler(struct CSM* csm);
|
||||
void mlacp_peerlink_up_handler(struct CSM* csm);
|
||||
void mlacp_peerlink_down_handler(struct CSM* csm);
|
||||
void update_stp_peer_link(struct CSM *csm, struct PeerInterface *peer_if, int po_state, int new_create);
|
||||
void update_peerlink_isolate_from_pif(struct CSM *csm, struct PeerInterface *pif, int po_state, int new_create);
|
||||
void mlacp_mlag_link_add_handler(struct CSM *csm, struct LocalInterface *lif);
|
||||
void mlacp_mlag_link_del_handler(struct CSM *csm, struct LocalInterface *lif);
|
||||
void set_peerlink_mlag_port_learn(struct LocalInterface *lif, int enable);
|
||||
void peerlink_port_isolate_cleanup(struct CSM* csm);
|
||||
void update_peerlink_isolate_from_all_csm_lif(struct CSM* csm);
|
||||
|
||||
int mlacp_fsm_arp_set(char *ifname, uint32_t ip, char *mac);
|
||||
int mlacp_fsm_arp_del(char *ifname, uint32_t ip);
|
||||
void del_mac_from_chip(struct MACMsg* mac_msg);
|
||||
void add_mac_to_chip(struct MACMsg* mac_msg, uint8_t mac_type);
|
||||
uint8_t set_mac_local_age_flag(struct CSM *csm, struct MACMsg* mac_msg, uint8_t set );
|
||||
void iccp_get_fdb_change_from_syncd( void);
|
||||
|
||||
extern int mclagd_ctl_sock_create();
|
||||
extern int mclagd_ctl_sock_accept(int fd);
|
||||
extern int mclagd_ctl_interactive_process(int client_fd);
|
||||
char *show_ip_str(uint32_t ipv4_addr);
|
||||
|
||||
void syncd_info_close();
|
||||
int iccp_connect_syncd();
|
||||
#endif
|
55
src/iccpd/include/mlacp_sync_prepare.h
Normal file
55
src/iccpd/include/mlacp_sync_prepare.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* mlacp_sync_prepare.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef __MLACP_SYNC_PREPARE__
|
||||
#define __MLACP_SYNC_PREPARE__
|
||||
|
||||
struct CSM;
|
||||
/*****************************************
|
||||
* Tool Function
|
||||
*
|
||||
* ***************************************/
|
||||
void update_system_id(struct CSM* csm);
|
||||
|
||||
/*****************************************
|
||||
* LACP Sync
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_sync_with_kernel_callback();
|
||||
|
||||
/*****************************************
|
||||
* MLACP Sync
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_sync_request_tlv(struct CSM* csm, char* buf, size_t max_buf_size);
|
||||
int mlacp_prepare_for_sync_data_tlv(struct CSM* csm, char* buf, size_t max_buf_size, int end);
|
||||
int mlacp_prepare_for_sys_config(struct CSM* csm, char* buf, size_t max_buf_size);
|
||||
int mlacp_prepare_for_mac_info_to_peer(struct CSM* csm, char* buf, size_t max_buf_size, struct MACMsg* mac_msg, int count);
|
||||
int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count);
|
||||
int mlacp_prepare_for_heartbeat(struct CSM* csm, char* buf, size_t max_buf_size);
|
||||
int mlacp_prepare_for_Aggport_state(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* local_if);
|
||||
int mlacp_prepare_for_Aggport_config(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* lif, int purge_flag);
|
||||
int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* port_channel);
|
||||
int mlacp_prepare_for_port_peerlink_info(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* peerlink_port);
|
||||
int iccp_netlink_if_hwaddr_set(uint32_t ifindex, uint8_t *addr, unsigned int addr_len);
|
||||
#endif
|
49
src/iccpd/include/mlacp_sync_update.h
Normal file
49
src/iccpd/include/mlacp_sync_update.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
*
|
||||
* mlacp_sync_update.h
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef __MLACP_SYNC_UPDATE__
|
||||
#define __MLACP_SYNC_UPDATE__
|
||||
|
||||
#include "iccp_csm.h"
|
||||
#include "mlacp_tlv.h"
|
||||
|
||||
/*****************************************
|
||||
* FSM Sync Update API
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_system_conf(struct CSM* csm, mLACPSysConfigTLV* tlv);
|
||||
|
||||
int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv);
|
||||
|
||||
int mlacp_fsm_update_arp_info(struct CSM* csm, struct mLACPARPInfoTLV* tlv);
|
||||
|
||||
int mlacp_fsm_update_heartbeat(struct CSM* csm, struct mLACPHeartbeatTLV* tlv);
|
||||
|
||||
int mlacp_fsm_update_warmboot(struct CSM* csm, struct mLACPWarmbootTLV* tlv);
|
||||
void mlacp_enqueue_arp(struct CSM* csm, struct Msg* msg);
|
||||
|
||||
int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf);
|
||||
int mlacp_fsm_update_port_channel_info(struct CSM* csm, struct mLACPPortChannelInfoTLV* tlv);
|
||||
int mlacp_fsm_update_peerlink_info(struct CSM* csm, struct mLACPPeerLinkInfoTLV* tlv);
|
||||
int mlacp_fsm_update_mac_info_from_peer(struct CSM* csm, struct mLACPMACInfoTLV* tlv);
|
||||
#endif
|
456
src/iccpd/include/mlacp_tlv.h
Normal file
456
src/iccpd/include/mlacp_tlv.h
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* mlacp_tlv.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef MLACP_TLV_H_
|
||||
#define MLACP_TLV_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "../include/msg_format.h"
|
||||
#include "../include/port.h"
|
||||
|
||||
#define MLACP_SYSCONF_NODEID_MSB_MASK 0x80
|
||||
#define MLACP_SYSCONF_NODEID_NODEID_MASK 0x70
|
||||
#define MLACP_SYSCONF_NODEID_FREE_MASK 0x0F
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.3. mLACP System Config TLV
|
||||
* [Page 51]
|
||||
*/
|
||||
struct mLACPSysConfigTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/* [IEEE-802.1AX], Section 5.3.2. */
|
||||
uint8_t sys_id[ETHER_ADDR_LEN];
|
||||
/* [IEEE-802.1AX], Section 5.3.2. */
|
||||
uint16_t sys_priority;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.3. mLACP System Config TLV
|
||||
* [Page 51]
|
||||
*/
|
||||
uint8_t node_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPSysConfigTLV mLACPSysConfigTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Aggregator Config TLV
|
||||
* [Page 52]
|
||||
* NOTE: In this project, Aggregator configuration and state TLV is not support.
|
||||
*/
|
||||
struct mLACPAggConfigTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Aggregator Config TLV
|
||||
* [Page 53]
|
||||
*/
|
||||
uint8_t ro_id[8];
|
||||
/* [IEEE-802.1AX], Section 5.4.6. */
|
||||
uint16_t agg_id;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Aggregator Config TLV
|
||||
* [Page 53]
|
||||
*/
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
/* [IEEE-802.1AX], Section 5.3.5. */
|
||||
uint16_t actor_key;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Aggregator Config TLV
|
||||
* [Page 53]
|
||||
*/
|
||||
uint16_t member_ports_priority;
|
||||
uint8_t flags;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Aggregator Config TLV
|
||||
* [Page 54]
|
||||
*/
|
||||
uint8_t agg_name_len;
|
||||
char agg_name[MAX_L_PORT_NAME];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPAggConfigTLV mLACPAggConfigTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Port Config TLV
|
||||
* [Page 54]
|
||||
*/
|
||||
struct mLACPPortConfigTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
uint16_t port_num;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.5. mLACP Port Config TLV
|
||||
* [Page 55]
|
||||
*/
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
/* [IEEE-802.1AX], Section 5.3.5. */
|
||||
uint16_t actor_key;
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
uint16_t port_priority;
|
||||
/* IF-MIB [RFC2863] */
|
||||
uint32_t port_speed;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Port Config TLV
|
||||
* [Page 55]
|
||||
*/
|
||||
uint8_t flags;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Port Config TLV
|
||||
* [Page 56]
|
||||
*/
|
||||
uint8_t port_name_len;
|
||||
/* IF-MIB [RFC2863] */
|
||||
char port_name[MAX_L_PORT_NAME];
|
||||
|
||||
/* NOS */
|
||||
uint8_t l3_mode;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPPortConfigTLV mLACPPortConfigTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.6. mLACP Port Priority TLV
|
||||
* [Page 56]
|
||||
*/
|
||||
struct mLACPPortPriorityTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.6. mLACP Port Priority TLV
|
||||
* [Page 57]
|
||||
*/
|
||||
uint16_t op_code;
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
uint16_t port_num;
|
||||
/* [IEEE-802.1AX], Section 5.4.6. */
|
||||
uint16_t agg_id;
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
uint16_t last_port_priority;
|
||||
uint16_t current_port_priority;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPPortPriorityTLV mLACPPortPriorityTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.7. mLACP Port State TLV
|
||||
* [Page 58]
|
||||
*/
|
||||
struct mLACPPortStateTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item r. */
|
||||
uint8_t partner_sys_id[ETHER_ADDR_LEN];
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item q. */
|
||||
uint16_t partner_sys_priority;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item u. */
|
||||
uint16_t partner_port_num;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item t. */
|
||||
uint16_t partner_port_priority;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item s. */
|
||||
uint16_t partner_key;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item v. */
|
||||
uint8_t partner_state;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item m. */
|
||||
uint8_t actor_state;
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
uint16_t actor_port_num;
|
||||
/* [IEEE-802.1AX], Section 5.3.5. */
|
||||
uint16_t actor_key;
|
||||
/* [IEEE-802.1AX], Section 5.4.8 */
|
||||
uint8_t selected;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.7. mLACP Port State TLV
|
||||
* [Page 60]
|
||||
*/
|
||||
uint8_t port_state;
|
||||
/* [IEEE-802.1AX], Section 5.4.6. */
|
||||
uint16_t agg_id;
|
||||
|
||||
/* NOS */
|
||||
uint16_t port_id;
|
||||
uint8_t l3_mode;
|
||||
uint8_t is_peer_link;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPPortStateTLV mLACPPortStateTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.8. mLACP Aggregator State TLV
|
||||
* [Page 60]
|
||||
* NOTE: In this project, Aggregator configuration and state TLV is not support.
|
||||
*/
|
||||
struct mLACPAggPortStateTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item r. */
|
||||
uint8_t partner_sys_id[ETHER_ADDR_LEN];
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item q. */
|
||||
uint16_t partner_sys_priority;
|
||||
/* [IEEE-802.1AX], Section 5.4.2.2, item s. */
|
||||
uint16_t partner_key;
|
||||
/* [IEEE-802.1AX], Section 5.4.6. */
|
||||
uint16_t agg_id;
|
||||
/* [IEEE-802.1AX], Section 5.3.5. */
|
||||
uint16_t actor_key;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.8. mLACP Aggregator State TLV
|
||||
* [Page 61]
|
||||
*/
|
||||
uint8_t agg_state;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPAggPortStateTLV mLACPAggPortStateTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.9. mLACP Synchronization Request TLV
|
||||
* [Page 61]
|
||||
*/
|
||||
struct mLACPSyncReqTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.9. mLACP Synchronization Request TLV
|
||||
* [Page 62]
|
||||
*/
|
||||
uint16_t req_num;
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t c_bit : 1;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.9. mLACP Synchronization Request TLV
|
||||
* [Page 63]
|
||||
*/
|
||||
uint16_t s_bit : 1;
|
||||
uint16_t req_type : 14;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint16_t req_type : 14;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.9. mLACP Synchronization Request TLV
|
||||
* [Page 63]
|
||||
*/
|
||||
uint16_t s_bit : 1;
|
||||
uint16_t c_bit : 1;
|
||||
#endif
|
||||
/* [IEEE-802.1AX], Section 5.3.4. */
|
||||
/* [IEEE-802.1AX], Section 5.4.6. */
|
||||
uint16_t port_num_agg_id;
|
||||
/* [IEEE-802.1AX], Section 5.3.5. */
|
||||
uint16_t actor_key;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPSyncReqTLV mLACPSyncReqTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.10. mLACP Synchronization Data TLV
|
||||
* [Page 63]
|
||||
*/
|
||||
struct mLACPSyncDataTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.10. mLACP Synchronization Data TLV
|
||||
* [Page 64]
|
||||
*/
|
||||
uint16_t req_num;
|
||||
uint16_t flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPSyncDataTLV mLACPSyncDataTLV;
|
||||
|
||||
/* VLAN Information TLV*/
|
||||
struct mLACPVLANData
|
||||
{
|
||||
uint16_t vlan_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* Port Channel Information TLV
|
||||
*/
|
||||
struct mLACPPortChannelInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint16_t agg_id;
|
||||
char if_name[MAX_L_PORT_NAME];
|
||||
uint8_t if_name_len;
|
||||
uint8_t l3_mode;
|
||||
uint32_t ipv4_addr;
|
||||
uint16_t po_id;
|
||||
uint16_t num_of_vlan_id;
|
||||
struct mLACPVLANData vlanData[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPPortChannelInfoTLV mLACPPortChannelInfoTLV;
|
||||
|
||||
/*
|
||||
* Port PeerLink Information TLV
|
||||
*/
|
||||
struct mLACPPeerLinkInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
char if_name[MAX_L_PORT_NAME];
|
||||
uint8_t port_type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct mLACPPeerLinkInfoTLV mLACPPeerLinkInfoTLV;
|
||||
|
||||
struct mLACPVLANInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint16_t id; /* Local Interface ID, not VLAN ID */
|
||||
uint16_t num_of_vlan_id;
|
||||
struct mLACPVLANData vlanData[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Mac entry Information TLV*/
|
||||
struct mLACPMACData
|
||||
{
|
||||
uint8_t type;/*add or del*/
|
||||
char mac_str[ETHER_ADDR_STR_LEN];
|
||||
uint16_t vid;
|
||||
/*Current if name that set in chip*/
|
||||
char ifname[MAX_L_PORT_NAME];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* MAC Information TLV
|
||||
*/
|
||||
struct mLACPMACInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint16_t num_of_entry;
|
||||
struct mLACPMACData MacEntry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ARPMsg
|
||||
{
|
||||
uint8_t op_type;
|
||||
char ifname[MAX_L_PORT_NAME];
|
||||
uint32_t ipv4_addr;
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* ARP Information TLV
|
||||
*/
|
||||
struct mLACPARPInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
/* Local Interface ID */
|
||||
uint16_t num_of_entry;
|
||||
struct ARPMsg ArpEntry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* NOS: STP Information TLV
|
||||
*/
|
||||
struct stp_msg_s;
|
||||
struct mLACPSTPInfoTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint8_t stp_msg[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* NOS: Heartbeat
|
||||
*/
|
||||
struct mLACPHeartbeatTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint8_t heartbeat;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* NOS: Warm_reboot
|
||||
*/
|
||||
struct mLACPWarmbootTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint8_t warmboot;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum ARP_OP_TYPE
|
||||
{
|
||||
ARP_SYNC_LIF,
|
||||
ARP_SYNC_ADD,
|
||||
ARP_SYNC_DEL,
|
||||
};
|
||||
|
||||
enum MAC_AGE_TYPE
|
||||
{
|
||||
MAC_AGE_LOCAL = 1, /*MAC in local switch is ageout*/
|
||||
MAC_AGE_PEER = 2, /*MAC in peer switch is ageout*/
|
||||
};
|
||||
|
||||
enum MAC_OP_TYPE
|
||||
{
|
||||
MAC_SYNC_ADD = 1,
|
||||
MAC_SYNC_DEL = 2,
|
||||
MAC_SYNC_ACK = 4,
|
||||
};
|
||||
|
||||
enum MAC_TYPE
|
||||
{
|
||||
MAC_TYPE_STATIC = 1,
|
||||
MAC_TYPE_DYNAMIC = 2,
|
||||
};
|
||||
|
||||
struct MACMsg
|
||||
{
|
||||
uint8_t op_type; /*add or del*/
|
||||
uint8_t fdb_type; /*static or dynamic*/
|
||||
char mac_str[ETHER_ADDR_STR_LEN];
|
||||
uint16_t vid;
|
||||
/*Current if name that set in chip*/
|
||||
char ifname[MAX_L_PORT_NAME];
|
||||
/*if we set the mac to peer-link, origin_ifname store the
|
||||
original if name that learned from chip*/
|
||||
char origin_ifname[MAX_L_PORT_NAME];
|
||||
uint8_t age_flag;/*local or peer is age?*/
|
||||
};
|
||||
|
||||
#endif /* MLACP_TLV_H_ */
|
499
src/iccpd/include/msg_format.h
Normal file
499
src/iccpd/include/msg_format.h
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* msg_format.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef MSG_FORMAT_H_
|
||||
#define MSG_FORMAT_H_
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include "../include/port.h"
|
||||
|
||||
#define MAX_MSG_LOG_SIZE 128
|
||||
|
||||
/*
|
||||
* RFC 5561
|
||||
* 4. Capability Message
|
||||
* [Page 7]
|
||||
*/
|
||||
#define MSG_T_CAPABILITY 0x0202
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.1.1. ICC Header - Message Length
|
||||
* [Page 25]
|
||||
* 2-octet integer specifying the total length of this message in octets,
|
||||
* excluding the "U-bit", "Message Type", and "Length" fields.
|
||||
*/
|
||||
#define MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS 4
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 12.1. Message Type Name Space
|
||||
* [Page 79]
|
||||
*/
|
||||
#define MSG_T_RG_CONNECT 0x0700
|
||||
#define MSG_T_RG_DISCONNECT 0x0701
|
||||
#define MSG_T_NOTIFICATION 0x0702
|
||||
#define MSG_T_RG_APP_DATA 0x0703
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 12.2. TLV Type Name Space
|
||||
* [Page 79]
|
||||
*/
|
||||
#define TLV_T_ICCP_CAPABILITY 0x0700
|
||||
#define TLV_L_ICCP_CAPABILITY 0x4
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 12.3. ICC RG Parameter Type Space
|
||||
* [Page 80]
|
||||
*/
|
||||
#define TLV_T_ICC_SENDER_NAME 0x0001
|
||||
#define MAX_L_ICC_SENDER_NAME 80
|
||||
#define TLV_T_NAK 0x0002
|
||||
#define TLV_T_REQUESTED_PROTOCOL_VER 0x0003
|
||||
#define TLV_T_DISCONNECT_CODE 0x0004
|
||||
#define TLV_L_DISCONNECT_CODE 0x4
|
||||
#define TLV_T_ICC_RG_ID 0x0005
|
||||
#define TLV_L_ICC_RG_ID 0x4
|
||||
|
||||
#define TLV_T_MLACP_CONNECT 0x0030
|
||||
#define TLV_T_MLACP_DISCONNECT 0x0031
|
||||
#define TLV_T_MLACP_SYSTEM_CONFIG 0x0032
|
||||
#define TLV_T_MLACP_PORT_CONFIG 0x0033 //no support
|
||||
#define TLV_T_MLACP_PORT_PRIORITY 0x0034 //no support
|
||||
#define TLV_T_MLACP_PORT_STATE 0x0035 //no support
|
||||
#define TLV_T_MLACP_AGGREGATOR_CONFIG 0x0036
|
||||
#define TLV_T_MLACP_AGGREGATOR_STATE 0x0037
|
||||
#define TLV_T_MLACP_SYNC_REQUEST 0x0038
|
||||
#define TLV_T_MLACP_SYNC_DATA 0x0039
|
||||
#define TLV_T_MLACP_HEARTBEAT 0x003A
|
||||
#define TLV_T_MLACP_DISCONNECT_CAUSE 0x003B //not yet
|
||||
|
||||
/* Self define Feature */
|
||||
#define TLV_T_MLACP_ORPHAN_PORT 0x1033 //not yet
|
||||
#define TLV_T_MLACP_PORT_CHANNEL_INFO 0x1034
|
||||
#define TLV_T_MLACP_PEERLINK_INFO 0x1035
|
||||
#define TLV_T_MLACP_ARP_INFO 0x1036
|
||||
#define TLV_T_MLACP_STP_INFO 0x1037//no support
|
||||
#define TLV_T_MLACP_MAC_INFO 0x1038
|
||||
#define TLV_T_MLACP_WARMBOOT_FLAG 0x1039
|
||||
#define TLV_T_MLACP_LIST_END 0x104a //list end
|
||||
|
||||
/* Debug */
|
||||
static char* get_tlv_type_string(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TLV_T_ICCP_CAPABILITY:
|
||||
return "TLV_T_ICCP_CAPABILITY";
|
||||
|
||||
case TLV_T_ICC_SENDER_NAME:
|
||||
return "TLV_T_ICC_SENDER_NAME";
|
||||
|
||||
case TLV_T_NAK:
|
||||
return "TLV_T_NAK";
|
||||
|
||||
case TLV_T_REQUESTED_PROTOCOL_VER:
|
||||
return "TLV_T_REQUESTED_PROTOCOL_VER";
|
||||
|
||||
case TLV_T_DISCONNECT_CODE:
|
||||
return "TLV_T_DISCONNECT_CODE";
|
||||
|
||||
case TLV_T_ICC_RG_ID:
|
||||
return "TLV_T_ICC_RG_ID";
|
||||
|
||||
case TLV_T_MLACP_CONNECT:
|
||||
return "TLV_T_MLACP_CONNECT";
|
||||
|
||||
case TLV_T_MLACP_DISCONNECT:
|
||||
return "TLV_T_MLACP_DISCONNECT";
|
||||
|
||||
case TLV_T_MLACP_SYSTEM_CONFIG:
|
||||
return "TLV_T_MLACP_SYSTEM_CONFIG";
|
||||
|
||||
case TLV_T_MLACP_PORT_CONFIG:
|
||||
return "TLV_T_MLACP_PORT_CONFIG";
|
||||
|
||||
case TLV_T_MLACP_PORT_PRIORITY:
|
||||
return "TLV_T_MLACP_PORT_PRIORITY";
|
||||
|
||||
case TLV_T_MLACP_PORT_STATE:
|
||||
return "TLV_T_MLACP_PORT_STATE";
|
||||
|
||||
case TLV_T_MLACP_AGGREGATOR_CONFIG:
|
||||
return "TLV_T_MLACP_AGGREGATOR_CONFIG";
|
||||
|
||||
case TLV_T_MLACP_AGGREGATOR_STATE:
|
||||
return "TLV_T_MLACP_AGGREGATOR_STATE";
|
||||
|
||||
case TLV_T_MLACP_SYNC_REQUEST:
|
||||
return "TLV_T_MLACP_SYNC_REQUEST";
|
||||
|
||||
case TLV_T_MLACP_SYNC_DATA:
|
||||
return "TLV_T_MLACP_SYNC_DATA";
|
||||
|
||||
case TLV_T_MLACP_HEARTBEAT:
|
||||
return "TLV_T_MLACP_HEARTBEAT";
|
||||
|
||||
case TLV_T_MLACP_DISCONNECT_CAUSE:
|
||||
return "TLV_T_MLACP_DISCONNECT_CAUSE";
|
||||
|
||||
/* NOS Feature */
|
||||
case TLV_T_MLACP_ORPHAN_PORT:
|
||||
return "TLV_T_MLACP_ORPHAN_PORT";
|
||||
|
||||
case TLV_T_MLACP_PORT_CHANNEL_INFO:
|
||||
return "TLV_T_MLACP_PORT_CHANNEL_INFO";
|
||||
|
||||
case TLV_T_MLACP_PEERLINK_INFO:
|
||||
return "TLV_T_MLACP_PEERLINK_INFO";
|
||||
|
||||
case TLV_T_MLACP_ARP_INFO:
|
||||
return "TLV_T_MLACP_ARP_INFO";
|
||||
|
||||
case TLV_T_MLACP_MAC_INFO:
|
||||
return "TLV_T_MLACP_MAC_INFO";
|
||||
|
||||
case TLV_T_MLACP_STP_INFO:
|
||||
return "TLV_T_MLACP_STP_INFO";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 12.4. Status Code Name Space
|
||||
* [Page 81]
|
||||
*/
|
||||
#define STATUS_CODE_U_ICCP_RG 0x00010001
|
||||
#define STATUS_CODE_ICCP_CONNECTION_COUNT_EXCEEDED 0x00010002
|
||||
#define STATUS_CODE_ICCP_APP_CONNECTION_COUNT_EXCEEDED 0x00010003
|
||||
#define STATUS_CODE_ICCP_APP_NOT_IN_RG 0x00010004
|
||||
#define STATUS_CODE_INCOMPATIBLE_ICCP_PROTOCOL_VER 0x00010005
|
||||
#define STATUS_CODE_ICCP_REJECTED_MSG 0x00010006
|
||||
#define STATUS_CODE_ICCP_ADMINISTRATIVELY_DISABLED 0x00010007
|
||||
#define STATUS_CODE_ICCP_RG_REMOVED 0x00010010
|
||||
#define STATUS_CODE_ICCP_APP_REMOVED_FROM_RG 0x00010011
|
||||
|
||||
|
||||
/* Debug */
|
||||
static char* get_status_string(int status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_CODE_U_ICCP_RG:
|
||||
return "Unknown ICCP RG";
|
||||
|
||||
case STATUS_CODE_ICCP_CONNECTION_COUNT_EXCEEDED:
|
||||
return "ICCP Connection Count Exceeded";
|
||||
|
||||
case STATUS_CODE_ICCP_APP_CONNECTION_COUNT_EXCEEDED:
|
||||
return "ICCP Application Connection Count Exceede";
|
||||
|
||||
case STATUS_CODE_ICCP_APP_NOT_IN_RG:
|
||||
return "ICCP Application not in RG";
|
||||
|
||||
case STATUS_CODE_INCOMPATIBLE_ICCP_PROTOCOL_VER:
|
||||
return "Incompatible ICCP Protocol Version";
|
||||
|
||||
case STATUS_CODE_ICCP_REJECTED_MSG:
|
||||
return "ICCP Rejected Message";
|
||||
|
||||
case STATUS_CODE_ICCP_ADMINISTRATIVELY_DISABLED:
|
||||
return "ICCP Administratively Disabled";
|
||||
|
||||
case STATUS_CODE_ICCP_RG_REMOVED:
|
||||
return "ICCP RG Removed";
|
||||
|
||||
case STATUS_CODE_ICCP_APP_REMOVED_FROM_RG:
|
||||
return "ICCP Application Removed from RG";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
/*
|
||||
* RFC 5036
|
||||
* 3.5. LDP Messages
|
||||
* [Page 44]
|
||||
*/
|
||||
struct LDPHdr
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t u_bit : 1;
|
||||
uint16_t msg_type : 15;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint16_t msg_type : 15;
|
||||
uint16_t u_bit : 1;
|
||||
#endif
|
||||
uint16_t msg_len;
|
||||
uint32_t msg_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct LDPHdr LDPHdr;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.1.1. ICC Header
|
||||
* [Page 24]
|
||||
*/
|
||||
struct ICCRGIDTLV
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t icc_rg_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct ICCRGIDTLV ICCRGIDTLV;
|
||||
|
||||
struct ICCHdr
|
||||
{
|
||||
LDPHdr ldp_hdr;
|
||||
ICCRGIDTLV icc_rg_id_tlv;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct ICCHdr ICCHdr;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.1.2. ICC Parameter Encoding
|
||||
* [Page 26]
|
||||
*/
|
||||
struct ICCParameter
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t u_bit : 1;
|
||||
uint16_t f_bit : 1;
|
||||
uint16_t type : 14;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint16_t type : 14;
|
||||
uint16_t f_bit : 1;
|
||||
uint16_t u_bit : 1;
|
||||
#endif
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct ICCParameter ICCParameter;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.2.1. ICC Sender Name TLV
|
||||
* [Page 28]
|
||||
*/
|
||||
struct ICCSenderNameTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
char sender_name[MAX_L_ICC_SENDER_NAME];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct ICCSenderNameTLV ICCSenderNameTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.3. RG Disconnect Message
|
||||
* [Page 29]
|
||||
*/
|
||||
struct DisconnectCodeTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint32_t iccp_status_code;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct DisconnectCodeTLV DisconnectCodeTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.4.1. Notification Message TLVs
|
||||
* [Page 32]
|
||||
*/
|
||||
struct NAKTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint32_t iccp_status_code;
|
||||
uint32_t rejected_msg_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct NAKTLV NAKTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 6.4.1. Notification Message TLVs
|
||||
* [Page 34]
|
||||
*/
|
||||
struct RequestedProtocolVerTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint16_t connection_ref;
|
||||
uint16_t requested_ver;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct RequestedProtocolVerTLV RequestedProtocolVerTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 8. LDP Capability Negotiation
|
||||
* [Page 65]
|
||||
*/
|
||||
struct LDPICCPCapabilityTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t s_bit : 1;
|
||||
uint16_t reserved : 15;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint16_t reserved : 15;
|
||||
uint16_t s_bit : 1;
|
||||
#endif
|
||||
uint8_t major_ver;
|
||||
uint8_t minior_ver;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct LDPICCPCapabilityTLV LDPICCPCapabilityTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.1. mLACP Connect TLV
|
||||
* [Page 47]
|
||||
*/
|
||||
struct AppConnectTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
uint16_t protocol_version;
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint16_t a_bit : 1;
|
||||
uint16_t reserved : 15;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint16_t reserved : 15;
|
||||
uint16_t a_bit : 1;
|
||||
#endif
|
||||
|
||||
/* Optional Sub-TLVs */
|
||||
/* No optional sub-TLVs in this version */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct AppConnectTLV AppConnectTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.2. mLACP Disconnect TLV
|
||||
* [Page 48]
|
||||
*/
|
||||
struct AppDisconnectTLV
|
||||
{
|
||||
ICCParameter icc_parameter;
|
||||
|
||||
/* Optional Sub-TLVs */
|
||||
/* mLACP Disconnect Cause TLV */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct AppDisconnectTLV AppDisconnectTLV;
|
||||
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.2.1. mLACP Disconnect Cause TLV
|
||||
* [Page 49]
|
||||
*/
|
||||
struct AppDisconnectCauseTLV
|
||||
{
|
||||
ICCParameter iccp_parameter;
|
||||
|
||||
/* Disconnect Cause String */
|
||||
char cause_string[0]; /* Trick */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*syncd send msg type to iccpd*/
|
||||
typedef enum mclag_syncd_msg_type_e_
|
||||
{
|
||||
MCLAG_SYNCD_MSG_TYPE_NONE = 0,
|
||||
MCLAG_SYNCD_MSG_TYPE_FDB_OPERATION = 1
|
||||
}mclag_syncd_msg_type_e;
|
||||
|
||||
typedef enum mclag_msg_type_e_
|
||||
{
|
||||
MCLAG_MSG_TYPE_NONE = 0,
|
||||
MCLAG_MSG_TYPE_PORT_ISOLATE = 1,
|
||||
MCLAG_MSG_TYPE_PORT_MAC_LEARN_MODE = 2,
|
||||
MCLAG_MSG_TYPE_FLUSH_FDB = 3,
|
||||
MCLAG_MSG_TYPE_SET_MAC = 4,
|
||||
MCLAG_MSG_TYPE_SET_FDB = 5,
|
||||
MCLAG_MSG_TYPE_GET_FDB_CHANGES = 20
|
||||
}mclag_msg_type_e;
|
||||
|
||||
|
||||
typedef enum mclag_sub_option_type_e_
|
||||
{
|
||||
MCLAG_SUB_OPTION_TYPE_NONE = 0,
|
||||
MCLAG_SUB_OPTION_TYPE_ISOLATE_SRC = 1,
|
||||
MCLAG_SUB_OPTION_TYPE_ISOLATE_DST = 2,
|
||||
MCLAG_SUB_OPTION_TYPE_MAC_LEARN_ENABLE = 3,
|
||||
MCLAG_SUB_OPTION_TYPE_MAC_LEARN_DISABLE = 4,
|
||||
MCLAG_SUB_OPTION_TYPE_SET_MAC_SRC = 5,
|
||||
MCLAG_SUB_OPTION_TYPE_SET_MAC_DST = 6
|
||||
} mclag_sub_option_type_e;
|
||||
|
||||
|
||||
struct IccpSyncdHDr
|
||||
{
|
||||
uint8_t ver;
|
||||
uint8_t type;
|
||||
uint16_t len;
|
||||
};
|
||||
|
||||
typedef struct mclag_sub_option_hdr_t_
|
||||
{
|
||||
|
||||
uint8_t op_type;
|
||||
|
||||
/*
|
||||
* Length of option value, not including the header.
|
||||
*/
|
||||
uint16_t op_len;
|
||||
uint8_t data[];
|
||||
}mclag_sub_option_hdr_t;
|
||||
|
||||
struct mclag_fdb_info
|
||||
{
|
||||
char mac[ETHER_ADDR_STR_LEN];
|
||||
unsigned int vid;
|
||||
char port_name[MAX_L_PORT_NAME];
|
||||
short type; /*dynamic or static*/
|
||||
short op_type; /*add or del*/
|
||||
};
|
||||
|
||||
/* For storing message log: For Notification TLV */
|
||||
struct MsgTypeSet
|
||||
{
|
||||
uint32_t msg_id;
|
||||
uint16_t type;
|
||||
uint16_t tlv;
|
||||
|
||||
};
|
||||
|
||||
struct MsgLog
|
||||
{
|
||||
struct MsgTypeSet msg[MAX_MSG_LOG_SIZE];
|
||||
uint32_t end_index;
|
||||
};
|
||||
|
||||
#endif /* MSG_FORMAT_H_ */
|
156
src/iccpd/include/port.h
Normal file
156
src/iccpd/include/port.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* port.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef PORT_H_
|
||||
#define PORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define ETHER_ADDR_LEN 6
|
||||
#define ETHER_ADDR_STR_LEN 18
|
||||
/*
|
||||
* RFC 7275
|
||||
* 7.2.4. mLACP Port Config TLV
|
||||
* [Page 56]
|
||||
*/
|
||||
#define MAX_L_PORT_NAME 20
|
||||
|
||||
/* defined in RFC 7275 - 7.2.7 (p.59) */
|
||||
#define PORT_STATE_UP 0x00
|
||||
#define PORT_STATE_DOWN 0x01
|
||||
#define PORT_STATE_ADMIN_DOWN 0x02
|
||||
#define PORT_STATE_TEST 0x03
|
||||
|
||||
/* Interface Type */
|
||||
#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
|
||||
typedef struct
|
||||
{
|
||||
char *ifname;
|
||||
int type;
|
||||
} itf_type_t;
|
||||
|
||||
struct If_info
|
||||
{
|
||||
char name[MAX_L_PORT_NAME];
|
||||
LIST_ENTRY(If_info) csm_next;
|
||||
};
|
||||
|
||||
struct VLAN_ID
|
||||
{
|
||||
uint16_t vid;
|
||||
uint16_t vlan_removed;
|
||||
struct LocalInterface* vlan_itf; /* loacl vlan interface */
|
||||
LIST_ENTRY(VLAN_ID) port_next;
|
||||
};
|
||||
|
||||
struct PeerInterface
|
||||
{
|
||||
int ifindex;
|
||||
int type;
|
||||
char name[MAX_L_PORT_NAME];
|
||||
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
uint8_t state;
|
||||
uint32_t ipv4_addr;
|
||||
|
||||
uint8_t l3_mode;
|
||||
uint8_t is_peer_link;
|
||||
int po_id;
|
||||
uint8_t po_active;
|
||||
|
||||
struct CSM* csm;
|
||||
|
||||
LIST_ENTRY(PeerInterface) mlacp_next;
|
||||
LIST_HEAD(peer_vlan_list, VLAN_ID) vlan_list;
|
||||
};
|
||||
|
||||
struct LocalInterface
|
||||
{
|
||||
int ifindex;
|
||||
int type;
|
||||
char name[MAX_L_PORT_NAME];
|
||||
|
||||
uint8_t mac_addr[ETHER_ADDR_LEN];
|
||||
uint8_t mac_addr_ori[ETHER_ADDR_LEN];
|
||||
uint8_t state;
|
||||
uint32_t ipv4_addr;
|
||||
uint8_t prefixlen;
|
||||
|
||||
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? */
|
||||
int mlacp_state; /* Record mlacp state */
|
||||
uint8_t isolate_to_peer_link;
|
||||
|
||||
struct CSM* csm;
|
||||
|
||||
uint8_t changed;
|
||||
uint8_t port_config_sync;
|
||||
|
||||
LIST_HEAD(local_vlan_list, VLAN_ID) vlan_list;
|
||||
|
||||
LIST_ENTRY(LocalInterface) system_next;
|
||||
LIST_ENTRY(LocalInterface) system_purge_next;
|
||||
LIST_ENTRY(LocalInterface) mlacp_next;
|
||||
LIST_ENTRY(LocalInterface) mlacp_purge_next;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
void local_if_destroy(char *ifname);
|
||||
void local_if_change_flag_clear(void);
|
||||
void local_if_purge_clear(void);
|
||||
int local_if_is_l3_mode(struct LocalInterface* local_if);
|
||||
|
||||
void local_if_init(struct LocalInterface*);
|
||||
void local_if_finalize(struct LocalInterface*);
|
||||
|
||||
struct PeerInterface* peer_if_create(struct CSM* csm, int peer_if_number, int type);
|
||||
struct PeerInterface* peer_if_find_by_name(struct CSM* csm, char* name);
|
||||
|
||||
void peer_if_destroy(struct PeerInterface* pif);
|
||||
int peer_if_add_vlan(struct PeerInterface* peer_if, uint16_t vlan_id);
|
||||
int peer_if_clean_unused_vlan(struct PeerInterface* peer_if);
|
||||
/* VLAN manipulation */
|
||||
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);
|
||||
|
||||
/* ARP manipulation */
|
||||
int set_sys_arp_accept_flag(char* ifname, int flag);
|
||||
|
||||
#endif /* PORT_H_ */
|
59
src/iccpd/include/scheduler.h
Normal file
59
src/iccpd/include/scheduler.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* scheduler.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef SCHEDULER_H_
|
||||
#define SCHEDULER_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct CSM;
|
||||
|
||||
#define CONNECT_INTERVAL_SEC 1
|
||||
#define CONNECT_TIMEOUT_MSEC 100
|
||||
#define HEARTBEAT_TIMEOUT_SEC 15
|
||||
#define TRANSIT_INTERVAL_SEC 1
|
||||
#define EPOLL_TIMEOUT_MSEC 100
|
||||
|
||||
int scheduler_prepare_session(struct CSM*);
|
||||
int scheduler_check_csm_config(struct CSM*);
|
||||
int scheduler_unregister_sock_read_event_callback(struct CSM*);
|
||||
void scheduler_session_disconnect_handler(struct CSM*);
|
||||
void scheduler_init();
|
||||
void scheduler_finalize();
|
||||
void scheduler_loop();
|
||||
void scheduler_start();
|
||||
void scheduler_server_sock_init();
|
||||
int scheduler_csm_read_callback(struct CSM* csm);
|
||||
int iccp_get_server_sock_fd();
|
||||
int scheduler_server_accept();
|
||||
int iccp_receive_signal_handler(struct System* sys);
|
||||
|
||||
#endif /* SCHEDULER_H_ */
|
102
src/iccpd/include/system.h
Normal file
102
src/iccpd/include/system.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* system.h
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_H_
|
||||
#define SYSTEM_H_
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../include/port.h"
|
||||
|
||||
#define FRONT_PANEL_PORT_PREFIX "Ethernet"
|
||||
#define PORTCHANNEL_PREFIX "PortChannel"
|
||||
#define VLAN_PREFIX "Vlan"
|
||||
#define VXLAN_TUNNEL_PREFIX "VTTNL"
|
||||
|
||||
#define WARM_REBOOT 1
|
||||
|
||||
#define MCLAG_ERROR -1
|
||||
|
||||
struct CSM;
|
||||
|
||||
#ifndef MAX_BUFSIZE
|
||||
#define MAX_BUFSIZE 4096
|
||||
#endif
|
||||
|
||||
struct System
|
||||
{
|
||||
int server_fd;/* Peer-Link Socket*/
|
||||
int sync_fd;
|
||||
int sync_ctrl_fd;
|
||||
int arp_receive_fd;
|
||||
int epoll_fd;
|
||||
|
||||
struct nl_sock * genric_sock;
|
||||
int genric_sock_seq;
|
||||
int family;
|
||||
struct nl_sock * route_sock;
|
||||
int route_sock_seq;
|
||||
struct nl_sock * genric_event_sock;
|
||||
struct nl_sock * route_event_sock;
|
||||
|
||||
int sig_pipe_r;
|
||||
int sig_pipe_w;
|
||||
int warmboot_start;
|
||||
int warmboot_exit;
|
||||
|
||||
/* Info List*/
|
||||
LIST_HEAD(csm_list, CSM) csm_list;
|
||||
LIST_HEAD(lif_all_list, LocalInterface) lif_list;
|
||||
LIST_HEAD(lif_purge_all_list, LocalInterface) lif_purge_list;
|
||||
|
||||
/* Settings */
|
||||
char* log_file_path;
|
||||
char* cmd_file_path;
|
||||
char* config_file_path;
|
||||
char* mclagdctl_file_path;
|
||||
int pid_file_fd;
|
||||
int telnet_port;
|
||||
fd_set readfd; /*record socket need to listen*/
|
||||
int readfd_count;
|
||||
time_t csm_trans_time;
|
||||
int need_sync_team_again;
|
||||
int need_sync_netlink_again;
|
||||
};
|
||||
|
||||
struct CSM* system_create_csm();
|
||||
struct CSM* system_get_csm_by_peer_ip(const char*);
|
||||
struct CSM* system_get_csm_by_mlacp_id(int id);
|
||||
struct System* system_get_instance();
|
||||
void system_finalize();
|
||||
void system_init(struct System*);
|
||||
|
||||
#endif /* SYSTEM_H_ */
|
55
src/iccpd/src/Makefile
Normal file
55
src/iccpd/src/Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
LIBNL_CFLAGS = -I/usr/include/libnl3
|
||||
LIBNL_LIBS = -lnl-cli-3 -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3
|
||||
|
||||
CC = gcc
|
||||
SOURCES = app_csm.c cmd_option.c iccp_cli.c iccp_cmd_show.c iccp_cmd.c \
|
||||
iccp_csm.c iccp_ifm.c iccp_main.c logger.c \
|
||||
port.c scheduler.c system.c iccp_consistency_check.c \
|
||||
mlacp_link_handler.c \
|
||||
mlacp_sync_prepare.c mlacp_sync_update.c\
|
||||
mlacp_fsm.c \
|
||||
iccp_netlink.c
|
||||
|
||||
OBJECTS = app_csm.o cmd_option.o iccp_cli.o iccp_cmd_show.o iccp_cmd.o \
|
||||
iccp_csm.o iccp_ifm.o iccp_main.o logger.o \
|
||||
port.o scheduler.o system.o iccp_consistency_check.o\
|
||||
mlacp_link_handler.o \
|
||||
mlacp_sync_prepare.o mlacp_sync_update.o \
|
||||
mlacp_fsm.o \
|
||||
iccp_netlink.o
|
||||
|
||||
HEADERS = ../include/app_csm.h ../include/cmd_option.h ../include/iccp_cli.h \
|
||||
../include/iccp_cmd_show.h \
|
||||
../include/iccp_csm.h ../include/iccp_ifm.h \
|
||||
../include/logger.h ../include/mlacp_fsm.h \
|
||||
../include/mlacp_tlv.h ../include/msg_format.h ../include/port.h \
|
||||
../include/scheduler.h ../include/system.h \
|
||||
../include/iccp_consistency_check.h ../include/route_info.h \
|
||||
../include/iccp_netlink.h
|
||||
|
||||
//CFLAGS = -g -O2 -fstack-protector-strong -Wformat -Werror=format-security $(LIBNL_CFLAGS) -I../include/
|
||||
CFLAGS = -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -I../include/ $(LIBNL_CFLAGS)
|
||||
LDFLAGS = $(LIBNL_LIBS) -lpthread
|
||||
LDADD = $(LIBZEBRA_BIN)
|
||||
|
||||
all: iccpd
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
|
||||
iccpd: $(OBJECTS)
|
||||
$(CC) -o ../iccpd $(OBJECTS) $(LDFLAGS)
|
||||
|
||||
DEPS = $(patsubst %.o, %.d, $(OBJECTS))
|
||||
|
||||
-include $(DEPS)
|
||||
%.d:%.c
|
||||
@set -e; rm -f $@; \
|
||||
gcc -MM $(CPPFLAGS) $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$
|
||||
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f $(OBJECTS) $(DEPS) ../iccpd
|
316
src/iccpd/src/app_csm.c
Normal file
316
src/iccpd/src/app_csm.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* app_csm.c
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/scheduler.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/iccp_netlink.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
/*****************************************
|
||||
* Define
|
||||
*
|
||||
* ***************************************/
|
||||
#define APP_CSM_QUEUE_REINIT(list) \
|
||||
{ \
|
||||
struct Msg* msg = NULL; \
|
||||
while (!TAILQ_EMPTY(&(list))) { \
|
||||
msg = TAILQ_FIRST(&(list)); \
|
||||
TAILQ_REMOVE(&(list), msg, tail); \
|
||||
free(msg->buf); \
|
||||
free(msg); \
|
||||
} \
|
||||
TAILQ_INIT(&(list)); \
|
||||
}
|
||||
|
||||
/* Application State Machine instance initialization */
|
||||
void app_csm_init(struct CSM* csm, int all)
|
||||
{
|
||||
if (csm == NULL )
|
||||
return;
|
||||
|
||||
APP_CSM_QUEUE_REINIT(csm->app_csm.app_msg_list);
|
||||
|
||||
if (all)
|
||||
{
|
||||
bzero(&(csm->app_csm), sizeof(struct AppCSM));
|
||||
APP_CSM_QUEUE_REINIT(csm->app_csm.app_msg_list);
|
||||
}
|
||||
|
||||
csm->app_csm.current_state = APP_NONEXISTENT;
|
||||
csm->app_csm.rx_connect_msg_id = 0;
|
||||
csm->app_csm.tx_connect_msg_id = 0;
|
||||
csm->app_csm.invalid_msg_id = 0;
|
||||
csm->app_csm.invalid_msg = 0;
|
||||
csm->app_csm.nak_msg = 0;
|
||||
|
||||
mlacp_init(csm, all);
|
||||
}
|
||||
|
||||
/* Application State Machine instance tear down */
|
||||
void app_csm_finalize(struct CSM* csm)
|
||||
{
|
||||
mlacp_finalize(csm);
|
||||
}
|
||||
|
||||
/* Application State Machine Transition */
|
||||
void app_csm_transit(struct CSM* csm)
|
||||
{
|
||||
if (csm == NULL )
|
||||
return;
|
||||
|
||||
/* torn down event */
|
||||
if (csm->app_csm.current_state != APP_NONEXISTENT && csm->sock_fd <= 0)
|
||||
{
|
||||
csm->app_csm.current_state = APP_NONEXISTENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (csm->app_csm.current_state != APP_OPERATIONAL && csm->current_state == ICCP_OPERATIONAL)
|
||||
{
|
||||
csm->app_csm.current_state = APP_OPERATIONAL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add received message into application message list */
|
||||
void app_csm_enqueue_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
ICCParameter* param = NULL;
|
||||
NAKTLV* naktlv = NULL;
|
||||
int tlv = -1;
|
||||
int i = 0;
|
||||
|
||||
if (csm == NULL )
|
||||
{
|
||||
if (msg != NULL )
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
if (msg == NULL )
|
||||
return;
|
||||
|
||||
icc_hdr = (ICCHdr*)msg->buf;
|
||||
param = (ICCParameter*)&msg->buf[sizeof(struct ICCHdr)];
|
||||
*(uint16_t *)param = ntohs(*(uint16_t *)param);
|
||||
|
||||
if ( icc_hdr->ldp_hdr.msg_type == MSG_T_RG_APP_DATA)
|
||||
{
|
||||
if (param->type > TLV_T_MLACP_CONNECT && param->type < TLV_T_MLACP_LIST_END)
|
||||
mlacp_enqueue_msg(csm, msg);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&(csm->app_csm.app_msg_list), msg, tail);
|
||||
}
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_NOTIFICATION)
|
||||
{
|
||||
naktlv = (NAKTLV*)&msg->buf[sizeof(ICCHdr)];
|
||||
|
||||
for (i = 0; i < MAX_MSG_LOG_SIZE; ++i)
|
||||
{
|
||||
if (ntohl(naktlv->rejected_msg_id) == csm->msg_log.msg[i].msg_id)
|
||||
{
|
||||
tlv = csm->msg_log.msg[i].tlv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tlv > TLV_T_MLACP_CONNECT && tlv <= TLV_T_MLACP_MAC_INFO)
|
||||
mlacp_enqueue_msg(csm, msg);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&(csm->app_csm.app_msg_list), msg, tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This packet is not for me, ignore it. */
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignore the packet with msg_type = %d", icc_hdr->ldp_hdr.msg_type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get received message from message list */
|
||||
struct Msg* app_csm_dequeue_msg(struct CSM* csm)
|
||||
{
|
||||
struct Msg* msg = NULL;
|
||||
|
||||
if (!TAILQ_EMPTY(&(csm->app_csm.app_msg_list)))
|
||||
{
|
||||
msg = TAILQ_FIRST(&(csm->app_csm.app_msg_list));
|
||||
TAILQ_REMOVE(&(csm->app_csm.app_msg_list), msg, tail);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* APP NAK message handle function */
|
||||
int app_csm_prepare_nak_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
NAKTLV* naktlv = (NAKTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(NAKTLV);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, " Response NAK");
|
||||
memset(buf, 0, max_buf_size);
|
||||
icc_hdr->ldp_hdr.u_bit = 0x0;
|
||||
icc_hdr->ldp_hdr.msg_type = htons(MSG_T_NOTIFICATION);
|
||||
icc_hdr->ldp_hdr.msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
icc_hdr->ldp_hdr.msg_id = htonl(ICCP_MSG_ID++);
|
||||
iccp_csm_fill_icc_rg_id_tlv(csm, icc_hdr);
|
||||
naktlv->icc_parameter.u_bit = 0;
|
||||
naktlv->icc_parameter.f_bit = 0;
|
||||
naktlv->icc_parameter.type = htons(TLV_T_NAK);
|
||||
naktlv->icc_parameter.len = htons(sizeof(NAKTLV) - 4);
|
||||
|
||||
naktlv->iccp_status_code = htonl(STATUS_CODE_ICCP_REJECTED_MSG);
|
||||
naktlv->rejected_msg_id = htonl(csm->app_csm.invalid_msg_id);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
int mlacp_bind_local_if(struct CSM* csm, struct LocalInterface* lif)
|
||||
{
|
||||
struct LocalInterface* lifp = NULL;
|
||||
struct LocalInterface* lif_po = NULL;
|
||||
|
||||
if (csm == NULL || lif == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (lif->csm == csm)
|
||||
return 0;
|
||||
|
||||
/* remove purge from the csm*/
|
||||
do {
|
||||
LIST_FOREACH(lifp, &(MLACP(csm).lif_purge_list), mlacp_purge_next)
|
||||
{
|
||||
if (lifp == lif)
|
||||
break;
|
||||
}
|
||||
if (lifp)
|
||||
LIST_REMOVE(lifp, mlacp_purge_next);
|
||||
} while (lifp);
|
||||
|
||||
/* already join csm?*/
|
||||
LIST_FOREACH(lifp, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lifp == lif)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* join another csm beofre? remove from csm*/
|
||||
if (lif->csm != NULL)
|
||||
mlacp_unbind_local_if(lif);
|
||||
|
||||
/* join new csm*/
|
||||
LIST_INSERT_HEAD(&(MLACP(csm).lif_list), lif, mlacp_next);
|
||||
lif->csm = csm;
|
||||
if (lif->type == IF_T_PORT_CHANNEL)
|
||||
lif->port_config_sync = 1;
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "%s: MLACP bind on csm %p", lif->name, csm);
|
||||
if (lif->type == IF_T_PORT_CHANNEL)
|
||||
return 0;
|
||||
|
||||
/* if join a po member, needs to check po joined also*/
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lif_po->type == IF_T_PORT_CHANNEL && lif_po->po_id == lif->po_id)
|
||||
{
|
||||
/*if join a po member, may swss restart, reset portchannel ip mac to mclagsyncd*/
|
||||
update_if_ipmac_on_standby(lif_po);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lif_po == NULL)
|
||||
{
|
||||
lif_po = local_if_find_by_po_id(lif->po_id);
|
||||
if (lif_po == NULL)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to find port_channel instance for %d.", lif->po_id);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
lif_po->csm = csm;
|
||||
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;
|
||||
}
|
||||
|
||||
int mlacp_unbind_local_if(struct LocalInterface* lif)
|
||||
{
|
||||
if (lif == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (lif->csm == NULL )
|
||||
return 0;
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "%s: MLACP un-bind from csm %p", lif->name, lif->csm);
|
||||
LIST_REMOVE(lif, mlacp_next);
|
||||
|
||||
if (MLACP(lif->csm).current_state == MLACP_STATE_EXCHANGE && lif->type == IF_T_PORT_CHANNEL)
|
||||
LIST_INSERT_HEAD(&(MLACP(lif->csm).lif_purge_list), lif, mlacp_purge_next);
|
||||
if (lif->type == IF_T_PORT)
|
||||
lif->po_id = -1;
|
||||
lif->csm = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlacp_bind_port_channel_to_csm(struct CSM* csm, const char *ifname)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface *lif_po = NULL;
|
||||
|
||||
sys = system_get_instance();
|
||||
if (sys == NULL)
|
||||
return 0;
|
||||
|
||||
if (csm == NULL)
|
||||
return 0;
|
||||
|
||||
/* bind po first*/
|
||||
lif_po = local_if_find_by_name(ifname);
|
||||
if (lif_po)
|
||||
{
|
||||
mlacp_bind_local_if(csm, lif_po);
|
||||
iccp_get_port_member_list(lif_po);
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "%s: Failed to find a port instance .", ifname);
|
||||
return 0;
|
||||
}
|
||||
/* process link state handler after attaching it.*/
|
||||
|
||||
mlacp_mlag_link_add_handler(csm, lif_po);
|
||||
|
||||
/*ICCPD_LOG_WARN(tag, "po%d active = %d\n", po_id, po_is_active);*/
|
||||
return 0;
|
||||
}
|
||||
|
266
src/iccpd/src/cmd_option.c
Normal file
266
src/iccpd/src/cmd_option.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* cmd_option.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include "../include/cmd_option.h"
|
||||
|
||||
struct CmdOption* cmd_option_find(struct CmdOptionParser* parser, char* opt_name)
|
||||
{
|
||||
struct CmdOption* opt = NULL;
|
||||
|
||||
if (opt_name == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(opt, &(parser->option_list), next)
|
||||
{
|
||||
if (strcmp(opt->option, opt_name) == 0)
|
||||
return opt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cmd_option_delete(struct CmdOption* opt)
|
||||
{
|
||||
if (opt == NULL)
|
||||
return;
|
||||
|
||||
LIST_REMOVE(opt, next);
|
||||
if (opt->option != NULL)
|
||||
free(opt->option);
|
||||
if (opt->parameter != NULL)
|
||||
free(opt->parameter);
|
||||
if (opt->desc != NULL)
|
||||
free(opt->desc);
|
||||
free(opt);
|
||||
}
|
||||
|
||||
struct CmdOption* cmd_option_add(struct CmdOptionParser* parser, char* opt_name)
|
||||
{
|
||||
struct CmdOption* opt = NULL;
|
||||
|
||||
if (opt_name == NULL)
|
||||
return NULL;
|
||||
if ((opt = cmd_option_find(parser, opt_name)) != NULL)
|
||||
return opt;
|
||||
|
||||
if ((opt = (struct CmdOption*)malloc(sizeof(struct CmdOption))) == NULL)
|
||||
{
|
||||
strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
opt->option = opt_name;
|
||||
opt->parameter = NULL;
|
||||
opt->desc = NULL;
|
||||
LIST_INSERT_HEAD(&(parser->option_list), opt, next);
|
||||
}
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
static void cmd_option_register(struct CmdOptionParser* parser, char* syntax, char* desc)
|
||||
{
|
||||
char buf[OPTION_MAX_LEN];
|
||||
struct CmdOption* opt = NULL;
|
||||
char* opt_name = NULL;
|
||||
char* param = NULL;
|
||||
char* desc_copy = NULL;
|
||||
char* token = NULL;
|
||||
|
||||
if (parser == NULL)
|
||||
return;
|
||||
if (syntax == NULL)
|
||||
return;
|
||||
|
||||
memset(buf, 0, OPTION_MAX_LEN);
|
||||
snprintf(buf, OPTION_MAX_LEN - 1, "%s", syntax);
|
||||
|
||||
if ((token = strtok(buf, " ")) == NULL)
|
||||
return;
|
||||
|
||||
opt_name = strdup(token);
|
||||
if ((token = strtok(NULL, " ")) != NULL)
|
||||
param = strdup(token);
|
||||
desc_copy = strdup(desc);
|
||||
if ((opt = cmd_option_find(parser, opt_name)) != NULL)
|
||||
goto failed;
|
||||
if ((opt = cmd_option_add(parser, opt_name)) == NULL)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
opt->parameter = param;
|
||||
opt->desc = desc_copy;
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
if (opt_name)
|
||||
free(opt_name);
|
||||
if (desc_copy != NULL)
|
||||
free(desc_copy);
|
||||
if (param != NULL)
|
||||
free(param);
|
||||
if (opt != NULL)
|
||||
free(opt);
|
||||
}
|
||||
|
||||
void cmd_option_parser_init(struct CmdOptionParser* parser)
|
||||
{
|
||||
if (parser == NULL)
|
||||
return;
|
||||
|
||||
LIST_INIT(&parser->option_list);
|
||||
cmd_option_register(parser, "-l <LOG_FILE_PATH>", "Set log file path.\n(Default: /var/log/iccpd.log)");
|
||||
cmd_option_register(parser, "-p <TCP_PORT>", "Set the port used for telnet listening port.\n(Default: 2015)");
|
||||
cmd_option_register(parser, "-c", "Dump log message to console. (Default: No)");
|
||||
cmd_option_register(parser, "-h", "Show the usage.");
|
||||
}
|
||||
|
||||
void cmd_option_parser_finalize(struct CmdOptionParser* parser)
|
||||
{
|
||||
while (!LIST_EMPTY(&(parser->option_list)))
|
||||
{
|
||||
struct CmdOption* opt = NULL;
|
||||
opt = LIST_FIRST(&(parser->option_list));
|
||||
cmd_option_delete(opt);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_option_parser_dump_usage(struct CmdOptionParser* parser, char* prog_name)
|
||||
{
|
||||
char buf[MSG_LEN];
|
||||
struct CmdOption* opt = NULL;
|
||||
int index, begin, length;
|
||||
char first_line = 0;
|
||||
|
||||
fprintf(stdout, "Usage: %s [Options]\n", prog_name);
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "Options:\n");
|
||||
LIST_FOREACH(opt, &(parser->option_list), next)
|
||||
{
|
||||
index = 0;
|
||||
begin = 0;
|
||||
length = 0;
|
||||
first_line = 1;
|
||||
memset(buf, 0, MSG_LEN);
|
||||
if (opt->parameter != NULL)
|
||||
snprintf(buf, MSG_LEN - 1, "%s %s", opt->option, opt->parameter);
|
||||
else
|
||||
snprintf(buf, MSG_LEN - 1, "%s", opt->option);
|
||||
fprintf(stdout, "%24s ", buf);
|
||||
|
||||
while (index < strlen(opt->desc))
|
||||
{
|
||||
while (index < strlen(opt->desc)
|
||||
&& opt->desc[index] != '\n' && length < 49)
|
||||
{
|
||||
++index;
|
||||
++length;
|
||||
}
|
||||
|
||||
memset(buf, 0, MSG_LEN);
|
||||
strncpy(buf, &(opt->desc[begin]), length);
|
||||
if (length == 49 && index < strlen(opt->desc)
|
||||
&& opt->desc[index] != '\n'
|
||||
&& opt->desc[index - 1] != ' '
|
||||
&& opt->desc[index] != ' ')
|
||||
{
|
||||
buf[length] = '-';
|
||||
buf[length + 1] = '\0';
|
||||
}
|
||||
if (length < 49)
|
||||
++index;
|
||||
begin = index;
|
||||
length = 0;
|
||||
if (first_line != 0)
|
||||
{
|
||||
fprintf(stdout, "%-52s\n", buf);
|
||||
first_line = 0;
|
||||
}
|
||||
else
|
||||
fprintf(stdout, "%28c%-52s\n", ' ', buf);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_option_parser_parse(struct CmdOptionParser* parser, int argc, char* argv[])
|
||||
{
|
||||
int index = 1;
|
||||
struct CmdOption* opt = NULL;
|
||||
char* opt_name = NULL;
|
||||
char* val = NULL;
|
||||
int num = 0;
|
||||
|
||||
if (parser == NULL)
|
||||
return -255;
|
||||
|
||||
while (index < argc)
|
||||
{
|
||||
opt_name = argv[index];
|
||||
opt = cmd_option_find(parser, opt_name);
|
||||
if (opt == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unknown option %s, skip it.\n", opt_name);
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opt->parameter != NULL)
|
||||
{
|
||||
++index;
|
||||
if (index >= argc)
|
||||
{
|
||||
fprintf(stderr, "Error: Insufficient parameter for option %s\n", opt_name);
|
||||
cmd_option_parser_dump_usage(parser, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
val = argv[index];
|
||||
}
|
||||
|
||||
if (strncmp(opt_name, "-h", 2) == 0)
|
||||
{
|
||||
cmd_option_parser_dump_usage(parser, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(opt_name, "-l", 2) == 0)
|
||||
parser->log_file_path = val;
|
||||
|
||||
if (strncmp(opt_name, "-p", 2) == 0)
|
||||
{
|
||||
num = atoi(val);
|
||||
if (num > 0 && num < 65535)
|
||||
parser->telnet_port = num;
|
||||
}
|
||||
else if (strncmp(opt_name, "-c", 2) == 0)
|
||||
parser->console_log = 1;
|
||||
else
|
||||
fprintf(stderr, "Unknown option name %s, skip it.\n", opt_name);
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
498
src/iccpd/src/iccp_cli.c
Normal file
498
src/iccpd/src/iccp_cli.c
Normal file
@ -0,0 +1,498 @@
|
||||
/*
|
||||
* iccp_cli.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../include/system.h"
|
||||
#include "../include/scheduler.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
#include "../include/iccp_netlink.h"
|
||||
/*
|
||||
* 'id <1-65535>' command
|
||||
*/
|
||||
int set_mc_lag_id( struct CSM *csm, uint16_t id)
|
||||
{
|
||||
if (!csm)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set mlag-id : %d", id);
|
||||
|
||||
/* Mlag-ID, RG-ID, MLACP-ID
|
||||
Temporary let the three id be the same*/
|
||||
csm->mlag_id = id;
|
||||
csm->iccp_info.icc_rg_id = id;
|
||||
csm->app_csm.mlacp.id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unset_mc_lag_id( struct CSM *csm, uint16_t id)
|
||||
{
|
||||
if (!csm)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Mlag-ID, RG-ID, MLACP-ID*/
|
||||
csm->mlag_id = 0;
|
||||
csm->iccp_info.icc_rg_id = 0;
|
||||
csm->app_csm.mlacp.id = 0;
|
||||
|
||||
iccp_csm_finalize(csm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'peer-link WORD' command
|
||||
*/
|
||||
int set_peer_link(int mid, const char* ifname)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface *lif = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
len = strlen(ifname);
|
||||
|
||||
if (strncmp(ifname, FRONT_PANEL_PORT_PREFIX, strlen(FRONT_PANEL_PORT_PREFIX)) != 0 && strncmp(ifname, PORTCHANNEL_PREFIX, strlen(PORTCHANNEL_PREFIX)) != 0 && strncmp(ifname, VXLAN_TUNNEL_PREFIX, strlen(VXLAN_TUNNEL_PREFIX)) != 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Peer-link is %s, must be Ethernet or PortChannel or VTTNL(Vxlan tunnel)", ifname);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (len > IFNAMSIZ)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (strlen(csm->peer_itf_name) > 0)
|
||||
{
|
||||
if (strcmp(csm->peer_itf_name, ifname) == 0)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Peer-link not be changed");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Change peer-link : %s -> %s",
|
||||
csm->peer_itf_name, ifname);
|
||||
|
||||
/*disconnect the link for mac and arp sync up before change peer_itf_name*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
if (csm->peer_link_if)
|
||||
{
|
||||
csm->peer_link_if->is_peer_link = 0;
|
||||
csm->peer_link_if = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set mlag %d peer-link : %s",
|
||||
csm->mlag_id, ifname);
|
||||
}
|
||||
|
||||
memset(csm->peer_itf_name, 0, IFNAMSIZ);
|
||||
memcpy(csm->peer_itf_name, ifname, len);
|
||||
|
||||
/* update peer-link link handler*/
|
||||
lif = local_if_find_by_name(csm->peer_itf_name);
|
||||
if (lif)
|
||||
{
|
||||
/*When set peer-link, the local-if is already created*/
|
||||
csm->peer_link_if = lif;
|
||||
lif->is_peer_link = 1;
|
||||
MLACP(csm).system_config_changed = 1;
|
||||
|
||||
if (lif->type == IF_T_PORT_CHANNEL)
|
||||
iccp_get_port_member_list(lif);
|
||||
}
|
||||
|
||||
/*disconnect the link for mac and arp sync up*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unset_peer_link(int mid)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
{
|
||||
/*must be enabled mac learn*/
|
||||
if (csm->peer_link_if)
|
||||
set_peerlink_mlag_port_learn(csm->peer_link_if, 1);
|
||||
}
|
||||
|
||||
/* update peer-link link handler*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
/* clean peer-link*/
|
||||
memset(csm->peer_itf_name, 0, IFNAMSIZ);
|
||||
if (csm->peer_link_if)
|
||||
{
|
||||
csm->peer_link_if->is_peer_link = 0;
|
||||
csm->peer_link_if = NULL;
|
||||
MLACP(csm).system_config_changed = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'local ip address A.B.C.D' command
|
||||
*/
|
||||
int set_local_address(int mid, const char* addr)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
if (addr == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (strlen(csm->sender_ip) > 0)
|
||||
{
|
||||
if (strcmp(csm->sender_ip, addr) == 0)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Local-address not be changed");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Change local-address : %s -> %s",
|
||||
csm->sender_ip, addr);
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set local-address : %s", addr);
|
||||
}
|
||||
|
||||
len = strlen(addr);
|
||||
memset(csm->sender_ip, 0, INET_ADDRSTRLEN);
|
||||
memcpy(csm->sender_ip, addr, len);
|
||||
memset(csm->iccp_info.sender_name, 0, INET_ADDRSTRLEN);
|
||||
memcpy(csm->iccp_info.sender_name, addr, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unset_local_address(int mid)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
memset(csm->sender_ip, 0, INET_ADDRSTRLEN);
|
||||
memset(csm->iccp_info.sender_name, 0, INET_ADDRSTRLEN);
|
||||
|
||||
/* reset link*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'peer-address A.B.C.D' command
|
||||
*/
|
||||
int set_peer_address(int mid, const char* addr)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
if (addr == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
len = strlen(addr);
|
||||
|
||||
if (strlen(csm->peer_ip) > 0)
|
||||
{
|
||||
if (strcmp(csm->peer_ip, addr) == 0)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Peer-address not be changed");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Change peer-address : %s -> %s",
|
||||
csm->peer_ip, addr);
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set peer-address : %s", addr);
|
||||
}
|
||||
|
||||
memset(csm->peer_ip, 0, INET_ADDRSTRLEN);
|
||||
memcpy(csm->peer_ip, addr, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unset_peer_address(int mid)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
memset(csm->peer_ip, 0, INET_ADDRSTRLEN);
|
||||
|
||||
/* reset link*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iccp_cli_attach_mclag_domain_to_port_channel( int domain, const char* ifname)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface *lif = NULL;
|
||||
struct If_info * cif = NULL;
|
||||
|
||||
if (!ifname)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (strncmp(ifname, PORTCHANNEL_PREFIX, strlen(PORTCHANNEL_PREFIX)) != 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Attach interface(%s) is not a port-channel", ifname);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(domain);
|
||||
if (csm == NULL)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "MC-LAG ID %d doesn't exist", domain);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
lif = local_if_find_by_name(ifname);
|
||||
if (lif)
|
||||
{
|
||||
mlacp_bind_port_channel_to_csm(csm, ifname);
|
||||
}
|
||||
|
||||
LIST_FOREACH(cif, &(csm->if_bind_list), csm_next)
|
||||
{
|
||||
if (strcmp(cif->name, ifname) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cif == NULL)
|
||||
{
|
||||
cif = (struct If_info *)malloc(sizeof(struct If_info));
|
||||
if (!cif)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
snprintf(cif->name, MAX_L_PORT_NAME, "%s", ifname);
|
||||
LIST_INSERT_HEAD(&(csm->if_bind_list), cif, csm_next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iccp_cli_detach_mclag_domain_to_port_channel( const char* ifname)
|
||||
{
|
||||
int unbind_poid = -1;
|
||||
struct CSM *csm = NULL;
|
||||
struct LocalInterface *lif_po = NULL;
|
||||
struct LocalInterface *lif = NULL;
|
||||
struct If_info * cif = NULL;
|
||||
|
||||
if (!ifname)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (strncmp(ifname, PORTCHANNEL_PREFIX, strlen(PORTCHANNEL_PREFIX)) != 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Detach interface(%s) is not a port-channel", ifname);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* find po*/
|
||||
if (!(lif_po = local_if_find_by_name(ifname))
|
||||
|| lif_po->type != IF_T_PORT_CHANNEL
|
||||
|| lif_po->po_id <= 0
|
||||
|| lif_po->csm == NULL)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* find csm*/
|
||||
csm = lif_po->csm;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Detach mclag id = %d from ifname = %s",
|
||||
csm->mlag_id, lif_po->name);
|
||||
|
||||
/* process link state handler before detaching it.*/
|
||||
mlacp_mlag_link_del_handler(csm, lif_po);
|
||||
|
||||
unbind_poid = lif_po->po_id;
|
||||
mlacp_unbind_local_if(lif_po);
|
||||
LIST_FOREACH(lif, &(csm->app_csm.mlacp.lif_list), mlacp_next)
|
||||
{
|
||||
if (lif->type == IF_T_PORT && lif->po_id == unbind_poid)
|
||||
mlacp_unbind_local_if(lif);
|
||||
}
|
||||
|
||||
LIST_FOREACH(cif, &(csm->if_bind_list), csm_next)
|
||||
{
|
||||
if (strcmp(ifname, cif->name) == 0)
|
||||
LIST_REMOVE(cif, csm_next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function parses a string to a binary mac address (uint8_t[6])
|
||||
The string should contain mac address only. No spaces are allowed.
|
||||
The mac address separators could be either ':' or '-'*/
|
||||
int parseMacString(const char * str_mac, uint8_t* bin_mac)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bin_mac == NULL)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* 6 hexadecimal numbers (two digits each) + 5 delimiters*/
|
||||
if (strlen(str_mac) != ETHER_ADDR_LEN * 2 + 5)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* first check that all mac address separators are equal to each other
|
||||
2, 5, 8, 11, and 14 are MAC address separator positions*/
|
||||
if (!(str_mac[2] == str_mac[5]
|
||||
&& str_mac[5] == str_mac[8]
|
||||
&& str_mac[8] == str_mac[11]
|
||||
&& str_mac[11] == str_mac[14]))
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* then check that the first separator is equal to ':' or '-'*/
|
||||
if (str_mac[2] != ':' && str_mac[2] != '-')
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < ETHER_ADDR_LEN; ++i)
|
||||
{
|
||||
int left = i * 3; /* left digit position of hexadecimal number*/
|
||||
int right = left + 1; /* right digit position of hexadecimal number*/
|
||||
|
||||
if (str_mac[left] >= '0' && str_mac[left] <= '9')
|
||||
{
|
||||
bin_mac[i] = (uint8_t)(str_mac[left] - '0');
|
||||
}
|
||||
else if (str_mac[left] >= 'A' && str_mac[left] <= 'F')
|
||||
{
|
||||
bin_mac[i] = (uint8_t)(str_mac[left] - 'A' + 0x0a);
|
||||
}
|
||||
else if (str_mac[left] >= 'a' && str_mac[left] <= 'f')
|
||||
{
|
||||
bin_mac[i] = (uint8_t)(str_mac[left] - 'a' + 0x0a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
bin_mac[i] = (uint8_t)(bin_mac[i] << 4);
|
||||
|
||||
if (str_mac[right] >= '0' && str_mac[right] <= '9')
|
||||
{
|
||||
bin_mac[i] |= (uint8_t)(str_mac[right] - '0');
|
||||
}
|
||||
else if (str_mac[right] >= 'A' && str_mac[right] <= 'F')
|
||||
{
|
||||
bin_mac[i] |= (uint8_t)(str_mac[right] - 'A' + 0x0a);
|
||||
}
|
||||
else if (str_mac[right] >= 'a' && str_mac[right] <= 'f')
|
||||
{
|
||||
bin_mac[i] |= (uint8_t)(str_mac[right] - 'a' + 0x0a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_local_system_id(const char* mac)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return 0;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
parseMacString(mac, MLACP(csm).system_id);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, " Set local systemID [%02X:%02X:%02X:%02X:%02X:%02X].",
|
||||
MLACP(csm).system_id[0], MLACP(csm).system_id[1], MLACP(csm).system_id[2],
|
||||
MLACP(csm).system_id[3], MLACP(csm).system_id[4], MLACP(csm).system_id[5]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unset_local_system_id( )
|
||||
{
|
||||
uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return 0;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
memcpy(MLACP(csm).system_id, null_mac, ETHER_ADDR_LEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
168
src/iccpd/src/iccp_cmd.c
Normal file
168
src/iccpd/src/iccp_cmd.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* iccp_cmd.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/queue.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/msg_format.h"
|
||||
#include "../include/system.h"
|
||||
|
||||
#include "../include/iccp_cmd_show.h"
|
||||
#include "../include/iccp_cli.h"
|
||||
#include "../include/logger.h"
|
||||
|
||||
int set_mc_lag_by_id(uint16_t mid)
|
||||
{
|
||||
int ret = 0;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
csm = system_get_csm_by_mlacp_id(mid);
|
||||
if (!csm)
|
||||
{
|
||||
csm = (struct CSM*)iccp_get_csm();
|
||||
if (csm == NULL)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
ret = set_mc_lag_id(csm, mid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CONFIG_LINE_LEN 512
|
||||
|
||||
int iccp_config_from_command(char * line)
|
||||
{
|
||||
char *cp, *start;
|
||||
char token[64];
|
||||
int slen;
|
||||
static int mid = 0;
|
||||
char *end;
|
||||
|
||||
if (line == NULL)
|
||||
return 0;
|
||||
|
||||
cp = line;
|
||||
|
||||
/* Skip white spaces. */
|
||||
while (isspace((int)*cp) && *cp != '\0')
|
||||
cp++;
|
||||
|
||||
/* Return if there is only white spaces */
|
||||
if (*cp == '\0')
|
||||
return 0;
|
||||
|
||||
end = cp;
|
||||
|
||||
/* Skip end white spaces. */
|
||||
while (!isspace((int)*end) && *end != '\0')
|
||||
end++;
|
||||
|
||||
*end = '\0';
|
||||
/*mc-lag id*/
|
||||
if (strncmp(cp, MCLAG_ID_STR, strlen(MCLAG_ID_STR)) == 0 )
|
||||
{
|
||||
cp += strlen(MCLAG_ID_STR) + 1;
|
||||
mid = atoi(cp);
|
||||
set_mc_lag_by_id(mid);
|
||||
}
|
||||
else if (strncmp(cp, LOCAL_IP_STR, strlen(LOCAL_IP_STR)) == 0) /*local ip*/
|
||||
{
|
||||
cp += strlen(LOCAL_IP_STR) + 1;
|
||||
set_local_address(mid, cp);
|
||||
}
|
||||
else if (strncmp(cp, PEER_IP_STR, strlen(PEER_IP_STR)) == 0) /*peer ip*/
|
||||
{
|
||||
cp += strlen(PEER_IP_STR) + 1;
|
||||
set_peer_address(mid, cp);
|
||||
}
|
||||
else if (strncmp(cp, PEER_LINK_STR, strlen(PEER_LINK_STR)) == 0)/*peer link*/
|
||||
{
|
||||
cp += strlen(PEER_LINK_STR) + 1;
|
||||
set_peer_link(mid, cp);
|
||||
}
|
||||
else if (strncmp(cp, MCLAG_INTF_STR, strlen(MCLAG_INTF_STR)) == 0)/*mclag interface*/
|
||||
{
|
||||
cp += strlen(MCLAG_INTF_STR) + 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
start = cp;
|
||||
|
||||
while (!(*cp == ',' || *cp == '\r' || *cp == '\n') &&
|
||||
*cp != '\0')
|
||||
cp++;
|
||||
|
||||
slen = cp - start;
|
||||
strncpy(token, start, slen);
|
||||
*(token + slen) = '\0';
|
||||
iccp_cli_attach_mclag_domain_to_port_channel(mid, token);
|
||||
|
||||
while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r' || *cp == ',') &&
|
||||
*cp != '\0')
|
||||
cp++;
|
||||
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (strncmp(cp, SYSTEM_MAC_STR, strlen(SYSTEM_MAC_STR)) == 0)/*system mac*/
|
||||
{
|
||||
cp += strlen(SYSTEM_MAC_STR) + 1;
|
||||
set_local_system_id(cp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*error*/
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Configration make from file. */
|
||||
int
|
||||
iccp_config_from_file(char *config_default_dir)
|
||||
{
|
||||
FILE *confp = NULL;
|
||||
char command_buf[CONFIG_LINE_LEN];
|
||||
|
||||
confp = fopen(config_default_dir, "r");
|
||||
if (confp == NULL)
|
||||
return (1);
|
||||
|
||||
while (fgets(command_buf, CONFIG_LINE_LEN, confp))
|
||||
{
|
||||
iccp_config_from_command(command_buf);
|
||||
}
|
||||
|
||||
fclose(confp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
477
src/iccpd/src/iccp_cmd_show.c
Normal file
477
src/iccpd/src/iccp_cmd_show.c
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* iccp_cmd_show.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/mlacp_tlv.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/logger.h"
|
||||
#include "mclagdctl/mclagdctl.h"
|
||||
#include "../include/iccp_cmd_show.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
|
||||
int iccp_mclag_config_dump(char * *buf, int *num, int mclag_id)
|
||||
{
|
||||
struct mclagd_state state_info;
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct LocalInterface *peer_link_if = NULL;
|
||||
struct LocalInterface *lif_po = NULL;
|
||||
struct LoggerConfig* logconfig;
|
||||
char unknown[] = { "Unknown" };
|
||||
int mclag_num = 0;
|
||||
int id_exist = 0;
|
||||
int str_size = 0;
|
||||
int len = 0;
|
||||
char *state_buf = NULL;
|
||||
int state_buf_size = MCLAGDCTL_CMD_SIZE;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
{
|
||||
return EXEC_TYPE_NO_EXIST_SYS;
|
||||
}
|
||||
|
||||
state_buf = (char*)malloc(state_buf_size);
|
||||
if (!state_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
memset(&state_info, 0, sizeof(struct mclagd_state));
|
||||
|
||||
if (csm->current_state == ICCP_OPERATIONAL)
|
||||
state_info.keepalive = 1;
|
||||
else
|
||||
state_info.keepalive = 0;
|
||||
|
||||
if (mclag_id > 0)
|
||||
{
|
||||
if (csm->mlag_id == mclag_id)
|
||||
id_exist = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
peer_link_if = local_if_find_by_name(csm->peer_itf_name);
|
||||
|
||||
if (csm->mlag_id <= 0)
|
||||
state_info.mclag_id = -1;
|
||||
else
|
||||
state_info.mclag_id = csm->mlag_id;
|
||||
|
||||
memcpy(state_info.local_ip, csm->sender_ip, ICCP_MAX_IP_STR_LEN);
|
||||
memcpy(state_info.peer_ip, csm->peer_ip, ICCP_MAX_IP_STR_LEN);
|
||||
|
||||
if (peer_link_if)
|
||||
memcpy(state_info.peer_link_if, peer_link_if->name, ICCP_MAX_PORT_NAME);
|
||||
else
|
||||
memcpy(state_info.peer_link_if, unknown, strlen(unknown));
|
||||
|
||||
if (peer_link_if)
|
||||
memcpy(state_info.peer_link_mac, peer_link_if->mac_addr, 6);
|
||||
|
||||
logconfig = logger_get_configuration();
|
||||
memcpy(state_info.loglevel, log_level_to_string(logconfig->log_level), strlen( log_level_to_string(logconfig->log_level)));
|
||||
|
||||
state_info.role = csm->role_type;
|
||||
|
||||
str_size = MCLAGDCTL_PORT_MEMBER_BUF_LEN;
|
||||
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
|
||||
if (str_size - len < ICCP_MAX_PORT_NAME)
|
||||
break;
|
||||
|
||||
if (lif_po->type == IF_T_PORT_CHANNEL)
|
||||
len += snprintf(state_info.enabled_po + len, str_size - len, "%s,", lif_po->name);
|
||||
}
|
||||
|
||||
/*Skip the last ','*/
|
||||
len = strlen(state_info.enabled_po);
|
||||
if (len > 0)
|
||||
{
|
||||
state_info.enabled_po[len - 1] = '\0';
|
||||
}
|
||||
|
||||
memcpy(state_buf + MCLAGD_REPLY_INFO_HDR + mclag_num * sizeof(struct mclagd_state),
|
||||
&state_info, sizeof(struct mclagd_state));
|
||||
mclag_num++;
|
||||
|
||||
if ((mclag_num + 1) * sizeof(struct mclagd_state) > (state_buf_size - MCLAGD_REPLY_INFO_HDR))
|
||||
{
|
||||
state_buf_size += MCLAGDCTL_CMD_SIZE;
|
||||
state_buf = (char*)realloc(state_buf, state_buf_size);
|
||||
if (!state_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
*buf = state_buf;
|
||||
*num = mclag_num;
|
||||
|
||||
if (mclag_id > 0 && !id_exist)
|
||||
return EXEC_TYPE_NO_EXIST_MCLAGID;
|
||||
|
||||
return EXEC_TYPE_SUCCESS;
|
||||
}
|
||||
|
||||
int iccp_arp_dump(char * *buf, int *num, int mclag_id)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct Msg *msg = NULL;
|
||||
struct ARPMsg *iccpd_arp = NULL;
|
||||
struct mclagd_arp_msg mclagd_arp;
|
||||
int arp_num = 0;
|
||||
int id_exist = 0;
|
||||
char * arp_buf = NULL;
|
||||
int arp_buf_size = MCLAGDCTL_CMD_SIZE;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
{
|
||||
return EXEC_TYPE_NO_EXIST_SYS;
|
||||
}
|
||||
|
||||
arp_buf = (char*)malloc(arp_buf_size);
|
||||
if (!arp_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (mclag_id > 0)
|
||||
{
|
||||
if (csm->mlag_id == mclag_id)
|
||||
id_exist = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
|
||||
{
|
||||
memset(&mclagd_arp, 0, sizeof(struct mclagd_arp_msg));
|
||||
iccpd_arp = (struct ARPMsg*)msg->buf;
|
||||
|
||||
mclagd_arp.op_type = iccpd_arp->op_type;
|
||||
memcpy(mclagd_arp.ifname, iccpd_arp->ifname, strlen(iccpd_arp->ifname));
|
||||
memcpy(mclagd_arp.ipv4_addr, show_ip_str(htonl(iccpd_arp->ipv4_addr)), 16);
|
||||
memcpy(mclagd_arp.mac_addr, iccpd_arp->mac_addr, 6);
|
||||
|
||||
memcpy(arp_buf + MCLAGD_REPLY_INFO_HDR + arp_num * sizeof(struct mclagd_arp_msg),
|
||||
&mclagd_arp, sizeof(struct mclagd_arp_msg));
|
||||
|
||||
arp_num++;
|
||||
|
||||
if ((arp_num + 1) * sizeof(struct mclagd_arp_msg) > (arp_buf_size - MCLAGD_REPLY_INFO_HDR))
|
||||
{
|
||||
arp_buf_size += MCLAGDCTL_CMD_SIZE;
|
||||
arp_buf = (char*)realloc(arp_buf, arp_buf_size);
|
||||
if (!arp_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*buf = arp_buf;
|
||||
*num = arp_num;
|
||||
|
||||
if (mclag_id > 0 && !id_exist)
|
||||
return EXEC_TYPE_NO_EXIST_MCLAGID;
|
||||
|
||||
return EXEC_TYPE_SUCCESS;
|
||||
}
|
||||
|
||||
int iccp_mac_dump(char * *buf, int *num, int mclag_id)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct Msg *msg = NULL;
|
||||
struct MACMsg *iccpd_mac = NULL;
|
||||
struct mclagd_mac_msg mclagd_mac;
|
||||
int mac_num = 0;
|
||||
int id_exist = 0;
|
||||
char * mac_buf = NULL;
|
||||
int mac_buf_size = MCLAGDCTL_CMD_SIZE;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
{
|
||||
return EXEC_TYPE_NO_EXIST_SYS;
|
||||
}
|
||||
|
||||
mac_buf = (char*)malloc(mac_buf_size);
|
||||
if (!mac_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (mclag_id > 0)
|
||||
{
|
||||
if (csm->mlag_id == mclag_id)
|
||||
id_exist = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(msg, &MLACP(csm).mac_list, tail)
|
||||
{
|
||||
memset(&mclagd_mac, 0, sizeof(struct mclagd_mac_msg));
|
||||
iccpd_mac = (struct MACMsg*)msg->buf;
|
||||
|
||||
mclagd_mac.op_type = iccpd_mac->op_type;
|
||||
mclagd_mac.fdb_type = iccpd_mac->fdb_type;
|
||||
memcpy(mclagd_mac.mac_str, iccpd_mac->mac_str, ETHER_ADDR_STR_LEN);
|
||||
mclagd_mac.vid = iccpd_mac->vid;
|
||||
memcpy(mclagd_mac.ifname, iccpd_mac->ifname, strlen(iccpd_mac->ifname));
|
||||
memcpy(mclagd_mac.origin_ifname, iccpd_mac->origin_ifname, strlen(iccpd_mac->origin_ifname));
|
||||
mclagd_mac.age_flag = iccpd_mac->age_flag;
|
||||
|
||||
memcpy(mac_buf + MCLAGD_REPLY_INFO_HDR + mac_num * sizeof(struct mclagd_mac_msg),
|
||||
&mclagd_mac, sizeof(struct mclagd_mac_msg));
|
||||
|
||||
mac_num++;
|
||||
|
||||
if ((mac_num + 1) * sizeof(struct mclagd_mac_msg) > (mac_buf_size - MCLAGD_REPLY_INFO_HDR))
|
||||
{
|
||||
mac_buf_size += MCLAGDCTL_CMD_SIZE;
|
||||
mac_buf = (char*)realloc(mac_buf, mac_buf_size);
|
||||
if (!mac_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*buf = mac_buf;
|
||||
*num = mac_num;
|
||||
|
||||
if (mclag_id > 0 && !id_exist)
|
||||
return EXEC_TYPE_NO_EXIST_MCLAGID;
|
||||
|
||||
return EXEC_TYPE_SUCCESS;
|
||||
}
|
||||
|
||||
int iccp_local_if_dump(char * *buf, int *num, int mclag_id)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct LocalInterface *lif_po = NULL;
|
||||
struct 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;
|
||||
char * lif_buf = NULL;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
{
|
||||
return EXEC_TYPE_NO_EXIST_SYS;
|
||||
}
|
||||
|
||||
lif_buf = (char*)malloc(lif_buf_size);
|
||||
if (!lif_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (mclag_id > 0)
|
||||
{
|
||||
if (csm->mlag_id == mclag_id)
|
||||
id_exist = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
memset(&mclagd_lif, 0, sizeof(struct mclagd_local_if));
|
||||
|
||||
mclagd_lif.ifindex = lif_po->ifindex;
|
||||
|
||||
if (lif_po->type == IF_T_UNKNOW)
|
||||
memcpy(mclagd_lif.type, "Unknown", 6);
|
||||
else if (lif_po->type == IF_T_PORT)
|
||||
memcpy(mclagd_lif.type, "Ethernet", 8);
|
||||
else if (lif_po->type == IF_T_PORT_CHANNEL)
|
||||
memcpy(mclagd_lif.type, "PortChannel", 11);
|
||||
|
||||
memcpy(mclagd_lif.name, lif_po->name, MAX_L_PORT_NAME);
|
||||
memcpy(mclagd_lif.mac_addr, lif_po->mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
if (lif_po->state == PORT_STATE_UP)
|
||||
memcpy(mclagd_lif.state, "Up", 2);
|
||||
else if (lif_po->state == PORT_STATE_DOWN)
|
||||
memcpy(mclagd_lif.state, "Down", 4);
|
||||
else if (lif_po->state == PORT_STATE_ADMIN_DOWN)
|
||||
memcpy(mclagd_lif.state, "Admin-down", 10);
|
||||
else if (lif_po->state == PORT_STATE_TEST)
|
||||
memcpy(mclagd_lif.state, "Test", 4);
|
||||
|
||||
memcpy(mclagd_lif.ipv4_addr, show_ip_str(htonl(lif_po->ipv4_addr)), 16);
|
||||
mclagd_lif.prefixlen = lif_po->prefixlen;
|
||||
|
||||
mclagd_lif.l3_mode = local_if_is_l3_mode(lif_po);
|
||||
|
||||
mclagd_lif.is_peer_link = lif_po->is_peer_link;
|
||||
|
||||
memcpy(mclagd_lif.portchannel_member_buf, lif_po->portchannel_member_buf, 512);
|
||||
|
||||
mclagd_lif.po_id = lif_po->po_id;
|
||||
mclagd_lif.po_active = lif_po->po_active;
|
||||
/*mlacp_state*/
|
||||
if (lif_po->mlacp_state == MLACP_STATE_INIT)
|
||||
memcpy(mclagd_lif.mlacp_state, "INIT", 4);
|
||||
else if (lif_po->mlacp_state == MLACP_STATE_STAGE1)
|
||||
memcpy(mclagd_lif.mlacp_state, "STAGE1", 6);
|
||||
else if (lif_po->mlacp_state == MLACP_STATE_STAGE2)
|
||||
memcpy(mclagd_lif.mlacp_state, "STAGE2", 6);
|
||||
else if (lif_po->mlacp_state == MLACP_STATE_EXCHANGE)
|
||||
memcpy(mclagd_lif.mlacp_state, "EXCHANGE", 8);
|
||||
else if (lif_po->mlacp_state == MLACP_STATE_ERROR)
|
||||
memcpy(mclagd_lif.mlacp_state, "ERROR", 5);
|
||||
|
||||
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)
|
||||
{
|
||||
if (vlan_id != NULL )
|
||||
{
|
||||
if (str_size - len < 4)
|
||||
break;
|
||||
len += snprintf(str_buf + len, str_size - len, "%d ", 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))
|
||||
{
|
||||
lif_buf_size += MCLAGDCTL_CMD_SIZE;
|
||||
lif_buf = (char*)realloc(lif_buf, lif_buf_size);
|
||||
if (!lif_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*buf = lif_buf;
|
||||
*num = lif_num;
|
||||
|
||||
if (mclag_id > 0 && !id_exist)
|
||||
return EXEC_TYPE_NO_EXIST_MCLAGID;
|
||||
|
||||
return EXEC_TYPE_SUCCESS;
|
||||
}
|
||||
|
||||
int iccp_peer_if_dump(char * *buf, int *num, int mclag_id)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct PeerInterface *pif_po = NULL;
|
||||
struct mclagd_peer_if mclagd_pif;
|
||||
int pif_num = 0;
|
||||
int id_exist = 0;
|
||||
int pif_buf_size = MCLAGDCTL_CMD_SIZE;
|
||||
char *pif_buf = NULL;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
{
|
||||
return EXEC_TYPE_NO_EXIST_SYS;
|
||||
}
|
||||
|
||||
pif_buf = (char*)malloc(pif_buf_size);
|
||||
if (!pif_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (mclag_id > 0)
|
||||
{
|
||||
if (csm->mlag_id == mclag_id)
|
||||
id_exist = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
LIST_FOREACH(pif_po, &(MLACP(csm).pif_list), mlacp_next)
|
||||
{
|
||||
memset(&mclagd_pif, 0, sizeof(struct mclagd_peer_if));
|
||||
|
||||
mclagd_pif.ifindex = pif_po->ifindex;
|
||||
|
||||
if (pif_po->type == IF_T_UNKNOW)
|
||||
memcpy(mclagd_pif.type, "Unknown", 6);
|
||||
else if (pif_po->type == IF_T_PORT)
|
||||
memcpy(mclagd_pif.type, "Ethernet", 8);
|
||||
else if (pif_po->type == IF_T_PORT_CHANNEL)
|
||||
memcpy(mclagd_pif.type, "PortChannel", 11);
|
||||
|
||||
memcpy(mclagd_pif.name, pif_po->name, MAX_L_PORT_NAME);
|
||||
memcpy(mclagd_pif.mac_addr, pif_po->mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
if (pif_po->state == PORT_STATE_UP)
|
||||
memcpy(mclagd_pif.state, "Up", 2);
|
||||
else if (pif_po->state == PORT_STATE_DOWN)
|
||||
memcpy(mclagd_pif.state, "Down", 4);
|
||||
else if (pif_po->state == PORT_STATE_ADMIN_DOWN)
|
||||
memcpy(mclagd_pif.state, "Admin-down", 10);
|
||||
else if (pif_po->state == PORT_STATE_TEST)
|
||||
memcpy(mclagd_pif.state, "Test", 4);
|
||||
|
||||
mclagd_pif.po_id = pif_po->po_id;
|
||||
mclagd_pif.po_active = pif_po->po_active;
|
||||
|
||||
memcpy(pif_buf + MCLAGD_REPLY_INFO_HDR + pif_num * sizeof(struct mclagd_peer_if),
|
||||
&mclagd_pif, sizeof(struct mclagd_peer_if));
|
||||
|
||||
pif_num++;
|
||||
|
||||
if ((pif_num + 1) * sizeof(struct mclagd_peer_if) > (pif_buf_size - MCLAGD_REPLY_INFO_HDR))
|
||||
{
|
||||
pif_buf_size += MCLAGDCTL_CMD_SIZE;
|
||||
pif_buf = (char*)realloc(pif_buf, pif_buf_size);
|
||||
if (!pif_buf)
|
||||
return EXEC_TYPE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*buf = pif_buf;
|
||||
*num = pif_num;
|
||||
|
||||
if (mclag_id > 0 && !id_exist)
|
||||
return EXEC_TYPE_NO_EXIST_MCLAGID;
|
||||
|
||||
return EXEC_TYPE_SUCCESS;
|
||||
}
|
||||
|
175
src/iccpd/src/iccp_consistency_check.c
Normal file
175
src/iccpd/src/iccp_consistency_check.c
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* iccp_consistency_check.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../include/iccp_consistency_check.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/port.h"
|
||||
#include "../include/logger.h"
|
||||
|
||||
/* Return 0 if the checking procedure is failed; otherwise, 1 (non-zero) will be returned. */
|
||||
typedef int (*ConsistencyCheckFunc)(char* ifname);
|
||||
|
||||
const char *reasons[] = {
|
||||
/* REASON_NONE */
|
||||
"Success",
|
||||
/* REASON_INTERRFACE_MODE_IS_ASYNC */
|
||||
"Port-channel interface is not in the same mode in local and peer device, please check whether the ip addr settings is correct or not.",
|
||||
/* REASON_PEER_IF_IP_IS_ASYNC */
|
||||
"IP address of peer interface is not synchronized, please check the IP address setting on the corresponding interface.",
|
||||
/* REASON_PEER_IF_VLAN_IS_ASYNC */
|
||||
"VLAN settings on this port-channel interface is not synchronized, please check your configuration.",
|
||||
/* REASON_MAX_ARRAY_SIZE */
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Consistency Checking functions */
|
||||
static int iccp_check_interface_mode( char* ifname)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
|
||||
local_if = local_if_find_by_name(ifname);
|
||||
if (local_if == NULL)
|
||||
return -2;
|
||||
|
||||
csm = local_if->csm;
|
||||
if (csm == NULL)
|
||||
return -3;
|
||||
|
||||
peer_if = peer_if_find_by_name(csm, ifname);
|
||||
if (peer_if == NULL)
|
||||
return -4;
|
||||
|
||||
if (peer_if->l3_mode != local_if->l3_mode)
|
||||
return -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int iccp_check_interface_layer3_addr(char* ifname)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
|
||||
local_if = local_if_find_by_name(ifname);
|
||||
if (local_if == NULL)
|
||||
return -2;
|
||||
|
||||
csm = local_if->csm;
|
||||
if (csm == NULL)
|
||||
return -3;
|
||||
|
||||
peer_if = peer_if_find_by_name(csm, ifname);
|
||||
if (peer_if == NULL)
|
||||
return -4;
|
||||
|
||||
if (peer_if->ipv4_addr != local_if->ipv4_addr)
|
||||
return -5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int iccp_check_interface_vlan(char* ifname)
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
struct VLAN_ID* local_vlan = NULL;
|
||||
struct VLAN_ID* peer_vlan = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
local_if = local_if_find_by_name(ifname);
|
||||
if (local_if == NULL)
|
||||
return -2;
|
||||
|
||||
csm = local_if->csm;
|
||||
if (csm == NULL)
|
||||
return -3;
|
||||
|
||||
peer_if = peer_if_find_by_name(csm, ifname);
|
||||
if (peer_if == NULL)
|
||||
return -4;
|
||||
|
||||
LIST_FOREACH(local_vlan, &(local_if->vlan_list), port_next)
|
||||
{
|
||||
LIST_FOREACH(peer_vlan, &(peer_if->vlan_list), port_next)
|
||||
{
|
||||
if (peer_vlan->vid == local_vlan->vid)
|
||||
break;
|
||||
}
|
||||
|
||||
if (peer_vlan == NULL)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
LIST_FOREACH(peer_vlan, &(peer_if->vlan_list), port_next)
|
||||
{
|
||||
|
||||
LIST_FOREACH(local_vlan, &(local_if->vlan_list), port_next)
|
||||
{
|
||||
if (peer_vlan->vid == local_vlan->vid)
|
||||
break;
|
||||
}
|
||||
|
||||
if (local_vlan == NULL)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const ConsistencyCheckFunc check_func[] = {
|
||||
NULL,
|
||||
iccp_check_interface_mode, /* REASON_INTERFACE_MODE_IS_ASYNC */
|
||||
iccp_check_interface_layer3_addr, /* REASON_PEER_IF_IP_IS_ASYNC */
|
||||
iccp_check_interface_vlan, /* REASON_PEER_IF_VLAN_IS_ASYNC */
|
||||
NULL /* REASON_MAX_ARRAY_SIZE */
|
||||
};
|
||||
#define ARRAY_SIZE(array_name) (sizeof(array_name) / sizeof(array_name[0]))
|
||||
|
||||
enum Reason_ID iccp_consistency_check(char* ifname)
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
for (i = REASON_INTERRFACE_MODE_IS_ASYNC; i < REASON_MAX_ARRAY_SIZE; ++i)
|
||||
{
|
||||
if (check_func[i] == NULL)
|
||||
continue;
|
||||
ret = check_func[i](ifname);
|
||||
if (ret != 1)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "%s ret = %d", reasons[i], ret);
|
||||
fprintf(stdout, "%s \n", reasons[i]);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return REASON_NONE;
|
||||
}
|
797
src/iccpd/src/iccp_csm.c
Normal file
797
src/iccpd/src/iccp_csm.c
Normal file
@ -0,0 +1,797 @@
|
||||
/*
|
||||
* iccp_csm.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../include/logger.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/scheduler.h"
|
||||
#include "../include/msg_format.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
/*****************************************
|
||||
* Define
|
||||
*
|
||||
* ***************************************/
|
||||
#define ICCP_CSM_QUEUE_REINIT(list) \
|
||||
{ \
|
||||
struct Msg* msg = NULL; \
|
||||
while (!TAILQ_EMPTY(&(list))) { \
|
||||
msg = TAILQ_FIRST(&(list)); \
|
||||
TAILQ_REMOVE(&(list), msg, tail); \
|
||||
free(msg->buf); \
|
||||
free(msg); \
|
||||
} \
|
||||
TAILQ_INIT(&(list)); \
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Global
|
||||
*
|
||||
* ***************************************/
|
||||
char g_csm_buf[CSM_BUFFER_SIZE] = { 0 };
|
||||
|
||||
uint32_t ICCP_MSG_ID = 0x1;
|
||||
|
||||
/* Enter Connection State Machine NONEXISTENT handle function */
|
||||
static void iccp_csm_enter_state_nonexistent(struct CSM* csm)
|
||||
{
|
||||
iccp_csm_finalize(csm);
|
||||
}
|
||||
|
||||
/* Enter Connection State Machine INITIALIZED handle function */
|
||||
static void iccp_csm_enter_state_initialized(struct CSM* csm)
|
||||
{
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
csm->iccp_info.sender_capability_flag = 0x1;
|
||||
}
|
||||
|
||||
/* Enter Connection State Machine CAPREC handle function */
|
||||
static void iccp_csm_enter_state_caprec(struct CSM* csm)
|
||||
{
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
csm->iccp_info.sender_capability_flag = 0x1;
|
||||
csm->iccp_info.peer_capability_flag = 0x1;
|
||||
}
|
||||
|
||||
/* Enter Connection State Machine CONNECTING handle function */
|
||||
static void iccp_csm_enter_state_connecting(struct CSM* csm)
|
||||
{
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
csm->iccp_info.sender_rg_connect_flag = 0x1;
|
||||
}
|
||||
|
||||
/* Enter Connection State Machine OPERATIONAL handle function */
|
||||
static void iccp_csm_enter_state_operational(struct CSM* csm)
|
||||
{
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
csm->iccp_info.sender_rg_connect_flag = 0x1;
|
||||
csm->iccp_info.peer_rg_connect_flag = 0x1;
|
||||
}
|
||||
|
||||
void *iccp_get_csm()
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
csm = system_create_csm();
|
||||
|
||||
return csm;
|
||||
}
|
||||
|
||||
/* Connection State Machine instance initialization */
|
||||
void iccp_csm_init(struct CSM* csm)
|
||||
{
|
||||
iccp_csm_status_reset(csm, 1);
|
||||
memset(csm->sender_ip, 0, INET_ADDRSTRLEN);
|
||||
memset(csm->peer_ip, 0, INET_ADDRSTRLEN);
|
||||
memset(csm->iccp_info.sender_name, 0, MAX_L_ICC_SENDER_NAME);
|
||||
csm->iccp_info.icc_rg_id = 0x0;
|
||||
}
|
||||
|
||||
/* Connection State Machine instance status reset */
|
||||
void iccp_csm_status_reset(struct CSM* csm, int all)
|
||||
{
|
||||
ICCP_CSM_QUEUE_REINIT(csm->msg_list);
|
||||
|
||||
if (all)
|
||||
{
|
||||
bzero(csm, sizeof(struct CSM));
|
||||
ICCP_CSM_QUEUE_REINIT(csm->msg_list);
|
||||
}
|
||||
|
||||
csm->sock_fd = -1;
|
||||
pthread_mutex_init(&csm->conn_mutex, NULL);
|
||||
csm->connTimePrev = 0;
|
||||
csm->heartbeat_send_time = 0;
|
||||
csm->heartbeat_update_time = 0;
|
||||
csm->peer_warm_reboot_time = 0;
|
||||
csm->warm_reboot_disconn_time = 0;
|
||||
csm->role_type = STP_ROLE_NONE;
|
||||
csm->sock_read_event_ptr = NULL;
|
||||
csm->peer_link_if = NULL;
|
||||
csm->u_msg_in_count = 0x0;
|
||||
csm->i_msg_in_count = 0x0;
|
||||
csm->icc_msg_in_count = 0x0;
|
||||
csm->icc_msg_out_count = 0x0;
|
||||
csm->iccp_info.status_code = 0x0;
|
||||
csm->iccp_info.rejected_msg_id = 0x0;
|
||||
csm->current_state = ICCP_NONEXISTENT;
|
||||
csm->iccp_info.peer_capability_flag = 0x0;
|
||||
csm->iccp_info.peer_rg_connect_flag = 0x0;
|
||||
csm->iccp_info.sender_capability_flag = 0x0;
|
||||
csm->iccp_info.sender_rg_connect_flag = 0x0;
|
||||
app_csm_init(csm, all);
|
||||
|
||||
memset(&csm->msg_log, 0, sizeof(struct MsgLog));
|
||||
}
|
||||
|
||||
/* Connection State Machine instance tear down */
|
||||
void iccp_csm_finalize(struct CSM* csm)
|
||||
{
|
||||
struct If_info * cif = NULL;
|
||||
struct System* sys = NULL;
|
||||
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
/*If warm reboot, don't change port block and peer link MAC learning*/
|
||||
if (sys->warmboot_exit != WARM_REBOOT)
|
||||
{
|
||||
/*Enable peer link port MAC learning*/
|
||||
if (csm->peer_link_if)
|
||||
set_peerlink_mlag_port_learn(csm->peer_link_if, 1);
|
||||
}
|
||||
|
||||
/* Disconnect from peer */
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
|
||||
/* Release all Connection State Machine instance */
|
||||
app_csm_finalize(csm);
|
||||
|
||||
LIST_FOREACH(cif, &(csm->if_bind_list), csm_next)
|
||||
{
|
||||
LIST_REMOVE(cif, csm_next);
|
||||
}
|
||||
|
||||
/* Release iccp_csm */
|
||||
pthread_mutex_destroy(&(csm->conn_mutex));
|
||||
iccp_csm_msg_list_finalize(csm);
|
||||
LIST_REMOVE(csm, next);
|
||||
free(csm);
|
||||
}
|
||||
|
||||
/* Message list of Connection State Machine instance tear down */
|
||||
void iccp_csm_msg_list_finalize(struct CSM* csm)
|
||||
{
|
||||
struct Msg* msg = NULL;
|
||||
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
while (!TAILQ_EMPTY(&(csm->msg_list)))
|
||||
{
|
||||
msg = TAILQ_FIRST(&(csm->msg_list));
|
||||
TAILQ_REMOVE(&(csm->msg_list), msg, tail);
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send message to peer */
|
||||
int iccp_csm_send(struct CSM* csm, char* buf, int msg_len)
|
||||
{
|
||||
LDPHdr* ldp_hdr = (LDPHdr*)buf;
|
||||
ICCParameter* param = NULL;
|
||||
|
||||
if (csm == NULL || buf == NULL || csm->sock_fd <= 0 || msg_len <= 0)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (ntohs(ldp_hdr->msg_type) == MSG_T_CAPABILITY)
|
||||
param = (struct ICCParameter*)&buf[sizeof(LDPHdr)];
|
||||
else
|
||||
param = (struct ICCParameter*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Send(%d): len=[%d] msg_type=[%s (0x%X, 0x%X)]", csm->sock_fd, msg_len, get_tlv_type_string(param->type), ldp_hdr->msg_type, param->type);*/
|
||||
csm->msg_log.msg[csm->msg_log.end_index].msg_id = ntohl(ldp_hdr->msg_id);
|
||||
csm->msg_log.msg[csm->msg_log.end_index].type = ntohs(ldp_hdr->msg_type);
|
||||
csm->msg_log.msg[csm->msg_log.end_index].tlv = ntohs(param->type);
|
||||
++csm->msg_log.end_index;
|
||||
if (csm->msg_log.end_index >= 128)
|
||||
csm->msg_log.end_index = 0;
|
||||
|
||||
return write(csm->sock_fd, buf, msg_len);
|
||||
}
|
||||
|
||||
/* Connection State Machine Transition */
|
||||
void iccp_csm_transit(struct CSM* csm)
|
||||
{
|
||||
int len = -1;
|
||||
struct Msg* msg = NULL;
|
||||
ICCP_CONNECTION_STATE_E prev_state;
|
||||
char *state_str[] = {"NONEXISTENT", "INITIALIZED", "CAPSENT", "CAPREC", "CONNECTING", "OPERATIONAL"};
|
||||
|
||||
if (!csm)
|
||||
return;
|
||||
|
||||
prev_state = csm->current_state;
|
||||
|
||||
/* No connection, but have state change? reset it...*/
|
||||
if (csm->current_state != ICCP_NONEXISTENT && csm->sock_fd <= 0)
|
||||
{
|
||||
ICCPD_LOG_NOTICE(__FUNCTION__, "csm %d change state from %s to NONEXISTENT.", csm->mlag_id, state_str[csm->current_state]);
|
||||
csm->current_state = ICCP_NONEXISTENT;
|
||||
iccp_csm_enter_state_nonexistent(csm);
|
||||
return;
|
||||
}
|
||||
|
||||
msg = iccp_csm_dequeue_msg(csm);
|
||||
|
||||
switch (csm->current_state)
|
||||
{
|
||||
case ICCP_NONEXISTENT:
|
||||
scheduler_prepare_session(csm);
|
||||
if (csm->sock_fd > 0 && scheduler_check_csm_config(csm) > 0)
|
||||
csm->current_state = ICCP_INITIALIZED;
|
||||
break;
|
||||
|
||||
case ICCP_INITIALIZED:
|
||||
if (msg)
|
||||
iccp_csm_correspond_from_msg(csm, msg);
|
||||
len = iccp_csm_prepare_iccp_msg(csm, g_csm_buf, CSM_BUFFER_SIZE);
|
||||
iccp_csm_send(csm, g_csm_buf, len);
|
||||
if (csm->iccp_info.sender_capability_flag == 0x1 && csm->iccp_info.peer_capability_flag == 0x0)
|
||||
csm->current_state = ICCP_CAPSENT;
|
||||
else if (csm->iccp_info.sender_capability_flag == 0x1 && csm->iccp_info.peer_capability_flag == 0x1)
|
||||
csm->current_state = ICCP_CAPREC;
|
||||
break;
|
||||
|
||||
case ICCP_CAPSENT:
|
||||
if (msg)
|
||||
iccp_csm_correspond_from_msg(csm, msg);
|
||||
if (csm->iccp_info.sender_capability_flag == 0x1 && csm->iccp_info.peer_capability_flag == 0x1)
|
||||
csm->current_state = ICCP_CAPREC;
|
||||
break;
|
||||
|
||||
case ICCP_CAPREC:
|
||||
if (msg)
|
||||
iccp_csm_correspond_from_msg(csm, msg);
|
||||
memset(g_csm_buf, 0, CSM_BUFFER_SIZE);
|
||||
len = iccp_csm_prepare_iccp_msg(csm, g_csm_buf, CSM_BUFFER_SIZE);
|
||||
iccp_csm_send(csm, g_csm_buf, len);
|
||||
if (csm->iccp_info.peer_rg_connect_flag == 0x0 && csm->iccp_info.status_code == 0x0)
|
||||
csm->current_state = ICCP_CONNECTING;
|
||||
else if (csm->iccp_info.peer_rg_connect_flag == 0x1 && csm->iccp_info.status_code == 0x0)
|
||||
csm->current_state = ICCP_OPERATIONAL;
|
||||
break;
|
||||
|
||||
case ICCP_CONNECTING:
|
||||
if (msg)
|
||||
iccp_csm_correspond_from_msg(csm, msg);
|
||||
memset(g_csm_buf, 0, CSM_BUFFER_SIZE);
|
||||
len = iccp_csm_prepare_iccp_msg(csm, g_csm_buf, CSM_BUFFER_SIZE);
|
||||
iccp_csm_send(csm, g_csm_buf, len);
|
||||
if (csm->iccp_info.status_code > 0x0)
|
||||
csm->current_state = ICCP_CAPREC;
|
||||
else if (csm->iccp_info.peer_rg_connect_flag == 0x1 && csm->iccp_info.status_code == 0x0)
|
||||
csm->current_state = ICCP_OPERATIONAL;
|
||||
break;
|
||||
|
||||
case ICCP_OPERATIONAL:
|
||||
if (msg)
|
||||
iccp_csm_correspond_from_msg(csm, msg);
|
||||
if (csm->iccp_info.sender_rg_connect_flag == 0x0 || csm->iccp_info.peer_rg_connect_flag == 0x0)
|
||||
{
|
||||
memset(g_csm_buf, 0, CSM_BUFFER_SIZE);
|
||||
len = iccp_csm_prepare_iccp_msg(csm, g_csm_buf, CSM_BUFFER_SIZE);
|
||||
iccp_csm_send(csm, g_csm_buf, len);
|
||||
csm->current_state = ICCP_CAPREC;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev_state != csm->current_state || (csm->current_state && msg != NULL))
|
||||
{
|
||||
if (prev_state != csm->current_state)
|
||||
ICCPD_LOG_NOTICE(__FUNCTION__, "csm %d change state from %s to %s.", csm->mlag_id, state_str[prev_state], state_str[csm->current_state]);
|
||||
|
||||
switch (csm->current_state)
|
||||
{
|
||||
case ICCP_NONEXISTENT:
|
||||
iccp_csm_enter_state_nonexistent(csm);
|
||||
break;
|
||||
|
||||
case ICCP_INITIALIZED:
|
||||
iccp_csm_enter_state_initialized(csm);
|
||||
break;
|
||||
|
||||
case ICCP_CAPSENT:
|
||||
/* Do nothing on this state */
|
||||
break;
|
||||
|
||||
case ICCP_CAPREC:
|
||||
iccp_csm_enter_state_caprec(csm);
|
||||
break;
|
||||
|
||||
case ICCP_CONNECTING:
|
||||
iccp_csm_enter_state_connecting(csm);
|
||||
break;
|
||||
|
||||
case ICCP_OPERATIONAL:
|
||||
iccp_csm_enter_state_operational(csm);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up ICCP message */
|
||||
int iccp_csm_prepare_iccp_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
size_t msg_len = -1;
|
||||
|
||||
if (csm == NULL || buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
switch (csm->current_state)
|
||||
{
|
||||
case ICCP_NONEXISTENT:
|
||||
/* Do nothing on this state */
|
||||
break;
|
||||
|
||||
case ICCP_INITIALIZED:
|
||||
msg_len = iccp_csm_prepare_capability_msg(csm, buf, max_buf_size);
|
||||
break;
|
||||
|
||||
case ICCP_CAPSENT:
|
||||
/* Do nothing on this state */
|
||||
break;
|
||||
|
||||
case ICCP_CAPREC:
|
||||
if (csm->iccp_info.status_code > 0x0)
|
||||
{
|
||||
msg_len = iccp_csm_prepare_nak_msg(csm, buf, max_buf_size);
|
||||
break;
|
||||
}
|
||||
msg_len = iccp_csm_prepare_rg_connect_msg(csm, buf, max_buf_size);
|
||||
break;
|
||||
|
||||
case ICCP_CONNECTING:
|
||||
if (csm->iccp_info.status_code > 0x0)
|
||||
{
|
||||
msg_len = iccp_csm_prepare_nak_msg(csm, buf, max_buf_size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ICCP_OPERATIONAL:
|
||||
if (csm->iccp_info.peer_rg_connect_flag == 0x0)
|
||||
{
|
||||
msg_len = iccp_csm_prepare_rg_disconnect_msg(csm, buf, max_buf_size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/* ICCP capability message handle function */
|
||||
int iccp_csm_prepare_capability_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
LDPHdr* ldp_hdr = (LDPHdr*)buf;
|
||||
LDPICCPCapabilityTLV* cap = (LDPICCPCapabilityTLV*)&buf[sizeof(LDPHdr)];
|
||||
size_t msg_len = sizeof(LDPHdr) + sizeof(LDPICCPCapabilityTLV);
|
||||
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
/* LDP header */
|
||||
ldp_hdr->u_bit = 0x0;
|
||||
ldp_hdr->msg_type = htons(MSG_T_CAPABILITY);
|
||||
ldp_hdr->msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
ldp_hdr->msg_id = htonl(ICCP_MSG_ID++);
|
||||
|
||||
/* LDP ICCP capability TLV */
|
||||
cap->icc_parameter.u_bit = 0x1;
|
||||
cap->icc_parameter.f_bit = 0x0;
|
||||
cap->icc_parameter.type = TLV_T_ICCP_CAPABILITY;
|
||||
*(uint16_t *)cap = htons(*(uint16_t *)cap);
|
||||
|
||||
cap->icc_parameter.len = htons(TLV_L_ICCP_CAPABILITY);
|
||||
|
||||
cap->s_bit = csm->iccp_info.sender_capability_flag;
|
||||
*(uint16_t *)((uint8_t *)cap + sizeof(ICCParameter)) = htons(*(uint16_t *)((uint8_t *)cap + sizeof(ICCParameter)));
|
||||
|
||||
cap->major_ver = 0x1;
|
||||
cap->minior_ver = 0x0;
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
void iccp_csm_fill_icc_rg_id_tlv(struct CSM* csm, ICCHdr* icc_hdr)
|
||||
{
|
||||
if (!csm || !icc_hdr)
|
||||
return;
|
||||
|
||||
icc_hdr->icc_rg_id_tlv.type = htons(TLV_T_ICC_RG_ID);
|
||||
icc_hdr->icc_rg_id_tlv.len = htons(TLV_L_ICC_RG_ID);
|
||||
icc_hdr->icc_rg_id_tlv.icc_rg_id = htonl(csm->iccp_info.icc_rg_id);
|
||||
}
|
||||
|
||||
/* ICCP NAK message handle function */
|
||||
int iccp_csm_prepare_nak_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
NAKTLV* nak = (NAKTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(NAKTLV);
|
||||
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr->ldp_hdr.u_bit = 0x0;
|
||||
icc_hdr->ldp_hdr.msg_type = htons(MSG_T_NOTIFICATION);
|
||||
icc_hdr->ldp_hdr.msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
icc_hdr->ldp_hdr.msg_id = htonl(ICCP_MSG_ID++);
|
||||
iccp_csm_fill_icc_rg_id_tlv(csm, icc_hdr);
|
||||
|
||||
/* NAL TLV */
|
||||
nak->icc_parameter.u_bit = 0x0;
|
||||
nak->icc_parameter.f_bit = 0x0;
|
||||
nak->icc_parameter.type = htons(TLV_T_NAK);
|
||||
nak->icc_parameter.len = htons(sizeof(((struct NAKTLV*)0)->iccp_status_code) + sizeof(((struct NAKTLV*)0)->rejected_msg_id));
|
||||
|
||||
switch (csm->iccp_info.status_code)
|
||||
{
|
||||
case STATUS_CODE_U_ICCP_RG:
|
||||
nak->iccp_status_code = htonl(csm->iccp_info.status_code);
|
||||
nak->rejected_msg_id = htonl(csm->iccp_info.rejected_msg_id);
|
||||
break;
|
||||
|
||||
/* Unsupported */
|
||||
case STATUS_CODE_ICCP_CONNECTION_COUNT_EXCEEDED:
|
||||
case STATUS_CODE_ICCP_APP_CONNECTION_COUNT_EXCEEDED:
|
||||
case STATUS_CODE_ICCP_APP_NOT_IN_RG:
|
||||
case STATUS_CODE_INCOMPATIBLE_ICCP_PROTOCOL_VER:
|
||||
case STATUS_CODE_ICCP_REJECTED_MSG:
|
||||
case STATUS_CODE_ICCP_ADMINISTRATIVELY_DISABLED:
|
||||
case STATUS_CODE_ICCP_RG_REMOVED:
|
||||
case STATUS_CODE_ICCP_APP_REMOVED_FROM_RG:
|
||||
break;
|
||||
}
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/* ICCP RG connect handle function */
|
||||
int iccp_csm_prepare_rg_connect_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
ICCSenderNameTLV* sender = (ICCSenderNameTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t name_len = strlen(csm->iccp_info.sender_name);
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(ICCParameter) + name_len;
|
||||
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr->ldp_hdr.u_bit = 0x0;
|
||||
icc_hdr->ldp_hdr.msg_type = htons(MSG_T_RG_CONNECT);
|
||||
icc_hdr->ldp_hdr.msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
icc_hdr->ldp_hdr.msg_id = htonl(ICCP_MSG_ID++);
|
||||
iccp_csm_fill_icc_rg_id_tlv(csm, icc_hdr);
|
||||
|
||||
/* ICC sender name TLV */
|
||||
sender->icc_parameter.u_bit = 0x0;
|
||||
sender->icc_parameter.f_bit = 0x0;
|
||||
sender->icc_parameter.type = htons(TLV_T_ICC_SENDER_NAME);
|
||||
sender->icc_parameter.len = htons(name_len);
|
||||
memcpy(sender->sender_name, csm->iccp_info.sender_name, name_len);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/* ICCP RG disconnect handle function */
|
||||
int iccp_csm_prepare_rg_disconnect_msg(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
DisconnectCodeTLV* disconn_code = (DisconnectCodeTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(DisconnectCodeTLV);
|
||||
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr->ldp_hdr.u_bit = 0x0;
|
||||
icc_hdr->ldp_hdr.msg_type = htons(MSG_T_RG_DISCONNECT);
|
||||
icc_hdr->ldp_hdr.msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
icc_hdr->ldp_hdr.msg_id = htonl(ICCP_MSG_ID++);
|
||||
iccp_csm_fill_icc_rg_id_tlv(csm, icc_hdr);
|
||||
|
||||
/* Disconnect code TLV */
|
||||
disconn_code->icc_parameter.u_bit = 0x0;
|
||||
disconn_code->icc_parameter.f_bit = 0x0;
|
||||
disconn_code->icc_parameter.type = htons(TLV_T_DISCONNECT_CODE);
|
||||
disconn_code->icc_parameter.len = htons(sizeof(((struct DisconnectCodeTLV*)0)->iccp_status_code));
|
||||
disconn_code->iccp_status_code = htonl(csm->iccp_info.status_code);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/* Check ID(MC-LAG ID, mLACP ID, RG ID) from received message */
|
||||
static void iccp_csm_check_id_from_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
|
||||
if (!csm || !msg || !msg->buf)
|
||||
return;
|
||||
|
||||
icc_hdr = (ICCHdr*)msg->buf;
|
||||
|
||||
/* Capability Message doesn't have ICC RG ID TLV */
|
||||
if (icc_hdr->ldp_hdr.msg_type == MSG_T_CAPABILITY)
|
||||
return;
|
||||
|
||||
/* Check if received message ID same as local configuration */
|
||||
if (ntohl(icc_hdr->icc_rg_id_tlv.icc_rg_id) == csm->iccp_info.icc_rg_id)
|
||||
{
|
||||
if (csm->iccp_info.status_code == STATUS_CODE_U_ICCP_RG)
|
||||
{
|
||||
csm->iccp_info.status_code = 0x0;
|
||||
csm->iccp_info.rejected_msg_id = 0x0;
|
||||
}
|
||||
}
|
||||
else if (ntohl(icc_hdr->icc_rg_id_tlv.icc_rg_id) != csm->iccp_info.icc_rg_id)
|
||||
{
|
||||
csm->iccp_info.status_code = STATUS_CODE_U_ICCP_RG;
|
||||
csm->iccp_info.rejected_msg_id = ntohl(icc_hdr->icc_rg_id_tlv.icc_rg_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive message correspond function */
|
||||
void iccp_csm_correspond_from_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
|
||||
if (csm == NULL || msg == NULL || msg->buf == NULL)
|
||||
return;
|
||||
|
||||
icc_hdr = (ICCHdr*)msg->buf;
|
||||
NAKTLV* nak = (NAKTLV*)( icc_hdr + sizeof(ICCHdr));
|
||||
iccp_csm_check_id_from_msg(csm, msg);
|
||||
|
||||
if (icc_hdr->ldp_hdr.msg_type == MSG_T_CAPABILITY)
|
||||
iccp_csm_correspond_from_capability_msg(csm, msg);
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_RG_CONNECT)
|
||||
iccp_csm_correspond_from_rg_connect_msg(csm, msg);
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_RG_DISCONNECT)
|
||||
iccp_csm_correspond_from_rg_disconnect_msg(csm, msg);
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_NOTIFICATION)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Received MSG_T_NOTIFICATION ,err status %s reason of %s", get_status_string(ntohl(nak->iccp_status_code)), get_status_string(csm->iccp_info.status_code));
|
||||
sleep(1);
|
||||
}
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_RG_APP_DATA)
|
||||
{
|
||||
;// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
++csm->u_msg_in_count;
|
||||
}
|
||||
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/* Receive capability message correspond function */
|
||||
void iccp_csm_correspond_from_capability_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
LDPICCPCapabilityTLV* cap = (LDPICCPCapabilityTLV*)&(msg->buf)[sizeof(LDPHdr)];
|
||||
|
||||
*(uint16_t *)cap = ntohs(*(uint16_t *)cap);
|
||||
*(uint16_t *)((uint8_t *)cap + sizeof(ICCParameter)) = ntohs(*(uint16_t *)((uint8_t *)cap + sizeof(ICCParameter)));
|
||||
|
||||
if (cap->icc_parameter.u_bit == 0x1
|
||||
&& cap->icc_parameter.f_bit == 0x0
|
||||
&& cap->icc_parameter.type == TLV_T_ICCP_CAPABILITY
|
||||
&& ntohs(cap->icc_parameter.len) == (TLV_L_ICCP_CAPABILITY)
|
||||
&& cap->s_bit == 1
|
||||
&& cap->major_ver == 0x1
|
||||
&& cap->minior_ver == 0x0)
|
||||
{
|
||||
csm->iccp_info.peer_capability_flag = 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive RG connect message correspond function */
|
||||
void iccp_csm_correspond_from_rg_connect_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
ICCSenderNameTLV* sender = (ICCSenderNameTLV*)&(msg->buf)[sizeof(ICCHdr)];
|
||||
|
||||
*(uint16_t *)sender = ntohs(*(uint16_t *)sender);
|
||||
|
||||
if (sender->icc_parameter.u_bit == 0x0 &&
|
||||
sender->icc_parameter.f_bit == 0x0 &&
|
||||
sender->icc_parameter.type == TLV_T_ICC_SENDER_NAME)
|
||||
{
|
||||
csm->iccp_info.peer_rg_connect_flag = 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive RG disconnect message correspond function */
|
||||
void iccp_csm_correspond_from_rg_disconnect_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
DisconnectCodeTLV* diconn_code = (DisconnectCodeTLV*)&(msg->buf)[sizeof(ICCHdr)];
|
||||
|
||||
*(uint16_t *)diconn_code = ntohs(*(uint16_t *)diconn_code);
|
||||
|
||||
if (diconn_code->icc_parameter.u_bit == 0x0
|
||||
&& diconn_code->icc_parameter.f_bit == 0x0
|
||||
&& diconn_code->icc_parameter.type == TLV_T_DISCONNECT_CODE
|
||||
&& ntohs(diconn_code->icc_parameter.len) == (TLV_L_DISCONNECT_CODE)
|
||||
&& ntohl(diconn_code->iccp_status_code) == (STATUS_CODE_ICCP_RG_REMOVED))
|
||||
{
|
||||
csm->iccp_info.sender_rg_connect_flag = 0x0;
|
||||
csm->iccp_info.peer_rg_connect_flag = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add received message into message list */
|
||||
void iccp_csm_enqueue_msg(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
NAKTLV* naktlv = NULL;
|
||||
int type = -1;
|
||||
int i = 0;
|
||||
|
||||
if (csm == NULL)
|
||||
{
|
||||
if (msg != NULL)
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
icc_hdr = (ICCHdr*)msg->buf;
|
||||
|
||||
*(uint16_t *)icc_hdr = ntohs(*(uint16_t *)icc_hdr);
|
||||
|
||||
if (icc_hdr->ldp_hdr.msg_type == MSG_T_RG_APP_DATA)
|
||||
{
|
||||
app_csm_enqueue_msg(csm, msg);
|
||||
}
|
||||
else if (icc_hdr->ldp_hdr.msg_type == MSG_T_NOTIFICATION)
|
||||
{
|
||||
naktlv = (NAKTLV*)&msg->buf[sizeof(ICCHdr)];
|
||||
|
||||
for (i = 0; i < MAX_MSG_LOG_SIZE; ++i)
|
||||
{
|
||||
if (ntohl(naktlv->rejected_msg_id) == csm->msg_log.msg[i].msg_id)
|
||||
{
|
||||
type = csm->msg_log.msg[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == MSG_T_RG_APP_DATA)
|
||||
app_csm_enqueue_msg(csm, msg);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&(csm->msg_list), msg, tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(csm->msg_list), msg, tail);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get received message from message list */
|
||||
struct Msg* iccp_csm_dequeue_msg(struct CSM* csm)
|
||||
{
|
||||
struct Msg* msg = NULL;
|
||||
|
||||
if (!TAILQ_EMPTY(&(csm->msg_list)))
|
||||
{
|
||||
msg = TAILQ_FIRST(&(csm->msg_list));
|
||||
TAILQ_REMOVE(&(csm->msg_list), msg, tail);
|
||||
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Message initialization */
|
||||
int iccp_csm_init_msg(struct Msg** msg, char* data, int len)
|
||||
{
|
||||
struct Msg* iccp_msg = NULL;
|
||||
|
||||
if (msg == NULL)
|
||||
return -2;
|
||||
|
||||
if (data == NULL || len <= 0)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
iccp_msg = (struct Msg*)malloc(sizeof(struct Msg));
|
||||
if (iccp_msg == NULL)
|
||||
goto err_ret;
|
||||
|
||||
iccp_msg->buf = (char*)malloc(len);
|
||||
if (iccp_msg->buf == NULL)
|
||||
goto err_ret;
|
||||
|
||||
memcpy(iccp_msg->buf, data, len);
|
||||
iccp_msg->len = len;
|
||||
*msg = iccp_msg;
|
||||
|
||||
return 0;
|
||||
|
||||
err_ret:
|
||||
if (iccp_msg)
|
||||
{
|
||||
if (iccp_msg->buf)
|
||||
free(iccp_msg->buf);
|
||||
free(iccp_msg);
|
||||
}
|
||||
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
void iccp_csm_stp_role_count(struct CSM *csm)
|
||||
{
|
||||
/* decide the role, lower ip to be active & socket client*/
|
||||
if (csm->role_type == STP_ROLE_NONE)
|
||||
{
|
||||
if (inet_addr(csm->sender_ip) < inet_addr(csm->peer_ip))
|
||||
{
|
||||
/* Active*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Role: [Active]");
|
||||
csm->role_type = STP_ROLE_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Standby*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Role [Standby]");
|
||||
csm->role_type = STP_ROLE_STANDBY;
|
||||
}
|
||||
}
|
||||
}
|
762
src/iccpd/src/iccp_ifm.c
Normal file
762
src/iccpd/src/iccp_ifm.c
Normal file
@ -0,0 +1,762 @@
|
||||
/*
|
||||
* iccp_ifm.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <netlink/msg.h>
|
||||
|
||||
#include "../include/system.h"
|
||||
#include "../include/iccp_cli.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/mlacp_sync_update.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
#include "../include/port.h"
|
||||
#include "../include/iccp_netlink.h"
|
||||
|
||||
#define fwd_neigh_state_valid(state) (state & (NUD_REACHABLE | NUD_STALE | NUD_DELAY | NUD_PROBE | NUD_PERMANENT))
|
||||
|
||||
#ifndef NDA_RTA
|
||||
#define NDA_RTA(r) \
|
||||
((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
#endif
|
||||
|
||||
static int iccp_valid_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
unsigned int event = 0;
|
||||
|
||||
if (nlh->nlmsg_type != RTM_NEWLINK)
|
||||
return 0;
|
||||
|
||||
if (nl_msg_parse(msg, &iccp_event_handler_obj_input_newlink, &event) < 0)
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Unknown message type.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Get kernel interfaces and ports during initialization*/
|
||||
int iccp_sys_local_if_list_get_init()
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct nl_cb *cb;
|
||||
struct nl_cb *orig_cb;
|
||||
struct rtgenmsg rt_hdr = {
|
||||
.rtgen_family = AF_UNSPEC,
|
||||
};
|
||||
int ret;
|
||||
int retry = 1;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return MCLAG_ERROR;
|
||||
|
||||
while (retry)
|
||||
{
|
||||
retry = 0;
|
||||
ret = nl_send_simple(sys->route_sock, RTM_GETLINK, NLM_F_DUMP,
|
||||
&rt_hdr, sizeof(rt_hdr));
|
||||
if (ret < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "send netlink msg error.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
orig_cb = nl_socket_get_cb(sys->route_sock);
|
||||
cb = nl_cb_clone(orig_cb);
|
||||
nl_cb_put(orig_cb);
|
||||
if (!cb)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "nl cb clone error.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, iccp_valid_handler, sys);
|
||||
|
||||
ret = nl_recvmsgs(sys->route_sock, cb);
|
||||
nl_cb_put(cb);
|
||||
if (ret < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "receive netlink msg error. ret = %d errno = %d ", ret, errno);
|
||||
if (ret != -NLE_DUMP_INTR)
|
||||
return ret;
|
||||
retry = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct Msg *msg = NULL;
|
||||
struct ARPMsg *arp_msg = NULL, *arp_info = NULL;
|
||||
struct VLAN_ID *vlan_id_list = NULL;
|
||||
struct Msg *msg_send = NULL;
|
||||
|
||||
char buf[MAX_BUFSIZE];
|
||||
size_t msg_len = 0;
|
||||
|
||||
struct LocalInterface *lif_po = NULL, *arp_lif = NULL;
|
||||
|
||||
int verify_arp = 0;
|
||||
int arp_update = 0;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return;
|
||||
|
||||
/* Find local itf*/
|
||||
if (!(arp_lif = local_if_find_by_ifindex(ndm->ndm_ifindex)))
|
||||
return;
|
||||
|
||||
/* create ARP msg*/
|
||||
memset(buf, 0, MAX_BUFSIZE);
|
||||
msg_len = sizeof(struct ARPMsg);
|
||||
arp_msg = (struct ARPMsg*)&buf;
|
||||
arp_msg->op_type = ARP_SYNC_LIF;
|
||||
sprintf(arp_msg->ifname, "%s", arp_lif->name);
|
||||
if (tb[NDA_DST])
|
||||
memcpy(&arp_msg->ipv4_addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
|
||||
if (tb[NDA_LLADDR])
|
||||
memcpy(arp_msg->mac_addr, RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]));
|
||||
|
||||
arp_msg->ipv4_addr = ntohl(arp_msg->ipv4_addr);
|
||||
|
||||
ICCPD_LOG_DEBUG(__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),
|
||||
ndm->ndm_ifindex, arp_lif->name,
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)),
|
||||
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]);
|
||||
|
||||
/*Debug*/
|
||||
#if 0
|
||||
/* dump receive kernel ARP req*/
|
||||
fprintf(stderr, "\n======== Kernel ARP ==========\n");
|
||||
fprintf(stderr, " Type = [%d] (New=%d, Del=%d)\n", msgtype, RTM_NEWNEIGH, RTM_DELNEIGH);
|
||||
fprintf(stderr, " State = (%04X)(%d)\n", ndm->ndm_state, fwd_neigh_state_valid(ndm->ndm_state));
|
||||
fprintf(stderr, " ifindex = [%d] (%s)\n", ndm->ndm_ifindex, arp_msg->ifname);
|
||||
fprintf(stderr, " IP = [%s]\n", show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
fprintf(stderr, " MAC = [%02X:%02X:%02X:%02X:%02X:%02X]\n",
|
||||
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]);
|
||||
fprintf(stderr, "==============================\n");
|
||||
#endif
|
||||
|
||||
/* Find MLACP itf, member of port-channel*/
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lif_po->type != IF_T_PORT_CHANNEL)
|
||||
continue;
|
||||
|
||||
if (!local_if_is_l3_mode(lif_po))
|
||||
{
|
||||
/* Is the L2 MLAG itf belong to a vlan?*/
|
||||
LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next)
|
||||
{
|
||||
if ( !(vlan_id_list->vlan_itf
|
||||
&& vlan_id_list->vlan_itf->ifindex == ndm->ndm_ifindex))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!vlan_id_list)
|
||||
continue;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %s",
|
||||
vlan_id_list->vlan_itf->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is the ARP belong to a L3 mode MLAG itf?*/
|
||||
if (ndm->ndm_ifindex != lif_po->ifindex)
|
||||
continue;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name);
|
||||
}
|
||||
|
||||
verify_arp = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (lif_po)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(csm && lif_po))
|
||||
return;
|
||||
if (!verify_arp)
|
||||
return;
|
||||
|
||||
/* update lif ARP*/
|
||||
TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
|
||||
{
|
||||
arp_info = (struct ARPMsg*)msg->buf;
|
||||
if (arp_info->ipv4_addr != arp_msg->ipv4_addr)
|
||||
continue;
|
||||
|
||||
if (msgtype == RTM_DELNEIGH)
|
||||
{
|
||||
/* delete ARP*/
|
||||
TAILQ_REMOVE(&MLACP(csm).arp_list, msg, tail);
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
msg = NULL;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Delete ARP %s", show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update ARP*/
|
||||
if (arp_info->op_type != arp_msg->op_type
|
||||
|| strcmp(arp_info->ifname, arp_msg->ifname) != 0
|
||||
|| memcmp(arp_info->mac_addr, arp_msg->mac_addr,
|
||||
ETHER_ADDR_LEN) != 0)
|
||||
{
|
||||
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(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg && !arp_update)
|
||||
return;
|
||||
|
||||
if (msgtype != RTM_DELNEIGH)
|
||||
{
|
||||
/* enquene lif_msg (add)*/
|
||||
if (!msg)
|
||||
{
|
||||
arp_msg->op_type = ARP_SYNC_LIF;
|
||||
if (iccp_csm_init_msg(&msg, (char*)arp_msg, msg_len) == 0)
|
||||
{
|
||||
mlacp_enqueue_arp(csm, msg);
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "ARP-list enqueue: %s, add %s",
|
||||
arp_msg->ifname, show_ip_str(htonl(arp_msg->ipv4_addr)));*/
|
||||
}
|
||||
else
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP-list: %s, add %s",
|
||||
arp_msg->ifname, show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
|
||||
/* enqueue iccp_msg (add)*/
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
{
|
||||
arp_msg->op_type = ARP_SYNC_ADD;
|
||||
if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] message for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));*/
|
||||
}
|
||||
else
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] message for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enqueue iccp_msg (delete)*/
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
{
|
||||
arp_msg->op_type = ARP_SYNC_DEL;
|
||||
if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[DEL] message for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));*/
|
||||
}
|
||||
else
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[DEL] message for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*Debug: dump for dequeue ARP Info*/
|
||||
#if 0
|
||||
fprintf(stderr, "\n======== ARP Info List ========\n");
|
||||
TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
fprintf(stderr, "type %d,ifname %s , ip %s\n", arp_msg->op_type, arp_msg->ifname, show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
fprintf(stderr, "==============================\n");
|
||||
#endif
|
||||
|
||||
/*TEST dump for dequeue ARP message*/
|
||||
#if 0
|
||||
|
||||
while (MLACP(csm).arp_updated && !TAILQ_EMPTY(&(MLACP(csm).arp_msg_list)))
|
||||
{
|
||||
msg = TAILQ_FIRST(&(MLACP(csm).arp_msg_list));
|
||||
TAILQ_REMOVE(&(MLACP(csm).arp_msg_list), msg, tail);
|
||||
arp_msg = (struct ARPMsg *)msg->buf;
|
||||
fprintf(stderr, "\n======== Dequeue ARP ========\n");
|
||||
fprintf(stderr, " Type = [%d]\n", arp_msg->op_type);
|
||||
fprintf(stderr, " State = (%04X)(%d)\n", ndm->ndm_state, fwd_neigh_state_valid(ndm->ndm_state));
|
||||
fprintf(stderr, " ifname = [%s]\n", arp_msg->ifname);
|
||||
fprintf(stderr, " IP = [%s]\n", show_ip_str(arp_msg->ipv4_addr));
|
||||
fprintf(stderr, " MAC = [%02X:%02X:%02X:%02X:%02X:%02X]\n",
|
||||
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]);
|
||||
fprintf(stderr, "==============================\n");
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
MLACP(csm).arp_updated = 0;
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ifm_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, int len)
|
||||
{
|
||||
while (RTA_OK(rta, len))
|
||||
{
|
||||
if (rta->rta_type <= max)
|
||||
tb[rta->rta_type] = rta;
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
}
|
||||
|
||||
int do_one_neigh_request(struct nlmsghdr *n)
|
||||
{
|
||||
struct ndmsg *ndm = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len;
|
||||
struct rtattr * tb[NDA_MAX + 1];
|
||||
|
||||
if (n->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* process msg_type RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH */
|
||||
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH )
|
||||
return(0);
|
||||
|
||||
len -= NLMSG_LENGTH(sizeof(*ndm));
|
||||
if (len < 0)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
ifm_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
|
||||
|
||||
if (n->nlmsg_type == RTM_NEWNEIGH
|
||||
&& (ndm->ndm_state == NUD_INCOMPLETE
|
||||
|| ndm->ndm_state == NUD_FAILED
|
||||
|| ndm->ndm_state == NUD_NOARP
|
||||
|| ndm->ndm_state == NUD_PERMANENT
|
||||
|| ndm->ndm_state == NUD_NONE))
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!tb[NDA_DST] || ndm->ndm_type != RTN_UNICAST)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (ndm->ndm_family == AF_INET)
|
||||
{
|
||||
do_arp_learn_from_kernel(ndm, tb, n->nlmsg_type);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*Handle arp received from kernel*/
|
||||
static int iccp_arp_valid_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
|
||||
do_one_neigh_request(nlh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Get kernel arp information during initialization*/
|
||||
int iccp_arp_get_init()
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct nl_cb *cb;
|
||||
struct nl_cb *orig_cb;
|
||||
struct rtgenmsg rt_hdr = {
|
||||
.rtgen_family = AF_UNSPEC,
|
||||
};
|
||||
int ret;
|
||||
int retry = 1;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return MCLAG_ERROR;
|
||||
|
||||
while (retry)
|
||||
{
|
||||
retry = 0;
|
||||
ret = nl_send_simple(sys->route_sock, RTM_GETNEIGH, NLM_F_DUMP,
|
||||
&rt_hdr, sizeof(rt_hdr));
|
||||
if (ret < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Send netlink msg error.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
orig_cb = nl_socket_get_cb(sys->route_sock);
|
||||
cb = nl_cb_clone(orig_cb);
|
||||
nl_cb_put(orig_cb);
|
||||
if (!cb)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "nl cb clone error.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, iccp_arp_valid_handler, sys);
|
||||
|
||||
ret = nl_recvmsgs(sys->route_sock, cb);
|
||||
nl_cb_put(cb);
|
||||
if (ret < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Receive netlink msg error.");
|
||||
if (ret != -NLE_DUMP_INTR)
|
||||
return ret;
|
||||
|
||||
retry = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*When received ARP packets from kernel, update arp information*/
|
||||
void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, uint8_t mac_addr[ETHER_ADDR_LEN])
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct Msg *msg = NULL;
|
||||
struct ARPMsg *arp_msg = NULL, *arp_info = NULL;
|
||||
struct VLAN_ID *vlan_id_list = NULL;
|
||||
struct Msg *msg_send = NULL;
|
||||
|
||||
char buf[MAX_BUFSIZE];
|
||||
size_t msg_len = 0;
|
||||
|
||||
struct LocalInterface *lif_po = NULL, *arp_lif = NULL;
|
||||
|
||||
int verify_arp = 0;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return;
|
||||
|
||||
/* Find local itf*/
|
||||
if (!(arp_lif = local_if_find_by_ifindex(ifindex)))
|
||||
return;
|
||||
|
||||
/* create ARP msg*/
|
||||
memset(buf, 0, MAX_BUFSIZE);
|
||||
msg_len = sizeof(struct ARPMsg);
|
||||
arp_msg = (struct ARPMsg*)&buf;
|
||||
arp_msg->op_type = ARP_SYNC_LIF;
|
||||
sprintf(arp_msg->ifname, "%s", arp_lif->name);
|
||||
memcpy(&arp_msg->ipv4_addr, &addr, 4);
|
||||
memcpy(arp_msg->mac_addr, mac_addr, 6);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP ifindex [%d] (%s) ip %s mac [%02X:%02X:%02X:%02X:%02X:%02X]",
|
||||
ifindex, arp_lif->name,
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)),
|
||||
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]);
|
||||
/*Debug*/
|
||||
#if 0
|
||||
/* dump receive kernel ARP req*/
|
||||
fprintf(stderr, "\n======== Kernel ARP Update==========\n");
|
||||
fprintf(stderr, " Type = (New=%d)\n", RTM_NEWNEIGH);
|
||||
fprintf(stderr, " ifindex = [%d] (%s)\n", ifindex, arp_lif->name);
|
||||
fprintf(stderr, " IP = [%s]\n", show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
fprintf(stderr, " MAC = [%02X:%02X:%02X:%02X:%02X:%02X]\n",
|
||||
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]);
|
||||
fprintf(stderr, "==============================\n");
|
||||
#endif
|
||||
|
||||
/* Find MLACP itf, member of port-channel*/
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lif_po->type != IF_T_PORT_CHANNEL)
|
||||
continue;
|
||||
|
||||
if (!local_if_is_l3_mode(lif_po))
|
||||
{
|
||||
/* Is the L2 MLAG itf belong to a vlan?*/
|
||||
LIST_FOREACH(vlan_id_list, &(lif_po->vlan_list), port_next)
|
||||
{
|
||||
if ( !(vlan_id_list->vlan_itf
|
||||
&& vlan_id_list->vlan_itf->ifindex == ifindex))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!vlan_id_list)
|
||||
continue;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled port %s of vlan %s",
|
||||
lif_po->name, vlan_id_list->vlan_itf->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is the ARP belong to a L3 mode MLAG itf?*/
|
||||
if (ifindex != lif_po->ifindex)
|
||||
continue;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name);
|
||||
}
|
||||
|
||||
verify_arp = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (lif_po)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(csm && lif_po))
|
||||
return;
|
||||
if (!verify_arp)
|
||||
return;
|
||||
|
||||
if (iccp_check_if_addr_from_netlink(AF_INET, &addr, arp_lif))
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP %s is identical with the ip address of interface %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)), arp_lif->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* update lif ARP*/
|
||||
TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
|
||||
{
|
||||
arp_info = (struct ARPMsg*)msg->buf;
|
||||
if (arp_info->ipv4_addr != arp_msg->ipv4_addr)
|
||||
continue;
|
||||
|
||||
/* update ARP*/
|
||||
if (arp_info->op_type != arp_msg->op_type
|
||||
|| strcmp(arp_info->ifname, arp_msg->ifname) != 0
|
||||
|| memcmp(arp_info->mac_addr, arp_msg->mac_addr,
|
||||
ETHER_ADDR_LEN) != 0)
|
||||
{
|
||||
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(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* enquene lif_msg (add)*/
|
||||
if (!msg)
|
||||
{
|
||||
arp_msg->op_type = ARP_SYNC_LIF;
|
||||
if (iccp_csm_init_msg(&msg, (char*)arp_msg, msg_len) == 0)
|
||||
{
|
||||
mlacp_enqueue_arp(csm, msg);
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "ARP-list enqueue: %s, add %s",
|
||||
arp_msg->ifname, show_ip_str(htonl(arp_msg->ipv4_addr)));*/
|
||||
}
|
||||
else
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP-list: %s, add %s",
|
||||
arp_msg->ifname, show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
|
||||
/* enqueue iccp_msg (add)*/
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
{
|
||||
arp_msg->op_type = ARP_SYNC_ADD;
|
||||
if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));*/
|
||||
}
|
||||
else
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] message for %s",
|
||||
show_ip_str(htonl(arp_msg->ipv4_addr)));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void iccp_from_netlink_port_state_handler( char * ifname, int state)
|
||||
{
|
||||
struct CSM *csm = NULL;
|
||||
struct LocalInterface *lif_po = NULL;
|
||||
struct System *sys;
|
||||
int po_is_active = 0;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to obtain System instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
po_is_active = (state == PORT_STATE_UP);
|
||||
|
||||
/* traverse all CSM */
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
/*If peer-link changes to down or up */
|
||||
if (strcmp(ifname, csm->peer_itf_name) == 0)
|
||||
{
|
||||
if (po_is_active == 0)
|
||||
mlacp_peerlink_down_handler(csm);
|
||||
else
|
||||
mlacp_peerlink_up_handler(csm);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lif_po->type == IF_T_PORT_CHANNEL && strncmp(lif_po->name, ifname, MAX_L_PORT_NAME) == 0)
|
||||
{
|
||||
mlacp_portchannel_state_handler(csm, lif_po, po_is_active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
|
||||
int len, unsigned short flags)
|
||||
{
|
||||
unsigned short type;
|
||||
|
||||
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
|
||||
|
||||
while (RTA_OK(rta, len))
|
||||
{
|
||||
type = rta->rta_type & ~flags;
|
||||
if ((type <= max) && (!tb[type]))
|
||||
tb[type] = rta;
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
|
||||
{
|
||||
return parse_rtattr_flags(tb, max, rta, len, 0);
|
||||
}
|
||||
|
||||
void iccp_parse_if_vlan_info_from_netlink(struct nlmsghdr *n)
|
||||
{
|
||||
struct LocalInterface *lif = NULL;
|
||||
int msglen = 0;
|
||||
|
||||
msglen = n->nlmsg_len;
|
||||
|
||||
while (NLMSG_OK(n, msglen))
|
||||
{
|
||||
struct ifinfomsg *ifm = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len;
|
||||
struct rtattr * tb[IFLA_MAX + 1];
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWLINK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
len -= NLMSG_LENGTH(sizeof(*ifm));
|
||||
if (len < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "BUG: wrong nlmsg len %d\n", len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ifm->ifi_family != AF_BRIDGE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((lif = local_if_find_by_ifindex(ifm->ifi_index)) != NULL)
|
||||
{
|
||||
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
|
||||
|
||||
/* if AF_SPEC isn't there, vlan table is not preset for this port */
|
||||
if (!tb[IFLA_AF_SPEC])
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Vlan table is not preset for %d", ifm->ifi_index);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct rtattr *i, *list = tb[IFLA_AF_SPEC];
|
||||
int rem = RTA_PAYLOAD(list);
|
||||
struct VLAN_ID *vlan = NULL;
|
||||
|
||||
/*set vlan flag is removed*/
|
||||
LIST_FOREACH(vlan, &(lif->vlan_list), port_next)
|
||||
{
|
||||
vlan->vlan_removed = 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
local_if_add_vlan(lif, vinfo->vid);
|
||||
}
|
||||
|
||||
/*After update vlan list, remove unused item*/
|
||||
LIST_FOREACH(vlan, &(lif->vlan_list), port_next)
|
||||
{
|
||||
if (vlan->vlan_removed == 1)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", lif->name, vlan->vid);
|
||||
|
||||
LIST_REMOVE(vlan, port_next);
|
||||
free(vlan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = NLMSG_NEXT(n, msglen);
|
||||
}
|
||||
}
|
272
src/iccpd/src/iccp_main.c
Normal file
272
src/iccpd/src/iccp_main.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* iccp_main.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "../include/cmd_option.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/scheduler.h"
|
||||
#include "../include/system.h"
|
||||
|
||||
int check_instance(char* pid_file_path)
|
||||
{
|
||||
int pid_file = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (pid_file_path == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
pid_file = open(pid_file_path, O_CREAT | O_RDWR, 0666);
|
||||
if (pid_file <= 0 )
|
||||
{
|
||||
fprintf(stderr, "Can't open a pid file. Terminate.\n");
|
||||
close(pid_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = flock(pid_file, LOCK_EX | LOCK_NB);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
{
|
||||
fprintf(stderr, "There is another instance running. Terminate.\n");
|
||||
close(pid_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return pid_file;
|
||||
}
|
||||
|
||||
void init_daemon(char* pid_file_path, int pid_file)
|
||||
{
|
||||
pid_t pid, sid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to enter daemon mode: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Please try to check your system resources.\n");
|
||||
close(pid_file);
|
||||
unlink(pid_file_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid > 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
umask(0);
|
||||
sid = setsid();
|
||||
if (sid < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to create a new SID for this program: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Please try to check your system resources.\n");
|
||||
close(pid_file);
|
||||
unlink(pid_file_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
freopen("/dev/null", "r", stdin);
|
||||
freopen("/dev/null", "w", stdout);
|
||||
freopen("/dev/null", "w", stderr);
|
||||
}
|
||||
|
||||
#ifndef ICCPD_RUN_DIR
|
||||
#define ICCPD_RUN_DIR "/var/run/iccpd/"
|
||||
#endif
|
||||
|
||||
static inline int iccpd_make_rundir(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mkdir(ICCPD_RUN_DIR, 0755);
|
||||
if (ret && errno != EEXIST)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Failed to create directory \"%s\"",
|
||||
ICCPD_RUN_DIR);
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iccpd_signal_handler(int sig)
|
||||
{
|
||||
int err;
|
||||
struct System* sys = NULL;
|
||||
const char warmboot_flag = 'w';
|
||||
|
||||
sys = system_get_instance();
|
||||
if (!sys)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
retry:
|
||||
err = write(sys->sig_pipe_w, &warmboot_flag, 1);
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto retry;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int iccpd_signal_init(struct System* sys)
|
||||
{
|
||||
int fds[2];
|
||||
int err;
|
||||
sigset_t ss;
|
||||
struct sigaction sa;
|
||||
struct epoll_event event;
|
||||
|
||||
err = pipe(fds);
|
||||
if (err)
|
||||
return -errno;
|
||||
|
||||
sys->sig_pipe_r = fds[0];
|
||||
sys->sig_pipe_w = fds[1];
|
||||
|
||||
if (sigemptyset(&ss) < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "sigemptyset(): %d", errno);
|
||||
goto close_pipe;
|
||||
}
|
||||
|
||||
if (sigaddset(&ss, SIGUSR1) < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "sigaddset(): %d", errno);
|
||||
goto close_pipe;
|
||||
}
|
||||
|
||||
if (sigprocmask(SIG_UNBLOCK, &ss, NULL) < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "sigprocmask(): %d", errno);
|
||||
goto close_pipe;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = iccpd_signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
if (sigaction(SIGUSR1, &sa, NULL) < 0)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "sigaction(): %d", errno);
|
||||
goto close_pipe;
|
||||
}
|
||||
|
||||
event.data.fd = fds[0];
|
||||
event.events = EPOLLIN;
|
||||
err = epoll_ctl(sys->epoll_fd, EPOLL_CTL_ADD, fds[0], &event);
|
||||
if (err)
|
||||
{
|
||||
goto close_pipe;
|
||||
}
|
||||
|
||||
FD_SET( fds[0], &(sys->readfd));
|
||||
sys->readfd_count++;
|
||||
|
||||
return 0;
|
||||
|
||||
close_pipe:
|
||||
close(sys->sig_pipe_r);
|
||||
close(sys->sig_pipe_w);
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int pid_file_fd = 0;
|
||||
struct System* sys = NULL;
|
||||
int err;
|
||||
struct CmdOptionParser parser = CMD_OPTION_PARSER_INIT_VALUE;
|
||||
|
||||
err = iccpd_make_rundir();
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
if (getuid() != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"This program needs root permission to do device manipulation. "
|
||||
"Please use sudo to execute it or change your user to root.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
parser.init(&parser);
|
||||
if (parser.parse(&parser, argc, argv) != 0)
|
||||
{
|
||||
parser.finalize(&parser);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
pid_file_fd = check_instance(parser.pid_file_path);
|
||||
if (pid_file_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Check instance with invalidate arguments, iccpd is terminated.\n");
|
||||
parser.finalize(&parser);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sys = system_get_instance();
|
||||
if (!sys)
|
||||
{
|
||||
fprintf(stderr, "Can't get a system instance, iccpd is terminated.\n");
|
||||
parser.finalize(&parser);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*if(!parser.console_log)
|
||||
init_daemon(parser.pid_file_path, pid_file_fd);*/
|
||||
|
||||
log_init(&parser);
|
||||
|
||||
if (sys->log_file_path != NULL)
|
||||
free(sys->log_file_path);
|
||||
if (sys->cmd_file_path != NULL)
|
||||
free(sys->cmd_file_path);
|
||||
if (sys->config_file_path != NULL)
|
||||
free(sys->config_file_path);
|
||||
sys->log_file_path = strdup(parser.log_file_path);
|
||||
sys->cmd_file_path = strdup(parser.cmd_file_path);
|
||||
sys->config_file_path = strdup(parser.config_file_path);
|
||||
sys->mclagdctl_file_path = strdup(parser.mclagdctl_file_path);
|
||||
sys->pid_file_fd = pid_file_fd;
|
||||
sys->telnet_port = parser.telnet_port;
|
||||
parser.finalize(&parser);
|
||||
iccpd_signal_init(sys);
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Iccpd is started, process id = %d. uid %d ", getpid(), getuid());
|
||||
scheduler_init();
|
||||
scheduler_start();
|
||||
system_finalize();
|
||||
/*scheduler_finalize();
|
||||
log_finalize();*/
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1545
src/iccpd/src/iccp_netlink.c
Normal file
1545
src/iccpd/src/iccp_netlink.c
Normal file
File diff suppressed because it is too large
Load Diff
140
src/iccpd/src/logger.c
Normal file
140
src/iccpd/src/logger.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* logger.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../include/cmd_option.h"
|
||||
#include "../include/logger.h"
|
||||
|
||||
static uint32_t _iccpd_log_level_map[] =
|
||||
{
|
||||
LOG_CRIT,
|
||||
LOG_ERR,
|
||||
LOG_WARNING,
|
||||
LOG_NOTICE,
|
||||
LOG_INFO,
|
||||
LOG_DEBUG,
|
||||
};
|
||||
|
||||
char* log_level_to_string(int level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case CRITICAL_LOG_LEVEL:
|
||||
return "CRITICAL";
|
||||
|
||||
case ERR_LOG_LEVEL:
|
||||
return "ERROR";
|
||||
|
||||
case WARN_LOG_LEVEL:
|
||||
return "WARN";
|
||||
|
||||
case NOTICE_LOG_LEVEL:
|
||||
return "NOTICE";
|
||||
|
||||
case INFO_LOG_LEVEL:
|
||||
return "INFO";
|
||||
|
||||
case DEBUG_LOG_LEVEL:
|
||||
return "DEBUG";
|
||||
}
|
||||
|
||||
return "INFO";
|
||||
}
|
||||
|
||||
struct LoggerConfig* logger_get_configuration()
|
||||
{
|
||||
static struct LoggerConfig config;
|
||||
|
||||
if (config.init == 0)
|
||||
{
|
||||
config.console_log_enabled = 0;
|
||||
config.log_level = NOTICE_LOG_LEVEL;
|
||||
config.init = 1;
|
||||
}
|
||||
|
||||
return &config;
|
||||
}
|
||||
|
||||
void logger_set_configuration(int log_level)
|
||||
{
|
||||
struct LoggerConfig* config = logger_get_configuration();
|
||||
|
||||
config->log_level = log_level;
|
||||
config->init = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void log_init(struct CmdOptionParser* parser)
|
||||
{
|
||||
struct LoggerConfig* config = logger_get_configuration();
|
||||
|
||||
config->console_log_enabled = parser->console_log;
|
||||
}
|
||||
|
||||
void log_finalize()
|
||||
{
|
||||
/*do nothing*/
|
||||
}
|
||||
|
||||
void write_log(const int level, const char* tag, const char* format, ...)
|
||||
{
|
||||
struct LoggerConfig* config = logger_get_configuration();
|
||||
char buf[LOGBUF_SIZE];
|
||||
va_list args;
|
||||
unsigned int prefix_len;
|
||||
unsigned int avbl_buf_len;
|
||||
unsigned int print_len;
|
||||
|
||||
#if 0
|
||||
if (!config->console_log_enabled)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (level > config->log_level)
|
||||
return;
|
||||
|
||||
prefix_len = snprintf(buf, LOGBUF_SIZE, "[%s.%s] ", tag, log_level_to_string(level));
|
||||
avbl_buf_len = LOGBUF_SIZE - prefix_len;
|
||||
|
||||
va_start(args, format);
|
||||
print_len = vsnprintf(buf + prefix_len, avbl_buf_len, format, args);
|
||||
va_end(args);
|
||||
|
||||
/* Since osal_vsnprintf doesn't always return the exact size written to the buffer,
|
||||
* we must check if the user string length exceeds the remaing buffer size.
|
||||
*/
|
||||
if (print_len > avbl_buf_len)
|
||||
{
|
||||
print_len = avbl_buf_len;
|
||||
}
|
||||
|
||||
buf[prefix_len + print_len] = '\0';
|
||||
ICCPD_UTILS_SYSLOG(_iccpd_log_level_map[level], "%s", buf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
28
src/iccpd/src/mclagdctl/Makefile
Normal file
28
src/iccpd/src/mclagdctl/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
C = gcc
|
||||
SOURCES = \
|
||||
mclagdctl.c
|
||||
|
||||
OBJECTS = \
|
||||
mclagdctl.o
|
||||
|
||||
HEADERS = \
|
||||
mclagdctl.h
|
||||
|
||||
CFLAGS = -g -O2 -fstack-protector-strong -Wformat -Werror=format-security
|
||||
LDFLAGS =
|
||||
LDADD =
|
||||
|
||||
all: mclagdctl
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
|
||||
mclagdctl: $(OBJECTS)
|
||||
$(CC) -o ./mclagdctl $(OBJECTS) $(LDFLAGS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f $(OBJECTS) ./mclagdctl
|
||||
|
||||
|
883
src/iccpd/src/mclagdctl/mclagdctl.c
Normal file
883
src/iccpd/src/mclagdctl/mclagdctl.c
Normal file
@ -0,0 +1,883 @@
|
||||
/*
|
||||
/* Copyright(c) 2016-2019 Nephos.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: Jim Jiang from nephos
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include "mclagdctl.h"
|
||||
|
||||
static int mclagdctl_sock_fd = -1;
|
||||
char *mclagdctl_sock_path = "/var/run/iccpd/mclagdctl.sock";
|
||||
|
||||
/*
|
||||
Already implemented command:
|
||||
mclagdctl -i dump state
|
||||
mclagdctl -i dump arp
|
||||
mclagdctl -i dump mac
|
||||
mclagdctl -i dump portlist local
|
||||
mclagdctl -i dump portlist peer
|
||||
*/
|
||||
|
||||
static struct command_type command_types[] =
|
||||
{
|
||||
{
|
||||
.id = ID_CMDTYPE_D,
|
||||
.name = "dump",
|
||||
.enca_msg = NULL,
|
||||
.parse_msg = NULL,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_S,
|
||||
.parent_id = ID_CMDTYPE_D,
|
||||
.info_type = INFO_TYPE_DUMP_STATE,
|
||||
.name = "state",
|
||||
.enca_msg = mclagdctl_enca_dump_state,
|
||||
.parse_msg = mclagdctl_parse_dump_state,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_A,
|
||||
.parent_id = ID_CMDTYPE_D,
|
||||
.info_type = INFO_TYPE_DUMP_ARP,
|
||||
.name = "arp",
|
||||
.enca_msg = mclagdctl_enca_dump_arp,
|
||||
.parse_msg = mclagdctl_parse_dump_arp,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_A,
|
||||
.parent_id = ID_CMDTYPE_D,
|
||||
.info_type = INFO_TYPE_DUMP_MAC,
|
||||
.name = "mac",
|
||||
.enca_msg = mclagdctl_enca_dump_mac,
|
||||
.parse_msg = mclagdctl_parse_dump_mac,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_P,
|
||||
.parent_id = ID_CMDTYPE_D,
|
||||
.name = "portlist",
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_P_L,
|
||||
.parent_id = ID_CMDTYPE_D_P,
|
||||
.info_type = INFO_TYPE_DUMP_LOCAL_PORTLIST,
|
||||
.name = "local",
|
||||
.enca_msg = mclagdctl_enca_dump_local_portlist,
|
||||
.parse_msg = mclagdctl_parse_dump_local_portlist,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_D_P_P,
|
||||
.parent_id = ID_CMDTYPE_D_P,
|
||||
.info_type = INFO_TYPE_DUMP_PEER_PORTLIST,
|
||||
.name = "peer",
|
||||
.enca_msg = mclagdctl_enca_dump_peer_portlist,
|
||||
.parse_msg = mclagdctl_parse_dump_peer_portlist,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_C,
|
||||
.name = "config",
|
||||
.enca_msg = NULL,
|
||||
.parse_msg = NULL,
|
||||
},
|
||||
{
|
||||
.id = ID_CMDTYPE_C_L,
|
||||
.parent_id = ID_CMDTYPE_C,
|
||||
.info_type = INFO_TYPE_CONFIG_LOGLEVEL,
|
||||
.name = "loglevel",
|
||||
.enca_msg = mclagdctl_enca_config_loglevel,
|
||||
.parse_msg = mclagdctl_parse_config_loglevel,
|
||||
},
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define COMMAND_TYPE_COUNT ARRAY_SIZE(command_types)
|
||||
|
||||
int mclagdctl_sock_connect()
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int addrlen = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (mclagdctl_sock_fd >= 0)
|
||||
return 0;
|
||||
|
||||
if (strlen(mclagdctl_sock_path) <= 0)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
mclagdctl_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (mclagdctl_sock_fd < 0)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "%s", mclagdctl_sock_path);
|
||||
addrlen = sizeof(addr.sun_family) + strlen(mclagdctl_sock_path);
|
||||
|
||||
if ((ret = connect(mclagdctl_sock_fd, (struct sockaddr*)&addr, addrlen)) < 0)
|
||||
{
|
||||
close(mclagdctl_sock_fd);
|
||||
mclagdctl_sock_fd = -1;
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mclagdctl_sock_close()
|
||||
{
|
||||
if (mclagdctl_sock_fd > 0)
|
||||
{
|
||||
close(mclagdctl_sock_fd);
|
||||
mclagdctl_sock_fd = -1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int mclagdctl_sock_write(int fd, unsigned char *w_buf, int total_len)
|
||||
{
|
||||
int write_len = 0;
|
||||
int ret = 0;
|
||||
|
||||
while (write_len < total_len)
|
||||
{
|
||||
ret = write(fd, w_buf + write_len, total_len - write_len);
|
||||
if (ret <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
write_len += ret;
|
||||
}
|
||||
|
||||
return write_len;
|
||||
}
|
||||
|
||||
int mclagdctl_sock_read(int fd, unsigned char *r_buf, int total_len)
|
||||
{
|
||||
int read_len = 0;
|
||||
int ret = 0;
|
||||
struct timeval tv = { 0 };
|
||||
fd_set read_fd;
|
||||
|
||||
while (read_len < total_len)
|
||||
{
|
||||
FD_ZERO(&read_fd);
|
||||
FD_SET(fd, &read_fd);
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
switch ((ret = select(fd + 1, &read_fd, NULL, NULL, &tv)))
|
||||
{
|
||||
case -1: // error
|
||||
fprintf(stdout, "Mclagdctl:Select return error:%s\n", strerror(errno));
|
||||
return MCLAG_ERROR;
|
||||
|
||||
case 0: // timeout
|
||||
fprintf(stdout, "Mclagdctl:Select timeout:%s\n", strerror(errno));
|
||||
return MCLAG_ERROR;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = read(fd, r_buf + read_len, total_len - read_len);
|
||||
if (ret <= 0)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
read_len += ret;
|
||||
}
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_dump_state(char *msg, int mclag_id, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_DUMP_STATE;
|
||||
req.mclag_id = mclag_id;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mclagdctl_parse_dump_state(char *msg, int data_len)
|
||||
{
|
||||
struct mclagd_state * state_info = NULL;
|
||||
int len = 0;
|
||||
int count = 0;
|
||||
int pos = 0;
|
||||
|
||||
len = sizeof(struct mclagd_state);
|
||||
|
||||
for (; data_len >= len; data_len -= len, count++)
|
||||
{
|
||||
state_info = (struct mclagd_state*)(msg + len * count);
|
||||
|
||||
fprintf(stdout, "%s: %s\n", "The MCLAG's keepalive is", state_info->keepalive ? "OK" : "ERROR");
|
||||
|
||||
if (state_info->mclag_id <= 0)
|
||||
fprintf(stdout, "%s: %s\n", "Domain id", "Unknown");
|
||||
else
|
||||
fprintf(stdout, "%s: %d\n", "Domain id", state_info->mclag_id);
|
||||
|
||||
fprintf(stdout, "%s: %s\n", "Local Ip", state_info->local_ip);
|
||||
fprintf(stdout, "%s: %s\n", "Peer Ip", state_info->peer_ip);
|
||||
fprintf(stdout, "%s: %s\n", "Peer Link Interface", state_info->peer_link_if);
|
||||
|
||||
fprintf(stdout, "%s: %02x:%02x:%02x:%02x:%02x:%02x \n",
|
||||
"Peer Link Mac",
|
||||
state_info->peer_link_mac[0], state_info->peer_link_mac[1],
|
||||
state_info->peer_link_mac[2], state_info->peer_link_mac[3],
|
||||
state_info->peer_link_mac[4], state_info->peer_link_mac[5]);
|
||||
|
||||
if (state_info->role == 0)
|
||||
fprintf(stdout, "%s: %s\n", "Role", "None");
|
||||
else if (state_info->role == 1)
|
||||
fprintf(stdout, "%s: %s\n", "Role", "Active");
|
||||
else if (state_info->role == 2)
|
||||
fprintf(stdout, "%s: %s\n", "Role", "Standby");
|
||||
|
||||
fprintf(stdout, "%s: %s\n", "MCLAG Interface", state_info->enabled_po);
|
||||
|
||||
fprintf(stdout, "%s: %s\n", "Loglevel", state_info->loglevel);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_dump_arp(char *msg, int mclag_id, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
if (mclag_id <= 0)
|
||||
{
|
||||
fprintf(stderr, "Need to specify mclag-id through the parameter i !\n");
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_DUMP_ARP;
|
||||
req.mclag_id = mclag_id;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mclagdctl_parse_dump_arp(char *msg, int data_len)
|
||||
{
|
||||
struct mclagd_arp_msg * arp_info = NULL;
|
||||
int len = 0;
|
||||
int count = 0;
|
||||
|
||||
fprintf(stdout, "%-6s", "No.");
|
||||
fprintf(stdout, "%-20s", "IP");
|
||||
fprintf(stdout, "%-20s", "MAC");
|
||||
fprintf(stdout, "%-20s", "DEV");
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
len = sizeof(struct mclagd_arp_msg);
|
||||
|
||||
for (; data_len >= len; data_len -= len, count++)
|
||||
{
|
||||
arp_info = (struct mclagd_arp_msg*)(msg + len * count);
|
||||
|
||||
fprintf(stdout, "%-6d", count + 1);
|
||||
fprintf(stdout, "%-20s", arp_info->ipv4_addr);
|
||||
fprintf(stdout, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
arp_info->mac_addr[0], arp_info->mac_addr[1],
|
||||
arp_info->mac_addr[2], arp_info->mac_addr[3],
|
||||
arp_info->mac_addr[4], arp_info->mac_addr[5]);
|
||||
fprintf(stdout, " ");
|
||||
fprintf(stdout, "%-20s", arp_info->ifname);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_dump_mac(char *msg, int mclag_id, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
if (mclag_id <= 0)
|
||||
{
|
||||
fprintf(stderr, "Need to specify mclag-id through the parameter i !\n");
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_DUMP_MAC;
|
||||
req.mclag_id = mclag_id;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mclagdctl_parse_dump_mac(char *msg, int data_len)
|
||||
{
|
||||
struct mclagd_mac_msg * mac_info = NULL;
|
||||
int len = 0;
|
||||
int count = 0;
|
||||
|
||||
fprintf(stdout, "%-60s\n", "TYPE: S-STATIC, D-DYNAMIC; AGE: L-Local age, P-Peer age");
|
||||
|
||||
fprintf(stdout, "%-6s", "No.");
|
||||
fprintf(stdout, "%-5s", "TYPE");
|
||||
fprintf(stdout, "%-20s", "MAC");
|
||||
fprintf(stdout, "%-5s", "VID");
|
||||
fprintf(stdout, "%-20s", "DEV");
|
||||
fprintf(stdout, "%-20s", "ORIGIN-DEV");
|
||||
fprintf(stdout, "%-5s", "AGE");
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
len = sizeof(struct mclagd_mac_msg);
|
||||
|
||||
for (; data_len >= len; data_len -= len, count++)
|
||||
{
|
||||
mac_info = (struct mclagd_mac_msg*)(msg + len * count);
|
||||
|
||||
fprintf(stdout, "%-6d", count + 1);
|
||||
|
||||
if (mac_info->fdb_type == MAC_TYPE_STATIC_CTL)
|
||||
fprintf(stdout, "%-5s", "S");
|
||||
else
|
||||
fprintf(stdout, "%-5s", "D");
|
||||
|
||||
fprintf(stdout, "%-20s", mac_info->mac_str);
|
||||
fprintf(stdout, "%-5d", mac_info->vid);
|
||||
fprintf(stdout, "%-20s", mac_info->ifname);
|
||||
fprintf(stdout, "%-20s", mac_info->origin_ifname);
|
||||
|
||||
if ((mac_info->age_flag & MAC_AGE_LOCAL_CTL) && (mac_info->age_flag & MAC_AGE_PEER_CTL))
|
||||
fprintf(stdout, "%-5s", "LP");
|
||||
else if (mac_info->age_flag & MAC_AGE_LOCAL_CTL)
|
||||
fprintf(stdout, "%-5s", "L");
|
||||
else if (mac_info->age_flag & MAC_AGE_PEER_CTL)
|
||||
fprintf(stdout, "%-5s", "P");
|
||||
else
|
||||
fprintf(stdout, "%-5s", " ");
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_dump_local_portlist(char *msg, int mclag_id, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
if (mclag_id <= 0)
|
||||
{
|
||||
fprintf(stderr, "Need to specify mclag-id through the parameter i !\n");
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_DUMP_LOCAL_PORTLIST;
|
||||
req.mclag_id = mclag_id;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
len = sizeof(struct mclagd_local_if);
|
||||
|
||||
for (; data_len >= len; data_len -= len, count++)
|
||||
{
|
||||
lif_info = (struct mclagd_local_if*)(msg + len * count);
|
||||
|
||||
for (pos = 0; pos < 60; ++pos)
|
||||
fprintf(stdout, "-");
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
if (memcmp(lif_info->type, "PortChannel", 11) == 0)
|
||||
{
|
||||
fprintf(stdout, "%s: %d\n", "Ifindex", lif_info->ifindex);
|
||||
fprintf(stdout, "%s: %s\n", "Type", lif_info->type);
|
||||
fprintf(stdout, "%s: %s\n", "PortName", lif_info->name);
|
||||
fprintf(stdout, "%s: %02x:%02x:%02x:%02x:%02x:%02x \n",
|
||||
"MAC",
|
||||
lif_info->mac_addr[0], lif_info->mac_addr[1],
|
||||
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", "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: %s\n", "IsIsolateWithPeerlink", lif_info->isolate_to_peer_link ? "Yes" : "No");
|
||||
fprintf(stdout, "%s: %s\n", "VlanList", lif_info->vlanlist);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout, "%s: %d\n", "Ifindex", lif_info->ifindex);
|
||||
fprintf(stdout, "%s: %s\n", "Type", lif_info->type);
|
||||
fprintf(stdout, "%s: %s\n", "PortName", lif_info->name);
|
||||
fprintf(stdout, "%s: %s\n", "State", lif_info->state);
|
||||
/*fprintf(stdout,"%s: %d\n" ,"PortchannelId", lif_info->po_id);*/
|
||||
}
|
||||
|
||||
for (pos = 0; pos < 60; ++pos)
|
||||
fprintf(stdout, "-");
|
||||
|
||||
fprintf(stdout, "\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_dump_peer_portlist(char *msg, int mclag_id, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
if (mclag_id <= 0)
|
||||
{
|
||||
fprintf(stderr, "Need to specify mclag-id through the parameter i !\n");
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_DUMP_PEER_PORTLIST;
|
||||
req.mclag_id = mclag_id;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mclagdctl_parse_dump_peer_portlist(char *msg, int data_len)
|
||||
{
|
||||
struct mclagd_peer_if * pif_info = NULL;
|
||||
int len = 0;
|
||||
int count = 0;
|
||||
int pos = 0;
|
||||
|
||||
len = sizeof(struct mclagd_peer_if);
|
||||
|
||||
for (; data_len >= len; data_len -= len, count++)
|
||||
{
|
||||
pif_info = (struct mclagd_peer_if*)(msg + len * count);
|
||||
|
||||
for (pos = 0; pos < 60; ++pos)
|
||||
fprintf(stdout, "-");
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
fprintf(stdout, "%s: %d\n", "Ifindex", pif_info->ifindex);
|
||||
fprintf(stdout, "%s: %s\n", "Type", pif_info->type);
|
||||
fprintf(stdout, "%s: %s\n", "PortName", pif_info->name);
|
||||
fprintf(stdout, "%s: %02x:%02x:%02x:%02x:%02x:%02x \n",
|
||||
"MAC",
|
||||
pif_info->mac_addr[0], pif_info->mac_addr[1],
|
||||
pif_info->mac_addr[2], pif_info->mac_addr[3],
|
||||
pif_info->mac_addr[4], pif_info->mac_addr[5]);
|
||||
|
||||
fprintf(stdout, "%s: %s\n", "State", pif_info->state);
|
||||
/*fprintf(stdout,"%s: %d\n" ,"PortchannelId", pif_info->po_id);
|
||||
fprintf(stdout,"%s: %d\n" ,"PortchannelIsActive", pif_info->po_active);*/
|
||||
|
||||
for (pos = 0; pos < 60; ++pos)
|
||||
fprintf(stdout, "-");
|
||||
|
||||
fprintf(stdout, "\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mclagdctl_enca_config_loglevel(char *msg, int log_level, int argc, char **argv)
|
||||
{
|
||||
struct mclagdctl_req_hdr req;
|
||||
|
||||
memset(&req, 0, sizeof(struct mclagdctl_req_hdr));
|
||||
req.info_type = INFO_TYPE_CONFIG_LOGLEVEL;
|
||||
req.mclag_id = log_level;
|
||||
memcpy((struct mclagdctl_req_hdr *)msg, &req, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mclagdctl_parse_config_loglevel(char *msg, int data_len)
|
||||
{
|
||||
|
||||
int ret = *(int*)msg;
|
||||
|
||||
if (ret == 0)
|
||||
fprintf(stdout, "%s\n", "Config loglevel success!");
|
||||
else
|
||||
fprintf(stdout, "%s\n", "Config loglevel failed!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __mclagdctl_cmd_executable(struct command_type *cmd_type)
|
||||
{
|
||||
if (!cmd_type->enca_msg || !cmd_type->parse_msg)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __mclagdctl_cmd_param_cnt(struct command_type *cmd_type)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (cmd_type->params[i])
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static struct command_type *__mclagdctl_get_cmd_by_parent(char *cmd_name,
|
||||
enum id_command_type parent_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < COMMAND_TYPE_COUNT; i++)
|
||||
{
|
||||
if (!strncmp(command_types[i].name, cmd_name, strlen(cmd_name))
|
||||
&& command_types[i].parent_id == parent_id)
|
||||
return &command_types[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct command_type *__mclagdctl_get_cmd_by_id(enum id_command_type id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < COMMAND_TYPE_COUNT; i++)
|
||||
{
|
||||
if (command_types[i].id == id)
|
||||
return &command_types[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mclagdctl_find_cmd(struct command_type **pcmd_type, int *argc, char ***argv)
|
||||
{
|
||||
char *cmd_name;
|
||||
enum id_command_type parent_id = ID_CMDTYPE_NONE;
|
||||
struct command_type *cmd_type;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!*argc)
|
||||
{
|
||||
fprintf(stderr, "None or incomplete command\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd_name = *argv[0];
|
||||
(*argc)--;
|
||||
(*argv)++;
|
||||
cmd_type = __mclagdctl_get_cmd_by_parent(cmd_name, parent_id);
|
||||
|
||||
if (!cmd_type)
|
||||
{
|
||||
fprintf(stderr, "Unknown command \"%s\".\n", cmd_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (__mclagdctl_cmd_executable(cmd_type) && __mclagdctl_cmd_param_cnt(cmd_type) >= *argc)
|
||||
{
|
||||
*pcmd_type = cmd_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parent_id = cmd_type->id;
|
||||
}
|
||||
}
|
||||
|
||||
static int mclagdctl_check_cmd_params(struct command_type *cmd_type,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (cmd_type->params[i])
|
||||
{
|
||||
if (i == argc)
|
||||
{
|
||||
fprintf(stderr, "Command line parameter \"%s\" expected.\n", cmd_type->params[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mclagdctl_print_cmd(struct command_type *cmd_type)
|
||||
{
|
||||
if (cmd_type->parent_id != ID_CMDTYPE_NONE)
|
||||
{
|
||||
mclagdctl_print_cmd(__mclagdctl_get_cmd_by_id(cmd_type->parent_id));
|
||||
fprintf(stdout, " ");
|
||||
}
|
||||
fprintf(stdout, "%s", cmd_type->name);
|
||||
}
|
||||
|
||||
static void mclagdctl_print_help(const char *argv0)
|
||||
{
|
||||
int i, j;
|
||||
struct command_type *cmd_type;
|
||||
|
||||
fprintf(stdout, "%s [options] command [command args]\n"
|
||||
" -h --help Show this help\n"
|
||||
" -i --mclag-id Specify one mclag id\n"
|
||||
" -l --level Specify log level critical,err,warn,notice,info,debug\n",
|
||||
argv0);
|
||||
fprintf(stdout, "Commands:\n");
|
||||
|
||||
for (i = 0; i < COMMAND_TYPE_COUNT; i++)
|
||||
{
|
||||
cmd_type = &command_types[i];
|
||||
if (!__mclagdctl_cmd_executable(cmd_type))
|
||||
continue;
|
||||
fprintf(stdout, " ");
|
||||
mclagdctl_print_cmd(cmd_type);
|
||||
|
||||
for (j = 0; cmd_type->params[j]; j++)
|
||||
fprintf(stdout, " %s", cmd_type->params[j]);
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[MCLAGDCTL_CMD_SIZE] = { 0 };
|
||||
char *argv0 = argv[0];
|
||||
char *rcv_buf = NULL;
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "mclag id", required_argument, NULL, 'i' },
|
||||
{ "log level", required_argument, NULL, 'l' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
int opt;
|
||||
int err;
|
||||
struct command_type *cmd_type;
|
||||
int ret;
|
||||
unsigned para_int = 0;
|
||||
|
||||
int len = 0;
|
||||
char *data;
|
||||
struct mclagd_reply_hdr *reply;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hi:l:", long_options, NULL)) >= 0)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'h':
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'i':
|
||||
para_int = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
switch (tolower(optarg[0]))
|
||||
{
|
||||
case 'c':
|
||||
para_int = CRITICAL;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
para_int = ERR;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
para_int = WARN;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
para_int = NOTICE;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
para_int = INFO;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
para_int = DEBUG;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unknown option \"%c\".\n", opt);
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
fprintf(stderr, "unknown option.\n");
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_FAILURE;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unknown option \"%c\".\n", opt);
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
err = mclagdctl_find_cmd(&cmd_type, &argc, &argv);
|
||||
if (err)
|
||||
{
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
err = mclagdctl_check_cmd_params(cmd_type, argc, argv);
|
||||
if (err)
|
||||
{
|
||||
mclagdctl_print_help(argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (mclagdctl_sock_fd <= 0)
|
||||
{
|
||||
ret = mclagdctl_sock_connect();
|
||||
if (ret < 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (cmd_type->enca_msg(buf, para_int, argc, argv) < 0)
|
||||
{
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
ret = mclagdctl_sock_write(mclagdctl_sock_fd, buf, sizeof(struct mclagdctl_req_hdr));
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to send command to mclagd\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
/*read data length*/
|
||||
memset(buf, 0, MCLAGDCTL_CMD_SIZE);
|
||||
ret = mclagdctl_sock_read(mclagdctl_sock_fd, buf, sizeof(int));
|
||||
if (ret <= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to read data length from mclagd\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
/*cont length*/
|
||||
len = *((int*)buf);
|
||||
if (len <= 0)
|
||||
{
|
||||
ret = EXIT_FAILURE;
|
||||
fprintf(stderr, "pkt len = %d, error\n", len);
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
rcv_buf = (char *)malloc(len);
|
||||
if (!rcv_buf)
|
||||
{
|
||||
fprintf(stderr, "Failed to malloc rcv_buf for mclagdctl\n");
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
/*read data*/
|
||||
ret = mclagdctl_sock_read(mclagdctl_sock_fd, rcv_buf, len);
|
||||
if (ret <= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to read data from mclagd\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
reply = (struct mclagd_reply_hdr *)rcv_buf;
|
||||
if (reply->info_type != cmd_type->info_type)
|
||||
{
|
||||
fprintf(stderr, "Reply info type from mclagd error\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
if (reply->exec_result == EXEC_TYPE_NO_EXIST_SYS)
|
||||
{
|
||||
fprintf(stderr, "No exist sys in iccpd!\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
if (reply->exec_result == EXEC_TYPE_NO_EXIST_MCLAGID)
|
||||
{
|
||||
fprintf(stderr, "Mclag-id %d hasn't been configured in iccpd!\n", para_int);
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
if (reply->exec_result == EXEC_TYPE_FAILED)
|
||||
{
|
||||
fprintf(stderr, "exec error in iccpd!\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto mclagdctl_disconnect;
|
||||
}
|
||||
|
||||
cmd_type->parse_msg((char *)(rcv_buf + sizeof(struct mclagd_reply_hdr)), len - sizeof(struct mclagd_reply_hdr));
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
mclagdctl_disconnect:
|
||||
mclagdctl_sock_close();
|
||||
|
||||
if (rcv_buf)
|
||||
free(rcv_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
198
src/iccpd/src/mclagdctl/mclagdctl.h
Normal file
198
src/iccpd/src/mclagdctl/mclagdctl.h
Normal file
@ -0,0 +1,198 @@
|
||||
/* Copyright(c) 2016-2019 Nephos.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: Jim Jiang from nephos
|
||||
*/
|
||||
|
||||
#define MCLAGDCTL_PARA1_LEN 16
|
||||
#define MCLAGDCTL_PARA2_LEN 32
|
||||
#define MCLAGDCTL_PARA3_LEN 64
|
||||
#define MCLAGDCTL_CMD_SIZE 4096
|
||||
|
||||
#define MCLAGDCTL_MAX_L_PORT_NANE 32
|
||||
#define MCLAGDCTL_INET_ADDR_LEN 32
|
||||
#define MCLAGDCTL_ETHER_ADDR_LEN 6
|
||||
#define MCLAGDCTL_PORT_MEMBER_BUF_LEN 512
|
||||
#define ETHER_ADDR_STR_LEN 18
|
||||
|
||||
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);
|
||||
|
||||
enum MAC_TYPE_CTL
|
||||
{
|
||||
MAC_TYPE_STATIC_CTL = 1,
|
||||
MAC_TYPE_DYNAMIC_CTL = 2,
|
||||
};
|
||||
|
||||
enum MAC_AGE_TYPE_CTL
|
||||
{
|
||||
MAC_AGE_LOCAL_CTL = 1, /*MAC in local switch is ageout*/
|
||||
MAC_AGE_PEER_CTL = 2 /*MAC in peer switch is ageout*/
|
||||
};
|
||||
|
||||
enum id_command_type
|
||||
{
|
||||
ID_CMDTYPE_NONE = 0,
|
||||
ID_CMDTYPE_D,
|
||||
ID_CMDTYPE_D_S,
|
||||
ID_CMDTYPE_D_A,
|
||||
ID_CMDTYPE_D_P,
|
||||
ID_CMDTYPE_D_P_L,
|
||||
ID_CMDTYPE_D_P_P,
|
||||
ID_CMDTYPE_C,
|
||||
ID_CMDTYPE_C_L,
|
||||
};
|
||||
|
||||
enum mclagdctl_notify_peer_type
|
||||
{
|
||||
INFO_TYPE_NONE = 0,
|
||||
INFO_TYPE_DUMP_STATE,
|
||||
INFO_TYPE_DUMP_ARP,
|
||||
INFO_TYPE_DUMP_MAC,
|
||||
INFO_TYPE_DUMP_LOCAL_PORTLIST,
|
||||
INFO_TYPE_DUMP_PEER_PORTLIST,
|
||||
INFO_TYPE_CONFIG_LOGLEVEL,
|
||||
INFO_TYPE_FINISH,
|
||||
};
|
||||
|
||||
enum log_level_type
|
||||
{
|
||||
CRITICAL = 0,
|
||||
ERR= 1,
|
||||
WARN = 2,
|
||||
NOTICE= 3,
|
||||
INFO = 4,
|
||||
DEBUG = 5
|
||||
};
|
||||
|
||||
struct mclagdctl_req_hdr
|
||||
{
|
||||
int info_type;
|
||||
int mclag_id;
|
||||
char para1[MCLAGDCTL_PARA2_LEN];
|
||||
char para2[MCLAGDCTL_PARA2_LEN];
|
||||
char para3[MCLAGDCTL_PARA2_LEN];
|
||||
};
|
||||
|
||||
struct mclagd_reply_hdr
|
||||
{
|
||||
int info_type;
|
||||
int data_len;
|
||||
int exec_result;
|
||||
};
|
||||
|
||||
#define EXEC_TYPE_SUCCESS -1
|
||||
#define EXEC_TYPE_NO_EXIST_SYS -2
|
||||
#define EXEC_TYPE_NO_EXIST_MCLAGID -3
|
||||
#define EXEC_TYPE_FAILED -4
|
||||
|
||||
#define MCLAG_ERROR -1
|
||||
|
||||
#define MCLAGD_REPLY_INFO_HDR (sizeof(struct mclagd_reply_hdr) + sizeof(int))
|
||||
|
||||
#define MCLAGDCTL_COMMAND_PARAM_MAX_CNT 8
|
||||
struct command_type
|
||||
{
|
||||
enum id_command_type id;
|
||||
enum id_command_type parent_id;
|
||||
enum mclagdctl_notify_peer_type info_type;
|
||||
char *name;
|
||||
char *params[MCLAGDCTL_COMMAND_PARAM_MAX_CNT];
|
||||
call_enca_msg_fun enca_msg;
|
||||
call_parse_msg_fun parse_msg;
|
||||
};
|
||||
|
||||
struct mclagd_state
|
||||
{
|
||||
int mclag_id;
|
||||
int keepalive;
|
||||
char local_ip[MCLAGDCTL_INET_ADDR_LEN];
|
||||
char peer_ip[MCLAGDCTL_INET_ADDR_LEN];
|
||||
char peer_link_if[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
unsigned char peer_link_mac[MCLAGDCTL_ETHER_ADDR_LEN];
|
||||
int role;
|
||||
char enabled_po[MCLAGDCTL_PORT_MEMBER_BUF_LEN];
|
||||
char loglevel[MCLAGDCTL_PARA1_LEN];
|
||||
};
|
||||
|
||||
struct mclagd_arp_msg
|
||||
{
|
||||
char op_type;
|
||||
char ifname[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
char ipv4_addr[MCLAGDCTL_INET_ADDR_LEN];
|
||||
unsigned char mac_addr[MCLAGDCTL_ETHER_ADDR_LEN];
|
||||
};
|
||||
|
||||
struct mclagd_mac_msg
|
||||
{
|
||||
unsigned char op_type;/*add or del*/
|
||||
unsigned char fdb_type;/*static or dynamic*/
|
||||
char mac_str[ETHER_ADDR_STR_LEN];
|
||||
unsigned short vid;
|
||||
/*Current if name that set in chip*/
|
||||
char ifname[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
/*if we set the mac to peer-link, origin_ifname store the
|
||||
original if name that learned from chip*/
|
||||
char origin_ifname[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
unsigned char age_flag;/*local or peer is age?*/
|
||||
};
|
||||
|
||||
struct mclagd_local_if
|
||||
{
|
||||
int ifindex;
|
||||
char type[MCLAGDCTL_PARA1_LEN];
|
||||
char name[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
unsigned char mac_addr[MCLAGDCTL_ETHER_ADDR_LEN];
|
||||
char state[MCLAGDCTL_PARA1_LEN];
|
||||
char ipv4_addr[MCLAGDCTL_INET_ADDR_LEN];
|
||||
unsigned char prefixlen;
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
struct mclagd_peer_if
|
||||
{
|
||||
int ifindex;
|
||||
unsigned char type[MCLAGDCTL_PARA1_LEN];
|
||||
char name[MCLAGDCTL_MAX_L_PORT_NANE];
|
||||
unsigned char mac_addr[MCLAGDCTL_ETHER_ADDR_LEN];
|
||||
unsigned char state[MCLAGDCTL_PARA1_LEN];
|
||||
int po_id;
|
||||
unsigned char po_active;
|
||||
};
|
||||
|
||||
extern int mclagdctl_enca_dump_state(char *msg, int mclag_id, int argc, char **argv);
|
||||
extern int mclagdctl_parse_dump_state(char *msg, int data_len);
|
||||
extern int mclagdctl_enca_dump_arp(char *msg, int mclag_id, int argc, char **argv);
|
||||
extern int mclagdctl_parse_dump_arp(char *msg, int data_len);
|
||||
extern int mclagdctl_enca_dump_mac(char *msg, int mclag_id, int argc, char **argv);
|
||||
extern int mclagdctl_parse_dump_mac(char *msg, int data_len);
|
||||
extern int mclagdctl_enca_dump_local_portlist(char *msg, int mclag_id, int argc, char **argv);
|
||||
extern int mclagdctl_parse_dump_local_portlist(char *msg, int data_len);
|
||||
extern int mclagdctl_enca_dump_peer_portlist(char *msg, int mclag_id, int argc, char **argv);
|
||||
extern int mclagdctl_parse_dump_peer_portlist(char *msg, int data_len);
|
||||
int mclagdctl_enca_config_loglevel(char *msg, int log_level, int argc, char **argv);
|
||||
int mclagdctl_parse_config_loglevel(char *msg, int data_len);
|
||||
|
1209
src/iccpd/src/mlacp_fsm.c
Normal file
1209
src/iccpd/src/mlacp_fsm.c
Normal file
File diff suppressed because it is too large
Load Diff
2401
src/iccpd/src/mlacp_link_handler.c
Normal file
2401
src/iccpd/src/mlacp_link_handler.c
Normal file
File diff suppressed because it is too large
Load Diff
624
src/iccpd/src/mlacp_sync_prepare.c
Normal file
624
src/iccpd/src/mlacp_sync_prepare.c
Normal file
@ -0,0 +1,624 @@
|
||||
/*
|
||||
* MLACP Sync Infomation Preparation
|
||||
* mlacp_sync_prepare.c
|
||||
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "../include/system.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/mlacp_fsm.h"
|
||||
#include "../include/mlacp_tlv.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
#include "../include/iccp_ifm.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
|
||||
/*****************************************
|
||||
* Static Function
|
||||
*
|
||||
* ***************************************/
|
||||
static int mlacp_fill_icc_header(struct CSM* csm, ICCHdr* icc_hdr, size_t msg_len);
|
||||
|
||||
/*****************************************
|
||||
* Create Sync Request TLV
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_sync_request_tlv(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
mLACPSyncReqTLV* tlv = NULL;
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(mLACPSyncReqTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (mLACPSyncReqTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* mLACP Synchronization Request TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_SYNC_REQUEST);
|
||||
tlv->icc_parameter.len = htons(sizeof(mLACPSyncReqTLV) - sizeof(ICCParameter));
|
||||
|
||||
tlv->req_num = 0;
|
||||
MLACP(csm).sync_req_num = 0;
|
||||
|
||||
tlv->c_bit = 1;
|
||||
tlv->s_bit = 1;
|
||||
tlv->req_type = 0x3FFF;
|
||||
*(uint16_t *)((uint8_t *)tlv + sizeof(ICCParameter) + sizeof(uint16_t)) = htons(*(uint16_t *)((uint8_t *)tlv + sizeof(ICCParameter) + sizeof(uint16_t)));
|
||||
|
||||
tlv->port_num_agg_id = 0;
|
||||
tlv->actor_key = 0;
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prprare Sync Data TLV
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_sync_data_tlv(struct CSM* csm, char* buf, size_t max_buf_size, int end)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
mLACPSyncDataTLV* tlv = (mLACPSyncDataTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(mLACPSyncDataTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (mLACPSyncDataTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* mLACP Synchronization Data TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_SYNC_DATA);
|
||||
tlv->icc_parameter.len = htons(sizeof(mLACPSyncDataTLV) - sizeof(ICCParameter));
|
||||
|
||||
tlv->req_num = htons(MLACP(csm).sync_req_num);
|
||||
if (end == 0)
|
||||
tlv->flags = 0x00;
|
||||
else
|
||||
tlv->flags = htons(0x01);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prprare Sync System-Config TLV
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_sys_config(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
mLACPSysConfigTLV* tlv = (mLACPSysConfigTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(mLACPSysConfigTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (mLACPSysConfigTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* System Config TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_SYSTEM_CONFIG);
|
||||
tlv->icc_parameter.len = htons(sizeof(mLACPSysConfigTLV) - sizeof(ICCParameter));
|
||||
|
||||
memcpy(tlv->sys_id, MLACP(csm).system_id, ETHER_ADDR_LEN);
|
||||
tlv->sys_priority = htons(MLACP(csm).system_priority);
|
||||
tlv->node_id = MLACP(csm).node_id;
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*Prprare Sync AggPort-State TLV */
|
||||
int mlacp_prepare_for_Aggport_state(struct CSM* csm, char* buf, size_t max_buf_size, struct LocalInterface* local_if)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
mLACPAggPortStateTLV* tlv = (mLACPAggPortStateTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(mLACPAggPortStateTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (local_if == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (local_if->type != IF_T_PORT_CHANNEL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (mLACPAggPortStateTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* Port State TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_AGGREGATOR_STATE);
|
||||
tlv->icc_parameter.len = htons(sizeof(mLACPAggPortStateTLV) - sizeof(ICCParameter));
|
||||
|
||||
tlv->partner_sys_priority = 0;
|
||||
tlv->partner_key = 0;
|
||||
tlv->agg_id = htons(local_if->po_id);
|
||||
tlv->actor_key = 0;
|
||||
tlv->agg_state = local_if->state;
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prprare Sync Purge Port
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_Aggport_config(struct CSM* csm,
|
||||
char* buf, size_t max_buf_size,
|
||||
struct LocalInterface* lif, int purge_flag)
|
||||
{
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
mLACPAggConfigTLV* tlv = (mLACPAggConfigTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(mLACPAggConfigTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (mLACPAggConfigTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* Port Config TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_AGGREGATOR_CONFIG);
|
||||
|
||||
tlv->icc_parameter.len = htons(sizeof(mLACPAggConfigTLV) - sizeof(ICCParameter));
|
||||
tlv->agg_id = htons(lif->po_id);
|
||||
if (purge_flag == 1)
|
||||
tlv->flags = 0x02; /*purge*/
|
||||
else
|
||||
tlv->flags = 0x1;
|
||||
tlv->agg_name_len = strlen(lif->name);
|
||||
memcpy(tlv->agg_name, lif->name, MAX_L_PORT_NAME);
|
||||
memcpy(tlv->mac_addr, lif->mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Preprare Sync MAC-Info TLV
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_mac_info_to_peer(struct CSM* csm, char* buf, size_t max_buf_size, struct MACMsg* mac_msg, int count)
|
||||
{
|
||||
struct mLACPMACInfoTLV* tlv = NULL;
|
||||
size_t msg_len = 0;
|
||||
size_t tlv_len = 0;
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
struct mLACPMACData *MacData;
|
||||
|
||||
if (!csm)
|
||||
return MCLAG_ERROR;
|
||||
if (!buf)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
tlv_len = sizeof(struct mLACPMACInfoTLV) + sizeof(struct mLACPMACData) * (count + 1);
|
||||
|
||||
if ((msg_len = sizeof(ICCHdr) + tlv_len) > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
/* Prepare for MAC information TLV */
|
||||
tlv = (struct mLACPMACInfoTLV*)&buf[sizeof(ICCHdr)];
|
||||
tlv->icc_parameter.len = htons(tlv_len - sizeof(ICCParameter));
|
||||
tlv->num_of_entry = htons(count + 1);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_MAC_INFO);
|
||||
}
|
||||
|
||||
MacData = (struct mLACPMACData *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPMACInfoTLV) + sizeof(struct mLACPMACData) * count];
|
||||
MacData->type = mac_msg->op_type;
|
||||
sprintf(MacData->mac_str, "%s", mac_msg->mac_str);
|
||||
sprintf(MacData->ifname, "%s", mac_msg->origin_ifname);
|
||||
MacData->vid = htons(mac_msg->vid);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Send MAC messge to peer, port %s mac = %s, vid = %d, type = %s count %d ", mac_msg->origin_ifname,
|
||||
mac_msg->mac_str, mac_msg->vid, mac_msg->op_type == MAC_SYNC_ADD ? "add" : "del", count);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Preprare Sync ARP-Info TLV
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_arp_info(struct CSM* csm, char* buf, size_t max_buf_size, struct ARPMsg* arp_msg, int count)
|
||||
{
|
||||
struct mLACPARPInfoTLV* tlv = NULL;
|
||||
size_t msg_len = 0;
|
||||
size_t tlv_len = 0;
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
struct ARPMsg* ArpData;
|
||||
|
||||
if (!csm)
|
||||
return MCLAG_ERROR;
|
||||
if (!buf)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
tlv_len = sizeof(struct mLACPARPInfoTLV) + sizeof(struct ARPMsg) * (count + 1);
|
||||
|
||||
if ((msg_len = sizeof(ICCHdr) + tlv_len) > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* Prepare for ARP information TLV */
|
||||
tlv = (struct mLACPARPInfoTLV*)&buf[sizeof(ICCHdr)];
|
||||
tlv->icc_parameter.len = htons(tlv_len - sizeof(ICCParameter));
|
||||
tlv->num_of_entry = htons(count + 1);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_ARP_INFO);
|
||||
}
|
||||
|
||||
ArpData = (struct mLACPMACData *)&buf[sizeof(ICCHdr) + sizeof(struct mLACPARPInfoTLV) + sizeof(struct ARPMsg) * count];
|
||||
|
||||
ArpData->op_type = arp_msg->op_type;
|
||||
sprintf(ArpData->ifname, "%s", arp_msg->ifname);
|
||||
ArpData->ipv4_addr = htonl(arp_msg->ipv4_addr);
|
||||
memcpy(ArpData->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Send ARP messge to peer, if name %s mac %02x:%02x:%02x:%02x:%02x:%02x IP %s", ArpData->ifname, ArpData->mac_addr[0], ArpData->mac_addr[1], ArpData->mac_addr[2],
|
||||
ArpData->mac_addr[3], ArpData->mac_addr[4], ArpData->mac_addr[5], show_ip_str( ArpData->ipv4_addr));
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prprare Send portchannel info
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_port_channel_info(struct CSM* csm, char* buf,
|
||||
size_t max_buf_size,
|
||||
struct LocalInterface* port_channel)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
struct mLACPPortChannelInfoTLV* tlv = NULL;
|
||||
size_t msg_len;
|
||||
size_t tlv_len;
|
||||
size_t name_len = MAX_L_PORT_NAME;
|
||||
struct VLAN_ID* vlan_id = NULL;
|
||||
int num_of_vlan_id = 0;
|
||||
|
||||
if (csm == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if (buf == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if (port_channel == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if (port_channel->type == IF_T_PORT)
|
||||
return MCLAG_ERROR;
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
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++;
|
||||
|
||||
tlv_len = sizeof(struct mLACPPortChannelInfoTLV) + sizeof(struct mLACPVLANData) * num_of_vlan_id;
|
||||
|
||||
if ((msg_len = sizeof(ICCHdr) + tlv_len) > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for port channel info */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (struct mLACPPortChannelInfoTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* Port Channel Info TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_PORT_CHANNEL_INFO);
|
||||
tlv->icc_parameter.len = htons(sizeof(struct mLACPPortChannelInfoTLV) - sizeof(ICCParameter) + sizeof(struct mLACPVLANData) * num_of_vlan_id);
|
||||
tlv->agg_id = htons(port_channel->po_id);
|
||||
tlv->ipv4_addr = htonl(port_channel->ipv4_addr);
|
||||
tlv->l3_mode = port_channel->l3_mode;
|
||||
tlv->po_id = htons(port_channel->po_id);
|
||||
|
||||
if (strlen(port_channel->name) < name_len)
|
||||
name_len = strlen(port_channel->name);
|
||||
memcpy(tlv->if_name, port_channel->name, name_len);
|
||||
tlv->if_name_len = name_len;
|
||||
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)
|
||||
{
|
||||
if (vlan_id != NULL )
|
||||
{
|
||||
tlv->vlanData[num_of_vlan_id].vlan_id = htons(vlan_id->vid);
|
||||
|
||||
num_of_vlan_id++;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "PortChannel%d: ipv4 addr = %s vlan id %d num %d ", port_channel->po_id, show_ip_str( tlv->ipv4_addr), vlan_id->vid, num_of_vlan_id );
|
||||
}
|
||||
}
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "PortChannel%d: ipv4 addr = %s l3 mode %d", port_channel->po_id, show_ip_str( tlv->ipv4_addr), tlv->l3_mode);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prprare Send port peerlink info
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_port_peerlink_info(struct CSM* csm, char* buf,
|
||||
size_t max_buf_size,
|
||||
struct LocalInterface* peerlink_port)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = NULL;
|
||||
struct mLACPPeerLinkInfoTLV* tlv = NULL;
|
||||
size_t msg_len;
|
||||
size_t tlv_len;
|
||||
|
||||
if (csm == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if (buf == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if (peerlink_port == NULL )
|
||||
return MCLAG_ERROR;
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for port channel info */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
tlv_len = sizeof(struct mLACPPeerLinkInfoTLV);
|
||||
|
||||
if ((msg_len = sizeof(ICCHdr) + tlv_len) > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (struct mLACPPeerLinkInfoTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* Port Channel Info TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_PEERLINK_INFO);
|
||||
|
||||
tlv->icc_parameter.len = htons(tlv_len - sizeof(ICCParameter));
|
||||
memcpy(tlv->if_name, peerlink_port->name, MAX_L_PORT_NAME);
|
||||
tlv->port_type = peerlink_port->type;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port is %s, type = %d", tlv->if_name, tlv->port_type);
|
||||
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Prprare Send Heartbeat
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_heartbeat(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
struct mLACPHeartbeatTLV* tlv = (struct mLACPHeartbeatTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(struct mLACPHeartbeatTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (struct mLACPHeartbeatTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* System Config TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_HEARTBEAT);
|
||||
|
||||
tlv->icc_parameter.len = htons(sizeof(struct mLACPHeartbeatTLV) - sizeof(ICCParameter));
|
||||
tlv->heartbeat = 0xFF;
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Prepare Send warm-reboot flag
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_prepare_for_warm_reboot(struct CSM* csm, char* buf, size_t max_buf_size)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
ICCHdr* icc_hdr = (ICCHdr*)buf;
|
||||
struct mLACPWarmbootTLV* tlv = (struct mLACPWarmbootTLV*)&buf[sizeof(ICCHdr)];
|
||||
size_t msg_len = sizeof(ICCHdr) + sizeof(struct mLACPWarmbootTLV);
|
||||
|
||||
if (csm == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (buf == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (msg_len > max_buf_size)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* Prepare for sync request */
|
||||
memset(buf, 0, max_buf_size);
|
||||
|
||||
icc_hdr = (ICCHdr*)buf;
|
||||
tlv = (struct mLACPWarmbootTLV*)&buf[sizeof(ICCHdr)];
|
||||
|
||||
/* ICC header */
|
||||
mlacp_fill_icc_header(csm, icc_hdr, msg_len);
|
||||
|
||||
/* System Config TLV */
|
||||
tlv->icc_parameter.u_bit = 0;
|
||||
tlv->icc_parameter.f_bit = 0;
|
||||
tlv->icc_parameter.type = htons(TLV_T_MLACP_WARMBOOT_FLAG);
|
||||
|
||||
tlv->icc_parameter.len = htons(sizeof(struct mLACPWarmbootTLV) - sizeof(ICCParameter));
|
||||
tlv->warmboot = 0x1;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Send warm reboot notification to peer!");
|
||||
return msg_len;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Tool : Prepare ICC Header
|
||||
*
|
||||
* ***************************************/
|
||||
static int mlacp_fill_icc_header(struct CSM* csm, ICCHdr* icc_hdr, size_t msg_len)
|
||||
{
|
||||
if (csm == NULL || icc_hdr == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
/* ICC header */
|
||||
icc_hdr->ldp_hdr.u_bit = 0x0;
|
||||
icc_hdr->ldp_hdr.msg_type = htons(MSG_T_RG_APP_DATA);
|
||||
|
||||
icc_hdr->ldp_hdr.msg_len = htons(msg_len - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
icc_hdr->ldp_hdr.msg_id = htonl(ICCP_MSG_ID);
|
||||
ICCP_MSG_ID++;
|
||||
iccp_csm_fill_icc_rg_id_tlv(csm, icc_hdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
740
src/iccpd/src/mlacp_sync_update.c
Normal file
740
src/iccpd/src/mlacp_sync_update.c
Normal file
@ -0,0 +1,740 @@
|
||||
/********************************************************************************
|
||||
* mlacp_sync_update.c
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*
|
||||
*******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include "../include/system.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/mlacp_tlv.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
#include "../include/iccp_consistency_check.h"
|
||||
#include "../include/port.h"
|
||||
/*****************************************
|
||||
* Port-Conf Update
|
||||
*
|
||||
* ***************************************/
|
||||
extern void update_if_ipmac_on_standby(struct LocalInterface* lif_po);
|
||||
int mlacp_fsm_update_system_conf(struct CSM* csm, mLACPSysConfigTLV*sysconf)
|
||||
{
|
||||
struct LocalInterface* lif = NULL;
|
||||
|
||||
/*NOTE
|
||||
a little tricky, we change the NodeID local side if collision happened first time*/
|
||||
if (sysconf->node_id == MLACP(csm).node_id)
|
||||
MLACP(csm).node_id++;
|
||||
|
||||
memcpy(MLACP(csm).remote_system.system_id, sysconf->sys_id, ETHER_ADDR_LEN);
|
||||
MLACP(csm).remote_system.system_priority = ntohs(sysconf->sys_priority);
|
||||
MLACP(csm).remote_system.node_id = sysconf->node_id;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "SystemID [%02X:%02X:%02X:%02X:%02X:%02X], SystemPriority [%d], Remote NodeID [%d], NodeID [%d]",
|
||||
MLACP(csm).remote_system.system_id[0], MLACP(csm).remote_system.system_id[1], MLACP(csm).remote_system.system_id[2],
|
||||
MLACP(csm).remote_system.system_id[3], MLACP(csm).remote_system.system_id[4], MLACP(csm).remote_system.system_id[5],
|
||||
MLACP(csm).remote_system.system_priority,
|
||||
MLACP(csm).remote_system.node_id,
|
||||
MLACP(csm).node_id);
|
||||
|
||||
LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
update_if_ipmac_on_standby(lif);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Port-Conf Update
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_Agg_conf(struct CSM* csm, mLACPAggConfigTLV* portconf)
|
||||
{
|
||||
struct PeerInterface* pif = NULL;
|
||||
uint8_t po_active;
|
||||
uint8_t new_create = 0;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Port name %s, po id %d flag %d MAC[%02x:%02x:%02x:%02x:%02x:%02x] ",
|
||||
portconf->agg_name, ntohs(portconf->agg_id), portconf->flags, portconf->mac_addr[0], portconf->mac_addr[1], portconf->mac_addr[2],
|
||||
portconf->mac_addr[3], portconf->mac_addr[4], portconf->mac_addr[5] );
|
||||
|
||||
/* Looking for the peer port instance, is any peer if exist?*/
|
||||
pif = peer_if_find_by_name(csm, portconf->agg_name);
|
||||
|
||||
/* Process purge*/
|
||||
if (portconf->flags & 0x02)
|
||||
{
|
||||
/*Purge*/
|
||||
if (pif != NULL )
|
||||
peer_if_destroy(pif);
|
||||
else
|
||||
MLACP(csm).need_to_sync = 1;
|
||||
/*ICCPD_LOG_INFO("mlacp_fsm",
|
||||
" Peer port %s is removed from port-channel member.",portconf->port_name);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pif == NULL && portconf->flags & 0x01)
|
||||
{
|
||||
pif = peer_if_create(csm, ntohs(portconf->agg_id), IF_T_PORT_CHANNEL);
|
||||
if (pif == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
new_create = 1;
|
||||
}
|
||||
|
||||
pif->po_id = ntohs(portconf->agg_id);
|
||||
memcpy(pif->name, portconf->agg_name, portconf->agg_name_len);
|
||||
memcpy(pif->mac_addr, portconf->mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
po_active = (pif->state == PORT_STATE_UP);
|
||||
update_stp_peer_link(csm, pif, po_active, new_create);
|
||||
update_peerlink_isolate_from_pif(csm, pif, po_active, new_create);
|
||||
pif->po_active = po_active;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Agg Port-State Update
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_Aggport_state(struct CSM* csm, mLACPAggPortStateTLV* tlv)
|
||||
{
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
uint8_t po_active;
|
||||
|
||||
if (csm == NULL || tlv == NULL)
|
||||
return MCLAG_ERROR;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Portchannel id %d state %d", ntohs(tlv->agg_id), tlv->agg_state);
|
||||
|
||||
po_active = (tlv->agg_state == PORT_STATE_UP);
|
||||
|
||||
LIST_FOREACH(peer_if, &(MLACP(csm).pif_list), mlacp_next)
|
||||
{
|
||||
if (peer_if->type != IF_T_PORT_CHANNEL)
|
||||
continue;
|
||||
|
||||
if (peer_if->po_id != ntohs(tlv->agg_id))
|
||||
continue;
|
||||
|
||||
peer_if->state = tlv->agg_state;
|
||||
|
||||
update_stp_peer_link(csm, peer_if, po_active, 0);
|
||||
update_peerlink_isolate_from_pif(csm, peer_if, po_active, 0);
|
||||
|
||||
peer_if->po_active = po_active;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Update peer interface %s to state %s", peer_if->name, tlv->agg_state ? "down" : "up");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Recv from peer, MAC-Info Update
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData *MacData)
|
||||
{
|
||||
|
||||
struct Msg* msg = NULL;
|
||||
struct MACMsg *mac_msg = NULL, mac_data;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__,
|
||||
"Received MAC Info, port[%s] vid[%d] MAC[%s] type[%s]",
|
||||
MacData->ifname, ntohs(MacData->vid), MacData->mac_str, MacData->type == MAC_SYNC_ADD ? "add" : "del");
|
||||
|
||||
/*Find the interface in MCLAG interface list*/
|
||||
LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (local_if->type == IF_T_PORT_CHANNEL && strcmp(local_if->name, MacData->ifname) == 0)
|
||||
{
|
||||
from_mclag_intf = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* update MAC list*/
|
||||
TAILQ_FOREACH(msg, &(MLACP(csm).mac_list), tail)
|
||||
{
|
||||
mac_msg = (struct MACMsg*)msg->buf;
|
||||
|
||||
/*Same MAC is exist in local switch, this may be mac move*/
|
||||
if (strcmp(mac_msg->mac_str, MacData->mac_str) == 0 && mac_msg->vid == ntohs(MacData->vid))
|
||||
{
|
||||
if (MacData->type == MAC_SYNC_ADD)
|
||||
{
|
||||
mac_msg->age_flag &= ~MAC_AGE_PEER;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ADD, Remove peer age flag:%d ifname %s, MAC %s vlan-id %d",
|
||||
mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid);
|
||||
|
||||
/*mac_msg->fdb_type = tlv->fdb_type;*/
|
||||
/*The port ifname is different to the local item*/
|
||||
if (from_mclag_intf == 0 || strcmp(mac_msg->ifname, MacData->ifname) != 0 || strcmp(mac_msg->origin_ifname, MacData->ifname) != 0)
|
||||
{
|
||||
if (mac_msg->fdb_type != MAC_TYPE_STATIC)
|
||||
{
|
||||
/*Update local item*/
|
||||
memcpy(&mac_msg->origin_ifname, MacData->ifname, MAX_L_PORT_NAME);
|
||||
}
|
||||
|
||||
/*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/
|
||||
if (from_mclag_intf == 0 || (local_if->state == PORT_STATE_DOWN && strcmp(mac_msg->ifname, csm->peer_itf_name) != 0))
|
||||
{
|
||||
/*Set MAC_AGE_LOCAL flag*/
|
||||
mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1);
|
||||
|
||||
if (strlen(csm->peer_itf_name) != 0)
|
||||
{
|
||||
if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0)
|
||||
{
|
||||
/* This MAC is already point to peer-link */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP)
|
||||
{
|
||||
/*Redirect the mac to peer-link*/
|
||||
memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ);
|
||||
|
||||
/*Send mac add message to mclagsyncd*/
|
||||
add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*must redirect but peerlink is down, del mac from ASIC*/
|
||||
/*if peerlink change to up, mac will add back to ASIC*/
|
||||
del_mac_from_chip(mac_msg);
|
||||
|
||||
/*Redirect the mac to peer-link*/
|
||||
memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*must redirect but no peerlink, del mac from ASIC*/
|
||||
del_mac_from_chip(mac_msg);
|
||||
|
||||
/*Update local item*/
|
||||
memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME);
|
||||
|
||||
/*if orphan port mac but no peerlink, don't keep this mac*/
|
||||
if (from_mclag_intf == 0)
|
||||
{
|
||||
TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail);
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*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);
|
||||
|
||||
/*from MCLAG port and the local port is up, add mac to ASIC to update port*/
|
||||
add_mac_to_chip(mac_msg, MAC_TYPE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
mac_msg->op_type = MAC_SYNC_ACK;
|
||||
if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
|
||||
{
|
||||
/*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail);
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ADD, MAC-msg-list enqueue: %s, add %s vlan-id %d, op_type %d",
|
||||
mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->op_type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
else if (tlv->type == MAC_SYNC_ACK)
|
||||
{
|
||||
/*Clean the MAC_AGE_PEER flag*/
|
||||
mac_msg->age_flag &= ~MAC_AGE_PEER;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ACK, Remove peer age flag:%d ifname %s, add %s vlan-id %d, op_type %d",
|
||||
mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->op_type);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete/add MAC list*/
|
||||
if (msg && MacData->type == MAC_SYNC_DEL)
|
||||
{
|
||||
mac_msg->age_flag |= MAC_AGE_PEER;
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Recv DEL, Add peer age flag: %d ifname %s, MAC %s vlan-id %d",
|
||||
mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid);
|
||||
|
||||
if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER))
|
||||
{
|
||||
/*send mac del message to mclagsyncd.*/
|
||||
del_mac_from_chip(mac_msg);
|
||||
|
||||
/*If local and peer both aged, del the mac*/
|
||||
TAILQ_REMOVE(&(MLACP(csm).mac_list), msg, tail);
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (!msg && MacData->type == MAC_SYNC_ADD)
|
||||
{
|
||||
mac_msg = (struct MACMsg*)&mac_data;
|
||||
mac_msg->fdb_type = MAC_TYPE_DYNAMIC;
|
||||
mac_msg->vid = ntohs(MacData->vid);
|
||||
sprintf(mac_msg->mac_str, "%s", MacData->mac_str);
|
||||
sprintf(mac_msg->ifname, "%s", MacData->ifname);
|
||||
sprintf(mac_msg->origin_ifname, "%s", MacData->ifname);
|
||||
mac_msg->age_flag = 0;
|
||||
|
||||
/*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/
|
||||
if (from_mclag_intf == 0 || local_if->state == PORT_STATE_DOWN)
|
||||
{
|
||||
/*Set MAC_AGE_LOCAL flag*/
|
||||
mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1);
|
||||
|
||||
if (strlen(csm->peer_itf_name) == 0)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "From orphan port or portchannel is down, but peer-link is not configured: ifname %s, MAC %s vlan-id %d",
|
||||
mac_msg->ifname, mac_msg->mac_str, mac_msg->vid);
|
||||
|
||||
/*if orphan port mac but no peerlink, don't keep this mac*/
|
||||
if (from_mclag_intf == 0)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Redirect the mac to peer-link*/
|
||||
memcpy(&mac_msg->ifname, csm->peer_itf_name, IFNAMSIZ);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Redirect to peerlink for orphan port or portchannel is down, Add local age flag: %d ifname %s, MAC %s vlan-id %d",
|
||||
mac_msg->age_flag, mac_msg->ifname, mac_msg->mac_str, mac_msg->vid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Remove MAC_AGE_LOCAL flag*/
|
||||
mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 0);
|
||||
}
|
||||
|
||||
if (iccp_csm_init_msg(&msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).mac_list), msg, tail);
|
||||
/*ICCPD_LOG_INFO(__FUNCTION__, "add mac queue successfully");*/
|
||||
|
||||
/*If the mac is from orphan port, or from MCLAG port but the local port is down*/
|
||||
if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0)
|
||||
{
|
||||
/*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);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*from MCLAG port and the local port is up*/
|
||||
add_mac_to_chip(mac_msg, mac_msg->fdb_type);
|
||||
}
|
||||
|
||||
#if 0
|
||||
mac_msg->op_type = MAC_SYNC_ACK;
|
||||
if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
|
||||
{
|
||||
/*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail);
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, op_type %d",
|
||||
mac_msg->ifname, mac_msg->mac_str, mac_msg->vid, mac_msg->op_type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlacp_fsm_update_mac_info_from_peer(struct CSM* csm, struct mLACPMACInfoTLV* tlv)
|
||||
{
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
if (!csm || !tlv)
|
||||
return MCLAG_ERROR;
|
||||
count = ntohs(tlv->num_of_entry);
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Received MAC Info count %d", count );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
mlacp_fsm_update_mac_entry_from_peer(csm, &(tlv->MacEntry[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Tool : Add ARP Info into ARP list
|
||||
*
|
||||
****************************************/
|
||||
void mlacp_enqueue_arp(struct CSM* csm, struct Msg* msg)
|
||||
{
|
||||
struct ARPMsg *arp_msg = NULL;
|
||||
|
||||
if (!csm)
|
||||
{
|
||||
if (msg)
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
if (arp_msg->op_type != ARP_SYNC_DEL)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_list), msg, tail);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* ARP-Info Update
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry)
|
||||
{
|
||||
struct Msg* msg = NULL;
|
||||
struct ARPMsg *arp_msg = NULL, arp_data;
|
||||
struct LocalInterface* local_if;
|
||||
struct LocalInterface *peer_link_if = NULL;
|
||||
struct VLAN_ID *vlan_id_list = NULL;
|
||||
int set_arp_flag = 0;
|
||||
char mac_str[18] = "";
|
||||
|
||||
if (!csm || !arp_entry)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2],
|
||||
arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]);
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__,
|
||||
"Received ARP Info, intf[%s] IP[%s], MAC[%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr),
|
||||
arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2],
|
||||
arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]);
|
||||
|
||||
if (strncmp(arp_entry->ifname, "Vlan", 4) == 0)
|
||||
{
|
||||
peer_link_if = local_if_find_by_name(csm->peer_itf_name);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!vlan_id_list->vlan_itf)
|
||||
continue;
|
||||
if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) != 0)
|
||||
continue;
|
||||
if (!local_if_is_l3_mode(vlan_id_list->vlan_itf))
|
||||
continue;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from intf %s, peer-link %s is the member of this vlan",
|
||||
vlan_id_list->vlan_itf->name, peer_link_if->name);
|
||||
|
||||
/* Peer-link belong to L3 vlan is alive, set the ARP info*/
|
||||
set_arp_flag = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (set_arp_flag == 0)
|
||||
{
|
||||
LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (local_if->type == IF_T_PORT_CHANNEL)
|
||||
{
|
||||
if (!local_if_is_l3_mode(local_if))
|
||||
{
|
||||
/* Is the L2 MLAG itf belong to a vlan the same as peer?*/
|
||||
LIST_FOREACH(vlan_id_list, &(local_if->vlan_list), port_next)
|
||||
{
|
||||
if (!vlan_id_list->vlan_itf)
|
||||
continue;
|
||||
if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) != 0)
|
||||
continue;
|
||||
if (!local_if_is_l3_mode(vlan_id_list->vlan_itf))
|
||||
continue;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from intf %s, mclag %s is the member of this vlan",
|
||||
vlan_id_list->vlan_itf->name, local_if->name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (vlan_id_list && local_if->po_active == 1)
|
||||
{
|
||||
/* Any po of L3 vlan is alive, set the ARP info*/
|
||||
set_arp_flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is the ARP belong to a L3 mode MLAG itf?*/
|
||||
if (strcmp(local_if->name, arp_entry->ifname) == 0)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is learnt from mclag L3 intf %s", local_if->name);
|
||||
if (local_if->po_active == 1)
|
||||
{
|
||||
/* po is alive, set the ARP info*/
|
||||
set_arp_flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set dynamic ARP*/
|
||||
if (set_arp_flag == 1)
|
||||
{
|
||||
if (arp_entry->op_type == ARP_SYNC_ADD)
|
||||
{
|
||||
if (mlacp_fsm_arp_set(arp_entry->ifname, ntohl(arp_entry->ipv4_addr), mac_str) < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "ARP add failure for %s %s %s",
|
||||
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mlacp_fsm_arp_del(arp_entry->ifname, ntohl(arp_entry->ipv4_addr)) < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "ARP delete failure for %s %s %s",
|
||||
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*ICCPD_LOG_DEBUG(__FUNCTION__, "%s: ARP update for %s %s %s",
|
||||
__FUNCTION__, arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Failure: port-channel is not alive");
|
||||
/*TODO Set static route through peer-link or just skip it?*/
|
||||
}
|
||||
|
||||
/* update ARP list*/
|
||||
TAILQ_FOREACH(msg, &(MLACP(csm).arp_list), tail)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
if (arp_msg->ipv4_addr == ntohl(arp_entry->ipv4_addr))
|
||||
{
|
||||
/*arp_msg->op_type = tlv->type;*/
|
||||
sprintf(arp_msg->ifname, "%s", arp_entry->ifname);
|
||||
memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete/add ARP list*/
|
||||
if (msg && arp_entry->op_type == ARP_SYNC_DEL)
|
||||
{
|
||||
TAILQ_REMOVE(&(MLACP(csm).arp_list), msg, tail);
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
/*ICCPD_LOG_INFO(__FUNCTION__, "Del arp queue successfully");*/
|
||||
}
|
||||
else if (!msg && arp_entry->op_type == ARP_SYNC_ADD)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)&arp_data;
|
||||
sprintf(arp_msg->ifname, "%s", arp_entry->ifname);
|
||||
arp_msg->ipv4_addr = ntohl(arp_entry->ipv4_addr);
|
||||
arp_msg->op_type = arp_entry->op_type;
|
||||
memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN);
|
||||
if (iccp_csm_init_msg(&msg, (char*)arp_msg, sizeof(struct ARPMsg)) == 0)
|
||||
{
|
||||
mlacp_enqueue_arp(csm, msg);
|
||||
/*ICCPD_LOG_INFO(__FUNCTION__, "Add arp queue successfully");*/
|
||||
}
|
||||
}
|
||||
|
||||
/* remove all ARP msg queue, when receive peer's ARP list at the same time*/
|
||||
TAILQ_FOREACH(msg, &(MLACP(csm).arp_msg_list), tail)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
if (arp_msg->ipv4_addr == ntohl(arp_entry->ipv4_addr))
|
||||
break;
|
||||
}
|
||||
|
||||
while (msg)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
TAILQ_REMOVE(&(MLACP(csm).arp_msg_list), msg, tail);
|
||||
free(msg->buf);
|
||||
free(msg);
|
||||
TAILQ_FOREACH(msg, &(MLACP(csm).arp_msg_list), tail)
|
||||
{
|
||||
arp_msg = (struct ARPMsg*)msg->buf;
|
||||
if (arp_msg->ipv4_addr == ntohl(arp_entry->ipv4_addr))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlacp_fsm_update_arp_info(struct CSM* csm, struct mLACPARPInfoTLV* tlv)
|
||||
{
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
if (!csm || !tlv)
|
||||
return MCLAG_ERROR;
|
||||
count = ntohs(tlv->num_of_entry);
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Received ARP Info count %d ", count );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
mlacp_fsm_update_arp_entry(csm, &(tlv->ArpEntry[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Port-Channel-Info Update
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_port_channel_info(struct CSM* csm,
|
||||
struct mLACPPortChannelInfoTLV* tlv)
|
||||
{
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
struct VLAN_ID* peer_vlan_id = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (csm == NULL || tlv == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
LIST_FOREACH(peer_if, &(MLACP(csm).pif_list), mlacp_next)
|
||||
{
|
||||
if (peer_if->type != IF_T_PORT_CHANNEL)
|
||||
continue;
|
||||
|
||||
if (peer_if->po_id != ntohs(tlv->agg_id))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH(peer_vlan_id, &(peer_if->vlan_list), port_next)
|
||||
{
|
||||
peer_vlan_id->vlan_removed = 1;
|
||||
}
|
||||
|
||||
/* Record peer info*/
|
||||
peer_if->ipv4_addr = ntohl(tlv->ipv4_addr);
|
||||
peer_if->l3_mode = tlv->l3_mode;
|
||||
|
||||
for (i = 0; i < ntohs(tlv->num_of_vlan_id); i++)
|
||||
{
|
||||
peer_if_add_vlan(peer_if, ntohs(tlv->vlanData[i].vlan_id));
|
||||
}
|
||||
|
||||
peer_if_clean_unused_vlan(peer_if);
|
||||
|
||||
iccp_consistency_check(peer_if->name);
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Peer intf %s info: ipv4 addr %s l3 mode %d", peer_if->name, show_ip_str( tlv->ipv4_addr), peer_if->l3_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Peerlink port Update
|
||||
* ***************************************/
|
||||
int mlacp_fsm_update_peerlink_info(struct CSM* csm,
|
||||
struct mLACPPeerLinkInfoTLV* tlv)
|
||||
{
|
||||
if (csm == NULL || tlv == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (!csm->peer_link_if)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Peerlink port info recv from peer, local peerlink is not exist!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (csm->peer_link_if->type != tlv->port_type)
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port type of peer %d is not same with local %d !", tlv->port_type, csm->peer_link_if->type);
|
||||
|
||||
if (tlv->port_type == IF_T_VXLAN && strncmp(csm->peer_itf_name, tlv->if_name, strlen(csm->peer_itf_name)))
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Peerlink port is vxlan port, but peerlink port of peer %s is not same with local %s !", tlv->if_name, csm->peer_itf_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Heartbeat Update
|
||||
*****************************************/
|
||||
int mlacp_fsm_update_heartbeat(struct CSM* csm, struct mLACPHeartbeatTLV* tlv)
|
||||
{
|
||||
if (!csm || !tlv)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
time(&csm->heartbeat_update_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* warm-reboot flag Update
|
||||
*****************************************/
|
||||
int mlacp_fsm_update_warmboot(struct CSM* csm, struct mLACPWarmbootTLV* tlv)
|
||||
{
|
||||
if (!csm || !tlv)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
time(&csm->peer_warm_reboot_time);
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Receive warm reboot notification from peer!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
665
src/iccpd/src/port.c
Normal file
665
src/iccpd/src/port.c
Normal file
@ -0,0 +1,665 @@
|
||||
/*
|
||||
* port.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#include "../include/logger.h"
|
||||
#include "../include/port.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
|
||||
void local_if_init(struct LocalInterface* local_if)
|
||||
{
|
||||
if (local_if == NULL)
|
||||
return;
|
||||
|
||||
memset(local_if, 0, sizeof(struct LocalInterface));
|
||||
local_if->po_id = -1;
|
||||
local_if->po_active = 1; //always guess the po is active
|
||||
local_if->mlacp_state = MLACP_STATE_INIT;
|
||||
local_if->type = IF_T_UNKNOW;
|
||||
local_if->changed = 1;
|
||||
local_if->port_config_sync = 0;
|
||||
local_if->is_peer_link = 0;
|
||||
local_if->is_arp_accept = 0;
|
||||
local_if->l3_mode = 0;
|
||||
local_if->state = PORT_STATE_DOWN;
|
||||
local_if->prefixlen = 32;
|
||||
local_if->csm = NULL;
|
||||
local_if->isolate_to_peer_link = 0;
|
||||
LIST_INIT(&local_if->vlan_list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void vlan_info_init(struct VLAN_ID* vlan)
|
||||
{
|
||||
vlan->vid = -1;
|
||||
vlan->vlan_removed = 0;
|
||||
vlan->vlan_itf = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct LocalInterface* local_if_create(int ifindex, char* ifname, int type)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
struct CSM* csm;
|
||||
struct If_info * cif = NULL;
|
||||
|
||||
if (!ifname)
|
||||
return NULL;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return NULL;
|
||||
|
||||
if (ifindex < 0)
|
||||
return NULL;
|
||||
|
||||
if ((local_if = local_if_find_by_ifindex(ifindex)))
|
||||
return local_if;
|
||||
|
||||
if (!(local_if = (struct LocalInterface*)malloc(sizeof(struct LocalInterface))))
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Port ifindex = %d, malloc failed", ifindex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
local_if_init(local_if);
|
||||
local_if->ifindex = ifindex;
|
||||
local_if->type = type;
|
||||
|
||||
if (local_if->type == IF_T_PORT_CHANNEL)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
len = strlen(ifname);
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
if (ifname[i] >= '0' && ifname[i] <= '9')
|
||||
break;
|
||||
|
||||
if (i >= len)
|
||||
return NULL;
|
||||
|
||||
local_if->po_id = atoi(&ifname[i]);
|
||||
}
|
||||
|
||||
if (ifname)
|
||||
snprintf(local_if->name, MAX_L_PORT_NAME, "%s", ifname);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case IF_T_PORT_CHANNEL:
|
||||
break;
|
||||
|
||||
case IF_T_PORT:
|
||||
break;
|
||||
|
||||
case IF_T_VLAN:
|
||||
/* do nothing currently. */
|
||||
break;
|
||||
|
||||
case IF_T_VXLAN:
|
||||
/* do nothing currently. */
|
||||
break;
|
||||
|
||||
default:
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "The type of local interface (%s) is not acceptable", ifname);
|
||||
if (local_if)
|
||||
free(local_if);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ICCPD_LOG_NOTICE(__FUNCTION__,
|
||||
"Create a local_if = %s ifindex = %d MAC = %02x:%02x:%02x:%02x:%02x:%02x, state = %s",
|
||||
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);
|
||||
|
||||
/*Check the intf is peer-link? Only support PortChannel and Ethernet currently*/
|
||||
/*When set peer-link, the local-if is probably not created*/
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (strcmp(local_if->name, csm->peer_itf_name) == 0)
|
||||
{
|
||||
local_if->is_peer_link = 1;
|
||||
csm->peer_link_if = local_if;
|
||||
break;
|
||||
}
|
||||
/*check the intf is bind with csm*/
|
||||
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;
|
||||
}
|
||||
|
||||
struct LocalInterface* local_if_find_by_name(const char* ifname)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
if (!ifname)
|
||||
return NULL;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(local_if, &(sys->lif_list), system_next)
|
||||
{
|
||||
if (strcmp(local_if->name, ifname) == 0)
|
||||
return local_if;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct LocalInterface* local_if_find_by_ifindex(int ifindex)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct LocalInterface* local_if_find_by_po_id(int po_id)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(local_if, &(sys->lif_list), system_next)
|
||||
{
|
||||
if (local_if->type == IF_T_PORT_CHANNEL && local_if->po_id == po_id)
|
||||
return local_if;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ((sys = system_get_instance()) != NULL)
|
||||
{
|
||||
LIST_FOREACH(lif, &(sys->lif_list), system_next)
|
||||
{
|
||||
LIST_FOREACH(vlan, &(lif->vlan_list), port_next)
|
||||
{
|
||||
if (lif_vlan != vlan->vlan_itf)
|
||||
continue;
|
||||
|
||||
vlan->vlan_itf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void local_if_po_remove(struct LocalInterface *lif_po)
|
||||
{
|
||||
struct System *sys = NULL;
|
||||
struct CSM *csm = NULL;
|
||||
struct LocalInterface *lif = NULL;
|
||||
|
||||
/* remove all po member*/
|
||||
if ((sys = system_get_instance()) != NULL)
|
||||
{
|
||||
csm = lif_po->csm;
|
||||
if (csm)
|
||||
{
|
||||
LIST_FOREACH(lif, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (lif->type != IF_T_PORT)
|
||||
continue;
|
||||
if (lif->po_id != lif_po->po_id)
|
||||
continue;
|
||||
|
||||
mlacp_unbind_local_if(lif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void local_if_remove(struct LocalInterface *lif)
|
||||
{
|
||||
mlacp_unbind_local_if(lif);
|
||||
lif->po_id = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void local_if_destroy(char *ifname)
|
||||
{
|
||||
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)
|
||||
local_if_vlan_remove(lif);
|
||||
else if (lif->type == IF_T_PORT_CHANNEL)
|
||||
local_if_po_remove(lif);
|
||||
else
|
||||
local_if_remove(lif);
|
||||
|
||||
csm = lif->csm;
|
||||
if (csm && csm->peer_link_if && strcmp(csm->peer_link_if->name, ifname) == 0)
|
||||
{
|
||||
/*if the peerlink interface is not created, peer connection can not establish*/
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
csm->peer_link_if->is_peer_link = 0;
|
||||
csm->peer_link_if = NULL;
|
||||
}
|
||||
|
||||
if (csm && MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
goto to_mlacp_purge;
|
||||
else
|
||||
goto to_sys_purge;
|
||||
|
||||
to_sys_purge:
|
||||
/* sys purge */
|
||||
LIST_REMOVE(lif, system_next);
|
||||
if (lif->csm)
|
||||
LIST_REMOVE(lif, mlacp_next);
|
||||
LIST_INSERT_HEAD(&(sys->lif_purge_list), lif, system_purge_next);
|
||||
return;
|
||||
|
||||
to_mlacp_purge:
|
||||
/* sys & mlacp purge */
|
||||
LIST_REMOVE(lif, system_next);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
int local_if_is_l3_mode(struct LocalInterface* local_if)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (local_if == NULL)
|
||||
return 0;
|
||||
|
||||
if (local_if->ipv4_addr != 0)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void local_if_change_flag_clear(void)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* lif = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
LIST_FOREACH(lif, &(sys->lif_list), system_next)
|
||||
{
|
||||
if (lif->changed == 1)
|
||||
{
|
||||
lif->changed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void local_if_purge_clear(void)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct LocalInterface* lif = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
/* destroy purge if*/
|
||||
while (!LIST_EMPTY(&(sys->lif_purge_list)))
|
||||
{
|
||||
lif = LIST_FIRST(&(sys->lif_purge_list));
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Purge %s", lif->name);
|
||||
LIST_REMOVE(lif, system_purge_next);
|
||||
if (lif->mlacp_purge_next.le_next != 0 && lif->mlacp_purge_next.le_prev != 0)
|
||||
LIST_REMOVE(lif, mlacp_purge_next);
|
||||
local_if_del_all_vlan(lif);
|
||||
free(lif);
|
||||
}
|
||||
|
||||
LIST_INIT(&(sys->lif_purge_list));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void local_if_finalize(struct LocalInterface* lif)
|
||||
{
|
||||
if (lif == NULL)
|
||||
return;
|
||||
|
||||
local_if_del_all_vlan(lif);
|
||||
|
||||
free(lif);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct PeerInterface* peer_if_create(struct CSM* csm,
|
||||
int peer_if_number, int type)
|
||||
{
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
|
||||
/* check csm*/
|
||||
if (csm == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check id*/
|
||||
if (peer_if_number < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "peer interface id < 0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check type*/
|
||||
if (type != IF_T_PORT && type != IF_T_PORT_CHANNEL)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__,
|
||||
"The type(%) of peer interface(%d) is not acceptable",
|
||||
type, peer_if_number);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create a new peer if*/
|
||||
if ((peer_if = (struct PeerInterface*)malloc(sizeof(struct PeerInterface))) == NULL)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Peer port id = %d, malloc failed", peer_if_number);
|
||||
return NULL;
|
||||
}
|
||||
memset(peer_if, 0, sizeof(struct PeerInterface));
|
||||
|
||||
if (type == IF_T_PORT)
|
||||
{
|
||||
peer_if->ifindex = peer_if_number;
|
||||
peer_if->type = IF_T_PORT;
|
||||
peer_if->csm = csm;
|
||||
}
|
||||
else if (type == IF_T_PORT_CHANNEL)
|
||||
{
|
||||
peer_if->ifindex = peer_if_number;
|
||||
peer_if->type = IF_T_PORT_CHANNEL;
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&(MLACP(csm).pif_list), peer_if, mlacp_next);
|
||||
|
||||
return peer_if;
|
||||
}
|
||||
|
||||
struct PeerInterface* peer_if_find_by_name(struct CSM* csm, char* name)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct PeerInterface* peer_if = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (csm == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(peer_if, &(csm->app_csm.mlacp.pif_list), mlacp_next)
|
||||
{
|
||||
if (strcmp(peer_if->name, name) == 0)
|
||||
return peer_if;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void peer_if_del_all_vlan(struct PeerInterface* pif)
|
||||
{
|
||||
struct VLAN_ID *pvlan = NULL;
|
||||
|
||||
while (!LIST_EMPTY(&(pif->vlan_list)))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void peer_if_destroy(struct PeerInterface* pif)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Destroy peer's interface %s, %d",
|
||||
pif->name, pif->ifindex);
|
||||
|
||||
/* destroy if*/
|
||||
LIST_REMOVE(pif, mlacp_next);
|
||||
peer_if_del_all_vlan(pif);
|
||||
|
||||
free(pif);
|
||||
return;
|
||||
}
|
||||
|
||||
int local_if_add_vlan(struct LocalInterface* local_if, uint16_t vid)
|
||||
{
|
||||
struct VLAN_ID *vlan = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!vlan)
|
||||
{
|
||||
vlan = (struct VLAN_ID*)malloc(sizeof(struct VLAN_ID));
|
||||
if (!vlan)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Add %s to VLAN %d", local_if->name, vid);
|
||||
local_if->port_config_sync = 1;
|
||||
LIST_INSERT_HEAD(&(local_if->vlan_list), vlan, port_next);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 (vlan->vid == vid)
|
||||
break;
|
||||
}
|
||||
|
||||
if (vlan != NULL)
|
||||
{
|
||||
LIST_REMOVE(vlan, port_next);
|
||||
free(vlan);
|
||||
local_if->port_config_sync = 1;
|
||||
}
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", local_if->name, vid);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void local_if_del_all_vlan(struct LocalInterface* lif)
|
||||
{
|
||||
struct VLAN_ID* vlan = NULL;
|
||||
|
||||
while (!LIST_EMPTY(&(lif->vlan_list)))
|
||||
{
|
||||
vlan = LIST_FIRST(&(lif->vlan_list));
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Remove %s from VLAN %d", lif->name, vlan->vid);
|
||||
LIST_REMOVE(vlan, port_next);
|
||||
free(vlan);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add VLAN from peer-link*/
|
||||
int peer_if_add_vlan(struct PeerInterface* peer_if, uint16_t vlan_id)
|
||||
{
|
||||
struct VLAN_ID *peer_vlan = NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!peer_vlan)
|
||||
{
|
||||
peer_vlan = (struct VLAN_ID*)malloc(sizeof(struct VLAN_ID));
|
||||
if (!peer_vlan)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Add peer intf %s to VLAN %d", peer_if->name, vlan_id);
|
||||
LIST_INSERT_HEAD(&(peer_if->vlan_list), peer_vlan, port_next);
|
||||
}
|
||||
|
||||
vlan_info_init(peer_vlan);
|
||||
peer_vlan->vid = vlan_id;
|
||||
peer_vlan->vlan_removed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Used by sync update*/
|
||||
int peer_if_clean_unused_vlan(struct PeerInterface* peer_if)
|
||||
{
|
||||
struct VLAN_ID *peer_vlan = NULL;
|
||||
struct VLAN_ID *peer_vlan_next = NULL;
|
||||
|
||||
/* traverse 1 time */
|
||||
LIST_FOREACH(peer_vlan_next, &(peer_if->vlan_list), port_next)
|
||||
{
|
||||
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);
|
||||
free(peer_vlan);
|
||||
peer_vlan = NULL;
|
||||
|
||||
}
|
||||
if (peer_vlan_next->vlan_removed == 1)
|
||||
peer_vlan = peer_vlan_next;
|
||||
}
|
||||
|
||||
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);
|
||||
free(peer_vlan);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_sys_arp_accept_flag(char* ifname, int flag)
|
||||
{
|
||||
FILE *file_ptr = NULL;
|
||||
char cmd[64];
|
||||
char arp_file[64];
|
||||
char buf[2];
|
||||
int result = MCLAG_ERROR;
|
||||
|
||||
memset(arp_file, 0, 64);
|
||||
snprintf(arp_file, 63, "/proc/sys/net/ipv4/conf/%s/arp_accept", ifname);
|
||||
if (!(file_ptr = fopen(arp_file, "r")))
|
||||
{
|
||||
ICCPD_LOG_WARN(__func__, "Failed to find device %s from %s", ifname, arp_file);
|
||||
return result;
|
||||
}
|
||||
|
||||
fgets(buf, sizeof(buf), file_ptr);
|
||||
if (atoi(buf) == flag)
|
||||
result = 0;
|
||||
else
|
||||
{
|
||||
memset(cmd, 0, 64);
|
||||
snprintf(cmd, 63, "echo %d > /proc/sys/net/ipv4/conf/%s/arp_accept", flag, ifname);
|
||||
if (system(cmd))
|
||||
ICCPD_LOG_WARN(__func__, "Failed to execute cmd = %s", flag, cmd);
|
||||
}
|
||||
|
||||
fclose(file_ptr);
|
||||
return result;
|
||||
}
|
770
src/iccpd/src/scheduler.c
Normal file
770
src/iccpd/src/scheduler.c
Normal file
@ -0,0 +1,770 @@
|
||||
/*
|
||||
* scheduler.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "../include/logger.h"
|
||||
#include "../include/system.h"
|
||||
#include "../include/scheduler.h"
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/iccp_ifm.h"
|
||||
#include "../include/iccp_cmd.h"
|
||||
#include "../include/mlacp_link_handler.h"
|
||||
#include "../include/iccp_netlink.h"
|
||||
|
||||
/******************************************************
|
||||
*
|
||||
* Global Variable
|
||||
*
|
||||
******************************************************/
|
||||
|
||||
static int session_conn_thread_lock(pthread_mutex_t *conn_mutex)
|
||||
{
|
||||
return 1; /*pthread_mutex_lock(conn_mutex);*/
|
||||
}
|
||||
|
||||
static int session_conn_thread_trylock(pthread_mutex_t *conn_mutex)
|
||||
{
|
||||
return 0; /*pthread_mutex_trylock(conn_mutex);*/
|
||||
}
|
||||
|
||||
static int session_conn_thread_unlock(pthread_mutex_t *conn_mutex)
|
||||
{
|
||||
return 1;/* pthread_mutex_unlock(conn_mutex);*/
|
||||
}
|
||||
|
||||
static void heartbeat_check(struct CSM *csm)
|
||||
{
|
||||
if (csm->heartbeat_update_time == 0)
|
||||
{
|
||||
time(&csm->heartbeat_update_time);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (time(NULL) - csm->heartbeat_update_time) > HEARTBEAT_TIMEOUT_SEC)
|
||||
{
|
||||
/* hearbeat timeout*/
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "iccpd connection timeout (heartbeat)");
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void heartbeat_update(struct CSM *csm)
|
||||
{
|
||||
if (csm->sock_fd > 0)
|
||||
{
|
||||
heartbeat_check(csm);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Transit FSM of all connections */
|
||||
static int scheduler_transit_fsm()
|
||||
{
|
||||
struct CSM* csm = NULL;
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
heartbeat_update(csm);
|
||||
iccp_csm_transit(csm);
|
||||
app_csm_transit(csm);
|
||||
mlacp_fsm_transit(csm);
|
||||
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE && (time(NULL) - sys->csm_trans_time) >= 60)
|
||||
{
|
||||
iccp_get_fdb_change_from_syncd();
|
||||
sys->csm_trans_time = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
local_if_change_flag_clear();
|
||||
local_if_purge_clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Receive packets call back function */
|
||||
int scheduler_csm_read_callback(struct CSM* csm)
|
||||
{
|
||||
struct Msg* msg = NULL;
|
||||
/*peer message*/
|
||||
char *peer_msg = g_csm_buf;
|
||||
LDPHdr* ldp_hdr = (LDPHdr*)peer_msg;
|
||||
char* data = &peer_msg[sizeof(LDPHdr)];
|
||||
size_t data_len = 0;
|
||||
size_t pos = 0;
|
||||
int recv_len = 0, len = 0, retval;
|
||||
|
||||
if (csm->sock_fd <= 0)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
memset(peer_msg, 0, CSM_BUFFER_SIZE);
|
||||
|
||||
recv_len = 0;
|
||||
|
||||
while (recv_len != sizeof(LDPHdr))
|
||||
{
|
||||
len = recv(csm->sock_fd, peer_msg + recv_len, sizeof(LDPHdr) - recv_len, 0);
|
||||
if (len == -1)
|
||||
{
|
||||
perror("recv(). Error");
|
||||
goto recv_err;
|
||||
}
|
||||
else if (len == 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Peer disconnect for receive error");
|
||||
goto recv_err;
|
||||
}
|
||||
recv_len += len;
|
||||
/*usleep(100);*/
|
||||
}
|
||||
|
||||
data_len = ntohs(ldp_hdr->msg_len) - MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS;
|
||||
pos = 0;
|
||||
|
||||
while (data_len > 0)
|
||||
{
|
||||
recv_len = recv(csm->sock_fd, &data[pos], data_len, 0);
|
||||
if (recv_len == -1)
|
||||
{
|
||||
perror("continue recv(). Error");
|
||||
goto recv_err;
|
||||
}
|
||||
else if (recv_len == 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Peer disconnect for read error");
|
||||
goto recv_err;
|
||||
}
|
||||
data_len -= recv_len;
|
||||
pos += recv_len;
|
||||
/*usleep(100);*/
|
||||
}
|
||||
|
||||
retval = iccp_csm_init_msg(&msg, peer_msg, ntohs(ldp_hdr->msg_len) + MSG_L_INCLUD_U_BIT_MSG_T_L_FIELDS);
|
||||
if (retval == 0)
|
||||
{
|
||||
iccp_csm_enqueue_msg(csm, msg);
|
||||
++csm->icc_msg_in_count;
|
||||
}
|
||||
else
|
||||
++csm->i_msg_in_count;
|
||||
|
||||
return 1;
|
||||
|
||||
recv_err:
|
||||
scheduler_session_disconnect_handler(csm);
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
/* Handle server accept client */
|
||||
int scheduler_server_accept()
|
||||
{
|
||||
int new_fd;
|
||||
int ret = MCLAG_ERROR;
|
||||
struct CSM* csm = NULL;
|
||||
struct System* sys = NULL;
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
if (sys->server_fd <= 0)
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
addr_len = sizeof(struct sockaddr_in);
|
||||
new_fd = accept(sys->server_fd, (struct sockaddr *)&client_addr, &addr_len);
|
||||
if (new_fd == -1)
|
||||
{
|
||||
goto reject_client;
|
||||
}
|
||||
else
|
||||
{
|
||||
csm = system_get_csm_by_peer_ip(inet_ntoa(client_addr.sin_addr));
|
||||
if (!csm)
|
||||
{
|
||||
/* can't find csm with peer ip*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "csm null with peer ip [%s]", inet_ntoa(client_addr.sin_addr));
|
||||
goto reject_client;
|
||||
}
|
||||
|
||||
if (csm->sock_fd > 0)
|
||||
{
|
||||
/* peer already connected*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "csm sock is connected with peer ip [%s]", inet_ntoa(client_addr.sin_addr));
|
||||
goto reject_client;
|
||||
}
|
||||
|
||||
if ((ret = scheduler_check_csm_config(csm)) < 0)
|
||||
{
|
||||
/* csm config error*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "csm config error with peer ip [%s]", inet_ntoa(client_addr.sin_addr));
|
||||
goto reject_client;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accept*/
|
||||
goto accept_client;
|
||||
|
||||
reject_client:
|
||||
if (new_fd >= 0)
|
||||
close(new_fd);
|
||||
return MCLAG_ERROR;
|
||||
|
||||
accept_client:
|
||||
session_conn_thread_lock(&csm->conn_mutex);
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Server Accept, SocketFD [%d], %p", new_fd, csm);
|
||||
|
||||
struct epoll_event event;
|
||||
int err;
|
||||
event.data.fd = new_fd;
|
||||
event.events = EPOLLIN;
|
||||
err = epoll_ctl(sys->epoll_fd, EPOLL_CTL_ADD, new_fd, &event);
|
||||
if (err)
|
||||
{
|
||||
session_conn_thread_unlock(&csm->conn_mutex);
|
||||
goto reject_client;
|
||||
}
|
||||
|
||||
csm->sock_fd = new_fd;
|
||||
csm->current_state = ICCP_NONEXISTENT;
|
||||
FD_SET(new_fd, &(sys->readfd));
|
||||
sys->readfd_count++;
|
||||
session_conn_thread_unlock(&csm->conn_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iccp_get_start_type(struct System* sys)
|
||||
{
|
||||
FILE* fp;
|
||||
|
||||
memset(g_csm_buf, 0, CSM_BUFFER_SIZE);
|
||||
|
||||
fp = fopen("/proc/cmdline", "r");
|
||||
if (!fp)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Error: Can't open file /proc/cmdline!");
|
||||
return;
|
||||
}
|
||||
|
||||
fread(g_csm_buf, CSM_BUFFER_SIZE, 1, fp);
|
||||
(void)fclose(fp);
|
||||
|
||||
if (strstr(g_csm_buf, "SONIC_BOOT_TYPE=warm"))
|
||||
sys->warmboot_start = WARM_REBOOT;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* scheduler initialization */
|
||||
void scheduler_init()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if (!(sys = system_get_instance()))
|
||||
return;
|
||||
|
||||
iccp_get_start_type(sys);
|
||||
/*Get kernel interface and port */
|
||||
iccp_sys_local_if_list_get_init();
|
||||
iccp_sys_local_if_list_get_addr();
|
||||
/*Interfaces must be created before this func called*/
|
||||
iccp_config_from_file(sys->config_file_path);
|
||||
|
||||
/*Get kernel ARP info */
|
||||
iccp_arp_get_init();
|
||||
|
||||
if (iccp_connect_syncd() < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Syncd info socket connect fail");
|
||||
}
|
||||
else
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Syncd info socket connect success");
|
||||
}
|
||||
|
||||
if (mclagd_ctl_sock_create() < 0)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Mclagd ctl info socket connect fail");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
extern int mlacp_prepare_for_warm_reboot(struct CSM* csm, char* buf, size_t max_buf_size);
|
||||
void mlacp_sync_send_warmboot_flag()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
int msg_len = 0;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
|
||||
{
|
||||
memset(g_csm_buf, 0, CSM_BUFFER_SIZE);
|
||||
msg_len = mlacp_prepare_for_warm_reboot(csm, g_csm_buf, CSM_BUFFER_SIZE);
|
||||
iccp_csm_send(csm, g_csm_buf, msg_len);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int iccp_receive_signal_handler(struct System* sys)
|
||||
{
|
||||
char ctrl_byte;
|
||||
int err = 0;
|
||||
|
||||
err = read(sys->sig_pipe_r, &ctrl_byte, 1);
|
||||
if (err == -1)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Read sig_pipe_r fail !");
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (ctrl_byte)
|
||||
{
|
||||
case 'w':
|
||||
/*send packet to peer*/
|
||||
mlacp_sync_send_warmboot_flag();
|
||||
sys->warmboot_exit = WARM_REBOOT;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Thread fetch to call */
|
||||
void scheduler_loop()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (sys->sync_fd <= 0)
|
||||
{
|
||||
iccp_connect_syncd();
|
||||
}
|
||||
|
||||
/*handle socket slelect event ,If no message received, it will block 0.1s*/
|
||||
iccp_handle_events(sys);
|
||||
/*csm, app state machine transit */
|
||||
scheduler_transit_fsm();
|
||||
|
||||
if (sys->warmboot_exit == WARM_REBOOT)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Warm reboot exit ......");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Sync portchannel MAC with kernel
|
||||
*
|
||||
* ***************************************/
|
||||
int mlacp_sync_with_kernel_callback()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* traverse all CSM */
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
/* Sync MLAG po state with kernel*/
|
||||
LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next)
|
||||
{
|
||||
if (local_if->type == IF_T_PORT_CHANNEL)
|
||||
{
|
||||
/* sync system info from one port-channel device*/
|
||||
if (memcmp(MLACP(csm).system_id, local_if->mac_addr, ETHER_ADDR_LEN) != 0)
|
||||
{
|
||||
memcpy(MLACP(csm).system_id, local_if->mac_addr, ETHER_ADDR_LEN);
|
||||
MLACP(csm).system_config_changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scheduler start while loop */
|
||||
void scheduler_start()
|
||||
{
|
||||
/*mlacp_sync_with_kernel_callback();*/
|
||||
|
||||
scheduler_loop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scheduler tear down */
|
||||
void scheduler_finalize()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
syncd_info_close();
|
||||
|
||||
log_finalize();
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Scheduler is terminated.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void session_client_conn_handler(struct CSM *csm)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct sockaddr_in peer_addr;
|
||||
int connFd = -1, connStat = -1;
|
||||
struct timeval con_tv;
|
||||
socklen_t len = sizeof(con_tv);
|
||||
int err = 0;
|
||||
|
||||
struct sockaddr_in src_addr;
|
||||
bzero(&(src_addr), sizeof(src_addr));
|
||||
src_addr.sin_family = PF_INET;
|
||||
src_addr.sin_port = 0;
|
||||
src_addr.sin_addr.s_addr = inet_addr(csm->sender_ip);
|
||||
|
||||
/* Lock the thread*/
|
||||
session_conn_thread_lock(&csm->conn_mutex);
|
||||
|
||||
sys = system_get_instance();
|
||||
if (!sys)
|
||||
goto conn_fail;
|
||||
|
||||
/* Create sock*/
|
||||
connFd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
bzero(&peer_addr, sizeof(peer_addr));
|
||||
peer_addr.sin_family = PF_INET;
|
||||
peer_addr.sin_port = htons(ICCP_TCP_PORT);
|
||||
peer_addr.sin_addr.s_addr = inet_addr(csm->peer_ip);
|
||||
if (connFd == -1)
|
||||
{
|
||||
ICCPD_LOG_DEBUG(__FUNCTION__, "Peer IP:%s Socket FD creation failed.",
|
||||
csm->peer_ip);
|
||||
goto conn_fail;
|
||||
}
|
||||
|
||||
/* Set connect timeout secs*/
|
||||
con_tv.tv_sec = 0;
|
||||
con_tv.tv_usec = CONNECT_TIMEOUT_MSEC * 1000;
|
||||
if (setsockopt(connFd, SOL_SOCKET, SO_SNDTIMEO, &con_tv, len) == -1)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set socket timeout fail");
|
||||
}
|
||||
|
||||
err = bind(connFd, (struct sockaddr*)&(src_addr), sizeof(src_addr));
|
||||
if (err < 0)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Bind socket failed. Error = %d errno = %d ",err,errno);
|
||||
goto conn_fail;
|
||||
}
|
||||
|
||||
/* Try conn*/
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Connecting. peer ip = [%s], %p", csm->peer_ip, csm);
|
||||
connStat = connect(connFd, (struct sockaddr*)&(peer_addr), sizeof(peer_addr));
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Connection. fd = [%d], status = [%d], %p",
|
||||
connFd, connStat, csm);
|
||||
|
||||
if (connStat != 0)
|
||||
{
|
||||
/* Conn Fail*/
|
||||
goto conn_fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Conn OK*/
|
||||
struct epoll_event event;
|
||||
int err;
|
||||
event.data.fd = connFd;
|
||||
event.events = EPOLLIN;
|
||||
err = epoll_ctl(sys->epoll_fd, EPOLL_CTL_ADD, connFd, &event);
|
||||
if (err)
|
||||
goto conn_fail;
|
||||
csm->sock_fd = connFd;
|
||||
FD_SET(connFd, &(sys->readfd));
|
||||
sys->readfd_count++;
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Connect to server %s sucess .", csm->peer_ip);
|
||||
goto conn_ok;
|
||||
}
|
||||
|
||||
conn_fail:
|
||||
if (connFd >= 0)
|
||||
{
|
||||
csm->sock_fd = -1;
|
||||
close(connFd);
|
||||
}
|
||||
conn_ok:
|
||||
time(&csm->connTimePrev);
|
||||
session_conn_thread_unlock(&csm->conn_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create socket connect to peer */
|
||||
int scheduler_prepare_session(struct CSM* csm)
|
||||
{
|
||||
int ret = MCLAG_ERROR;
|
||||
uint32_t local_ip = 0;
|
||||
uint32_t peer_ip = 0;
|
||||
|
||||
/* Init time_t*/
|
||||
if (csm->connTimePrev == 0)
|
||||
{
|
||||
time(&csm->connTimePrev);
|
||||
}
|
||||
|
||||
/* Don't conn to svr continously*/
|
||||
if ((time(NULL) - csm->connTimePrev) < CONNECT_INTERVAL_SEC)
|
||||
{
|
||||
goto no_time_update;
|
||||
}
|
||||
|
||||
/* Already conn?*/
|
||||
if (csm->sock_fd > 0)
|
||||
{
|
||||
goto time_update;
|
||||
}
|
||||
|
||||
if ((ret = scheduler_check_csm_config(csm)) < 0)
|
||||
goto time_update;
|
||||
|
||||
/* Who is client*/
|
||||
local_ip = inet_addr(csm->sender_ip);
|
||||
peer_ip = inet_addr(csm->peer_ip);
|
||||
if (local_ip > peer_ip)
|
||||
{
|
||||
goto time_update;
|
||||
}
|
||||
else if (local_ip == peer_ip)
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Local IP must not be the same as the peer IP.");
|
||||
goto time_update;
|
||||
}
|
||||
|
||||
if (session_conn_thread_trylock(&csm->conn_mutex) == 0)
|
||||
{
|
||||
session_client_conn_handler(csm);
|
||||
session_conn_thread_unlock(&csm->conn_mutex);
|
||||
}
|
||||
|
||||
time_update:
|
||||
time(&csm->connTimePrev);
|
||||
return 0;
|
||||
|
||||
no_time_update:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Server socket initialization */
|
||||
void scheduler_server_sock_init()
|
||||
{
|
||||
int optval = 1;
|
||||
struct System* sys = NULL;
|
||||
struct sockaddr_in src_addr;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return;
|
||||
|
||||
sys->server_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
bzero(&(src_addr), sizeof(src_addr));
|
||||
src_addr.sin_family = PF_INET;
|
||||
src_addr.sin_port = htons(ICCP_TCP_PORT);
|
||||
src_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (sys->server_fd == -1)
|
||||
{
|
||||
ICCPD_LOG_ERR(__FUNCTION__, "Server Socket FD creation failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (setsockopt(sys->server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Set socket option failed. Error");
|
||||
/*return;*/
|
||||
}
|
||||
|
||||
if (bind(sys->server_fd, (struct sockaddr*)&(src_addr), sizeof(src_addr)) < 0)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Bind socket failed. Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(sys->server_fd, MAX_ACCEPT_CONNETIONS) == -1)
|
||||
{
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Listen failed. Error");
|
||||
return;
|
||||
}
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "Server socket init done.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int iccp_get_server_sock_fd()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return 0;
|
||||
|
||||
return sys->server_fd;
|
||||
}
|
||||
|
||||
/* Server socket initialization */
|
||||
int scheduler_check_csm_config(struct CSM* csm)
|
||||
{
|
||||
int ret = 1;
|
||||
struct LocalInterface* lif = NULL;
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL)
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (csm == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (csm->mlag_id <= 0)
|
||||
ret = MCLAG_ERROR;
|
||||
else if (strlen(csm->peer_ip) <= 0)
|
||||
ret = MCLAG_ERROR;
|
||||
else if (strlen(csm->sender_ip) <= 0)
|
||||
ret = MCLAG_ERROR;
|
||||
else if (strlen(csm->peer_itf_name) != 0)
|
||||
{
|
||||
lif = local_if_find_by_name(csm->peer_itf_name);
|
||||
if (lif == NULL)
|
||||
{
|
||||
/*if peer-link is configured but the interface is not created, peer connection can not establish*/
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
lif->is_peer_link = 1;
|
||||
csm->peer_link_if = lif;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == MCLAG_ERROR)
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "mclag config is not complete or conflicting, please check!");
|
||||
|
||||
/* Decide STP role*/
|
||||
iccp_csm_stp_role_count(csm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int scheduler_unregister_sock_read_event_callback(struct CSM* csm)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return MCLAG_ERROR;
|
||||
|
||||
if (csm == NULL )
|
||||
{
|
||||
return MCLAG_ERROR;
|
||||
}
|
||||
|
||||
FD_CLR(csm->sock_fd, &(sys->readfd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scheduler_session_disconnect_handler(struct CSM* csm)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return;
|
||||
|
||||
struct epoll_event event;
|
||||
|
||||
if (csm == NULL)
|
||||
return;
|
||||
|
||||
session_conn_thread_lock(&csm->conn_mutex);
|
||||
scheduler_unregister_sock_read_event_callback(csm);
|
||||
if (csm->sock_fd > 0)
|
||||
{
|
||||
event.data.fd = csm->sock_fd;
|
||||
event.events = EPOLLIN;
|
||||
epoll_ctl(sys->epoll_fd, EPOLL_CTL_DEL, csm->sock_fd, &event);
|
||||
|
||||
close(csm->sock_fd);
|
||||
csm->sock_fd = -1;
|
||||
}
|
||||
|
||||
mlacp_peer_disconn_handler(csm);
|
||||
MLACP(csm).current_state = MLACP_STATE_INIT;
|
||||
iccp_csm_status_reset(csm, 0);
|
||||
time(&csm->connTimePrev);
|
||||
session_conn_thread_unlock(&csm->conn_mutex);
|
||||
|
||||
return;
|
||||
}
|
200
src/iccpd/src/system.c
Normal file
200
src/iccpd/src/system.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* system.c
|
||||
*
|
||||
* Copyright(c) 2016-2019 Nephos/Estinet.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Maintainer: jianjun, grace Li from nephos
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../include/iccp_csm.h"
|
||||
#include "../include/logger.h"
|
||||
#include "../include/iccp_netlink.h"
|
||||
#include "../include/scheduler.h"
|
||||
|
||||
/* Singleton */
|
||||
struct System* system_get_instance()
|
||||
{
|
||||
static struct System* sys = NULL;
|
||||
|
||||
if (sys == NULL )
|
||||
{
|
||||
sys = (struct System*)malloc(sizeof(struct System));
|
||||
if (sys == NULL )
|
||||
{
|
||||
ICCPD_LOG_WARN(__FUNCTION__, "Failed to obtain system instance.");
|
||||
return NULL;
|
||||
}
|
||||
system_init(sys);
|
||||
}
|
||||
|
||||
return sys;
|
||||
}
|
||||
|
||||
/* System instance initialization */
|
||||
void system_init(struct System* sys)
|
||||
{
|
||||
if (sys == NULL )
|
||||
return;
|
||||
|
||||
sys->server_fd = -1;
|
||||
sys->sync_fd = -1;
|
||||
sys->sync_ctrl_fd = -1;
|
||||
sys->arp_receive_fd = -1;
|
||||
sys->epoll_fd = -1;
|
||||
sys->family = -1;
|
||||
sys->warmboot_start = 0;
|
||||
sys->warmboot_exit = 0;
|
||||
LIST_INIT(&(sys->csm_list));
|
||||
LIST_INIT(&(sys->lif_list));
|
||||
LIST_INIT(&(sys->lif_purge_list));
|
||||
|
||||
sys->log_file_path = strdup("/var/log/iccpd.log");
|
||||
sys->cmd_file_path = strdup("/var/run/iccpd/iccpd.vty");
|
||||
sys->config_file_path = strdup("/etc/iccpd/iccpd.conf");
|
||||
sys->mclagdctl_file_path = strdup("/var/run/iccpd/mclagdctl.sock");
|
||||
sys->pid_file_fd = 0;
|
||||
sys->telnet_port = 2015;
|
||||
FD_ZERO(&(sys->readfd));
|
||||
sys->readfd_count = 0;
|
||||
sys->csm_trans_time = 0;
|
||||
sys->need_sync_team_again = 0;
|
||||
sys->need_sync_netlink_again = 0;
|
||||
scheduler_server_sock_init();
|
||||
iccp_system_init_netlink_socket();
|
||||
iccp_init_netlink_event_fd(sys);
|
||||
}
|
||||
|
||||
/* System instance tear down */
|
||||
void system_finalize()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
struct LocalInterface* local_if = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return;
|
||||
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "System resource pool is destructing.");
|
||||
|
||||
while (!LIST_EMPTY(&(sys->csm_list)))
|
||||
{
|
||||
csm = LIST_FIRST(&(sys->csm_list));
|
||||
iccp_csm_finalize(csm);
|
||||
}
|
||||
|
||||
/* Release all port objects */
|
||||
while (!LIST_EMPTY(&(sys->lif_list)))
|
||||
{
|
||||
local_if = LIST_FIRST(&(sys->lif_list));
|
||||
LIST_REMOVE(local_if, system_next);
|
||||
local_if_finalize(local_if);
|
||||
}
|
||||
|
||||
while (!LIST_EMPTY(&(sys->lif_purge_list)))
|
||||
{
|
||||
local_if = LIST_FIRST(&(sys->lif_purge_list));
|
||||
LIST_REMOVE(local_if, system_purge_next);
|
||||
local_if_finalize(local_if);
|
||||
}
|
||||
|
||||
iccp_system_dinit_netlink_socket();
|
||||
|
||||
if (sys->log_file_path != NULL )
|
||||
free(sys->log_file_path);
|
||||
if (sys->cmd_file_path != NULL )
|
||||
free(sys->cmd_file_path);
|
||||
if (sys->config_file_path != NULL )
|
||||
free(sys->config_file_path);
|
||||
if (sys->pid_file_fd > 0)
|
||||
close(sys->pid_file_fd);
|
||||
if (sys->server_fd > 0)
|
||||
close(sys->server_fd);
|
||||
if (sys->sync_fd > 0)
|
||||
close(sys->sync_fd);
|
||||
if (sys->sync_ctrl_fd > 0)
|
||||
close(sys->sync_ctrl_fd);
|
||||
if (sys->arp_receive_fd > 0)
|
||||
close(sys->arp_receive_fd);
|
||||
if (sys->sig_pipe_r > 0)
|
||||
close(sys->sig_pipe_r);
|
||||
if (sys->sig_pipe_w > 0)
|
||||
close(sys->sig_pipe_w);
|
||||
|
||||
if (sys->epoll_fd)
|
||||
close(sys->epoll_fd);
|
||||
|
||||
free(sys);
|
||||
ICCPD_LOG_INFO(__FUNCTION__, "System resource pool destructed successfully...");
|
||||
}
|
||||
|
||||
struct CSM* system_create_csm()
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return NULL;
|
||||
|
||||
/* Create a new csm */
|
||||
csm = (struct CSM*)malloc(sizeof(struct CSM));
|
||||
if (csm == NULL )
|
||||
return NULL;
|
||||
else
|
||||
memset(csm, 0, sizeof(struct CSM));
|
||||
iccp_csm_init(csm);
|
||||
LIST_INSERT_HEAD(&(sys->csm_list), csm, next);
|
||||
|
||||
return csm;
|
||||
}
|
||||
|
||||
/* Get connect state machine instance by peer ip */
|
||||
struct CSM* system_get_csm_by_peer_ip(const char* peer_ip)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (strcmp(csm->peer_ip, peer_ip) == 0)
|
||||
return csm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CSM* system_get_csm_by_mlacp_id(int id)
|
||||
{
|
||||
struct System* sys = NULL;
|
||||
struct CSM* csm = NULL;
|
||||
|
||||
if ((sys = system_get_instance()) == NULL )
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(csm, &(sys->csm_list), next)
|
||||
{
|
||||
if (csm->app_csm.mlacp.id == id)
|
||||
return csm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
Loading…
Reference in New Issue
Block a user