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 break; 261407af329SVlad Yasevich 262407af329SVlad Yasevich case RTM_DELLINK: 263407af329SVlad Yasevich if (p) { 264407af329SVlad Yasevich nbp_vlan_delete(p, vinfo->vid); 265407af329SVlad Yasevich if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) 266407af329SVlad Yasevich br_vlan_delete(p->br, vinfo->vid); 267407af329SVlad Yasevich } else 268407af329SVlad Yasevich br_vlan_delete(br, vinfo->vid); 269407af329SVlad Yasevich break; 270407af329SVlad Yasevich } 271407af329SVlad Yasevich } 272407af329SVlad Yasevich 273407af329SVlad Yasevich return err; 274407af329SVlad Yasevich } 275407af329SVlad Yasevich 2763ac636b8SJiri Pirko static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { 27725c71c75Sstephen hemminger [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, 27825c71c75Sstephen hemminger [IFLA_BRPORT_COST] = { .type = NLA_U32 }, 27925c71c75Sstephen hemminger [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, 28025c71c75Sstephen hemminger [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, 281a2e01a65Sstephen hemminger [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, 2821007dd1aSstephen hemminger [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, 2839ba18891SVlad Yasevich [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, 284867a5943SVlad Yasevich [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, 28525c71c75Sstephen hemminger }; 28625c71c75Sstephen hemminger 28725c71c75Sstephen hemminger /* Change the state of the port and notify spanning tree */ 28825c71c75Sstephen hemminger static int br_set_port_state(struct net_bridge_port *p, u8 state) 28911dc1f36SStephen Hemminger { 29025c71c75Sstephen hemminger if (state > BR_STATE_BLOCKING) 291b5ed54e9Sstephen hemminger return -EINVAL; 29211dc1f36SStephen Hemminger 29311dc1f36SStephen Hemminger /* if kernel STP is running, don't allow changes */ 2949cde0708SStephen Hemminger if (p->br->stp_enabled == BR_KERNEL_STP) 29511dc1f36SStephen Hemminger return -EBUSY; 29611dc1f36SStephen Hemminger 297576eb625Sstephen hemminger /* if device is not up, change is not allowed 298576eb625Sstephen hemminger * if link is not present, only allowable state is disabled 299576eb625Sstephen hemminger */ 30025c71c75Sstephen hemminger if (!netif_running(p->dev) || 301576eb625Sstephen hemminger (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED)) 30211dc1f36SStephen Hemminger return -ENETDOWN; 30311dc1f36SStephen Hemminger 30425c71c75Sstephen hemminger p->state = state; 30511dc1f36SStephen Hemminger br_log_state(p); 30625c71c75Sstephen hemminger br_port_state_selection(p->br); 30725c71c75Sstephen hemminger return 0; 30825c71c75Sstephen hemminger } 30925c71c75Sstephen hemminger 31025c71c75Sstephen hemminger /* Set/clear or port flags based on attribute */ 31125c71c75Sstephen hemminger static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], 31225c71c75Sstephen hemminger int attrtype, unsigned long mask) 31325c71c75Sstephen hemminger { 31425c71c75Sstephen hemminger if (tb[attrtype]) { 31525c71c75Sstephen hemminger u8 flag = nla_get_u8(tb[attrtype]); 31625c71c75Sstephen hemminger if (flag) 31725c71c75Sstephen hemminger p->flags |= mask; 31825c71c75Sstephen hemminger else 31925c71c75Sstephen hemminger p->flags &= ~mask; 32025c71c75Sstephen hemminger } 32125c71c75Sstephen hemminger } 32225c71c75Sstephen hemminger 32325c71c75Sstephen hemminger /* Process bridge protocol info on port */ 32425c71c75Sstephen hemminger static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) 32525c71c75Sstephen hemminger { 32625c71c75Sstephen hemminger int err; 327e028e4b8SVlad Yasevich unsigned long old_flags = p->flags; 32825c71c75Sstephen hemminger 32925c71c75Sstephen hemminger br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); 330a2e01a65Sstephen hemminger br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); 331c2d3babfSDavid S. Miller br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); 3323d84fa98SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); 3339ba18891SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); 334867a5943SVlad Yasevich br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); 33525c71c75Sstephen hemminger 33625c71c75Sstephen hemminger if (tb[IFLA_BRPORT_COST]) { 33725c71c75Sstephen hemminger err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); 33825c71c75Sstephen hemminger if (err) 33925c71c75Sstephen hemminger return err; 34025c71c75Sstephen hemminger } 34125c71c75Sstephen hemminger 34225c71c75Sstephen hemminger if (tb[IFLA_BRPORT_PRIORITY]) { 34325c71c75Sstephen hemminger err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY])); 34425c71c75Sstephen hemminger if (err) 34525c71c75Sstephen hemminger return err; 34625c71c75Sstephen hemminger } 34725c71c75Sstephen hemminger 34825c71c75Sstephen hemminger if (tb[IFLA_BRPORT_STATE]) { 34925c71c75Sstephen hemminger err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE])); 35025c71c75Sstephen hemminger if (err) 35125c71c75Sstephen hemminger return err; 35225c71c75Sstephen hemminger } 353e028e4b8SVlad Yasevich 354e028e4b8SVlad Yasevich br_port_flags_change(p, old_flags ^ p->flags); 35525c71c75Sstephen hemminger return 0; 35625c71c75Sstephen hemminger } 35725c71c75Sstephen hemminger 35825c71c75Sstephen hemminger /* Change state and parameters on port. */ 35925c71c75Sstephen hemminger int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) 36025c71c75Sstephen hemminger { 36125c71c75Sstephen hemminger struct nlattr *protinfo; 362407af329SVlad Yasevich struct nlattr *afspec; 36325c71c75Sstephen hemminger struct net_bridge_port *p; 3642062cc20SDan Carpenter struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 3657b99a993SHong zhi guo int err = 0; 36625c71c75Sstephen hemminger 367c60ee67fSHong zhi guo protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO); 368c60ee67fSHong zhi guo afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); 369407af329SVlad Yasevich if (!protinfo && !afspec) 37025c71c75Sstephen hemminger return 0; 37125c71c75Sstephen hemminger 37225c71c75Sstephen hemminger p = br_port_get_rtnl(dev); 373407af329SVlad Yasevich /* We want to accept dev as bridge itself if the AF_SPEC 3748e3bff96Sstephen hemminger * is set to see if someone is setting vlan info on the bridge 375407af329SVlad Yasevich */ 3767b99a993SHong zhi guo if (!p && !afspec) 37725c71c75Sstephen hemminger return -EINVAL; 37825c71c75Sstephen hemminger 379407af329SVlad Yasevich if (p && protinfo) { 38025c71c75Sstephen hemminger if (protinfo->nla_type & NLA_F_NESTED) { 38125c71c75Sstephen hemminger err = nla_parse_nested(tb, IFLA_BRPORT_MAX, 3823ac636b8SJiri Pirko protinfo, br_port_policy); 38325c71c75Sstephen hemminger if (err) 38425c71c75Sstephen hemminger return err; 385b03b6dd5SVitalii Demianets 386b03b6dd5SVitalii Demianets spin_lock_bh(&p->br->lock); 38725c71c75Sstephen hemminger err = br_setport(p, tb); 388b03b6dd5SVitalii Demianets spin_unlock_bh(&p->br->lock); 38925c71c75Sstephen hemminger } else { 3908e3bff96Sstephen hemminger /* Binary compatibility with old RSTP */ 39125c71c75Sstephen hemminger if (nla_len(protinfo) < sizeof(u8)) 39225c71c75Sstephen hemminger return -EINVAL; 393b03b6dd5SVitalii Demianets 39425c71c75Sstephen hemminger spin_lock_bh(&p->br->lock); 39525c71c75Sstephen hemminger err = br_set_port_state(p, nla_get_u8(protinfo)); 39625c71c75Sstephen hemminger spin_unlock_bh(&p->br->lock); 39725c71c75Sstephen hemminger } 398407af329SVlad Yasevich if (err) 399407af329SVlad Yasevich goto out; 400407af329SVlad Yasevich } 401407af329SVlad Yasevich 402407af329SVlad Yasevich if (afspec) { 403407af329SVlad Yasevich err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 404407af329SVlad Yasevich afspec, RTM_SETLINK); 405407af329SVlad Yasevich } 40625c71c75Sstephen hemminger 40725c71c75Sstephen hemminger if (err == 0) 40825c71c75Sstephen hemminger br_ifinfo_notify(RTM_NEWLINK, p); 40925c71c75Sstephen hemminger 410407af329SVlad Yasevich out: 41125c71c75Sstephen hemminger return err; 41211dc1f36SStephen Hemminger } 41311dc1f36SStephen Hemminger 414407af329SVlad Yasevich /* Delete port information */ 415407af329SVlad Yasevich int br_dellink(struct net_device *dev, struct nlmsghdr *nlh) 416407af329SVlad Yasevich { 417407af329SVlad Yasevich struct nlattr *afspec; 418407af329SVlad Yasevich struct net_bridge_port *p; 419407af329SVlad Yasevich int err; 420407af329SVlad Yasevich 421c60ee67fSHong zhi guo afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); 422407af329SVlad Yasevich if (!afspec) 423407af329SVlad Yasevich return 0; 424407af329SVlad Yasevich 425407af329SVlad Yasevich p = br_port_get_rtnl(dev); 426407af329SVlad Yasevich /* We want to accept dev as bridge itself as well */ 427407af329SVlad Yasevich if (!p && !(dev->priv_flags & IFF_EBRIDGE)) 428407af329SVlad Yasevich return -EINVAL; 429407af329SVlad Yasevich 430407af329SVlad Yasevich err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 431407af329SVlad Yasevich afspec, RTM_DELLINK); 432407af329SVlad Yasevich 433407af329SVlad Yasevich return err; 434407af329SVlad Yasevich } 435bb900b27Sstephen hemminger static int br_validate(struct nlattr *tb[], struct nlattr *data[]) 43611dc1f36SStephen Hemminger { 437bb900b27Sstephen hemminger if (tb[IFLA_ADDRESS]) { 438bb900b27Sstephen hemminger if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 439bb900b27Sstephen hemminger return -EINVAL; 440bb900b27Sstephen hemminger if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 441bb900b27Sstephen hemminger return -EADDRNOTAVAIL; 442bb900b27Sstephen hemminger } 44332fe21c0SThomas Graf 44432fe21c0SThomas Graf return 0; 44511dc1f36SStephen Hemminger } 44611dc1f36SStephen Hemminger 44730313a3dSToshiaki Makita static int br_dev_newlink(struct net *src_net, struct net_device *dev, 44830313a3dSToshiaki Makita struct nlattr *tb[], struct nlattr *data[]) 44930313a3dSToshiaki Makita { 45030313a3dSToshiaki Makita struct net_bridge *br = netdev_priv(dev); 45130313a3dSToshiaki Makita 45230313a3dSToshiaki Makita if (tb[IFLA_ADDRESS]) { 45330313a3dSToshiaki Makita spin_lock_bh(&br->lock); 45430313a3dSToshiaki Makita br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS])); 45530313a3dSToshiaki Makita spin_unlock_bh(&br->lock); 45630313a3dSToshiaki Makita } 45730313a3dSToshiaki Makita 45830313a3dSToshiaki Makita return register_netdevice(dev); 45930313a3dSToshiaki Makita } 46030313a3dSToshiaki Makita 4613ac636b8SJiri Pirko static int br_port_slave_changelink(struct net_device *brdev, 4623ac636b8SJiri Pirko struct net_device *dev, 4633ac636b8SJiri Pirko struct nlattr *tb[], 4643ac636b8SJiri Pirko struct nlattr *data[]) 4653ac636b8SJiri Pirko { 4663ac636b8SJiri Pirko if (!data) 4673ac636b8SJiri Pirko return 0; 4683ac636b8SJiri Pirko return br_setport(br_port_get_rtnl(dev), data); 4693ac636b8SJiri Pirko } 4703ac636b8SJiri Pirko 471ced8283fSJiri Pirko static int br_port_fill_slave_info(struct sk_buff *skb, 472ced8283fSJiri Pirko const struct net_device *brdev, 473ced8283fSJiri Pirko const struct net_device *dev) 474ced8283fSJiri Pirko { 475ced8283fSJiri Pirko return br_port_fill_attrs(skb, br_port_get_rtnl(dev)); 476ced8283fSJiri Pirko } 477ced8283fSJiri Pirko 478ced8283fSJiri Pirko static size_t br_port_get_slave_size(const struct net_device *brdev, 479ced8283fSJiri Pirko const struct net_device *dev) 480ced8283fSJiri Pirko { 481ced8283fSJiri Pirko return br_port_info_size(); 482ced8283fSJiri Pirko } 483ced8283fSJiri Pirko 48413323516SJiri Pirko static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { 48513323516SJiri Pirko [IFLA_BR_FORWARD_DELAY] = { .type = NLA_U32 }, 48613323516SJiri Pirko [IFLA_BR_HELLO_TIME] = { .type = NLA_U32 }, 48713323516SJiri Pirko [IFLA_BR_MAX_AGE] = { .type = NLA_U32 }, 48813323516SJiri Pirko }; 48913323516SJiri Pirko 49013323516SJiri Pirko static int br_changelink(struct net_device *brdev, struct nlattr *tb[], 49113323516SJiri Pirko struct nlattr *data[]) 49213323516SJiri Pirko { 49313323516SJiri Pirko struct net_bridge *br = netdev_priv(brdev); 49413323516SJiri Pirko int err; 49513323516SJiri Pirko 49613323516SJiri Pirko if (!data) 49713323516SJiri Pirko return 0; 49813323516SJiri Pirko 49913323516SJiri Pirko if (data[IFLA_BR_FORWARD_DELAY]) { 50013323516SJiri Pirko err = br_set_forward_delay(br, nla_get_u32(data[IFLA_BR_FORWARD_DELAY])); 50113323516SJiri Pirko if (err) 50213323516SJiri Pirko return err; 50313323516SJiri Pirko } 50413323516SJiri Pirko 50513323516SJiri Pirko if (data[IFLA_BR_HELLO_TIME]) { 50613323516SJiri Pirko err = br_set_hello_time(br, nla_get_u32(data[IFLA_BR_HELLO_TIME])); 50713323516SJiri Pirko if (err) 50813323516SJiri Pirko return err; 50913323516SJiri Pirko } 51013323516SJiri Pirko 51113323516SJiri Pirko if (data[IFLA_BR_MAX_AGE]) { 51213323516SJiri Pirko err = br_set_max_age(br, nla_get_u32(data[IFLA_BR_MAX_AGE])); 51313323516SJiri Pirko if (err) 51413323516SJiri Pirko return err; 51513323516SJiri Pirko } 51613323516SJiri Pirko 51713323516SJiri Pirko return 0; 51813323516SJiri Pirko } 51913323516SJiri Pirko 520e5c3ea5cSJiri Pirko static size_t br_get_size(const struct net_device *brdev) 521e5c3ea5cSJiri Pirko { 522e5c3ea5cSJiri Pirko return nla_total_size(sizeof(u32)) + /* IFLA_BR_FORWARD_DELAY */ 523e5c3ea5cSJiri Pirko nla_total_size(sizeof(u32)) + /* IFLA_BR_HELLO_TIME */ 524e5c3ea5cSJiri Pirko nla_total_size(sizeof(u32)) + /* IFLA_BR_MAX_AGE */ 525e5c3ea5cSJiri Pirko 0; 526e5c3ea5cSJiri Pirko } 527e5c3ea5cSJiri Pirko 528e5c3ea5cSJiri Pirko static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) 529e5c3ea5cSJiri Pirko { 530e5c3ea5cSJiri Pirko struct net_bridge *br = netdev_priv(brdev); 531e5c3ea5cSJiri Pirko u32 forward_delay = jiffies_to_clock_t(br->forward_delay); 532e5c3ea5cSJiri Pirko u32 hello_time = jiffies_to_clock_t(br->hello_time); 533e5c3ea5cSJiri Pirko u32 age_time = jiffies_to_clock_t(br->max_age); 534e5c3ea5cSJiri Pirko 535e5c3ea5cSJiri Pirko if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) || 536e5c3ea5cSJiri Pirko nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) || 537e5c3ea5cSJiri Pirko nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time)) 538e5c3ea5cSJiri Pirko return -EMSGSIZE; 539e5c3ea5cSJiri Pirko 540e5c3ea5cSJiri Pirko return 0; 541e5c3ea5cSJiri Pirko } 542e5c3ea5cSJiri Pirko 5436cbdceebSVlad Yasevich static size_t br_get_link_af_size(const struct net_device *dev) 5446cbdceebSVlad Yasevich { 5456cbdceebSVlad Yasevich struct net_port_vlans *pv; 5466cbdceebSVlad Yasevich 5476cbdceebSVlad Yasevich if (br_port_exists(dev)) 5481fb1754aSHong Zhiguo pv = nbp_get_vlan_info(br_port_get_rtnl(dev)); 5496cbdceebSVlad Yasevich else if (dev->priv_flags & IFF_EBRIDGE) 5506cbdceebSVlad Yasevich pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev)); 5516cbdceebSVlad Yasevich else 5526cbdceebSVlad Yasevich return 0; 5536cbdceebSVlad Yasevich 5546cbdceebSVlad Yasevich if (!pv) 5556cbdceebSVlad Yasevich return 0; 5566cbdceebSVlad Yasevich 5576cbdceebSVlad Yasevich /* Each VLAN is returned in bridge_vlan_info along with flags */ 5586cbdceebSVlad Yasevich return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info)); 5596cbdceebSVlad Yasevich } 5606cbdceebSVlad Yasevich 56115004cabSCong Wang static struct rtnl_af_ops br_af_ops = { 5626cbdceebSVlad Yasevich .family = AF_BRIDGE, 5636cbdceebSVlad Yasevich .get_link_af_size = br_get_link_af_size, 5646cbdceebSVlad Yasevich }; 5656cbdceebSVlad Yasevich 566149ddd83Sstephen hemminger struct rtnl_link_ops br_link_ops __read_mostly = { 567bb900b27Sstephen hemminger .kind = "bridge", 568bb900b27Sstephen hemminger .priv_size = sizeof(struct net_bridge), 569bb900b27Sstephen hemminger .setup = br_dev_setup, 57013323516SJiri Pirko .maxtype = IFLA_BRPORT_MAX, 57113323516SJiri Pirko .policy = br_policy, 572bb900b27Sstephen hemminger .validate = br_validate, 57330313a3dSToshiaki Makita .newlink = br_dev_newlink, 57413323516SJiri Pirko .changelink = br_changelink, 5751ce5cce8Sstephen hemminger .dellink = br_dev_delete, 576e5c3ea5cSJiri Pirko .get_size = br_get_size, 577e5c3ea5cSJiri Pirko .fill_info = br_fill_info, 5783ac636b8SJiri Pirko 5793ac636b8SJiri Pirko .slave_maxtype = IFLA_BRPORT_MAX, 5803ac636b8SJiri Pirko .slave_policy = br_port_policy, 5813ac636b8SJiri Pirko .slave_changelink = br_port_slave_changelink, 582ced8283fSJiri Pirko .get_slave_size = br_port_get_slave_size, 583ced8283fSJiri Pirko .fill_slave_info = br_port_fill_slave_info, 584bb900b27Sstephen hemminger }; 585bb900b27Sstephen hemminger 586bb900b27Sstephen hemminger int __init br_netlink_init(void) 58711dc1f36SStephen Hemminger { 5883ec8e9f0SVlad Yasevich int err; 5893ec8e9f0SVlad Yasevich 5903ec8e9f0SVlad Yasevich br_mdb_init(); 5913678a9d8Sstephen hemminger rtnl_af_register(&br_af_ops); 5923ec8e9f0SVlad Yasevich 5936cbdceebSVlad Yasevich err = rtnl_link_register(&br_link_ops); 5946cbdceebSVlad Yasevich if (err) 5956cbdceebSVlad Yasevich goto out_af; 5966cbdceebSVlad Yasevich 5973ec8e9f0SVlad Yasevich return 0; 5986cbdceebSVlad Yasevich 5996cbdceebSVlad Yasevich out_af: 6006cbdceebSVlad Yasevich rtnl_af_unregister(&br_af_ops); 6013ec8e9f0SVlad Yasevich br_mdb_uninit(); 6023ec8e9f0SVlad Yasevich return err; 60311dc1f36SStephen Hemminger } 60411dc1f36SStephen Hemminger 605*34666d46SPablo Neira Ayuso void br_netlink_fini(void) 606bb900b27Sstephen hemminger { 6073ec8e9f0SVlad Yasevich br_mdb_uninit(); 6086cbdceebSVlad Yasevich rtnl_af_unregister(&br_af_ops); 609bb900b27Sstephen hemminger rtnl_link_unregister(&br_link_ops); 610bb900b27Sstephen hemminger } 611