Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.20 192 lines 4.8 kB view raw
1/* 2 * Bridge netlink control interface 3 * 4 * Authors: 5 * Stephen Hemminger <shemminger@osdl.org> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 */ 12 13#include <linux/kernel.h> 14#include <linux/rtnetlink.h> 15#include <net/netlink.h> 16#include "br_private.h" 17 18static inline size_t br_nlmsg_size(void) 19{ 20 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 21 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 22 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 23 + nla_total_size(4) /* IFLA_MASTER */ 24 + nla_total_size(4) /* IFLA_MTU */ 25 + nla_total_size(4) /* IFLA_LINK */ 26 + nla_total_size(1) /* IFLA_OPERSTATE */ 27 + nla_total_size(1); /* IFLA_PROTINFO */ 28} 29 30/* 31 * Create one netlink message for one interface 32 * Contains port and master info as well as carrier and bridge state. 33 */ 34static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, 35 u32 pid, u32 seq, int event, unsigned int flags) 36{ 37 const struct net_bridge *br = port->br; 38 const struct net_device *dev = port->dev; 39 struct ifinfomsg *hdr; 40 struct nlmsghdr *nlh; 41 u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; 42 43 pr_debug("br_fill_info event %d port %s master %s\n", 44 event, dev->name, br->dev->name); 45 46 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); 47 if (nlh == NULL) 48 return -ENOBUFS; 49 50 hdr = nlmsg_data(nlh); 51 hdr->ifi_family = AF_BRIDGE; 52 hdr->__ifi_pad = 0; 53 hdr->ifi_type = dev->type; 54 hdr->ifi_index = dev->ifindex; 55 hdr->ifi_flags = dev_get_flags(dev); 56 hdr->ifi_change = 0; 57 58 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); 59 NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex); 60 NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); 61 NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate); 62 63 if (dev->addr_len) 64 NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); 65 66 if (dev->ifindex != dev->iflink) 67 NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); 68 69 if (event == RTM_NEWLINK) 70 NLA_PUT_U8(skb, IFLA_PROTINFO, port->state); 71 72 return nlmsg_end(skb, nlh); 73 74nla_put_failure: 75 return nlmsg_cancel(skb, nlh); 76} 77 78/* 79 * Notify listeners of a change in port information 80 */ 81void br_ifinfo_notify(int event, struct net_bridge_port *port) 82{ 83 struct sk_buff *skb; 84 int err = -ENOBUFS; 85 86 pr_debug("bridge notify event=%d\n", event); 87 skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); 88 if (skb == NULL) 89 goto errout; 90 91 err = br_fill_ifinfo(skb, port, 0, 0, event, 0); 92 /* failure implies BUG in br_nlmsg_size() */ 93 BUG_ON(err < 0); 94 95 err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 96errout: 97 if (err < 0) 98 rtnl_set_sk_err(RTNLGRP_LINK, err); 99} 100 101/* 102 * Dump information about all ports, in response to GETLINK 103 */ 104static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 105{ 106 struct net_device *dev; 107 int idx; 108 109 read_lock(&dev_base_lock); 110 for (dev = dev_base, idx = 0; dev; dev = dev->next) { 111 /* not a bridge port */ 112 if (dev->br_port == NULL || idx < cb->args[0]) 113 goto skip; 114 115 if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, 116 cb->nlh->nlmsg_seq, RTM_NEWLINK, 117 NLM_F_MULTI) < 0) 118 break; 119skip: 120 ++idx; 121 } 122 read_unlock(&dev_base_lock); 123 124 cb->args[0] = idx; 125 126 return skb->len; 127} 128 129/* 130 * Change state of port (ie from forwarding to blocking etc) 131 * Used by spanning tree in user space. 132 */ 133static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 134{ 135 struct ifinfomsg *ifm; 136 struct nlattr *protinfo; 137 struct net_device *dev; 138 struct net_bridge_port *p; 139 u8 new_state; 140 141 if (nlmsg_len(nlh) < sizeof(*ifm)) 142 return -EINVAL; 143 144 ifm = nlmsg_data(nlh); 145 if (ifm->ifi_family != AF_BRIDGE) 146 return -EPFNOSUPPORT; 147 148 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 149 if (!protinfo || nla_len(protinfo) < sizeof(u8)) 150 return -EINVAL; 151 152 new_state = nla_get_u8(protinfo); 153 if (new_state > BR_STATE_BLOCKING) 154 return -EINVAL; 155 156 dev = __dev_get_by_index(ifm->ifi_index); 157 if (!dev) 158 return -ENODEV; 159 160 p = dev->br_port; 161 if (!p) 162 return -EINVAL; 163 164 /* if kernel STP is running, don't allow changes */ 165 if (p->br->stp_enabled) 166 return -EBUSY; 167 168 if (!netif_running(dev) || 169 (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) 170 return -ENETDOWN; 171 172 p->state = new_state; 173 br_log_state(p); 174 return 0; 175} 176 177 178static struct rtnetlink_link bridge_rtnetlink_table[RTM_NR_MSGTYPES] = { 179 [RTM_GETLINK - RTM_BASE] = { .dumpit = br_dump_ifinfo, }, 180 [RTM_SETLINK - RTM_BASE] = { .doit = br_rtm_setlink, }, 181}; 182 183void __init br_netlink_init(void) 184{ 185 rtnetlink_links[PF_BRIDGE] = bridge_rtnetlink_table; 186} 187 188void __exit br_netlink_fini(void) 189{ 190 rtnetlink_links[PF_BRIDGE] = NULL; 191} 192