diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 0409f9b5bdbc..d4c8cf828240 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -296,6 +296,36 @@ int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) | |||
296 | } | 296 | } |
297 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); | 297 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); |
298 | 298 | ||
299 | /** | ||
300 | * switchdev_port_obj_dump - Dump port objects | ||
301 | * | ||
302 | * @dev: port device | ||
303 | * @obj: object to dump | ||
304 | */ | ||
305 | int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj) | ||
306 | { | ||
307 | const struct switchdev_ops *ops = dev->switchdev_ops; | ||
308 | struct net_device *lower_dev; | ||
309 | struct list_head *iter; | ||
310 | int err = -EOPNOTSUPP; | ||
311 | |||
312 | if (ops && ops->switchdev_port_obj_dump) | ||
313 | return ops->switchdev_port_obj_dump(dev, obj); | ||
314 | |||
315 | /* Switch device port(s) may be stacked under | ||
316 | * bond/team/vlan dev, so recurse down to dump objects on | ||
317 | * first port at bottom of stack. | ||
318 | */ | ||
319 | |||
320 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | ||
321 | err = switchdev_port_obj_dump(lower_dev, obj); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | return err; | ||
326 | } | ||
327 | EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); | ||
328 | |||
299 | static DEFINE_MUTEX(switchdev_mutex); | 329 | static DEFINE_MUTEX(switchdev_mutex); |
300 | static RAW_NOTIFIER_HEAD(switchdev_notif_chain); | 330 | static RAW_NOTIFIER_HEAD(switchdev_notif_chain); |
301 | 331 | ||
@@ -566,6 +596,151 @@ int switchdev_port_bridge_dellink(struct net_device *dev, | |||
566 | } | 596 | } |
567 | EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); | 597 | EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); |
568 | 598 | ||
599 | /** | ||
600 | * switchdev_port_fdb_add - Add FDB (MAC/VLAN) entry to port | ||
601 | * | ||
602 | * @ndmsg: netlink hdr | ||
603 | * @nlattr: netlink attributes | ||
604 | * @dev: port device | ||
605 | * @addr: MAC address to add | ||
606 | * @vid: VLAN to add | ||
607 | * | ||
608 | * Add FDB entry to switch device. | ||
609 | */ | ||
610 | int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | ||
611 | struct net_device *dev, const unsigned char *addr, | ||
612 | u16 vid, u16 nlm_flags) | ||
613 | { | ||
614 | struct switchdev_obj obj = { | ||
615 | .id = SWITCHDEV_OBJ_PORT_FDB, | ||
616 | .u.fdb = { | ||
617 | .addr = addr, | ||
618 | .vid = vid, | ||
619 | }, | ||
620 | }; | ||
621 | |||
622 | return switchdev_port_obj_add(dev, &obj); | ||
623 | } | ||
624 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); | ||
625 | |||
626 | /** | ||
627 | * switchdev_port_fdb_del - Delete FDB (MAC/VLAN) entry from port | ||
628 | * | ||
629 | * @ndmsg: netlink hdr | ||
630 | * @nlattr: netlink attributes | ||
631 | * @dev: port device | ||
632 | * @addr: MAC address to delete | ||
633 | * @vid: VLAN to delete | ||
634 | * | ||
635 | * Delete FDB entry from switch device. | ||
636 | */ | ||
637 | int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | ||
638 | struct net_device *dev, const unsigned char *addr, | ||
639 | u16 vid) | ||
640 | { | ||
641 | struct switchdev_obj obj = { | ||
642 | .id = SWITCHDEV_OBJ_PORT_FDB, | ||
643 | .u.fdb = { | ||
644 | .addr = addr, | ||
645 | .vid = vid, | ||
646 | }, | ||
647 | }; | ||
648 | |||
649 | return switchdev_port_obj_del(dev, &obj); | ||
650 | } | ||
651 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); | ||
652 | |||
653 | struct switchdev_fdb_dump { | ||
654 | struct switchdev_obj obj; | ||
655 | struct sk_buff *skb; | ||
656 | struct netlink_callback *cb; | ||
657 | struct net_device *filter_dev; | ||
658 | int idx; | ||
659 | }; | ||
660 | |||
661 | static int switchdev_port_fdb_dump_cb(struct net_device *dev, | ||
662 | struct switchdev_obj *obj) | ||
663 | { | ||
664 | struct switchdev_fdb_dump *dump = | ||
665 | container_of(obj, struct switchdev_fdb_dump, obj); | ||
666 | u32 portid = NETLINK_CB(dump->cb->skb).portid; | ||
667 | u32 seq = dump->cb->nlh->nlmsg_seq; | ||
668 | struct nlmsghdr *nlh; | ||
669 | struct ndmsg *ndm; | ||
670 | struct net_device *master = netdev_master_upper_dev_get(dev); | ||
671 | |||
672 | if (dump->idx < dump->cb->args[0]) | ||
673 | goto skip; | ||
674 | |||
675 | if (master && dump->filter_dev != master) | ||
676 | goto skip; | ||
677 | |||
678 | nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, | ||
679 | sizeof(*ndm), NLM_F_MULTI); | ||
680 | if (!nlh) | ||
681 | return -EMSGSIZE; | ||
682 | |||
683 | ndm = nlmsg_data(nlh); | ||
684 | ndm->ndm_family = AF_BRIDGE; | ||
685 | ndm->ndm_pad1 = 0; | ||
686 | ndm->ndm_pad2 = 0; | ||
687 | ndm->ndm_flags = NTF_SELF; | ||
688 | ndm->ndm_type = 0; | ||
689 | ndm->ndm_ifindex = dev->ifindex; | ||
690 | ndm->ndm_state = NUD_REACHABLE; | ||
691 | |||
692 | if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, obj->u.fdb.addr)) | ||
693 | goto nla_put_failure; | ||
694 | |||
695 | if (obj->u.fdb.vid && nla_put_u16(dump->skb, NDA_VLAN, obj->u.fdb.vid)) | ||
696 | goto nla_put_failure; | ||
697 | |||
698 | nlmsg_end(dump->skb, nlh); | ||
699 | |||
700 | skip: | ||
701 | dump->idx++; | ||
702 | return 0; | ||
703 | |||
704 | nla_put_failure: | ||
705 | nlmsg_cancel(dump->skb, nlh); | ||
706 | return -EMSGSIZE; | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * switchdev_port_fdb_dump - Dump port FDB (MAC/VLAN) entries | ||
711 | * | ||
712 | * @skb: netlink skb | ||
713 | * @cb: netlink callback | ||
714 | * @dev: port device | ||
715 | * @filter_dev: filter device | ||
716 | * @idx: | ||
717 | * | ||
718 | * Delete FDB entry from switch device. | ||
719 | */ | ||
720 | int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | ||
721 | struct net_device *dev, | ||
722 | struct net_device *filter_dev, int idx) | ||
723 | { | ||
724 | struct switchdev_fdb_dump dump = { | ||
725 | .obj = { | ||
726 | .id = SWITCHDEV_OBJ_PORT_FDB, | ||
727 | .cb = switchdev_port_fdb_dump_cb, | ||
728 | }, | ||
729 | .skb = skb, | ||
730 | .cb = cb, | ||
731 | .filter_dev = filter_dev, | ||
732 | .idx = idx, | ||
733 | }; | ||
734 | int err; | ||
735 | |||
736 | err = switchdev_port_obj_dump(dev, &dump.obj); | ||
737 | if (err) | ||
738 | return err; | ||
739 | |||
740 | return dump.idx; | ||
741 | } | ||
742 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); | ||
743 | |||
569 | static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) | 744 | static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) |
570 | { | 745 | { |
571 | const struct switchdev_ops *ops = dev->switchdev_ops; | 746 | const struct switchdev_ops *ops = dev->switchdev_ops; |