From b600a2c3f85c73aafcabe690b3dc542ac637fa46 Mon Sep 17 00:00:00 2001 From: Srinivas Aji Date: Fri, 30 Nov 2007 02:04:32 +0530 Subject: [PATCH] Use new RSTP library. This is a somewhat big commit which replaces the use of RSTPLIB in the RSTP daemon by the new RSTP library. This makes the daemon much more compliant with the 802.1D-2004 standard. The control program, rstpctl, has been modified so its output closer to the output of brctl showstp. Signed-off-by: Srinivas Aji --- Makefile | 16 +- bridge_track.c | 711 ++++++++++++-------------------------------- ctl_cli_wrap.c | 30 +- ctl_functions.h | 32 +- ctl_main.c | 593 ++++++++++-------------------------- ctl_socket.c | 60 +++- ctl_socket.h | 94 +++--- ctl_socket_client.c | 35 ++- ctl_socket_client.h | 6 +- ctl_socket_server.h | 5 + log.h | 13 +- rstpctl.8 | 41 +-- 12 files changed, 524 insertions(+), 1112 deletions(-) diff --git a/Makefile b/Makefile index 4840a00..c65dd39 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -DSOURCES = brstate.c libnetlink.c epoll_loop.c bridge_track.c \ +DSOURCES = brstate.c libnetlink.c epoll_loop.c bridge_track.c rstp.c \ packet.c ctl_socket.c netif_utils.c main.c brmon.c DOBJECTS = $(DSOURCES:.c=.o) @@ -9,24 +9,18 @@ CTLSOURCES = ctl_main.c ctl_cli_wrap.c ctl_socket_client.c CTLOBJECTS = $(CTLSOURCES:.c=.o) CC=gcc -CFLAGS = -Wall -Werror -O2 -g -D_REENTRANT -D__LINUX__ -DVERSION=$(version) -DBUILD=$(build) -I. -I./include -I./rstplib +CFLAGS = -Wall -Werror -O2 -g -D_REENTRANT -D__LINUX__ -DVERSION=$(version) -DBUILD=$(build) -I. -I./include all: rstpd rstpctl -rstplib: - make -C rstplib librstp.a - -.PHONY: rstplib - -rstpd: $(DOBJECTS) rstplib - $(CC) -o $@ $(DOBJECTS) -L ./rstplib -lrstp +rstpd: $(DOBJECTS) + $(CC) -o $@ $(DOBJECTS) rstpctl: $(CTLOBJECTS) $(CC) -o $@ $(CTLOBJECTS) clean: rm -f *.o rstpd rstpctl - make -C rstplib clean rm -fr $(TOPDIR) $(BUILDDIR) install: all @@ -38,7 +32,7 @@ install: all install -m 644 rstpctl.8 $(INSTALLPREFIX)/usr/share/man/man8 # RPM Building, as non root -version := 0.16 +version := 0.21 build := 1 BUILDROOT := $(CURDIR)/rpm_buildroot diff --git a/bridge_track.c b/bridge_track.c index cd84cd9..e93c014 100644 --- a/bridge_track.c +++ b/bridge_track.c @@ -34,17 +34,12 @@ #include #include -#include -#include -#include -#include -#include - #include #include #include "log.h" +#include "rstp.h" /*------------------------------------------------------------*/ struct ifdata { @@ -60,16 +55,8 @@ struct ifdata { struct ifdata *port_list; int do_stp; int stp_up; - struct stp_instance *stp; - UID_BRIDGE_ID_T bridge_id; - /* Bridge config */ - UID_STP_MODE_T stp_enabled; - int bridge_priority; - int max_age; - int hello_time; - int forward_delay; - int force_version; - int hold_time; + STP_Bridge *stp_bridge; + /* If port */ int speed; @@ -78,12 +65,7 @@ struct ifdata { struct ifdata *port_next; /* STP port index */ int port_index; - /* STP port config */ - int port_priority; - int admin_port_path_cost; - ADMIN_P2P_T admin_point2point; - unsigned char admin_edge; - unsigned char admin_non_stp; /* 1- doesn't participate in STP, 1 - regular */ + STP_Port *stp_port; struct epoll_event_handler event; }; @@ -91,22 +73,6 @@ struct ifdata { /* Instances */ struct ifdata *current_br = NULL; -void instance_begin(struct ifdata *br) -{ - if (current_br) { - ERROR("BUG: Trying to set instance over existing instance."); - ERROR("%d", *(int *)0); /* ABORT */ - } - current_br = br; - STP_IN_instance_begin(br->stp); -} - -void instance_end(void) -{ - STP_IN_instance_end(current_br->stp); - current_br = NULL; -} - struct ifdata *find_port(int port_index) { struct ifdata *ifc = current_br->port_list; @@ -115,170 +81,6 @@ struct ifdata *find_port(int port_index) return ifc; } -/*************************************************************/ -/* Bridge and port defaults */ - -UID_STP_CFG_T default_bridge_stp_cfg = { - .field_mask = BR_CFG_ALL, - .bridge_priority = DEF_BR_PRIO, - .max_age = DEF_BR_MAXAGE, - .hello_time = DEF_BR_HELLOT, - .forward_delay = DEF_BR_FWDELAY, - .force_version = DEF_FORCE_VERS, /*NORMAL_RSTP */ -}; - -void update_bridge_stp_config(struct ifdata *br, UID_STP_CFG_T * cfg) -{ - if (cfg->field_mask & BR_CFG_PRIO) - br->bridge_priority = cfg->bridge_priority; - if (cfg->field_mask & BR_CFG_AGE) - br->max_age = cfg->max_age; - if (cfg->field_mask & BR_CFG_HELLO) - br->hello_time = cfg->hello_time; - if (cfg->field_mask & BR_CFG_DELAY) - br->forward_delay = cfg->forward_delay; - if (cfg->field_mask & BR_CFG_FORCE_VER) - br->force_version = cfg->force_version; -} - -UID_STP_PORT_CFG_T default_port_stp_cfg = { - .field_mask = PT_CFG_ALL, - .port_priority = DEF_PORT_PRIO, - .admin_non_stp = DEF_ADMIN_NON_STP, - .admin_edge = False, // DEF_ADMIN_EDGE, - .admin_port_path_cost = ADMIN_PORT_PATH_COST_AUTO, - .admin_point2point = DEF_P2P, -}; - -void update_port_stp_config(struct ifdata *ifc, UID_STP_PORT_CFG_T * cfg) -{ - if (cfg->field_mask & PT_CFG_PRIO) - ifc->port_priority = cfg->port_priority; - if (cfg->field_mask & PT_CFG_NON_STP) - ifc->admin_non_stp = cfg->admin_non_stp; - if (cfg->field_mask & PT_CFG_EDGE) - ifc->admin_edge = cfg->admin_edge; - if (cfg->field_mask & PT_CFG_COST) - ifc->admin_port_path_cost = cfg->admin_port_path_cost; - if (cfg->field_mask & PT_CFG_P2P) - ifc->admin_point2point = cfg->admin_point2point; -} - -/**************************************************************/ - -int add_port_stp(struct ifdata *ifc) -{ /* Bridge is ifc->master */ - TST((ifc->port_index = get_bridge_portno(ifc->name)) >= 0, -1); - - /* Add port to STP */ - instance_begin(ifc->master); - int r = STP_IN_port_create(0, ifc->port_index); - if (r == 0) { /* Update bridge ID */ - UID_STP_STATE_T state; - STP_IN_stpm_get_state(0, &state); - ifc->master->bridge_id = state.bridge_id; - } - instance_end(); - if (r /* check for failure */ ) { - ERROR("Couldn't add port for ifindex %d to STP", ifc->if_index); - return -1; - } - return 0; -} - -void remove_port_stp(struct ifdata *ifc) -{ - /* Remove port from STP */ - instance_begin(ifc->master); - int r = STP_IN_port_delete(0, ifc->port_index); - instance_end(); - ifc->port_index = -1; - if (r != 0) { - ERROR("removing port %s failed for bridge %s: %s", - ifc->name, ifc->master->name, - STP_IN_get_error_explanation(r)); - } -} - -int init_rstplib_instance(struct ifdata *br) -{ - br->stp = STP_IN_instance_create(); - if (br->stp == NULL) { - ERROR("Couldn't create STP instance for bridge %s", br->name); - return -1; - } - - BITMAP_T ports; - BitmapClear(&ports); - instance_begin(br); - int r = STP_IN_stpm_create(0, br->name, &ports); - instance_end(); - if (r != 0) { - ERROR("stpm create failed for bridge %s: %s", - br->name, STP_IN_get_error_explanation(r)); - return -1; - } - - return 0; -} - -void clear_rstplib_instance(struct ifdata *br) -{ - instance_begin(br); - int r = STP_IN_delete_all(); - instance_end(); - if (r != 0) { - ERROR("stpm delete failed for bridge %s: %s", - br->name, STP_IN_get_error_explanation(r)); - } - - STP_IN_instance_delete(br->stp); - br->stp = NULL; -} - -int init_bridge_stp(struct ifdata *br) -{ - if (br->stp_up) { - ERROR("STP already started"); - return 0; - } - - /* Init STP state */ - TST(init_rstplib_instance(br) == 0, -1); - - struct ifdata *p = br->port_list; - while (p) { - if (add_port_stp(p) != 0) - break; - p = p->port_next; - } - if (p) { - struct ifdata *q = br->port_list; - while (q != p) { - remove_port_stp(q); - q = q->port_next; - } - /* Clear bridge STP state */ - clear_rstplib_instance(br); - return -1; - } - br->stp_up = 1; - return 0; -} - -void clear_bridge_stp(struct ifdata *br) -{ - if (!br->stp_up) - return; - br->stp_up = 0; - struct ifdata *p = br->port_list; - while (p) { - remove_port_stp(p); - p = p->port_next; - } - /* Clear bridge STP state */ - clear_rstplib_instance(br); -} struct ifdata *if_head = NULL; struct ifdata *br_head = NULL; @@ -327,15 +129,26 @@ struct ifdata *create_if(int if_index, struct ifdata *br) if (p->is_bridge) { INFO("Add bridge %s", p->name); + p->stp_bridge = STP_IN_bridge_create(p); + if (!p->stp_bridge) { + ERROR("Couldn't create STP Bridge"); + free(p); + return NULL; + } + STP_IN_set_bridge_address(p->stp_bridge, + (STP_MacAddress *)p->macaddr); + INFO("Set bridge address %s to %02x:%02x:%02x:%02x:%02x:%02x", + p->name, + p->macaddr[0], p->macaddr[1], p->macaddr[2], + p->macaddr[1], p->macaddr[4], p->macaddr[5] + ); /* Init slave list */ p->port_list = NULL; p->do_stp = 0; p->up = 0; p->stp_up = 0; - p->stp = NULL; - update_bridge_stp_config(p, &default_bridge_stp_cfg); - ADD_TO_LIST(br_head, bridge_next, p); /* Add to bridge list */ + ADD_TO_LIST(br_head, bridge_next, p); /* Add to bridge list */ } else { INFO("Add iface %s to bridge %s", p->name, br->name); p->up = 0; @@ -343,12 +156,22 @@ struct ifdata *create_if(int if_index, struct ifdata *br) p->duplex = 0; p->master = br; - update_port_stp_config(p, &default_port_stp_cfg); + p->port_index = get_bridge_portno(p->name); + if (p->port_index < 0) { + ERROR("Couldn't get port number for %s", p->name); + free(p); + return NULL; + } + p->stp_port = STP_IN_port_create(p->master->stp_bridge, + p->port_index, p); + if (!p->stp_port) { + ERROR("Couldn't create STP Port"); + free(p); + return NULL; + } + ADD_TO_LIST(br->port_list, port_next, p); /* Add to bridge port list */ - if (br->stp_up) { - add_port_stp(p); - } } /* Add to interface list */ @@ -361,8 +184,7 @@ void delete_if(struct ifdata *ifc) { INFO("Delete iface %s", ifc->name); if (ifc->is_bridge) { /* Bridge: */ - /* Stop STP */ - clear_bridge_stp(ifc); + STP_IN_set_bridge_enable(ifc->stp_bridge, 0); /* Delete ports */ while (ifc->port_list) delete_if(ifc->port_list); @@ -370,13 +192,13 @@ void delete_if(struct ifdata *ifc) REMOVE_FROM_LIST(br_head, bridge_next, ifc, "Can't find interface ifindex %d bridge list", ifc->if_index); + STP_IN_bridge_delete(ifc->stp_bridge); } else { /* Port */ - if (ifc->master->stp_up) - remove_port_stp(ifc); /* Remove from bridge port list */ REMOVE_FROM_LIST(ifc->master->port_list, port_next, ifc, "Can't find interface ifindex %d on br %d's port list", ifc->if_index, ifc->master->if_index); + STP_IN_port_delete(ifc->stp_port); } /* Remove from bridge interface list */ @@ -392,6 +214,7 @@ static int check_mac_address(char *name, unsigned char *addr) { unsigned char temp_addr[6]; if (get_hwaddr(name, temp_addr)) { + LOG("Error getting hw address: %s", name); /* Error. Ignore the new value */ return 0; } @@ -424,26 +247,32 @@ static int stp_enabled(struct ifdata *br) void set_br_up(struct ifdata *br, int up) { int stp_up = stp_enabled(br); - INFO("%s was %s stp was %s", br->name,up ? "up" : "down", br->stp_up ? "up" : "down"); + INFO("%s was %s stp was %s", br->name, br->up ? "up" : "down", br->stp_up ? "up" : "down"); INFO("Set bridge %s %s stp %s" , br->name, up ? "up" : "down", stp_up ? "up" : "down"); - if (up != br->up) + int changed = 0; + + if (up != br->up) { br->up = up; + changed = 1; + } + if (br->stp_up != stp_up) { + br->stp_up = stp_up; + changed = 1; + } + if (check_mac_address(br->name, br->macaddr)) { /* MAC address changed */ - if (br->stp_up && stp_up) { - /* Notify bridge address change */ - } + /* Notify bridge address change */ + STP_IN_set_bridge_address( + br->stp_bridge, (STP_MacAddress *)br->macaddr); } - if (br->stp_up != stp_up) { - if (stp_up) - init_bridge_stp(br); - else - clear_bridge_stp(br); - } + if (changed) + STP_IN_set_bridge_enable(br->stp_bridge, + (br->up && br->stp_up)?1:0); } void set_if_up(struct ifdata *ifc, int up) @@ -451,21 +280,23 @@ void set_if_up(struct ifdata *ifc, int up) INFO("Port %s : %s", ifc->name, (up ? "up" : "down")); int speed = -1; int duplex = -1; - int notify_flags = 0; - const int NOTIFY_UP = 1, NOTIFY_SPEED = 2, NOTIFY_DUPLEX = 4; + int changed = 0; if (check_mac_address(ifc->name, ifc->macaddr)) { /* MAC address changed */ if (check_mac_address(ifc->master->name, ifc->master->macaddr) - && ifc->master->stp_up) { + ) { /* Notify bridge address change */ + STP_IN_set_bridge_address( + ifc->master->stp_bridge, + (STP_MacAddress *)ifc->master->macaddr); } } if (!up) { /* Down */ if (ifc->up) { ifc->up = up; - notify_flags |= NOTIFY_UP; + changed = 1; } } else { /* Up */ int r = ethtool_get_speed_duplex(ifc->name, &speed, &duplex); @@ -478,29 +309,20 @@ void set_if_up(struct ifdata *ifc, int up) if (speed != ifc->speed) { ifc->speed = speed; - notify_flags |= NOTIFY_SPEED; + changed = 1; } if (duplex != ifc->duplex) { ifc->duplex = duplex; - notify_flags |= NOTIFY_DUPLEX; + changed = 1; } if (!ifc->up) { ifc->up = 1; - notify_flags |= NOTIFY_UP; + changed = 1; } } - if (notify_flags && ifc->master->stp_up) { - instance_begin(ifc->master); - - if (notify_flags & NOTIFY_SPEED) - STP_IN_changed_port_speed(ifc->port_index, speed); - if (notify_flags & NOTIFY_DUPLEX) - STP_IN_changed_port_duplex(ifc->port_index); - if (notify_flags & NOTIFY_UP) - STP_IN_enable_port(ifc->port_index, ifc->up); - - instance_end(); - } + if (changed) + STP_IN_set_port_enable(ifc->stp_port, + ifc->up, ifc->speed, ifc->duplex); } /*------------------------------------------------------------*/ @@ -509,7 +331,8 @@ int bridge_notify(int br_index, int if_index, int newlink, int up) { if (up) up = 1; - LOG("br_index %d, if_index %d, up %d", br_index, if_index, up); + LOG("br_index %d, if_index %d, newlink %d, up %d", + br_index, if_index, newlink, up); struct ifdata *br = NULL; if (br_index >= 0) { @@ -528,7 +351,7 @@ int bridge_notify(int br_index, int if_index, int newlink, int up) return -1; } /* Bridge must be up if we get such notifications */ - set_br_up(br, 1); + // Not true anymore - set_br_up(br, 1); } struct ifdata *ifc = find_if(if_index); @@ -619,14 +442,14 @@ const unsigned char STP_SAP = 0x42; void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len) { struct ifdata *ifc = find_if(if_index); - BPDU_T *bpdu; LOG("ifindex %d, len %d", if_index, len); if (!ifc) return; TST(ifc->up,); - TST(ifc->master->stp_up,); + if (!ifc->master->stp_up) + return; /* Validate Ethernet and LLC header */ { @@ -635,48 +458,19 @@ void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len) TST(len > sizeof(struct llc_header),); h = (struct llc_header *)data; TST(memcmp(h->dest_addr, bridge_group_address, ETH_ALEN) == 0, - ); + INFO("ifindex %d, len %d, %02x:%02x:%02x:%02x:%02x:%02x", + if_index, len, + h->dest_addr[0],h->dest_addr[1],h->dest_addr[2], + h->dest_addr[3],h->dest_addr[4],h->dest_addr[5])); l = ntohs(h->len8023); TST(l <= ETH_DATA_LEN && l <= len - ETH_HLEN && l >= 3,); TST(h->d_sap == STP_SAP && h->s_sap == STP_SAP && (h->llc_ui & 0x3) == 0x3 /* LLC UI */,); - /* BPDU_T includes ETH_HEADER_T, i.e. {d_sap, s_sap, llc_ui} */ - bpdu = (BPDU_T *)(data + sizeof(*h) - sizeof(ETH_HEADER_T)); - len = l + 2; /* ETH_HEADER_T includes the 2 bytes of len8023 */ - } - - TST(len > sizeof(ETH_HEADER_T) + sizeof(BPDU_HEADER_T),); - /* Do some BPDU validation as per 9.3.4 of standard */ - if (bpdu->hdr.protocol[0] || bpdu->hdr.protocol[1]) - return; - - switch (bpdu->hdr.bpdu_type) { - case BPDU_RSTP: - TST(len >= sizeof(ETH_HEADER_T) + 36,); - case BPDU_CONFIG_TYPE: - TST(len >= sizeof(ETH_HEADER_T) + 35,); - /* 802.1w doesn't ask for this */ - // TST(ntohs(*(uint16_t*)bpdu.body.message_age) - // < ntohs(*(uint16_t*)bpdu.body.max_age), ); - TST(memcmp(bpdu->body.bridge_id, &ifc->master->bridge_id, 8) != 0 - || (ntohs(*(uint16_t *) bpdu->body.port_id) & 0xfff) != - ifc->port_index,); - break; - case BPDU_TOPO_CHANGE_TYPE: - break; - default: - LOG("Receive unknown bpdu type %x", bpdu->hdr.bpdu_type); - return; + STP_IN_rx_bpdu(ifc->stp_port, + /* Don't include LLC header */ + data + sizeof(*h), l - 3); } - - // dump_hex(data, len); - instance_begin(ifc->master); - int r = STP_IN_rx_bpdu(0, ifc->port_index, bpdu, len); - if (r) - ERROR("STP_IN_rx_bpdu on port %s returned %s", ifc->name, - STP_IN_get_error_explanation(r)); - instance_end(); } void bridge_one_second(void) @@ -684,20 +478,8 @@ void bridge_one_second(void) // LOG(""); struct ifdata *br; for (br = br_head; br; br = br->bridge_next) { - if (br->stp_up) { - instance_begin(br); - STP_IN_one_second(); - instance_end(); - } + STP_IN_one_second(br->stp_bridge); } - - /* To get information about port changes when bridge is down */ - /* But won't work so well since we will not sense deletions */ - static int count = 0; - count++; - if (count % 60 == 0) - bridge_get_configuration(); - } /* Implementing STP_OUT functions */ @@ -712,203 +494,121 @@ int flush_port(char *sys_name) return 0; } -int -STP_OUT_flush_lt(IN int port_index, IN int vlan_id, - IN LT_FLASH_TYPE_T type, IN char *reason) +void STP_OUT_port_fdb_flush(void *user_ref) { - LOG("port index %d, flash type %d, reason %s", port_index, type, - reason); - TST(vlan_id == 0, 0); - + struct ifdata *port = user_ref; char fname[128]; - if (port_index == 0) { /* i.e. passed port_index was 0 */ - sprintf(fname, "/sys/class/net/%s/bridge/flush", - current_br->name); - flush_port(fname); - } else if (type == LT_FLASH_ONLY_THE_PORT) { - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - sprintf(fname, "/sys/class/net/%s/brif/%s/flush", - current_br->name, port->name); - flush_port(fname); - } else if (type == LT_FLASH_ALL_PORTS_EXCLUDE_THIS) { - struct ifdata *port; - for (port = current_br->port_list; port; port = port->port_next) { - if (port->port_index != port_index) { - sprintf(fname, - "/sys/class/net/%s/brif/%s/flush", - current_br->name, port->name); - flush_port(fname); - } - } - } else - TST(0, 0); - - return 0; -} - -void /* for bridge id calculation */ STP_OUT_get_port_mac(IN int port_index, - OUT unsigned char - *mac) -{ - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL,); - memcpy(mac, port->macaddr, sizeof(port->macaddr)); -} - -unsigned long STP_OUT_get_port_oper_speed(IN unsigned int port_index) -{ - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - LOG("Speed: %d", port->speed); - return port->speed; + snprintf(fname, sizeof(fname), + "/sys/class/net/%s/brport/flush", port->name); + fname[sizeof(fname) - 1] = 0; + TST(flush_port(fname) == 0,); } -int /* 1- Up, 0- Down */ STP_OUT_get_port_link_status(IN int port_index) +void STP_OUT_port_set_state(void *user_ref, unsigned int flags) { - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - LOG("Link status: %d", port->up); - return port->up; -} - -int /* 1- Full, 0- Half */ STP_OUT_get_duplex(IN int port_index) -{ - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - LOG("Duplex: %d", port->duplex); - return port->duplex; -} - -int -STP_OUT_set_port_state(IN int port_index, IN int vlan_id, - IN RSTP_PORT_STATE state) -{ - LOG("port index %d, state %d", port_index, state); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - TST(vlan_id == 0, 0); - + struct ifdata *port = user_ref; int br_state; - switch (state) { - case UID_PORT_DISCARDING: - br_state = BR_STATE_BLOCKING; - break; - case UID_PORT_LEARNING: - br_state = BR_STATE_LEARNING; - break; - case UID_PORT_FORWARDING: + + LOG("port index %d, flags %d", port->if_index, flags); + + if (flags & STP_PORT_STATE_FLAG_FORWARDING) br_state = BR_STATE_FORWARDING; - break; - default: - fprintf(stderr, "set_port_state: Unexpected state %d\n", state); - return -1; - } + else if (flags & STP_PORT_STATE_FLAG_LEARNING) + br_state = BR_STATE_LEARNING; + else + br_state = BR_STATE_BLOCKING; + if (port->up) bridge_set_state(port->if_index, br_state); - return 0; } -int STP_OUT_set_hardware_mode(int vlan_id, UID_STP_MODE_T mode) -{ - LOG("vlan id %d, mode %d", vlan_id, mode); - return 0; -} -int -STP_OUT_tx_bpdu(IN int port_index, IN int vlan_id, - IN unsigned char *bpdu, IN size_t bpdu_len) +void STP_OUT_tx_bpdu(void *port_user_ref, void *base, unsigned int len) { - LOG("port index %d, len %zd", port_index, bpdu_len); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - TST(vlan_id == 0, 0); + struct ifdata *port = port_user_ref; + + LOG("port index %d, len %d", port->if_index, len); struct llc_header h; memcpy(h.dest_addr, bridge_group_address, ETH_ALEN); memcpy(h.src_addr, port->macaddr, ETH_ALEN); /* bpdu_len excludes MAC and LLC headers */ - h.len8023 = htons(bpdu_len + 3); + h.len8023 = htons(len + 3); h.d_sap = h.s_sap = STP_SAP; - h.llc_ui = 0x03; /* LLC UI packet */ + h.llc_ui = 0x03; /* LLC UI packet */ struct iovec iov[2] = { { .iov_base = &h, .iov_len = sizeof(h) }, - { .iov_base = bpdu + sizeof(h), .iov_len = bpdu_len } + { .iov_base = base, .iov_len = len } }; - packet_send(port->if_index, iov, 2, sizeof(h) + bpdu_len); - return 0; + packet_send(port->if_index, iov, 2, sizeof(h) + len); } -const char *STP_OUT_get_port_name(IN int port_index) -{ - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - return port->name; -} -int STP_OUT_get_init_stpm_cfg(IN int vlan_id, INOUT UID_STP_CFG_T * cfg) +void STP_OUT_logmsg(void *br_user_ref, void *port_user_ref, + int level, char *fmt, ...) { - LOG(""); - TST(vlan_id == 0, 0); - - cfg->bridge_priority = current_br->bridge_priority; - cfg->max_age = current_br->max_age; - cfg->hello_time = current_br->hello_time; - cfg->forward_delay = current_br->forward_delay; - cfg->force_version = current_br->force_version; + struct ifdata *bridge = br_user_ref; + struct ifdata *port = port_user_ref; + char buf[256]; + int r; + int ll = (level < STP_LOG_LEVEL_DEBUG) ? + LOG_LEVEL_INFO : LOG_LEVEL_DEBUG; + struct timeval tv; + gettimeofday(&tv, NULL); + r = snprintf(buf, sizeof(buf), "LOG Level %d:%s:%s: %02d.%03d: ", + level, + (bridge?bridge->name:""), (port?port->name:""), + (int)tv.tv_sec % 60, (int)tv.tv_usec / 1000); + if (r >= sizeof(buf)) { + buf[sizeof(buf) - 1] = 0; + Dprintf(ll, "%s", buf); + r = 0; + } - return 0; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf + r, sizeof(buf) - r, fmt, ap); + buf[sizeof(buf) - 1] = 0; + Dprintf(ll, "%s", buf); + va_end(ap); + if (level == STP_LOG_LEVEL_ERROR) + ctl_err_log("%s", buf + r); } -int -STP_OUT_get_init_port_cfg(IN int vlan_id, - IN int port_index, INOUT UID_STP_PORT_CFG_T * cfg) +void *STP_OUT_mem_zalloc(unsigned int size) { - LOG("port index %d", port_index); - struct ifdata *port = find_port(port_index); - TST(port != NULL, 0); - TST(vlan_id == 0, 0); - - cfg->port_priority = port->port_priority; - cfg->admin_non_stp = port->admin_non_stp; - cfg->admin_edge = port->admin_edge; - cfg->admin_port_path_cost = port->admin_port_path_cost; - cfg->admin_point2point = port->admin_point2point; - - return 0; + return calloc(1, size); } -extern void stp_trace(const char *fmt, ...) + +void STP_OUT_mem_free(void *p) { - va_list ap; - va_start(ap, fmt); - vDprintf(LOG_LEVEL_RSTPLIB, fmt, ap); - va_end(ap); + free(p); } + /* Commands and status */ #include "ctl_functions.h" #define CTL_CHECK_BRIDGE \ - struct ifdata *br = find_if(br_index); \ - if (br == NULL || !br->is_bridge) return Err_Interface_not_a_bridge; \ - if (!br->do_stp) return Err_Bridge_RSTP_not_enabled; \ - if (!br->stp_up) return Err_Bridge_is_down; \ - do { } while (0) + struct ifdata *br = find_if(br_index); \ + if (br == NULL || !br->is_bridge) { \ + ERROR("Couldn't find bridge with index %d", br_index); \ + return -1; \ + } \ + do { } while (0) #define CTL_CHECK_BRIDGE_PORT \ - CTL_CHECK_BRIDGE; \ - struct ifdata *port = find_if(port_index); \ - if (port == NULL || port->is_bridge || port->master != br) \ - return Err_Port_does_not_belong_to_bridge; \ - do { } while (0) + CTL_CHECK_BRIDGE; \ + struct ifdata *port = find_if(port_index); \ + if (port == NULL || port->is_bridge || port->master != br) { \ + ERROR("Interface with index %d not a port of bridge " \ + "with index %d", port_index, br_index); \ + return -1; \ + } \ + do { } while (0) int CTL_enable_bridge_rstp(int br_index, int enable) { @@ -922,110 +622,77 @@ int CTL_enable_bridge_rstp(int br_index, int enable) if (if_indextoname(br_index, ifname) && is_bridge(ifname)) br = create_if(br_index, NULL); } - if (br == NULL || !br->is_bridge) - return Err_Interface_not_a_bridge; - if (br->do_stp != enable) { - br->do_stp = enable; - if (br->up) - r = enable ? init_bridge_stp(br) - : (clear_bridge_stp(br), 0); + if (br == NULL || !br->is_bridge) { + ERROR("Couldn't find bridge with index %d", br_index); + return -1; } + if (br->up) + set_br_up(br, 1); return r; } -int CTL_get_bridge_state(int br_index, - UID_STP_CFG_T * cfg, UID_STP_STATE_T * state) +int CTL_get_bridge_status(int br_index, STP_BridgeStatus *status) { LOG("bridge %d", br_index); CTL_CHECK_BRIDGE; - int r; - instance_begin(br); - r = STP_IN_stpm_get_state(0, state); - if (r) { - ERROR("Error getting bridge state for %d: %s", br_index, - STP_IN_get_error_explanation(r)); - instance_end(); - return r; - } - r = STP_IN_stpm_get_cfg(0, cfg); - if (r) { - ERROR("Error getting bridge config for %d: %s", br_index, - STP_IN_get_error_explanation(r)); - instance_end(); - return r; - } - instance_end(); + + STP_IN_get_bridge_status(br->stp_bridge, status); return 0; } -int CTL_set_bridge_config(int br_index, UID_STP_CFG_T * cfg) +int CTL_set_bridge_config(int br_index, STP_BridgeConfig *cfg) { - INFO("bridge %d, flags %#lx", br_index, cfg->field_mask); + INFO("bridge %d", br_index); CTL_CHECK_BRIDGE; - int r; - instance_begin(br); - r = STP_IN_stpm_set_cfg(0, NULL, cfg); + + if (cfg->set_bridge_address) { + ERROR("Setting bridge address not permitted: %s", br->name); + return -1; + } + + int r = STP_IN_set_bridge_config(br->stp_bridge, cfg); + if (r) { - ERROR("Error setting bridge config for %d: %s", br_index, - STP_IN_get_error_explanation(r)); - instance_end(); + ERROR("Error setting bridge config for %s", br->name); return r; } - instance_end(); - /* Change init config in ifdata so it will be applied if we - disable and enable rstp */ - update_bridge_stp_config(br, cfg); return 0; } -int CTL_get_port_state(int br_index, int port_index, - UID_STP_PORT_CFG_T * cfg, UID_STP_PORT_STATE_T * state) +int CTL_get_port_status(int br_index, int port_index, STP_PortStatus *status) { LOG("bridge %d port %d", br_index, port_index); CTL_CHECK_BRIDGE_PORT; - int r; - instance_begin(br); - state->port_no = port->port_index; - r = STP_IN_port_get_state(0, state); - if (r) { - ERROR("Error getting port state for port %d, bridge %d: %s", - port->port_index, br_index, - STP_IN_get_error_explanation(r)); - instance_end(); - return r; - } - r = STP_IN_port_get_cfg(0, port->port_index, cfg); + + STP_IN_get_port_status(port->stp_port, status); + return 0; +} + +int CTL_set_port_config(int br_index, int port_index, STP_PortConfig *cfg) +{ + INFO("bridge %d, port %d", br_index, port_index); + CTL_CHECK_BRIDGE_PORT; + + int r = STP_IN_set_port_config(port->stp_port, cfg); if (r) { - ERROR("Error getting port config for port %d, bridge %d: %s", - port->port_index, br_index, - STP_IN_get_error_explanation(r)); - instance_end(); + ERROR("Error setting port config for %s", port->name); return r; } - instance_end(); + return 0; - } -int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg) +int CTL_port_mcheck(int br_index, int port_index) { - INFO("bridge %d, port %d, flags %#lx", br_index, port_index, - cfg->field_mask); + INFO("bridge %d, port %d", br_index, port_index); CTL_CHECK_BRIDGE_PORT; - int r; - instance_begin(br); - r = STP_IN_set_port_cfg(0, port->port_index, cfg); + + int r = STP_IN_port_mcheck(port->stp_port); if (r) { - ERROR("Error setting port config for port %d, bridge %d: %s", - port->port_index, br_index, - STP_IN_get_error_explanation(r)); - instance_end(); + ERROR("Error doing port mcheck for %s", port->name); return r; } - instance_end(); - /* Change init config in ifdata so it will be applied if we - disable and enable rstp */ - update_port_stp_config(port, cfg); + return 0; } diff --git a/ctl_cli_wrap.c b/ctl_cli_wrap.c index 72665a8..6edde4a 100644 --- a/ctl_cli_wrap.c +++ b/ctl_cli_wrap.c @@ -28,30 +28,12 @@ #include "log.h" CLIENT_SIDE_FUNCTION(enable_bridge_rstp) - CLIENT_SIDE_FUNCTION(get_bridge_state) - CLIENT_SIDE_FUNCTION(set_bridge_config) - CLIENT_SIDE_FUNCTION(get_port_state) - CLIENT_SIDE_FUNCTION(set_port_config) - CLIENT_SIDE_FUNCTION(set_debug_level) -#include -const char *CTL_error_explanation(int err_no) -{ -#define CHOOSE(a) #a - static const char *rstp_error_names[] = RSTP_ERRORS; - static const char *ctl_error_names[] = { CTL_ERRORS }; - -#undef CHOOSE - if (err_no < 0) - return "Error doing ctl command"; - else if (err_no >= STP_OK && err_no < STP_LAST_DUMMY) - return rstp_error_names[err_no]; - else if (err_no > Err_Dummy_Start && err_no < Err_Dummy_End) - return ctl_error_names[err_no - Err_Dummy_Start - 1]; - - static char buf[32]; - sprintf(buf, "Unknown error code %d", err_no); - return buf; -} +CLIENT_SIDE_FUNCTION(get_bridge_status) +CLIENT_SIDE_FUNCTION(set_bridge_config) +CLIENT_SIDE_FUNCTION(get_port_status) +CLIENT_SIDE_FUNCTION(set_port_config) +CLIENT_SIDE_FUNCTION(port_mcheck) +CLIENT_SIDE_FUNCTION(set_debug_level) void Dprintf(int level, const char *fmt, ...) { diff --git a/ctl_functions.h b/ctl_functions.h index 9d630f6..74ac158 100644 --- a/ctl_functions.h +++ b/ctl_functions.h @@ -25,38 +25,20 @@ #ifndef CTL_FUNCTIONS_H #define CTL_FUNCTIONS_H -#include -#include +#include "rstp.h" int CTL_enable_bridge_rstp(int br_index, int enable); -int CTL_get_bridge_state(int br_index, - UID_STP_CFG_T * cfg, UID_STP_STATE_T * state); +int CTL_get_bridge_status(int br_index, STP_BridgeStatus *status); -int CTL_set_bridge_config(int br_index, UID_STP_CFG_T * cfg); +int CTL_set_bridge_config(int br_index, STP_BridgeConfig *cfg); -int CTL_get_port_state(int br_index, int port_index, - UID_STP_PORT_CFG_T * cfg, UID_STP_PORT_STATE_T * state); +int CTL_get_port_status(int br_index, int port_index, STP_PortStatus *status); -int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg); +int CTL_set_port_config(int br_index, int port_index, STP_PortConfig *cfg); -int CTL_set_debug_level(int level); - -#define CTL_ERRORS \ - CHOOSE(Err_Interface_not_a_bridge), \ - CHOOSE(Err_Bridge_RSTP_not_enabled), \ - CHOOSE(Err_Bridge_is_down), \ - CHOOSE(Err_Port_does_not_belong_to_bridge), \ - -#define CHOOSE(a) a +int CTL_port_mcheck(int br_index, int port_index); -enum Errors { - Err_Dummy_Start = 1000, - CTL_ERRORS Err_Dummy_End -}; - -#undef CHOOSE - -const char *CTL_error_explanation(int err); +int CTL_set_debug_level(int level); #endif diff --git a/ctl_main.c b/ctl_main.c index 8eaa76d..82bf02c 100644 --- a/ctl_main.c +++ b/ctl_main.c @@ -20,73 +20,6 @@ #include "ctl_socket_client.h" #include "ctl_functions.h" -#ifndef False -# define False 0 -# define True 1 -#endif - -#define STP_IN_get_error_explanation CTL_error_explanation - -static void print_bridge_id(UID_BRIDGE_ID_T * bridge_id, unsigned char cr) -{ - printf("%04lX-%02x%02x%02x%02x%02x%02x", - (unsigned long)bridge_id->prio, - (unsigned char)bridge_id->addr[0], - (unsigned char)bridge_id->addr[1], - (unsigned char)bridge_id->addr[2], - (unsigned char)bridge_id->addr[3], - (unsigned char)bridge_id->addr[4], - (unsigned char)bridge_id->addr[5]); - if (cr) - printf("\n"); -} - -static char *stp_state2str(RSTP_PORT_STATE stp_port_state, int detail) -{ - if (detail) { - switch (stp_port_state) { - case UID_PORT_DISABLED: - return "Disabled"; - case UID_PORT_DISCARDING: - return "Discarding"; - case UID_PORT_LEARNING: - return "Learning"; - case UID_PORT_FORWARDING: - return "Forwarding"; - case UID_PORT_NON_STP: - return "NoStp"; - default: - return "Unknown"; - } - } - - switch (stp_port_state) { - case UID_PORT_DISABLED: - return "Dis"; - case UID_PORT_DISCARDING: - return "Blk"; - case UID_PORT_LEARNING: - return "Lrn"; - case UID_PORT_FORWARDING: - return "Fwd"; - case UID_PORT_NON_STP: - return "Non"; - default: - return "Unk"; - } -} - -static void CLI_out_port_id(int port, unsigned char cr) -{ - static char ifname[IFNAMSIZ]; - if (if_indextoname(port, ifname)) - printf("%s", ifname); - else - printf("Ifindex %02d", port); - if (cr) - printf("\n"); -} - int get_index_die(const char *ifname, const char *doc, int die) { int r = if_nametoindex(ifname); @@ -106,99 +39,44 @@ int get_index(const char *ifname, const char *doc) return get_index_die(ifname, doc, 1); } -static int cmd_rstp(int argc, char *const *argv) -{ - int stp, r; - int br_index = get_index(argv[1], "bridge"); +#define BR_ID_FMT "%02x%02x.%02x%02x%02x%02x%02x%02x" +#define BR_ID_ARGS(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7] - if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes") - || !strcmp(argv[2], "1")) - stp = 1; - else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no") - || !strcmp(argv[2], "0")) - stp = 0; - else { - fprintf(stderr, "expect on/off for argument\n"); - return 1; - } - r = CTL_enable_bridge_rstp(br_index, stp); - if (r) { - fprintf(stderr, "Failed to enable/disable RSTP: %s\n", - CTL_error_explanation(r)); - return -1; - } - return 0; -} +#define BOOL_STR(x) ((x) ? "yes" : "no") static int do_showbridge(const char *br_name) { - UID_STP_STATE_T uid_state; - UID_STP_CFG_T uid_cfg; + STP_BridgeStatus s; int br_index = get_index_die(br_name, "bridge", 0); if (br_index < 0) return -1; - int r = CTL_get_bridge_state(br_index, &uid_cfg, &uid_state); + int r = CTL_get_bridge_status(br_index, &s); if (r) { - fprintf(stderr, "Failed to get bridge state: %s\n", - CTL_error_explanation(r)); return -1; } -#if 0 - printf("Interface: %-7s (tag:%d) State: ", - uid_state.vlan_name, (int)uid_state.vlan_id); -#else - printf("Bridge: %-7s State:", - uid_state.vlan_name); -#endif - switch (uid_state.stp_enabled) { - case STP_ENABLED: - printf("enabled\n"); - break; - case STP_DISABLED: - printf("disabled\n"); - break; - default: - printf("unknown\n"); - return 0; - } - - printf("BridgeId: "); - print_bridge_id(&uid_state.bridge_id, 0); - printf(" Bridge Proirity: %lu (0x%lX)\n", - (unsigned long)uid_state.bridge_id.prio, - (unsigned long)uid_state.bridge_id.prio); - if (uid_cfg.force_version < 2) - printf("Force Version: stp\n"); - - printf("Designated Root: "); - print_bridge_id(&uid_state.designated_root, 1); - if (uid_state.root_port) { - printf("Root Port: %04lx", - (unsigned long)uid_state.root_port); - // CLI_out_port_id (uid_state.root_port & 0xfff, False); - // printf("not implemented"); // XXX - printf(", Root Cost: %-lu\n", - (unsigned long)uid_state.root_path_cost); - } else { - printf("Root Port: none\n"); - } - - if (uid_state.Topo_Change) - printf("Topology Change Count: %lu\n", - uid_state.Topo_Change_Count); - else - printf("Time Since Topology Change: %lu\n", - uid_state.timeSince_Topo_Change); - - printf("Max Age: %2d Bridge Max Age: %-2d\n", - (int)uid_state.max_age, (int)uid_cfg.max_age); - printf("Hello Time: %2d Bridge Hello Time: %-2d\n", - (int)uid_state.hello_time, (int)uid_cfg.hello_time); - printf("Forward Delay: %2d Bridge Forward Delay: %-2d\n", - (int)uid_state.forward_delay, (int)uid_cfg.forward_delay); - printf("Hold Time: %2d\n", (int)uid_cfg.hold_time); + printf("%s\n", br_name); + printf(" enabled\t\t%4s\n", BOOL_STR(s.enabled)); + printf(" bridge id\t\t" BR_ID_FMT "\n", BR_ID_ARGS(s.bridge_id)); + printf(" designated root\t" BR_ID_FMT "\n", + BR_ID_ARGS(s.designated_root)); + //printf(" designated bridge\t\t", BR_ID_FMT "\n", + // BR_ID_ARGS(s.designated_bridge)); + printf(" root port\t\t%4u", s.root_port); + printf("\t\t\tpath cost\t\t%4u\n", s.root_path_cost); + printf(" max age\t\t%4u", s.max_age); + printf("\t\t\tbridge max age\t\t%4u\n", s.bridge_max_age); + printf(" hello time\t\t%4u", s.hello_time); + printf("\t\t\tbridge hello time\t%4u\n", s.bridge_hello_time); + printf(" forward delay\t\t%4u", s.forward_delay); + printf("\t\t\tbridge forward delay\t%4u\n", s.bridge_forward_delay); + printf(" tx hold count\t\t%4u\n", s.tx_hold_count); + printf(" protocol version\t%4u\n", s.protocol_version); + printf(" time since topology change\t%4u\n", + s.time_since_topology_change); + printf(" toplogy change count\t\t%4u\n", s.topology_change_count); + printf(" topology change\t\t%4s\n", BOOL_STR(s.topology_change)); return 0; } @@ -254,157 +132,95 @@ static int cmd_showbridge(int argc, char *const *argv) return r; } + +#define STATE_STR(_state) \ + ({ \ + int _s = _state; \ + char *_str = "unknown"; \ + switch (_s) \ + { \ + case STP_PORT_STATE_DISCARDING: _str = "discarding"; break; \ + case STP_PORT_STATE_LEARNING: _str = "learning"; break; \ + case STP_PORT_STATE_FORWARDING: _str = "forwarding"; break; \ + } \ + _str; \ + }) + +#define SHORT_STATE_STR(_state) \ + ({ \ + int _s = _state; \ + char *_str = "unkn"; \ + switch (_s) \ + { \ + case STP_PORT_STATE_DISCARDING: _str = "disc"; break; \ + case STP_PORT_STATE_LEARNING: _str = "lear"; break; \ + case STP_PORT_STATE_FORWARDING: _str = "forw"; break; \ + } \ + _str; \ + }) + +#define ADMIN_P2P_STR(_state) \ + ({ \ + int _s = _state; \ + char *_str = "unkn"; \ + switch (_s) \ + { \ + case STP_ADMIN_P2P_FORCE_FALSE: _str = "no"; break; \ + case STP_ADMIN_P2P_FORCE_TRUE: _str = "yes"; break; \ + case STP_ADMIN_P2P_AUTO: _str = "auto"; break; \ + } \ + _str; \ + }) + + int detail = 0; -static int do_showport(int br_index, const char *port_name, - UID_STP_STATE_T * uid_state) +static int do_showport(int br_index, const char *port_name) { - UID_STP_PORT_STATE_T uid_port; - UID_STP_PORT_CFG_T uid_cfg; + STP_PortStatus s; int r = 0; int port_index = get_index_die(port_name, "port", 0); if (port_index < 0) return -1; - memset(&uid_cfg, 0, sizeof(UID_STP_PORT_CFG_T)); - r = CTL_get_port_state(br_index, port_index, &uid_cfg, &uid_port); + r = CTL_get_port_status(br_index, port_index, &s); if (r) { - fprintf(stderr, "Failed to get port state for port %d: %s\n", - port_index, CTL_error_explanation(r)); + fprintf(stderr, "Failed to get port state for port %d\n", + port_index); return -1; } if (detail) { - printf("Stp Port "); - CLI_out_port_id(port_index, False); -#if 0 - printf(": PortId: %04lx in vlan '%s' with tag %d:\n", - (unsigned long)uid_port.port_id, uid_state->vlan_name, - (int)uid_state->vlan_id); -#else - printf(": PortId: %04lx in Bridge '%s':\n", - (unsigned long)uid_port.port_id, uid_state->vlan_name); -#endif - printf("Priority: %-d\n", - (int)(uid_port.port_id >> 8)); - printf("State: %-16s", - stp_state2str(uid_port.state, 1)); - printf(" Uptime: %-9lu\n", uid_port.uptime); - printf("PortPathCost: admin: "); - if (ADMIN_PORT_PATH_COST_AUTO == uid_cfg.admin_port_path_cost) - printf("%-9s", "Auto"); - else - printf("%-9lu", uid_cfg.admin_port_path_cost); - printf(" oper: %-9lu\n", uid_port.oper_port_path_cost); - - printf("Point2Point: admin: "); - switch (uid_cfg.admin_point2point) { - case P2P_FORCE_TRUE: - printf("%-9s", "ForceYes"); - break; - case P2P_FORCE_FALSE: - printf("%-9s", "ForceNo"); - break; - case P2P_AUTO: - printf("%-9s", "Auto"); - break; - } - printf(" oper: %-9s\n", - uid_port.oper_point2point ? "Yes" : "No"); - printf("Edge: admin: %-9s oper: %-9s\n", - uid_cfg.admin_edge ? "Y" : "N", - uid_port.oper_edge ? "Y" : "N"); - printf("Partner: oper: %-9s\n", - uid_port.oper_stp_neigb ? "Slow" : "Rapid"); - - if (' ' != uid_port.role) { - if ('-' != uid_port.role) { - printf("PathCost: %-lu\n", - (unsigned long)(uid_port.path_cost)); - printf("Designated Root: "); - print_bridge_id(&uid_port.designated_root, 1); - printf("Designated Cost: %-ld\n", - (unsigned long)uid_port.designated_cost); - printf("Designated Bridge: "); - print_bridge_id(&uid_port.designated_bridge, 1); - printf("Designated Port: %-4lx\n\r", - (unsigned long)uid_port.designated_port); - } - printf("Role: "); - switch (uid_port.role) { - case 'A': - printf("Alternate\n"); - break; - case 'B': - printf("Backup\n"); - break; - case 'R': - printf("Root\n"); - break; - case 'D': - printf("Designated\n"); - break; - case '-': - printf("NonStp\n"); - break; - default: - printf("Unknown(%c)\n", uid_port.role); - break; - } - - if ('R' == uid_port.role || 'D' == uid_port.role) { - /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */ - printf("TcAck: %c ", - uid_port.top_change_ack ? 'Y' : 'N'); - printf("TcWhile: %3d\n", - (int)uid_port.tcWhile); - } - } - - if (UID_PORT_DISABLED == uid_port.state || '-' == uid_port.role) { -#if 0 - printf("helloWhen: %3d ", - (int)uid_port.helloWhen); - printf("lnkWhile: %3d\n", (int)uid_port.lnkWhile); - printf("fdWhile: %3d\n", (int)uid_port.fdWhile); -#endif - } else if ('-' != uid_port.role) { - printf("fdWhile: %3d ", (int)uid_port.fdWhile); - printf("rcvdInfoWhile: %3d\n", - (int)uid_port.rcvdInfoWhile); - printf("rbWhile: %3d ", (int)uid_port.rbWhile); - printf("rrWhile: %3d\n", (int)uid_port.rrWhile); -#if 0 - printf("mdelayWhile: %3d ", - (int)uid_port.mdelayWhile); - printf("lnkWhile: %3d\n", (int)uid_port.lnkWhile); - printf("helloWhen: %3d ", - (int)uid_port.helloWhen); - printf("txCount: %3d\n", (int)uid_port.txCount); -#endif - } - - printf("RSTP BPDU rx: %lu\n", - (unsigned long)uid_port.rx_rstp_bpdu_cnt); - printf("CONFIG BPDU rx: %lu\n", - (unsigned long)uid_port.rx_cfg_bpdu_cnt); - printf("TCN BPDU rx: %lu\n", - (unsigned long)uid_port.rx_tcn_bpdu_cnt); + printf("%s (%u)\n", port_name, (s.id & 0xfff)); + printf(" enabled\t\t%4s\n", BOOL_STR(s.enabled)); + printf(" port id\t\t%04x\t\t\tstate\t\t%15s\n", + s.id, STATE_STR(s.state)); + printf(" path cost\t%12d\t\t\tadmin path cost\t%12d\n", + s.path_cost, s.admin_path_cost); + printf(" designated root\t" BR_ID_FMT, + BR_ID_ARGS(s.designated_root)); + printf("\tdesignated cost\t%12u\n", s.designated_cost); + printf(" designated bridge\t" BR_ID_FMT, + BR_ID_ARGS(s.designated_bridge)); + printf("\tdesignated port\t\t%04x\n", s.designated_port); + printf(" admin edge port\t%4s", BOOL_STR(s.admin_edge_port)); + printf("\t\t\tauto edge port\t\t%4s\n", + BOOL_STR(s.auto_edge_port)); + printf(" oper edge port\t\t%4s", BOOL_STR(s.oper_edge_port)); + printf("\t\t\ttoplogy change ack\t%4s\n", BOOL_STR(s.tc_ack)); + printf(" point to point\t\t%4s", BOOL_STR(s.oper_p2p)); + printf("\t\t\tadmin point to point\t%4s\n", + ADMIN_P2P_STR(s.admin_p2p)); } else { - printf("%c%c%c ", - (uid_port.oper_point2point) ? ' ' : '*', - (uid_port.oper_edge) ? 'E' : ' ', - (uid_port.oper_stp_neigb) ? 's' : ' '); - CLI_out_port_id(port_index, False); - printf(" %04lx %3s ", (unsigned long)uid_port.port_id, - stp_state2str(uid_port.state, 0)); - printf(" "); - print_bridge_id(&uid_port.designated_root, 0); - printf(" "); - print_bridge_id(&uid_port.designated_bridge, 0); - printf(" %4lx %c", (unsigned long)uid_port.designated_port, - uid_port.role); - printf("\n"); + printf("%c%c %4s %04x %4s " BR_ID_FMT " " BR_ID_FMT " %04x\n", + (s.oper_p2p) ? ' ' : '*', + (s.oper_edge_port) ? 'E' : ' ', + port_name, + s.id, + s.enabled?SHORT_STATE_STR(s.state):"down", + BR_ID_ARGS(s.designated_root), + BR_ID_ARGS(s.designated_bridge), + s.designated_port); } return 0; } @@ -418,19 +234,10 @@ static int not_dot_dotdot(const struct dirent *entry) static int cmd_showport(int argc, char *const *argv) { - UID_STP_STATE_T uid_state; - UID_STP_CFG_T uid_br_cfg; int r = 0; int br_index = get_index(argv[1], "bridge"); - r = CTL_get_bridge_state(br_index, &uid_br_cfg, &uid_state); - if (r) { - fprintf(stderr, "Failed to get bridge state: %s\n", - CTL_error_explanation(r)); - return -1; - } - int i, count = 0; struct dirent **namelist; @@ -455,7 +262,7 @@ static int cmd_showport(int argc, char *const *argv) else name = namelist[i]->d_name; - int err = do_showport(br_index, name, &uid_state); + int err = do_showport(br_index, name); if (err) r = err; } @@ -508,170 +315,82 @@ int getyesno(const char *s, const char *yes, const char *no) return 1 - getenum(s, opt); } -static int set_bridge_cfg_value(int br_index, unsigned long value, - unsigned long val_mask) -{ - UID_STP_CFG_T uid_cfg; - char *val_name; - int rc; - - uid_cfg.field_mask = val_mask; - switch (val_mask) { - case BR_CFG_STATE: - uid_cfg.stp_enabled = value; - val_name = "state"; - break; - case BR_CFG_PRIO: - uid_cfg.bridge_priority = value; - val_name = "priority"; - break; - case BR_CFG_AGE: - uid_cfg.max_age = value; - val_name = "max_age"; - break; - case BR_CFG_HELLO: - uid_cfg.hello_time = value; - val_name = "hello_time"; - break; - case BR_CFG_DELAY: - uid_cfg.forward_delay = value; - val_name = "forward_delay"; - break; - case BR_CFG_FORCE_VER: - uid_cfg.force_version = value; - val_name = "force_version"; - break; - case BR_CFG_AGE_MODE: - case BR_CFG_AGE_TIME: - default: - printf("Invalid value mask 0X%lx\n", val_mask); - return -1; - break; - } - - rc = CTL_set_bridge_config(br_index, &uid_cfg); - - if (0 != rc) { - printf("Can't change rstp bridge %s:%s\n", val_name, - STP_IN_get_error_explanation(rc)); - return -1; - } - return 0; -} - -static int cmd_setbridgestate(int argc, char *const *argv) -{ +#define set_bridge_cfg(field, value) \ +({ \ + STP_BridgeConfig c; \ + memset(&c, 0, sizeof(c)); \ + c.field = value; \ + c.set_ ## field = 1; \ + int r = CTL_set_bridge_config(br_index, &c); \ + if (r) \ + printf("Couldn't change bridge " #field "\n"); \ + r; \ +}) + +#define set_port_cfg(field, value) \ +({ \ + STP_PortConfig c; \ + memset(&c, 0, sizeof(c)); \ + c.field = value; \ + c.set_ ## field = 1; \ + int r = CTL_set_port_config(br_index, port_index, &c); \ + if (r) \ + printf("Couldn't change port " #field "\n"); \ + r; \ +}) + - int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, - getyesno(argv[2], "on", "off"), - BR_CFG_STATE); -} static int cmd_setbridgeprio(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_PRIO); + return set_bridge_cfg(bridge_priority, getuint(argv[2])); } static int cmd_setbridgemaxage(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_AGE); + return set_bridge_cfg(bridge_max_age, getuint(argv[2])); } static int cmd_setbridgehello(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_HELLO); + return set_bridge_cfg(bridge_hello_time, getuint(argv[2])); } static int cmd_setbridgefdelay(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_DELAY); + return set_bridge_cfg(bridge_forward_delay, getuint(argv[2])); } static int cmd_setbridgeforcevers(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); - return set_bridge_cfg_value(br_index, - 2 * getyesno(argv[2], "normal", "slow"), - BR_CFG_FORCE_VER); + return set_bridge_cfg(bridge_protocol_version, + 2 * getyesno(argv[2], "normal", "slow")); } -static int -set_port_cfg_value(int br_index, int port_index, - unsigned long value, unsigned long val_mask) +static int cmd_setbridgetxholdcount(int argc, char *const *argv) { - UID_STP_PORT_CFG_T uid_cfg; - int rc; - char *val_name; - - BitmapClear(&uid_cfg.port_bmp); - uid_cfg.field_mask = val_mask; - switch (val_mask) { - case PT_CFG_MCHECK: - val_name = "mcheck"; - break; - case PT_CFG_COST: - uid_cfg.admin_port_path_cost = value; - val_name = "path cost"; - break; - case PT_CFG_PRIO: - uid_cfg.port_priority = value; - val_name = "priority"; - break; - case PT_CFG_P2P: - uid_cfg.admin_point2point = (ADMIN_P2P_T) value; - val_name = "p2p flag"; - break; - case PT_CFG_EDGE: - uid_cfg.admin_edge = value; - val_name = "adminEdge"; - break; - case PT_CFG_NON_STP: - uid_cfg.admin_non_stp = value; - val_name = "adminNonStp"; - break; -#ifdef STP_DBG - case PT_CFG_DBG_SKIP_TX: - uid_cfg.skip_tx = value; - val_name = "skip tx"; - break; - case PT_CFG_DBG_SKIP_RX: - uid_cfg.skip_rx = value; - val_name = "skip rx"; - break; -#endif - case PT_CFG_STATE: - default: - printf("Invalid value mask 0X%lx\n", val_mask); - return -1; - } - rc = CTL_set_port_config(br_index, port_index, &uid_cfg); - - if (0 != rc) { - printf("can't change rstp port[s] %s: %s\n", - val_name, STP_IN_get_error_explanation(rc)); - return -1; - } - return 0; + int br_index = get_index(argv[1], "bridge"); + return set_bridge_cfg(bridge_tx_hold_count, getuint(argv[2])); } + static int cmd_setportprio(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - return set_port_cfg_value(br_index, port_index, - getuint(argv[3]), PT_CFG_PRIO); + return set_port_cfg(port_priority, getuint(argv[3])); } static int cmd_setportpathcost(int argc, char *const *argv) @@ -679,27 +398,23 @@ static int cmd_setportpathcost(int argc, char *const *argv) int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - return set_port_cfg_value(br_index, port_index, - getuint(argv[3]), PT_CFG_COST); + return set_port_cfg(port_pathcost, getuint(argv[3])); } -static int cmd_setportedge(int argc, char *const *argv) +static int cmd_setportadminedge(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - return set_port_cfg_value(br_index, port_index, - getyesno(argv[3], "yes", "no"), PT_CFG_EDGE); + return set_port_cfg(port_admin_edge, getyesno(argv[3], "yes", "no")); } -static int cmd_setportnonstp(int argc, char *const *argv) +static int cmd_setportautoedge(int argc, char *const *argv) { int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - return set_port_cfg_value(br_index, port_index, - getyesno(argv[3], "yes", "no"), - PT_CFG_NON_STP); + return set_port_cfg(port_auto_edge, getyesno(argv[3], "yes", "no")); } static int cmd_setportp2p(int argc, char *const *argv) @@ -707,11 +422,11 @@ static int cmd_setportp2p(int argc, char *const *argv) int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - const char *opts[] = { "yes", "no", "auto", NULL }; - int vals[] = { P2P_FORCE_TRUE, P2P_FORCE_FALSE, P2P_AUTO }; + const char *opts[] = { "no", "yes", "auto", NULL }; + int vals[] = { STP_ADMIN_P2P_FORCE_FALSE, STP_ADMIN_P2P_FORCE_TRUE, + STP_ADMIN_P2P_AUTO }; - return set_port_cfg_value(br_index, port_index, - vals[getenum(argv[3], opts)], PT_CFG_P2P); + return set_port_cfg(port_admin_p2p, vals[getenum(argv[3], opts)]); } static int cmd_portmcheck(int argc, char *const *argv) @@ -719,7 +434,7 @@ static int cmd_portmcheck(int argc, char *const *argv) int br_index = get_index(argv[1], "bridge"); int port_index = get_index(argv[2], "port"); - return set_port_cfg_value(br_index, port_index, 0, PT_CFG_MCHECK); + return CTL_port_mcheck(br_index, port_index); } static int cmd_debuglevel(int argc, char *const *argv) @@ -742,10 +457,6 @@ static const struct command commands[] = { " [ ... ]\tshow port state"}, {1, 32, "showportdetail", cmd_showportdetail, " [ ... ]\tshow port state (detail)"}, - {2, 0, "rstp", cmd_rstp, - " {on|off}\tenable/disable rstpd control"}, - {2, 0, "setbridgestate", cmd_setbridgestate, - " {on|off}\tstart/stop rstp (when enabled)"}, {2, 0, "setbridgeprio", cmd_setbridgeprio, " \tset bridge priority (0-61440)"}, {2, 0, "sethello", cmd_setbridgehello, @@ -756,14 +467,16 @@ static const struct command commands[] = { " \tset bridge forward delay (4-30)"}, {2, 0, "setforcevers", cmd_setbridgeforcevers, " {normal|slow}\tnormal RSTP or force to STP"}, + {2, 0, "settxholdcount", cmd_setbridgetxholdcount, + " \tset bridge transmit hold count (1-10)"}, {3, 0, "setportprio", cmd_setportprio, " \tset port priority (0-240)"}, {3, 0, "setportpathcost", cmd_setportpathcost, " \tset port path cost"}, - {3, 0, "setportedge", cmd_setportedge, - " {yes|no}\tconfigure if it is an edge port"}, - {3, 0, "setportnonstp", cmd_setportnonstp, - " {yes|no}\tdisable STP for the port"}, + {3, 0, "setportadminedge", cmd_setportadminedge, + " {yes|no}\tconfigure if it is an admin edge port"}, + {3, 0, "setportautoedge", cmd_setportautoedge, + " {yes|no}\tconfigure if it is an auto edge port"}, {3, 0, "setportp2p", cmd_setportp2p, " {yes|no|auto}\tset whether p2p connection"}, {2, 0, "portmcheck", cmd_portmcheck, diff --git a/ctl_socket.c b/ctl_socket.c index f37e8b1..d918861 100644 --- a/ctl_socket.c +++ b/ctl_socket.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "epoll_loop.h" #include "log.h" @@ -59,14 +61,15 @@ int server_socket(void) return s; } -int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout) +int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int lout) { switch (cmd) { SERVER_MESSAGE_CASE(enable_bridge_rstp); - SERVER_MESSAGE_CASE(get_bridge_state); + SERVER_MESSAGE_CASE(get_bridge_status); SERVER_MESSAGE_CASE(set_bridge_config); - SERVER_MESSAGE_CASE(get_port_state); + SERVER_MESSAGE_CASE(get_port_status); SERVER_MESSAGE_CASE(set_port_config); + SERVER_MESSAGE_CASE(port_mcheck); SERVER_MESSAGE_CASE(set_debug_level); default: @@ -75,28 +78,52 @@ int handle_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout) } } +int ctl_in_handler = 0; +static unsigned char msg_logbuf[1024]; +static unsigned int msg_log_offset; +void _ctl_err_log(char *fmt, ...) +{ + if (msg_log_offset >= sizeof(msg_logbuf) - 1) + return; + int r; + va_list ap; + va_start(ap, fmt); + r = vsnprintf((char *)msg_logbuf + msg_log_offset, + sizeof(msg_logbuf) - msg_log_offset, + fmt, ap); + va_end(ap); + msg_log_offset += r; + if (msg_log_offset == sizeof(msg_logbuf)) { + msg_log_offset = sizeof(msg_logbuf) - 1; + msg_logbuf[sizeof(msg_logbuf) - 1] = 0; + } +} + + #define msg_buf_len 1024 -unsigned char msg_inbuf[1024]; -unsigned char msg_outbuf[1024]; +static unsigned char msg_inbuf[1024]; +static unsigned char msg_outbuf[1024]; void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p) { struct ctl_msg_hdr mhdr; struct msghdr msg; struct sockaddr_un sa; - struct iovec iov[2]; + struct iovec iov[3]; int l; msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_iov = iov; - msg.msg_iovlen = 2; + msg.msg_iovlen = 3; msg.msg_control = NULL; msg.msg_controllen = 0; iov[0].iov_base = &mhdr; iov[0].iov_len = sizeof(mhdr); iov[1].iov_base = msg_inbuf; iov[1].iov_len = msg_buf_len; + iov[2].iov_base = NULL; + iov[2].iov_len = 0; l = recvmsg(p->fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT); TST(l > 0,); if (msg.msg_flags != 0 || l < sizeof(mhdr) || @@ -106,17 +133,22 @@ void ctl_rcv_handler(uint32_t events, struct epoll_event_handler *p) return; } - if (mhdr.lout) - mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, - msg_outbuf, &mhdr.lout); - else - mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, - NULL, NULL); + msg_log_offset = 0; + ctl_in_handler = 1; + + mhdr.res = handle_message(mhdr.cmd, msg_inbuf, mhdr.lin, + msg_outbuf, mhdr.lout); + ctl_in_handler = 0; if (mhdr.res < 0) - mhdr.lout = 0; + memset(msg_outbuf, 0, mhdr.lout); + if (msg_log_offset < mhdr.llog) + mhdr.llog = msg_log_offset; + iov[1].iov_base = msg_outbuf; iov[1].iov_len = mhdr.lout; + iov[2].iov_base = msg_logbuf; + iov[2].iov_len = mhdr.llog; l = sendmsg(p->fd, &msg, MSG_NOSIGNAL); if (l < 0) ERROR("CTL: Couldn't send response: %m"); diff --git a/ctl_socket.h b/ctl_socket.h index 089a717..a41c322 100644 --- a/ctl_socket.h +++ b/ctl_socket.h @@ -34,9 +34,17 @@ struct ctl_msg_hdr { int cmd; int lin; int lout; + int llog; int res; }; +#define LOG_STRING_LEN 256 + +typedef struct _log_string +{ + char buf[LOG_STRING_LEN]; +} LogString; + #define set_socket_address(sa, string) \ do {\ (sa)->sun_family = AF_UNIX; \ @@ -65,31 +73,29 @@ struct enable_bridge_rstp_OUT { #define enable_bridge_rstp_CALL (in->br_index, in->enable) #if 0 -int CTL_get_bridge_state(int br_index, - UID_STP_CFG_T * cfg, UID_STP_STATE_T * state); +int CTL_get_bridge_status(int br_index, STP_BridgeStatus *status); #endif -#define CMD_CODE_get_bridge_state 102 -#define get_bridge_state_ARGS (int br_index, UID_STP_CFG_T *cfg, UID_STP_STATE_T *state) -struct get_bridge_state_IN { +#define CMD_CODE_get_bridge_status 102 +#define get_bridge_status_ARGS (int br_index, STP_BridgeStatus *status) +struct get_bridge_status_IN { int br_index; }; -struct get_bridge_state_OUT { - UID_STP_CFG_T cfg; - UID_STP_STATE_T state; +struct get_bridge_status_OUT { + STP_BridgeStatus status; }; -#define get_bridge_state_COPY_IN \ +#define get_bridge_status_COPY_IN \ ({ in->br_index = br_index; }) -#define get_bridge_state_COPY_OUT ({ *cfg = out->cfg; *state = out->state; }) -#define get_bridge_state_CALL (in->br_index, &out->cfg, &out->state) +#define get_bridge_status_COPY_OUT ({ *status = out->status; }) +#define get_bridge_status_CALL (in->br_index, &out->status) #if 0 -int CTL_set_bridge_config(int br_index, UID_STP_CFG_T * cfg); +int CTL_set_bridge_config(int br_index, STP_BridgeConfig *cfg); #endif #define CMD_CODE_set_bridge_config 103 -#define set_bridge_config_ARGS (int br_index, UID_STP_CFG_T *cfg) +#define set_bridge_config_ARGS (int br_index, STP_BridgeConfig *cfg) struct set_bridge_config_IN { int br_index; - UID_STP_CFG_T cfg; + STP_BridgeConfig cfg; }; struct set_bridge_config_OUT { }; @@ -99,33 +105,31 @@ struct set_bridge_config_OUT { #define set_bridge_config_CALL (in->br_index, &in->cfg) #if 0 -int CTL_get_port_state(int br_index, int port_index, - UID_STP_PORT_CFG_T * cfg, UID_STP_PORT_STATE_T * state); +int CTL_get_port_status(int br_index, int port_index, STP_PortStatus *status); #endif -#define CMD_CODE_get_port_state 104 -#define get_port_state_ARGS (int br_index, int port_index, UID_STP_PORT_CFG_T *cfg, UID_STP_PORT_STATE_T *state) -struct get_port_state_IN { +#define CMD_CODE_get_port_status 104 +#define get_port_status_ARGS (int br_index, int port_index, STP_PortStatus *status) +struct get_port_status_IN { int br_index; int port_index; }; -struct get_port_state_OUT { - UID_STP_PORT_CFG_T cfg; - UID_STP_PORT_STATE_T state; +struct get_port_status_OUT { + STP_PortStatus status; }; -#define get_port_state_COPY_IN \ +#define get_port_status_COPY_IN \ ({ in->br_index = br_index; in->port_index = port_index; }) -#define get_port_state_COPY_OUT ({ *cfg = out->cfg; *state = out->state; }) -#define get_port_state_CALL (in->br_index, in->port_index, &out->cfg, &out->state) +#define get_port_status_COPY_OUT ({ *status = out->status; }) +#define get_port_status_CALL (in->br_index, in->port_index, &out->status) #if 0 -int CTL_set_port_config(int br_index, int port_index, UID_STP_PORT_CFG_T * cfg); +int CTL_set_port_config(int br_index, int port_index, STP_PortConfig *cfg); #endif #define CMD_CODE_set_port_config 105 -#define set_port_config_ARGS (int br_index, int port_index, UID_STP_PORT_CFG_T *cfg) +#define set_port_config_ARGS (int br_index, int port_index, STP_PortConfig *cfg) struct set_port_config_IN { int br_index; int port_index; - UID_STP_PORT_CFG_T cfg; + STP_PortConfig cfg; }; struct set_port_config_OUT { }; @@ -134,10 +138,26 @@ struct set_port_config_OUT { #define set_port_config_COPY_OUT ({ (void)0; }) #define set_port_config_CALL (in->br_index, in->port_index, &in->cfg) +#if 0 +int CTL_port_mcheck(int br_index, int port_index); +#endif +#define CMD_CODE_port_mcheck 106 +#define port_mcheck_ARGS (int br_index, int port_index) +struct port_mcheck_IN { + int br_index; + int port_index; +}; +struct port_mcheck_OUT { +}; +#define port_mcheck_COPY_IN \ + ({ in->br_index = br_index; in->port_index = port_index; }) +#define port_mcheck_COPY_OUT ({ (void)0; }) +#define port_mcheck_CALL (in->br_index, in->port_index) + #if 0 int CTL_set_debug_level(int level); #endif -#define CMD_CODE_set_debug_level 106 +#define CMD_CODE_set_debug_level 107 #define set_debug_level_ARGS (int level) struct set_debug_level_IN { int level; @@ -155,15 +175,15 @@ case CMD_CODE_ ## name : do { \ if (0) LOG("CTL command " #name); \ struct name ## _IN in0, *in = &in0; \ struct name ## _OUT out0, *out = &out0; \ - if (sizeof(*in) != lin || sizeof(*out) != (outbuf?*lout:0)) { \ + if (sizeof(*in) != lin || sizeof(*out) != lout) { \ LOG("Bad sizes lin %d != %zd or lout %d != %zd", \ - lin, sizeof(*in), lout?*lout:0, sizeof(*out)); \ + lin, sizeof(*in), lout, sizeof(*out)); \ return -1; \ } \ memcpy(in, inbuf, lin); \ int r = CTL_ ## name name ## _CALL; \ if (r) return r; \ - if (outbuf) memcpy(outbuf, out, *lout); \ + if (outbuf) memcpy(outbuf, out, lout); \ return r; \ } while (0) @@ -173,16 +193,16 @@ int CTL_ ## name name ## _ARGS \ { \ struct name ## _IN in0, *in=&in0; \ struct name ## _OUT out0, *out = &out0; \ - int l = sizeof(*out); \ name ## _COPY_IN; \ int res = 0; \ - int r = send_ctl_message(CMD_CODE_ ## name, in, sizeof(*in), out, &l, \ - &res); \ - if (r || res) LOG("Got return code %d, %d", r, res); \ + LogString log = { .buf = "" }; \ + int r = send_ctl_message(CMD_CODE_ ## name, in, sizeof(*in), \ + out, sizeof(*out), &log, &res); \ + if (r || res) LOG("Got return code %d, %d\n%s", r, res, log.buf); \ if (r) return r; \ if (res) return res; \ name ## _COPY_OUT; \ - return r; \ + return 0; \ } #endif diff --git a/ctl_socket_client.c b/ctl_socket_client.c index 46d5851..1a219bc 100644 --- a/ctl_socket_client.c +++ b/ctl_socket_client.c @@ -32,6 +32,7 @@ #include #include +#define NO_DAEMON #include "log.h" static int fd = -1; @@ -81,28 +82,31 @@ void ctl_client_cleanup(void) } } -int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout, - int *res) +int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int lout, + LogString *log, int *res) { struct ctl_msg_hdr mhdr; struct msghdr msg; - struct iovec iov[2]; + struct iovec iov[3]; int l; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; - msg.msg_iovlen = 2; + msg.msg_iovlen = 3; msg.msg_control = NULL; msg.msg_controllen = 0; mhdr.cmd = cmd; mhdr.lin = lin; - mhdr.lout = lout != NULL ? *lout : 0; + mhdr.lout = lout; + mhdr.llog = sizeof(log->buf) - 1; iov[0].iov_base = &mhdr; iov[0].iov_len = sizeof(mhdr); iov[1].iov_base = (void *)inbuf; iov[1].iov_len = lin; + iov[2].iov_base = log->buf; + iov[2].iov_len = 0; l = sendmsg(fd, &msg, 0); if (l < 0) { @@ -115,7 +119,10 @@ int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout, } iov[1].iov_base = outbuf; - iov[1].iov_len = lout != NULL ? *lout : 0; + iov[1].iov_len = lout; + + iov[2].iov_base = log->buf; + iov[2].iov_len = sizeof(log->buf); { struct pollfd pfd; @@ -145,16 +152,24 @@ int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout, ERROR("Error getting message from server: %m"); return -1; } - if (l < sizeof(mhdr) || l != sizeof(mhdr) + mhdr.lout + if (l < sizeof(mhdr) + || l != sizeof(mhdr) + mhdr.lout + mhdr.llog || mhdr.cmd != cmd) { ERROR("Error getting message from server: Bad format"); return -1; } + if (mhdr.lout != lout) { + ERROR("Error, unexpected result length %d, " + "expected %d\n", mhdr.lout, lout); + return -1; + } + if (mhdr.llog >= sizeof(log->buf)) { + ERROR("Invalid log message length %d", mhdr.llog); + return -1; + } } - if (lout) - *lout = mhdr.lout; if (res) *res = mhdr.res; - + log->buf[mhdr.llog] = 0; return 0; } diff --git a/ctl_socket_client.h b/ctl_socket_client.h index 5d8a7d3..c3f2fac 100644 --- a/ctl_socket_client.h +++ b/ctl_socket_client.h @@ -25,8 +25,10 @@ #ifndef CTL_SOCKET_CLIENT_H #define CTL_SOCKET_CLIENT_H -int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int *lout, - int *res); +#include "ctl_socket.h" + +int send_ctl_message(int cmd, void *inbuf, int lin, void *outbuf, int lout, + LogString *log, int *res); int ctl_client_init(void); diff --git a/ctl_socket_server.h b/ctl_socket_server.h index 88f6bf4..df18ad3 100644 --- a/ctl_socket_server.h +++ b/ctl_socket_server.h @@ -28,4 +28,9 @@ int ctl_socket_init(void); void ctl_socket_cleanup(void); +extern int ctl_in_handler; +void _ctl_err_log(char *fmt, ...); + +#define ctl_err_log(_fmt...) ({ if (ctl_in_handler) _ctl_err_log(_fmt); }) + #endif diff --git a/log.h b/log.h index 1452438..ce0d94e 100644 --- a/log.h +++ b/log.h @@ -27,12 +27,12 @@ #include #include +#include "ctl_socket_server.h" #define LOG_LEVEL_NONE 0 #define LOG_LEVEL_ERROR 1 #define LOG_LEVEL_INFO 2 #define LOG_LEVEL_DEBUG 3 -#define LOG_LEVEL_RSTPLIB 4 #define LOG_LEVEL_MAX 100 #define LOG_LEVEL_DEFAULT LOG_LEVEL_INFO @@ -60,9 +60,18 @@ extern int log_level; #define INFO(_fmt, _args...) \ PRINT(LOG_LEVEL_INFO, "%s: " _fmt, __PRETTY_FUNCTION__, ##_args) +#ifdef NO_DAEMON + #define ERROR(_fmt, _args...) \ - PRINT(LOG_LEVEL_ERROR, "error, %s: " _fmt, __PRETTY_FUNCTION__, ##_args) + PRINT(LOG_LEVEL_ERROR, "%s: " _fmt, ##_args) +#else +#define ERROR(_fmt, _args...) \ + ({ \ + PRINT(LOG_LEVEL_ERROR, "error, %s: " _fmt, __PRETTY_FUNCTION__, ##_args); \ + ctl_err_log(_fmt "\n", ##_args); \ + }) +#endif static inline void dump_hex(void *b, int l) { unsigned char *buf = b; diff --git a/rstpctl.8 b/rstpctl.8 index 456a879..ca72eaf 100644 --- a/rstpctl.8 +++ b/rstpctl.8 @@ -18,11 +18,6 @@ command. .SH COMMANDS -.B rstpctl rstp {on|off} -configures whether rstpd implements RSTP (Rapid Spanning Tree -Protocol) for the specified bridge. The remaining commands are -applicable only if rstpd is configured to run RSTP on that bridge. - .B rstpctl showbridge [ ... ] displays the spanning tree configuration and status for the specified bridges. If no bridges are given, it displays the information for all @@ -35,7 +30,7 @@ the information for all ports of the bridge. The format of the line is : .br -.B "pes name iiii sss rrrr-rootbridgeid dddd-desgbridgeid dprt R" +.B "pe name iiii ssss rrrr-rootbridgeid dddd-desgbridgeid dprt" .br where the following abbreviations are used. @@ -43,23 +38,18 @@ where the following abbreviations are used. .br \fBe\fR: 'E' if the port is operating as an edge port, ' ' otherwise. .br -\fBs\fR: 's' if the port is in STP (slow) mode, ' ' otherwise. -.br \fBname\fR: The name of the port, i.e, the network interface name. .br \fBiiii\fR: The port id, containing the port priority and port number .br -\fBsss\fR: The port state, one of Dis (disabled), Blk (blocking), Lrn -(learning), Fwd (forwading), Non (non-stp), Unk (unknown). +\fBssss\fR: The port state, one of down (disabled), disc (discarding), +lear (learning), forw (forwading), unkn (unknown). .br \fBrrrr-rootbridgeid\fR: Root bridge id, including priority. .br \fBdddd-desgbridgeid\fR: Designated bridge id, including priority .br \fBdprt\fR: Designated port id -.br -\fBR\fR: Port role, one of 'A' (alternate), 'B' (backup), 'R' (root), 'D' -(designated), '-' (non-stp) .B rstpctl showportdetail [ ... ] @@ -67,12 +57,6 @@ displays the spanning tree configuration and status for the specified ports much more verbosely. If no ports are specified, it displays the information for all ports of the bridge. -.B rstpctl setbridgestate {on|off} -enables/disables the operation of RSTP. When RSTP is configured with -the -.BR rstp -subcommand listed above, the default is enabled. - .B rstpctl setbridgeprio sets the bridge's priority to . The priority value is a number between 0 and 61440 in steps of 4096, and defaults to 32768. @@ -94,6 +78,11 @@ sets the bridge's spanning tree algorithm to operate in normal mode. In normal mode, RSTP falls back to STP on ports where it sees other hosts operating in STP mode. +.B rstpctl settxholdcount +sets the transmit hold count, which limits the rate of transmission +of BPDUs. No more than + 1 BPDUs are transmitted in +one second. This is a number from 1 to 10. + .B rstpctl setportprio sets the ports's priority to . The priority value is a number from 0 to 240 in steps of 16, defaulting to 128. @@ -104,15 +93,17 @@ automatically based on the link speed. This setting overrides the automatic setting. Setting this to zero puts it back in automatic mode. -.B rstpctl setportedge {yes|no} -sets or unsets the port's configures as an edge port. If a port is an -edge port, then it is assumed to be a leaf link in the graph, not +.B rstpctl setportadminedge {yes|no} +sets or unsets the port's configuration as an edge port. If a port is +an edge port, then it is assumed to be a leaf link in the graph, not connected to any other bridges. Receiving any STP BPDU's on a port configured as an edge port turns off edge port behaviour for the port. -.B rstpctl setportnonstp {yes|no} -: Setting this to yes disables RSTP operation on the port, which then -is always kept in FORWARDING state. +.B rstpctl setportautoedge {yes|no} +sets or unsets the port's configuration as an auto edge port. +If it is configured as auto edge, the port is brought up based on a +shorter timer when no response in received and treated as an edge port. +Receiving any STP BPDU's turns off edge port behaviour for the port. .B rstpctl portmcheck : This command is used when the port is operating in STP compatibility -- 2.47.3