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:
shine4chen 2020-04-05 06:24:06 +08:00 committed by GitHub
parent abbd871d55
commit 524cf9e56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 15620 additions and 0 deletions

View 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"]

View 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 "$@"

View 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']}}

View 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

View 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

View 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

View File

@ -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 %}

View 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

View File

@ -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 %}

View File

@ -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
View 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
View 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
View 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

View 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:

View 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_ */

View 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_ */

View 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

View 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_ */

View 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

View 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

View 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_ */

View 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

View 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

View 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_ */

View 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 */

View 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

View 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

View 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

View 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_ */

View 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
View 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_ */

View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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;
}

View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

140
src/iccpd/src/logger.c Normal file
View 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;
}

View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}

View 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
View 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
View 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
View 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;
}