111dc1f36SStephen Hemminger /* 211dc1f36SStephen Hemminger * Bridge netlink control interface 311dc1f36SStephen Hemminger * 411dc1f36SStephen Hemminger * Authors: 511dc1f36SStephen Hemminger * Stephen Hemminger <shemminger@osdl.org> 611dc1f36SStephen Hemminger * 711dc1f36SStephen Hemminger * This program is free software; you can redistribute it and/or 811dc1f36SStephen Hemminger * modify it under the terms of the GNU General Public License 911dc1f36SStephen Hemminger * as published by the Free Software Foundation; either version 1011dc1f36SStephen Hemminger * 2 of the License, or (at your option) any later version. 1111dc1f36SStephen Hemminger */ 1211dc1f36SStephen Hemminger 1311dc1f36SStephen Hemminger #include <linux/kernel.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15bb900b27Sstephen hemminger #include <linux/etherdevice.h> 1632fe21c0SThomas Graf #include <net/rtnetlink.h> 17881d966bSEric W. Biederman #include <net/net_namespace.h> 18b854272bSDenis V. Lunev #include <net/sock.h> 19407af329SVlad Yasevich #include <uapi/linux/if_bridge.h> 20bb900b27Sstephen hemminger 2111dc1f36SStephen Hemminger #include "br_private.h" 22b03b6dd5SVitalii Demianets #include "br_private_stp.h" 2311dc1f36SStephen Hemminger 2425c71c75Sstephen hemminger static inline size_t br_port_info_size(void) 2525c71c75Sstephen hemminger { 2625c71c75Sstephen hemminger return nla_total_size(1) /* IFLA_BRPORT_STATE */ 2725c71c75Sstephen hemminger + nla_total_size(2) /* IFLA_BRPORT_PRIORITY */ 2825c71c75Sstephen hemminger + nla_total_size(4) /* IFLA_BRPORT_COST */ 2925c71c75Sstephen hemminger + nla_total_size(1) /* IFLA_BRPORT_MODE */ 30a2e01a65Sstephen hemminger + nla_total_size(1) /* IFLA_BRPORT_GUARD */ 311007dd1aSstephen hemminger + nla_total_size(1) /* IFLA_BRPORT_PROTECT */ 323da889b6Sstephen hemminger + nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */ 339ba18891SVlad Yasevich + nla_total_size(1) /* IFLA_BRPORT_LEARNING */ 34867a5943SVlad Yasevich + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */ 3525c71c75Sstephen hemminger + 0; 3625c71c75Sstephen hemminger } 3725c71c75Sstephen hemminger 38339bf98fSThomas Graf static inline size_t br_nlmsg_size(void) 39339bf98fSThomas Graf { 40339bf98fSThomas Graf return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 41339bf98fSThomas Graf + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 42339bf98fSThomas Graf + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 43339bf98fSThomas Graf + nla_total_size(4) /* IFLA_MASTER */ 44339bf98fSThomas Graf + nla_total_size(4) /* IFLA_MTU */ 45339bf98fSThomas Graf + nla_total_size(4) /* IFLA_LINK */ 46339bf98fSThomas Graf + nla_total_size(1) /* IFLA_OPERSTATE */ 4725c71c75Sstephen hemminger + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */ 4825c71c75Sstephen hemminger } 4925c71c75Sstephen hemminger 5025c71c75Sstephen hemminger static int br_port_fill_attrs(struct sk_buff *skb, 5125c71c75Sstephen hemminger const struct net_bridge_port *p) 5225c71c75Sstephen hemminger { 5325c71c75Sstephen hemminger u8 mode = !!(p->flags & BR_HAIRPIN_MODE); 5425c71c75Sstephen hemminger 5525c71c75Sstephen hemminger if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) || 5625c71c75Sstephen hemminger nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) || 5725c71c75Sstephen hemminger nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) || 58a2e01a65Sstephen hemminger nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || 591007dd1aSstephen hemminger nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || 60c2d3babfSDavid S. Miller nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) || 619ba18891SVlad Yasevich nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || 62867a5943SVlad Yasevich nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) || 63867a5943SVlad Yasevich nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD))) 6425c71c75Sstephen hemminger return -EMSGSIZE; 6525c71c75Sstephen hemminger 6625c71c75Sstephen hemminger return 0; 67339bf98fSThomas Graf } 68339bf98fSThomas Graf 6911dc1f36SStephen Hemminger /* 7011dc1f36SStephen Hemminger * Create one netlink message for one interface 7111dc1f36SStephen Hemminger * Contains port and master info as well as carrier and bridge state. 7211dc1f36SStephen Hemminger */ 736cbdceebSVlad Yasevich static int br_fill_ifinfo(struct sk_buff *skb, 746cbdceebSVlad Yasevich const struct net_bridge_port *port, 756cbdceebSVlad Yasevich u32 pid, u32 seq, int event, unsigned int flags, 766cbdceebSVlad Yasevich u32 filter_mask, const struct net_device *dev) 7711dc1f36SStephen Hemminger { 786cbdceebSVlad Yasevich const struct net_bridge *br; 7974685962SThomas Graf struct ifinfomsg *hdr; 8011dc1f36SStephen Hemminger struct nlmsghdr *nlh; 8111dc1f36SStephen Hemminger u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; 8211dc1f36SStephen Hemminger 836cbdceebSVlad Yasevich if (port) 846cbdceebSVlad Yasevich br = port->br; 856cbdceebSVlad Yasevich else 866cbdceebSVlad Yasevich br = netdev_priv(dev); 876cbdceebSVlad Yasevich 8828a16c97Sstephen hemminger br_debug(br, "br_fill_info event %d port %s master %s\n", 8911dc1f36SStephen Hemminger event, dev->name, br->dev->name); 9011dc1f36SStephen Hemminger 9174685962SThomas Graf nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); 9274685962SThomas Graf if (nlh == NULL) 9326932566SPatrick McHardy return -EMSGSIZE; 9411dc1f36SStephen Hemminger 9574685962SThomas Graf hdr = nlmsg_data(nlh); 9674685962SThomas Graf hdr->ifi_family = AF_BRIDGE; 9774685962SThomas Graf hdr->__ifi_pad = 0; 9874685962SThomas Graf hdr->ifi_type = dev->type; 9974685962SThomas Graf hdr->ifi_index = dev->ifindex; 10074685962SThomas Graf hdr->ifi_flags = dev_get_flags(dev); 10174685962SThomas Graf hdr->ifi_change = 0; 10211dc1f36SStephen Hemminger 1032eb812e6SDavid S. Miller if (nla_put_string(skb, IFLA_IFNAME, dev->name) || 1042eb812e6SDavid S. Miller nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) || 1052eb812e6SDavid S. Miller nla_put_u32(skb, IFLA_MTU, dev->mtu) || 1062eb812e6SDavid S. Miller nla_put_u8(skb, IFLA_OPERSTATE, operstate) || 1072eb812e6SDavid S. Miller (dev->addr_len && 1082eb812e6SDavid S. Miller nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || 1092eb812e6SDavid S. Miller (dev->ifindex != dev->iflink && 11025c71c75Sstephen hemminger nla_put_u32(skb, IFLA_LINK, dev->iflink))) 1112eb812e6SDavid S. Miller goto nla_put_failure; 11225c71c75Sstephen hemminger 1136cbdceebSVlad Yasevich if (event == RTM_NEWLINK && port) { 11425c71c75Sstephen hemminger struct nlattr *nest 11525c71c75Sstephen hemminger = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); 11625c71c75Sstephen hemminger 11725c71c75Sstephen hemminger if (nest == NULL || br_port_fill_attrs(skb, port) < 0) 11825c71c75Sstephen hemminger goto nla_put_failure; 11925c71c75Sstephen hemminger nla_nest_end(skb, nest); 12025c71c75Sstephen hemminger } 12125c71c75Sstephen hemminger 1226cbdceebSVlad Yasevich /* Check if the VID information is requested */ 1236cbdceebSVlad Yasevich if (filter_mask & RTEXT_FILTER_BRVLAN) { 1246cbdceebSVlad Yasevich struct nlattr *af; 1256cbdceebSVlad Yasevich const struct net_port_vlans *pv; 1266cbdceebSVlad Yasevich struct bridge_vlan_info vinfo; 1276cbdceebSVlad Yasevich u16 vid; 128552406c4SVlad Yasevich u16 pvid; 1296cbdceebSVlad Yasevich 1306cbdceebSVlad Yasevich if (port) 1316cbdceebSVlad Yasevich pv = nbp_get_vlan_info(port); 1326cbdceebSVlad Yasevich else 1336cbdceebSVlad Yasevich pv = br_get_vlan_info(br); 1346cbdceebSVlad Yasevich 135ef40b7efSToshiaki Makita if (!pv || bitmap_empty(pv->vlan_bitmap, VLAN_N_VID)) 1366cbdceebSVlad Yasevich goto done; 1376cbdceebSVlad Yasevich 1386cbdceebSVlad Yasevich af = nla_nest_start(skb, IFLA_AF_SPEC); 1396cbdceebSVlad Yasevich if (!af) 1406cbdceebSVlad Yasevich goto nla_put_failure; 1416cbdceebSVlad Yasevich 142552406c4SVlad Yasevich pvid = br_get_pvid(pv); 143ef40b7efSToshiaki Makita for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) { 1446cbdceebSVlad Yasevich vinfo.vid = vid; 1456cbdceebSVlad Yasevich vinfo.flags = 0; 146552406c4SVlad Yasevich if (vid == pvid) 147552406c4SVlad Yasevich vinfo.flags |= BRIDGE_VLAN_INFO_PVID; 14835e03f3aSVlad Yasevich 14935e03f3aSVlad Yasevich if (test_bit(vid, pv->untagged_bitmap)) 15035e03f3aSVlad Yasevich vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; 15135e03f3aSVlad Yasevich 1526cbdceebSVlad Yasevich if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO, 1536cbdceebSVlad Yasevich sizeof(vinfo), &vinfo)) 1546cbdceebSVlad Yasevich goto nla_put_failure; 1556cbdceebSVlad Yasevich } 1566cbdceebSVlad Yasevich 1576cbdceebSVlad Yasevich nla_nest_end(skb, af); 1586cbdceebSVlad Yasevich } 1596cbdceebSVlad Yasevich 1606cbdceebSVlad Yasevich done: 16174685962SThomas Graf return nlmsg_end(skb, nlh); 16211dc1f36SStephen Hemminger 16374685962SThomas Graf nla_put_failure: 16426932566SPatrick McHardy nlmsg_cancel(skb, nlh); 16526932566SPatrick McHardy return -EMSGSIZE; 16611dc1f36SStephen Hemminger } 16711dc1f36SStephen Hemminger 16811dc1f36SStephen Hemminger /* 16911dc1f36SStephen Hemminger * Notify listeners of a change in port information 17011dc1f36SStephen Hemminger */ 17111dc1f36SStephen Hemminger void br_ifinfo_notify(int event, struct net_bridge_port *port) 17211dc1f36SStephen Hemminger { 173407af329SVlad Yasevich struct net *net; 17411dc1f36SStephen Hemminger struct sk_buff *skb; 175280a306cSThomas Graf int err = -ENOBUFS; 17611dc1f36SStephen Hemminger 177407af329SVlad Yasevich if (!port) 178407af329SVlad Yasevich return; 179407af329SVlad Yasevich 180407af329SVlad Yasevich net = dev_net(port->dev); 18128a16c97Sstephen hemminger br_debug(port->br, "port %u(%s) event %d\n", 18295c96174SEric Dumazet (unsigned int)port->port_no, port->dev->name, event); 18328a16c97Sstephen hemminger 184339bf98fSThomas Graf skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); 185280a306cSThomas Graf if (skb == NULL) 186280a306cSThomas Graf goto errout; 18711dc1f36SStephen Hemminger 1886cbdceebSVlad Yasevich err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev); 18926932566SPatrick McHardy if (err < 0) { 19026932566SPatrick McHardy /* -EMSGSIZE implies BUG in br_nlmsg_size() */ 19126932566SPatrick McHardy WARN_ON(err == -EMSGSIZE); 19226932566SPatrick McHardy kfree_skb(skb); 19326932566SPatrick McHardy goto errout; 19426932566SPatrick McHardy } 1951ce85fe4SPablo Neira Ayuso rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1961ce85fe4SPablo Neira Ayuso return; 197280a306cSThomas Graf errout: 1984aa678baSAlexey Dobriyan rtnl_set_sk_err(net, RTNLGRP_LINK, err); 19911dc1f36SStephen Hemminger } 20011dc1f36SStephen Hemminger 201407af329SVlad Yasevich 20211dc1f36SStephen Hemminger /* 20311dc1f36SStephen Hemminger * Dump information about all ports, in response to GETLINK 20411dc1f36SStephen Hemminger */ 205e5a55a89SJohn Fastabend int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, 2066cbdceebSVlad Yasevich struct net_device *dev, u32 filter_mask) 20711dc1f36SStephen Hemminger { 208e5a55a89SJohn Fastabend int err = 0; 2091fb1754aSHong Zhiguo struct net_bridge_port *port = br_port_get_rtnl(dev); 210b5ed54e9Sstephen hemminger 2116cbdceebSVlad Yasevich if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) 212e5a55a89SJohn Fastabend goto out; 21311dc1f36SStephen Hemminger 2146cbdceebSVlad Yasevich err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, 2156cbdceebSVlad Yasevich filter_mask, dev); 216e5a55a89SJohn Fastabend out: 217e5a55a89SJohn Fastabend return err; 21811dc1f36SStephen Hemminger } 21911dc1f36SStephen Hemminger 22015004cabSCong Wang static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = { 221407af329SVlad Yasevich [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, 222407af329SVlad Yasevich [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, 223407af329SVlad Yasevich [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, 224407af329SVlad Yasevich .len = sizeof(struct bridge_vlan_info), }, 225407af329SVlad Yasevich }; 226407af329SVlad Yasevich 227407af329SVlad Yasevich static int br_afspec(struct net_bridge *br, 228407af329SVlad Yasevich struct net_bridge_port *p, 229407af329SVlad Yasevich struct nlattr *af_spec, 230407af329SVlad Yasevich int cmd) 231407af329SVlad Yasevich { 232407af329SVlad Yasevich struct nlattr *tb[IFLA_BRIDGE_MAX+1]; 233407af329SVlad Yasevich int err = 0; 234407af329SVlad Yasevich 235407af329SVlad Yasevich err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy); 236407af329SVlad Yasevich if (err) 237407af329SVlad Yasevich return err; 238407af329SVlad Yasevich 239407af329SVlad Yasevich if (tb[IFLA_BRIDGE_VLAN_INFO]) { 240407af329SVlad Yasevich struct bridge_vlan_info *vinfo; 241407af329SVlad Yasevich 242407af329SVlad Yasevich vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); 243407af329SVlad Yasevich 2448adff41cSToshiaki Makita if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) 245407af329SVlad Yasevich return -EINVAL; 246407af329SVlad Yasevich 247407af329SVlad Yasevich switch (cmd) { 248407af329SVlad Yasevich case RTM_SETLINK: 249407af329SVlad Yasevich if (p) { 250552406c4SVlad Yasevich err = nbp_vlan_add(p, vinfo->vid, vinfo->flags); 251407af329SVlad Yasevich if (err) 252407af329SVlad Yasevich break; 253407af329SVlad Yasevich 254407af329SVlad Yasevich if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) 255552406c4SVlad Yasevich err = br_vlan_add(p->br, vinfo->vid, 256552406c4SVlad Yasevich vinfo->flags); 257407af329SVlad Yasevich } else 258552406c4SVlad Yasevich err = br_vlan_add(br, vinfo->vid, vinfo->flags); 259407af329SVlad Yasevich 260407af329SVlad Yasevich if (err) 261407af329SVlad Yasevich break; 262407af329SVlad Yasevich 263407af329SVlad Yasevich break; 264407af329SVlad Yasevich 265407af329SVlad Yasevich case RTM_DELLINK: 266407af329SVlad Yasevich if (p) { 267407af329SVlad Yasevich nbp_vlan_delete(p, vinfo->vid); 268407af329SVlad Yasevich if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) 269407af329SVlad Yasevich br_vlan_delete(p->br, vinfo->vid); 270407af329SVlad Yasevich } else 271407af329SVlad Yasevich br_vlan_delete(br, vinfo->vid); 272407af329SVlad Yasevich break; 273407af329SVlad Yasevich } 274407af329SVlad Yasevich } 275407af329SVlad Yasevich 276407af329SVlad Yasevich return err; 277407af329SVlad Yasevich } 278407af329SVlad Yasevich 27925c71c75Sstephen hemminger static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { 28025c71c75Sstephen hemminger [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, 28125c71c75Sstephen hemminger [IFLA_BRPORT_COST] = { .type = NLA_U32 }, 28225c71c75Sstephen hemminger [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, 28325c71c75Sstephen hemminger [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, 284a2e01a65Sstephen hemminger [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, 2851007dd1aSstephen hemminger [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, 2869ba18891SVlad Yasevich [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, 287867a5943SVlad Yasevich [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, 28825c71c75Sstephen hemminger }; 28925c71c75Sstephen hemminger 29025c71c75Sstephen hemminger /* Change the state of the port and notify spanning tree */ 29125c71c75Sstephen hemminger static int br_set_port_state(struct net_bridge_port *p, u8 state) 29211dc1f36SStephen Hemminger { 29325c71c75Sstephen hemminger if (state > BR_STATE_BLOCKING) 294b5ed54e9Sstephen hemminger return -EINVAL; 29511dc1f36SStephen Hemminger 29611dc1f36SStephen Hemminger /* if kernel STP is running, don't allow changes */ 2979cde0708SStephen Hemminger if (p->br->stp_enabled == BR_KERNEL_STP) 29811dc1f36SStephen Hemminger return -EBUSY; 29911dc1f36SStephen Hemminger 300576eb625Sstephen hemminger /* if device is not up, change is not allowed 301576eb625Sstephen hemminger * if link is not present, only allowable state is disabled 302576eb625Sstephen hemminger */ 30325c71c75Sstephen hemminger if (!netif_running(p->dev) || 304576eb625Sstephen hemminger (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED)) 30511dc1f36SStephen Hemminger return -ENETDOWN; 30611dc1f36SStephen Hemminger 30725c71c75Sstephen hemminger p->state = state; 30811dc1f36SStephen Hemminger br_log_state(p); 30925c71c75Sstephen hemminger br_port_state_selection(p->br); 31025c71c75Sstephen hemminger return 0; 31125c71c75Sstephen hemminger } 31225c71c75Sstephen hemminger 31325c71c75Sstephen hemminger /* Set/clear or port flags based on attribute */ 31425c71c75Sstephen hemminger static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], 31525c71c75Sstephen hemminger int attrtype, unsigned long mask) 31625c71c75Sstephen hemminger { 31725c71c75Sstephen hemminger if (tb[attrtype]) { 31825c71c75Sstephen hemminger u8 flag = nla_get_u8(tb[attrtype]); 31925c71c75Sstephen hemminger if (flag) 32025c71c75Sstephen hemminger p->flags |= mask; 32125c71c75Sstephen hemminger else 32225c71c75Sstephen hemminger p->flags &= ~mask; 32325c71c75Sstephen hemminger } 32425c71c75Sstephen hemminger } 32525c71c75Sstephen hemminger 32625c71c75Sstephen hemminger /* Process bridge protocol info on port */ 32725c71c75Sstephen hemminger static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) 32825c71c75Sstephen hemminger { 32925c71c75Sstephen hemminger int err; 330e028e4b8SVlad Yasevich unsigned long old_flags = p->flags; 33125c71c75Sstephen hemminger 33225c71c75Sstephen hemminger br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); 333a2e01a65Sstephen hemminger br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); 334c2d3babfSDavid S. Miller br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); 3353d84fa98SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); 3369ba18891SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); 337867a5943SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); 33825c71c75Sstephen hemminger 33925c71c75Sstephen hemminger if (tb[IFLA_BRPORT_COST]) { 34025c71c75Sstephen hemminger err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); 34125c71c75Sstephen hemminger if (err) 34225c71c75Sstephen hemminger return err; 34325c71c75Sstephen hemminger } 34425c71c75Sstephen hemminger 34525c71c75Sstephen hemminger if (tb[IFLA_BRPORT_PRIORITY]) { 34625c71c75Sstephen hemminger err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY])); 34725c71c75Sstephen hemminger if (err) 34825c71c75Sstephen hemminger return err; 34925c71c75Sstephen hemminger } 35025c71c75Sstephen hemminger 35125c71c75Sstephen hemminger if (tb[IFLA_BRPORT_STATE]) { 35225c71c75Sstephen hemminger err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE])); 35325c71c75Sstephen hemminger if (err) 35425c71c75Sstephen hemminger return err; 35525c71c75Sstephen hemminger } 356e028e4b8SVlad Yasevich 357e028e4b8SVlad Yasevich br_port_flags_change(p, old_flags ^ p->flags); 35825c71c75Sstephen hemminger return 0; 35925c71c75Sstephen hemminger } 36025c71c75Sstephen hemminger 36125c71c75Sstephen hemminger /* Change state and parameters on port. */ 36225c71c75Sstephen hemminger int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) 36325c71c75Sstephen hemminger { 36425c71c75Sstephen hemminger struct nlattr *protinfo; 365407af329SVlad Yasevich struct nlattr *afspec; 36625c71c75Sstephen hemminger struct net_bridge_port *p; 3672062cc20SDan Carpenter struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 3687b99a993SHong zhi guo int err = 0; 36925c71c75Sstephen hemminger 370c60ee67fSHong zhi guo protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO); 371c60ee67fSHong zhi guo afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); 372407af329SVlad Yasevich if (!protinfo && !afspec) 37325c71c75Sstephen hemminger return 0; 37425c71c75Sstephen hemminger 37525c71c75Sstephen hemminger p = br_port_get_rtnl(dev); 376407af329SVlad Yasevich /* We want to accept dev as bridge itself if the AF_SPEC 3778e3bff96Sstephen hemminger * is set to see if someone is setting vlan info on the bridge 378407af329SVlad Yasevich */ 3797b99a993SHong zhi guo if (!p && !afspec) 38025c71c75Sstephen hemminger return -EINVAL; 38125c71c75Sstephen hemminger 382407af329SVlad Yasevich if (p && protinfo) { 38325c71c75Sstephen hemminger if (protinfo->nla_type & NLA_F_NESTED) { 38425c71c75Sstephen hemminger err = nla_parse_nested(tb, IFLA_BRPORT_MAX, 38525c71c75Sstephen hemminger protinfo, ifla_brport_policy); 38625c71c75Sstephen hemminger if (err) 38725c71c75Sstephen hemminger return err; 388b03b6dd5SVitalii Demianets 389b03b6dd5SVitalii Demianets spin_lock_bh(&p->br->lock); 39025c71c75Sstephen hemminger err = br_setport(p, tb); 391b03b6dd5SVitalii Demianets spin_unlock_bh(&p->br->lock); 39225c71c75Sstephen hemminger } else { 3938e3bff96Sstephen hemminger /* Binary compatibility with old RSTP */ 39425c71c75Sstephen hemminger if (nla_len(protinfo) < sizeof(u8)) 39525c71c75Sstephen hemminger return -EINVAL; 396b03b6dd5SVitalii Demianets 39725c71c75Sstephen hemminger spin_lock_bh(&p->br->lock); 39825c71c75Sstephen hemminger err = br_set_port_state(p, nla_get_u8(protinfo)); 39925c71c75Sstephen hemminger spin_unlock_bh(&p->br->lock); 40025c71c75Sstephen hemminger } 401407af329SVlad Yasevich if (err) 402407af329SVlad Yasevich goto out; 403407af329SVlad Yasevich } 404407af329SVlad Yasevich 405407af329SVlad Yasevich if (afspec) { 406407af329SVlad Yasevich err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 407407af329SVlad Yasevich afspec, RTM_SETLINK); 408407af329SVlad Yasevich } 40925c71c75Sstephen hemminger 41025c71c75Sstephen hemminger if (err == 0) 41125c71c75Sstephen hemminger br_ifinfo_notify(RTM_NEWLINK, p); 41225c71c75Sstephen hemminger 413407af329SVlad Yasevich out: 41425c71c75Sstephen hemminger return err; 41511dc1f36SStephen Hemminger } 41611dc1f36SStephen Hemminger 417407af329SVlad Yasevich /* Delete port information */ 418407af329SVlad Yasevich int br_dellink(struct net_device *dev, struct nlmsghdr *nlh) 419407af329SVlad Yasevich { 420407af329SVlad Yasevich struct nlattr *afspec; 421407af329SVlad Yasevich struct net_bridge_port *p; 422407af329SVlad Yasevich int err; 423407af329SVlad Yasevich 424c60ee67fSHong zhi guo afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); 425407af329SVlad Yasevich if (!afspec) 426407af329SVlad Yasevich return 0; 427407af329SVlad Yasevich 428407af329SVlad Yasevich p = br_port_get_rtnl(dev); 429407af329SVlad Yasevich /* We want to accept dev as bridge itself as well */ 430407af329SVlad Yasevich if (!p && !(dev->priv_flags & IFF_EBRIDGE)) 431407af329SVlad Yasevich return -EINVAL; 432407af329SVlad Yasevich 433407af329SVlad Yasevich err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 434407af329SVlad Yasevich afspec, RTM_DELLINK); 435407af329SVlad Yasevich 436407af329SVlad Yasevich return err; 437407af329SVlad Yasevich } 438bb900b27Sstephen hemminger static int br_validate(struct nlattr *tb[], struct nlattr *data[]) 43911dc1f36SStephen Hemminger { 440bb900b27Sstephen hemminger if (tb[IFLA_ADDRESS]) { 441bb900b27Sstephen hemminger if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 442bb900b27Sstephen hemminger return -EINVAL; 443bb900b27Sstephen hemminger if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 444bb900b27Sstephen hemminger return -EADDRNOTAVAIL; 445bb900b27Sstephen hemminger } 44632fe21c0SThomas Graf 44732fe21c0SThomas Graf return 0; 44811dc1f36SStephen Hemminger } 44911dc1f36SStephen Hemminger 45030313a3dSToshiaki Makita static int br_dev_newlink(struct net *src_net, struct net_device *dev, 45130313a3dSToshiaki Makita struct nlattr *tb[], struct nlattr *data[]) 45230313a3dSToshiaki Makita { 45330313a3dSToshiaki Makita struct net_bridge *br = netdev_priv(dev); 45430313a3dSToshiaki Makita 45530313a3dSToshiaki Makita if (tb[IFLA_ADDRESS]) { 45630313a3dSToshiaki Makita spin_lock_bh(&br->lock); 45730313a3dSToshiaki Makita br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS])); 45830313a3dSToshiaki Makita spin_unlock_bh(&br->lock); 45930313a3dSToshiaki Makita } 46030313a3dSToshiaki Makita 46130313a3dSToshiaki Makita return register_netdevice(dev); 46230313a3dSToshiaki Makita } 46330313a3dSToshiaki Makita 464*ced8283fSJiri Pirko static int br_port_fill_slave_info(struct sk_buff *skb, 465*ced8283fSJiri Pirko const struct net_device *brdev, 466*ced8283fSJiri Pirko const struct net_device *dev) 467*ced8283fSJiri Pirko { 468*ced8283fSJiri Pirko return br_port_fill_attrs(skb, br_port_get_rtnl(dev)); 469*ced8283fSJiri Pirko } 470*ced8283fSJiri Pirko 471*ced8283fSJiri Pirko static size_t br_port_get_slave_size(const struct net_device *brdev, 472*ced8283fSJiri Pirko const struct net_device *dev) 473*ced8283fSJiri Pirko { 474*ced8283fSJiri Pirko return br_port_info_size(); 475*ced8283fSJiri Pirko } 476*ced8283fSJiri Pirko 4776cbdceebSVlad Yasevich static size_t br_get_link_af_size(const struct net_device *dev) 4786cbdceebSVlad Yasevich { 4796cbdceebSVlad Yasevich struct net_port_vlans *pv; 4806cbdceebSVlad Yasevich 4816cbdceebSVlad Yasevich if (br_port_exists(dev)) 4821fb1754aSHong Zhiguo pv = nbp_get_vlan_info(br_port_get_rtnl(dev)); 4836cbdceebSVlad Yasevich else if (dev->priv_flags & IFF_EBRIDGE) 4846cbdceebSVlad Yasevich pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev)); 4856cbdceebSVlad Yasevich else 4866cbdceebSVlad Yasevich return 0; 4876cbdceebSVlad Yasevich 4886cbdceebSVlad Yasevich if (!pv) 4896cbdceebSVlad Yasevich return 0; 4906cbdceebSVlad Yasevich 4916cbdceebSVlad Yasevich /* Each VLAN is returned in bridge_vlan_info along with flags */ 4926cbdceebSVlad Yasevich return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info)); 4936cbdceebSVlad Yasevich } 4946cbdceebSVlad Yasevich 49515004cabSCong Wang static struct rtnl_af_ops br_af_ops = { 4966cbdceebSVlad Yasevich .family = AF_BRIDGE, 4976cbdceebSVlad Yasevich .get_link_af_size = br_get_link_af_size, 4986cbdceebSVlad Yasevich }; 4996cbdceebSVlad Yasevich 500149ddd83Sstephen hemminger struct rtnl_link_ops br_link_ops __read_mostly = { 501bb900b27Sstephen hemminger .kind = "bridge", 502bb900b27Sstephen hemminger .priv_size = sizeof(struct net_bridge), 503bb900b27Sstephen hemminger .setup = br_dev_setup, 504bb900b27Sstephen hemminger .validate = br_validate, 50530313a3dSToshiaki Makita .newlink = br_dev_newlink, 5061ce5cce8Sstephen hemminger .dellink = br_dev_delete, 507*ced8283fSJiri Pirko .get_slave_size = br_port_get_slave_size, 508*ced8283fSJiri Pirko .fill_slave_info = br_port_fill_slave_info, 509bb900b27Sstephen hemminger }; 510bb900b27Sstephen hemminger 511bb900b27Sstephen hemminger int __init br_netlink_init(void) 51211dc1f36SStephen Hemminger { 5133ec8e9f0SVlad Yasevich int err; 5143ec8e9f0SVlad Yasevich 5153ec8e9f0SVlad Yasevich br_mdb_init(); 5163678a9d8Sstephen hemminger rtnl_af_register(&br_af_ops); 5173ec8e9f0SVlad Yasevich 5186cbdceebSVlad Yasevich err = rtnl_link_register(&br_link_ops); 5196cbdceebSVlad Yasevich if (err) 5206cbdceebSVlad Yasevich goto out_af; 5216cbdceebSVlad Yasevich 5223ec8e9f0SVlad Yasevich return 0; 5236cbdceebSVlad Yasevich 5246cbdceebSVlad Yasevich out_af: 5256cbdceebSVlad Yasevich rtnl_af_unregister(&br_af_ops); 5263ec8e9f0SVlad Yasevich br_mdb_uninit(); 5273ec8e9f0SVlad Yasevich return err; 52811dc1f36SStephen Hemminger } 52911dc1f36SStephen Hemminger 530bb900b27Sstephen hemminger void __exit br_netlink_fini(void) 531bb900b27Sstephen hemminger { 5323ec8e9f0SVlad Yasevich br_mdb_uninit(); 5336cbdceebSVlad Yasevich rtnl_af_unregister(&br_af_ops); 534bb900b27Sstephen hemminger rtnl_link_unregister(&br_link_ops); 535bb900b27Sstephen hemminger } 536