Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce76ca68 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

rocker: implement ndo_fdb_dump

parent 6c707945
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -3587,6 +3587,78 @@ static int rocker_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
	return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
}

static int rocker_fdb_fill_info(struct sk_buff *skb,
				struct rocker_port *rocker_port,
				const unsigned char *addr, u16 vid,
				u32 portid, u32 seq, int type,
				unsigned int flags)
{
	struct nlmsghdr *nlh;
	struct ndmsg *ndm;

	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
	if (!nlh)
		return -EMSGSIZE;

	ndm = nlmsg_data(nlh);
	ndm->ndm_family	 = AF_BRIDGE;
	ndm->ndm_pad1    = 0;
	ndm->ndm_pad2    = 0;
	ndm->ndm_flags	 = NTF_SELF;
	ndm->ndm_type	 = 0;
	ndm->ndm_ifindex = rocker_port->dev->ifindex;
	ndm->ndm_state   = NUD_REACHABLE;

	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr))
		goto nla_put_failure;

	if (vid && nla_put_u16(skb, NDA_VLAN, vid))
		goto nla_put_failure;

	return nlmsg_end(skb, nlh);

nla_put_failure:
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
}

static int rocker_port_fdb_dump(struct sk_buff *skb,
				struct netlink_callback *cb,
				struct net_device *dev,
				struct net_device *filter_dev,
				int idx)
{
	struct rocker_port *rocker_port = netdev_priv(dev);
	struct rocker *rocker = rocker_port->rocker;
	struct rocker_fdb_tbl_entry *found;
	struct hlist_node *tmp;
	int bkt;
	unsigned long lock_flags;
	const unsigned char *addr;
	u16 vid;
	int err;

	spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
	hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
		if (found->key.lport != rocker_port->lport)
			continue;
		if (idx < cb->args[0])
			goto skip;
		addr = found->key.addr;
		vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id);
		err = rocker_fdb_fill_info(skb, rocker_port, addr, vid,
					   NETLINK_CB(cb->skb).portid,
					   cb->nlh->nlmsg_seq,
					   RTM_NEWNEIGH, NLM_F_MULTI);
		if (err < 0)
			break;
skip:
		++idx;
	}
	spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
	return idx;
}

static int rocker_port_switch_parent_id_get(struct net_device *dev,
					    struct netdev_phys_item_id *psid)
{
@@ -3614,6 +3686,7 @@ static const struct net_device_ops rocker_port_netdev_ops = {
	.ndo_vlan_rx_kill_vid		= rocker_port_vlan_rx_kill_vid,
	.ndo_fdb_add			= rocker_port_fdb_add,
	.ndo_fdb_del			= rocker_port_fdb_del,
	.ndo_fdb_dump			= rocker_port_fdb_dump,
	.ndo_switch_parent_id_get	= rocker_port_switch_parent_id_get,
	.ndo_switch_port_stp_update	= rocker_port_switch_port_stp_update,
};