Beispiel #1
0
/* called under bridge lock */
static void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr)
{
	unsigned char oldaddr[6];
	struct net_bridge_port *p;
	int wasroot;

	wasroot = br_is_root_bridge(br);

	memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN);
	memcpy(br->bridge_id.addr, addr, ETH_ALEN);
	memcpy(br->dev.dev_addr, addr, ETH_ALEN);

	p = br->port_list;
	while (p != NULL) {
		if (!memcmp(p->designated_bridge.addr, oldaddr, ETH_ALEN))
			memcpy(p->designated_bridge.addr, addr, ETH_ALEN);

		if (!memcmp(p->designated_root.addr, oldaddr, ETH_ALEN))
			memcpy(p->designated_root.addr, addr, ETH_ALEN);

		p = p->next;
	}

	br_configuration_update(br);
	br_port_state_selection(br);
	if (br_is_root_bridge(br) && !wasroot)
		br_become_root_bridge(br);
}
Beispiel #2
0
/*
 * Change state of port (ie from forwarding to blocking etc)
 * Used by spanning tree in user space.
 */
static int br_rtm_setlink(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct ifinfomsg *ifm;
	struct nlattr *protinfo;
	struct net_device *dev;
	struct net_bridge_port *p;
	u8 new_state;

	if (nlmsg_len(nlh) < sizeof(*ifm))
		return -EINVAL;

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_family != AF_BRIDGE)
		return -EPFNOSUPPORT;

	protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
	if (!protinfo || nla_len(protinfo) < sizeof(u8))
		return -EINVAL;

	new_state = nla_get_u8(protinfo);
	if (new_state > BR_STATE_BLOCKING)
		return -EINVAL;

	dev = __dev_get_by_index(net, ifm->ifi_index);
	if (!dev)
		return -ENODEV;

	p = br_port_get_rtnl(dev);
	if (!p)
		return -EINVAL;

	/* if kernel STP is running, don't allow changes */
	if (p->br->stp_enabled == BR_KERNEL_STP)
		return -EBUSY;

	if (!netif_running(dev) ||
	    (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
		return -ENETDOWN;

	p->state = new_state;
	br_log_state(p);

	spin_lock_bh(&p->br->lock);
	br_port_state_selection(p->br);
	spin_unlock_bh(&p->br->lock);

	br_ifinfo_notify(RTM_NEWLINK, p);

	return 0;
}
/* Change the state of the port and notify spanning tree */
static int br_set_port_state(struct net_bridge_port *p, u8 state)
{
	if (state > BR_STATE_BLOCKING)
		return -EINVAL;

	/* if kernel STP is running, don't allow changes */
	if (p->br->stp_enabled == BR_KERNEL_STP)
		return -EBUSY;

	if (!netif_running(p->dev) ||
	    (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
		return -ENETDOWN;

	p->state = state;
	br_log_state(p);
	br_port_state_selection(p->br);
	return 0;
}
Beispiel #4
0
/* Change the state of the port and notify spanning tree */
static int br_set_port_state(struct net_bridge_port *p, u8 state)
{
	if (state > BR_STATE_BLOCKING)
		return -EINVAL;

	/* if kernel STP is running, don't allow changes */
	if (p->br->stp_enabled == BR_KERNEL_STP)
		return -EBUSY;

	/* if device is not up, change is not allowed
	 * if link is not present, only allowable state is disabled
	 */
	if (!netif_running(p->dev) ||
	    (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED))
		return -ENETDOWN;

	p->state = state;
	br_log_state(p);
	br_port_state_selection(p->br);
	return 0;
}
Beispiel #5
0
/* lock-safe */
void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
{
	struct net_bridge *br;
	int was_root;

	if (p->state == BR_STATE_DISABLED)
		return;

	br = p->br;
	read_lock(&br->lock);

	was_root = br_is_root_bridge(br);
	if (br_supersedes_port_info(p, bpdu)) {
		br_record_config_information(p, bpdu);
		br_configuration_update(br);
		br_port_state_selection(br);

		if (!br_is_root_bridge(br) && was_root) {
			br_timer_clear(&br->hello_timer);
			if (br->topology_change_detected) {
				br_timer_clear(&br->topology_change_timer);
				br_transmit_tcn(br);
				br_timer_set(&br->tcn_timer, jiffies);
			}
		}

		if (p->port_no == br->root_port) {
			br_record_config_timeout_values(br, bpdu);
			br_config_bpdu_generation(br);
			if (bpdu->topology_change_ack)
				br_topology_change_acknowledged(br);
		}
	} else if (br_is_designated_port(p)) {		
		br_reply(p);		
	}

	read_unlock(&br->lock);
}
Beispiel #6
0
/* called under bridge lock */
void br_stp_disable_port(struct net_bridge_port *p)
{
	struct net_bridge *br;
	int wasroot;

	br = p->br;
	printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
	       br->dev.name, p->port_no, p->dev->name, "disabled");

	wasroot = br_is_root_bridge(br);
	br_become_designated_port(p);
	p->state = BR_STATE_DISABLED;
	p->topology_change_ack = 0;
	p->config_pending = 0;
	br_timer_clear(&p->message_age_timer);
	br_timer_clear(&p->forward_delay_timer);
	br_timer_clear(&p->hold_timer);
	br_configuration_update(br);
	br_port_state_selection(br);

	if (br_is_root_bridge(br) && !wasroot)
		br_become_root_bridge(br);
}
Beispiel #7
0
/* called under bridge lock */
static void br_message_age_timer_expired(struct net_bridge_port *p)
{
	struct net_bridge *br;
	int was_root;

	br = p->br;
	printk(KERN_INFO "%s: ", br->dev.name);
	printk("neighbour ");
	dump_bridge_id(&p->designated_bridge);
	printk(" lost on port %i(%s)\n", p->port_no, p->dev->name);

	/*
	 * According to the spec, the message age timer cannot be
	 * running when we are the root bridge. So..  this was_root
	 * check is redundant. I'm leaving it in for now, though.
	 */
	was_root = br_is_root_bridge(br);

	br_become_designated_port(p);
	br_configuration_update(br);
	br_port_state_selection(br);
	if (br_is_root_bridge(br) && !was_root)
		br_become_root_bridge(br);
}
Beispiel #8
0
/* called under bridge lock */
void br_stp_enable_port(struct net_bridge_port *p)
{
	br_init_port(p);
	br_port_state_selection(p->br);
}