|
@@ -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);
|
|
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,
|
|
static int rocker_port_switch_parent_id_get(struct net_device *dev,
|
|
struct netdev_phys_item_id *psid)
|
|
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_vlan_rx_kill_vid = rocker_port_vlan_rx_kill_vid,
|
|
.ndo_fdb_add = rocker_port_fdb_add,
|
|
.ndo_fdb_add = rocker_port_fdb_add,
|
|
.ndo_fdb_del = rocker_port_fdb_del,
|
|
.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_parent_id_get = rocker_port_switch_parent_id_get,
|
|
.ndo_switch_port_stp_update = rocker_port_switch_port_stp_update,
|
|
.ndo_switch_port_stp_update = rocker_port_switch_port_stp_update,
|
|
};
|
|
};
|