Commit 38985e8c authored by Amit Cohen's avatar Amit Cohen Committed by David S. Miller

net: Handle bulk delete policy in bridge driver

The merge commit 92716869 ("Merge branch 'br-flush-filtering'")
added support for FDB flushing in bridge driver. The following patches
will extend VXLAN driver to support FDB flushing as well. The netlink
message for bulk delete is shared between the drivers. With the existing
implementation, there is no way to prevent user from flushing with
attributes that are not supported per driver. For example, when VNI will
be added, user will not get an error for flush FDB entries in bridge
with VNI, although this attribute is not relevant for bridge.

As preparation for support of FDB flush in VXLAN driver, move the policy
to be handled in bridge driver, later a new policy for VXLAN will be
added in VXLAN driver. Do not pass 'vid' as part of ndo_fdb_del_bulk(),
as this field is relevant only for bridge.
Signed-off-by: default avatarAmit Cohen <amcohen@nvidia.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e6bb5b7
...@@ -1287,9 +1287,7 @@ struct netdev_net_notifier { ...@@ -1287,9 +1287,7 @@ struct netdev_net_notifier {
* struct net_device *dev, * struct net_device *dev,
* const unsigned char *addr, u16 vid) * const unsigned char *addr, u16 vid)
* Deletes the FDB entry from dev coresponding to addr. * Deletes the FDB entry from dev coresponding to addr.
* int (*ndo_fdb_del_bulk)(struct ndmsg *ndm, struct nlattr *tb[], * int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh, struct net_device *dev,
* struct net_device *dev,
* u16 vid,
* struct netlink_ext_ack *extack); * struct netlink_ext_ack *extack);
* int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
* struct net_device *dev, struct net_device *filter_dev, * struct net_device *dev, struct net_device *filter_dev,
...@@ -1564,10 +1562,8 @@ struct net_device_ops { ...@@ -1564,10 +1562,8 @@ struct net_device_ops {
struct net_device *dev, struct net_device *dev,
const unsigned char *addr, const unsigned char *addr,
u16 vid, struct netlink_ext_ack *extack); u16 vid, struct netlink_ext_ack *extack);
int (*ndo_fdb_del_bulk)(struct ndmsg *ndm, int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh,
struct nlattr *tb[],
struct net_device *dev, struct net_device *dev,
u16 vid,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int (*ndo_fdb_dump)(struct sk_buff *skb, int (*ndo_fdb_dump)(struct sk_buff *skb,
struct netlink_callback *cb, struct netlink_callback *cb,
......
...@@ -661,14 +661,30 @@ static int __fdb_flush_validate_ifindex(const struct net_bridge *br, ...@@ -661,14 +661,30 @@ static int __fdb_flush_validate_ifindex(const struct net_bridge *br,
return 0; return 0;
} }
int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], static const struct nla_policy br_fdb_del_bulk_policy[NDA_MAX + 1] = {
struct net_device *dev, u16 vid, [NDA_VLAN] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
[NDA_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 1),
[NDA_NDM_STATE_MASK] = { .type = NLA_U16 },
[NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 },
};
int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
u8 ndm_flags = ndm->ndm_flags & ~FDB_FLUSH_IGNORED_NDM_FLAGS; struct net_bridge_fdb_flush_desc desc = {};
struct net_bridge_fdb_flush_desc desc = { .vlan_id = vid }; struct ndmsg *ndm = nlmsg_data(nlh);
struct net_bridge_port *p = NULL; struct net_bridge_port *p = NULL;
struct nlattr *tb[NDA_MAX + 1];
struct net_bridge *br; struct net_bridge *br;
u8 ndm_flags;
int err;
ndm_flags = ndm->ndm_flags & ~FDB_FLUSH_IGNORED_NDM_FLAGS;
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX,
br_fdb_del_bulk_policy, extack);
if (err)
return err;
if (netif_is_bridge_master(dev)) { if (netif_is_bridge_master(dev)) {
br = netdev_priv(dev); br = netdev_priv(dev);
...@@ -681,6 +697,9 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], ...@@ -681,6 +697,9 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[],
br = p->br; br = p->br;
} }
if (tb[NDA_VLAN])
desc.vlan_id = nla_get_u16(tb[NDA_VLAN]);
if (ndm_flags & ~FDB_FLUSH_ALLOWED_NDM_FLAGS) { if (ndm_flags & ~FDB_FLUSH_ALLOWED_NDM_FLAGS) {
NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm flag bits set"); NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm flag bits set");
return -EINVAL; return -EINVAL;
...@@ -703,7 +722,7 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], ...@@ -703,7 +722,7 @@ int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[],
desc.flags_mask |= __ndm_flags_to_fdb_flags(ndm_flags_mask); desc.flags_mask |= __ndm_flags_to_fdb_flags(ndm_flags_mask);
} }
if (tb[NDA_IFINDEX]) { if (tb[NDA_IFINDEX]) {
int err, ifidx = nla_get_s32(tb[NDA_IFINDEX]); int ifidx = nla_get_s32(tb[NDA_IFINDEX]);
err = __fdb_flush_validate_ifindex(br, ifidx, extack); err = __fdb_flush_validate_ifindex(br, ifidx, extack);
if (err) if (err)
......
...@@ -847,8 +847,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, ...@@ -847,8 +847,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev, const unsigned char *addr, u16 vid, struct net_device *dev, const unsigned char *addr, u16 vid,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[], int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev,
struct net_device *dev, u16 vid,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
const unsigned char *addr, u16 vid, u16 nlh_flags, const unsigned char *addr, u16 vid, u16 nlh_flags,
......
...@@ -4367,13 +4367,6 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm, ...@@ -4367,13 +4367,6 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm,
} }
EXPORT_SYMBOL(ndo_dflt_fdb_del); EXPORT_SYMBOL(ndo_dflt_fdb_del);
static const struct nla_policy fdb_del_bulk_policy[NDA_MAX + 1] = {
[NDA_VLAN] = { .type = NLA_U16 },
[NDA_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 1),
[NDA_NDM_STATE_MASK] = { .type = NLA_U16 },
[NDA_NDM_FLAGS_MASK] = { .type = NLA_U8 },
};
static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
...@@ -4394,8 +4387,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4394,8 +4387,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
NULL, extack); NULL, extack);
} else { } else {
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, /* For bulk delete, the drivers will parse the message with
fdb_del_bulk_policy, extack); * policy.
*/
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack);
} }
if (err < 0) if (err < 0)
return err; return err;
...@@ -4418,6 +4413,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4418,6 +4413,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
return -EINVAL; return -EINVAL;
} }
addr = nla_data(tb[NDA_LLADDR]); addr = nla_data(tb[NDA_LLADDR]);
err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack);
if (err)
return err;
} }
if (dev->type != ARPHRD_ETHER) { if (dev->type != ARPHRD_ETHER) {
...@@ -4425,10 +4424,6 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4425,10 +4424,6 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
return -EINVAL; return -EINVAL;
} }
err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack);
if (err)
return err;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
/* Support fdb on master device the net/bridge default case */ /* Support fdb on master device the net/bridge default case */
...@@ -4442,8 +4437,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4442,8 +4437,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid, extack); err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid, extack);
} else { } else {
if (ops->ndo_fdb_del_bulk) if (ops->ndo_fdb_del_bulk)
err = ops->ndo_fdb_del_bulk(ndm, tb, dev, vid, err = ops->ndo_fdb_del_bulk(nlh, dev, extack);
extack);
} }
if (err) if (err)
...@@ -4464,8 +4458,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4464,8 +4458,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
/* in case err was cleared by NTF_MASTER call */ /* in case err was cleared by NTF_MASTER call */
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (ops->ndo_fdb_del_bulk) if (ops->ndo_fdb_del_bulk)
err = ops->ndo_fdb_del_bulk(ndm, tb, dev, vid, err = ops->ndo_fdb_del_bulk(nlh, dev, extack);
extack);
} }
if (!err) { if (!err) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment