diff options
Diffstat (limited to 'net/bridge/br_mdb.c')
-rw-r--r-- | net/bridge/br_mdb.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 25c48d81a597..cb8270a5480b 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -458,6 +458,39 @@ out: return skb->len; } +int br_mdb_dump_new(struct net_device *dev, struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct net_bridge *br = netdev_priv(dev); + struct br_port_msg *bpm; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, RTM_GETMDB, sizeof(*bpm), + NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + bpm = nlmsg_data(nlh); + memset(bpm, 0, sizeof(*bpm)); + bpm->ifindex = dev->ifindex; + + rcu_read_lock(); + + err = br_mdb_fill_info(skb, cb, dev); + if (err) + goto out; + err = br_rports_fill_info(skb, &br->multicast_ctx); + if (err) + goto out; + +out: + rcu_read_unlock(); + nlmsg_end(skb, nlh); + return err; +} + static int nlmsg_populate_mdb_fill(struct sk_buff *skb, struct net_device *dev, struct net_bridge_mdb_entry *mp, @@ -1459,6 +1492,65 @@ out: return err; } +int br_mdb_add_new(struct net_device *dev, struct nlattr *tb[], u16 nlmsg_flags, + struct netlink_ext_ack *extack) +{ + struct net_bridge_vlan_group *vg; + struct br_mdb_config cfg = {}; + struct net_bridge_vlan *v; + int err; + + /* Configuration structure will be initialized here. */ + + err = -EINVAL; + /* host join errors which can happen before creating the group */ + if (!cfg.p && !br_group_is_l2(&cfg.group)) { + /* don't allow any flags for host-joined IP groups */ + if (cfg.entry->state) { + NL_SET_ERR_MSG_MOD(extack, "Flags are not allowed for host groups"); + goto out; + } + if (!br_multicast_is_star_g(&cfg.group)) { + NL_SET_ERR_MSG_MOD(extack, "Groups with sources cannot be manually host joined"); + goto out; + } + } + + if (br_group_is_l2(&cfg.group) && cfg.entry->state != MDB_PERMANENT) { + NL_SET_ERR_MSG_MOD(extack, "Only permanent L2 entries allowed"); + goto out; + } + + if (cfg.p) { + if (cfg.p->state == BR_STATE_DISABLED && cfg.entry->state != MDB_PERMANENT) { + NL_SET_ERR_MSG_MOD(extack, "Port is in disabled state and entry is not permanent"); + goto out; + } + vg = nbp_vlan_group(cfg.p); + } else { + vg = br_vlan_group(cfg.br); + } + + /* If vlan filtering is enabled and VLAN is not specified + * install mdb entry on all vlans configured on the port. + */ + if (br_vlan_enabled(cfg.br->dev) && vg && cfg.entry->vid == 0) { + list_for_each_entry(v, &vg->vlan_list, vlist) { + cfg.entry->vid = v->vid; + cfg.group.vid = v->vid; + err = __br_mdb_add(&cfg, extack); + if (err) + break; + } + } else { + err = __br_mdb_add(&cfg, extack); + } + +out: + br_mdb_config_fini(&cfg); + return err; +} + static int __br_mdb_del(const struct br_mdb_config *cfg) { struct br_mdb_entry *entry = cfg->entry; @@ -1535,6 +1627,38 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, return err; } +int br_mdb_del_new(struct net_device *dev, struct nlattr *tb[], + struct netlink_ext_ack *extack) +{ + struct net_bridge_vlan_group *vg; + struct br_mdb_config cfg = {}; + struct net_bridge_vlan *v; + int err = 0; + + /* Configuration structure will be initialized here. */ + + if (cfg.p) + vg = nbp_vlan_group(cfg.p); + else + vg = br_vlan_group(cfg.br); + + /* If vlan filtering is enabled and VLAN is not specified + * delete mdb entry on all vlans configured on the port. + */ + if (br_vlan_enabled(cfg.br->dev) && vg && cfg.entry->vid == 0) { + list_for_each_entry(v, &vg->vlan_list, vlist) { + cfg.entry->vid = v->vid; + cfg.group.vid = v->vid; + err = __br_mdb_del(&cfg); + } + } else { + err = __br_mdb_del(&cfg); + } + + br_mdb_config_fini(&cfg); + return err; +} + void br_mdb_init(void) { rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, 0); |