-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)
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
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
#include <arpa/inet.h>
#include <sys/types.h>
-#include <bitmap.h>
-#include <uid_stp.h>
-#include <stp_bpdu.h>
-#include <stp_in.h>
-#include <stp_to.h>
-
#include <stdio.h>
#include <string.h>
#include "log.h"
+#include "rstp.h"
/*------------------------------------------------------------*/
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;
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;
};
/* 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;
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;
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;
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 */
{
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);
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 */
{
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;
}
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)
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);
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);
}
/*------------------------------------------------------------*/
{
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) {
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);
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 */
{
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)
// 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 */
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)
{
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;
}
#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 <base.h>
-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, ...)
{
#ifndef CTL_FUNCTIONS_H
#define CTL_FUNCTIONS_H
-#include <bitmap.h>
-#include <uid_stp.h>
+#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
#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);
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;
}
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;
}
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;
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;
}
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)
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)
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)
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)
"<bridge> [<port> ... ]\tshow port state"},
{1, 32, "showportdetail", cmd_showportdetail,
"<bridge> [<port> ... ]\tshow port state (detail)"},
- {2, 0, "rstp", cmd_rstp,
- "<bridge> {on|off}\tenable/disable rstpd control"},
- {2, 0, "setbridgestate", cmd_setbridgestate,
- "<bridge> {on|off}\tstart/stop rstp (when enabled)"},
{2, 0, "setbridgeprio", cmd_setbridgeprio,
"<bridge> <priority>\tset bridge priority (0-61440)"},
{2, 0, "sethello", cmd_setbridgehello,
"<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
{2, 0, "setforcevers", cmd_setbridgeforcevers,
"<bridge> {normal|slow}\tnormal RSTP or force to STP"},
+ {2, 0, "settxholdcount", cmd_setbridgetxholdcount,
+ "<bridge> <tx_hold_count>\tset bridge transmit hold count (1-10)"},
{3, 0, "setportprio", cmd_setportprio,
"<bridge> <port> <priority>\tset port priority (0-240)"},
{3, 0, "setportpathcost", cmd_setportpathcost,
"<bridge> <port> <cost>\tset port path cost"},
- {3, 0, "setportedge", cmd_setportedge,
- "<bridge> <port> {yes|no}\tconfigure if it is an edge port"},
- {3, 0, "setportnonstp", cmd_setportnonstp,
- "<bridge> <port> {yes|no}\tdisable STP for the port"},
+ {3, 0, "setportadminedge", cmd_setportadminedge,
+ "<bridge> <port> {yes|no}\tconfigure if it is an admin edge port"},
+ {3, 0, "setportautoedge", cmd_setportautoedge,
+ "<bridge> <port> {yes|no}\tconfigure if it is an auto edge port"},
{3, 0, "setportp2p", cmd_setportp2p,
"<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
{2, 0, "portmcheck", cmd_portmcheck,
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
#include "epoll_loop.h"
#include "log.h"
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:
}
}
+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) ||
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");
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; \
#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 {
};
#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 {
};
#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;
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)
{ \
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
#include <stdio.h>
#include <stdlib.h>
+#define NO_DAEMON
#include "log.h"
static int fd = -1;
}
}
-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) {
}
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;
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;
}
#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);
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
#include <stdio.h>
#include <stdarg.h>
+#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
#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;
.SH COMMANDS
-.B rstpctl rstp <bridge> {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 [<bridge> ... ]
displays the spanning tree configuration and status for the specified
bridges. If no bridges are given, it displays the information for all
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.
.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 <bridge> [<port> ... ]
ports much more verbosely. If no ports are specified, it displays the
information for all ports of the bridge.
-.B rstpctl setbridgestate <bridge> {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 <bridge> <priority>
sets the bridge's priority to <priority>. The priority value is a
number between 0 and 61440 in steps of 4096, and defaults to 32768.
mode. In normal mode, RSTP falls back to STP on ports where it
sees other hosts operating in STP mode.
+.B rstpctl settxholdcount <bridge> <tx_hold_count>
+sets the transmit hold count, which limits the rate of transmission
+of BPDUs. No more than <tx_hold_count> + 1 BPDUs are transmitted in
+one second. This is a number from 1 to 10.
+
.B rstpctl setportprio <bridge> <port> <priority>
sets the ports's priority to <priority>. The priority value is a
number from 0 to 240 in steps of 16, defaulting to 128.
automatic setting. Setting this to zero puts it back in automatic
mode.
-.B rstpctl setportedge <bridge> <port> {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 <bridge> <port> {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 <bridge> <port> {yes|no}
-: Setting this to yes disables RSTP operation on the port, which then
-is always kept in FORWARDING state.
+.B rstpctl setportautoedge <bridge> <port> {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 <bridge> <port>
: This command is used when the port is operating in STP compatibility