diff options
| author | Samudrala, Sridhar <sridhar.samudrala@intel.com> | 2015-05-14 00:55:43 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-05-17 22:49:09 -0400 |
| commit | 45d4122ca7cdb3a4b91f392605cd22cfa75f1d99 (patch) | |
| tree | 5b4524c25f701e345a1526ce9379ea5b3c1beee2 /net/switchdev | |
| parent | 5d48ef3e954cae2f237ff8e006322d2f3b672375 (diff) | |
switchdev: add support for fdb add/del/dump via switchdev_port_obj ops.
- introduce port fdb obj and generic switchdev_port_fdb_add/del/dump()
- use switchdev_port_fdb_add/del/dump in rocker/team/bonding ndo ops.
- add support for fdb obj in switchdev_port_obj_add/del/dump()
- switch rocker to implement fdb ops via switchdev_ops
v3: updated to sync with named union changes.
Signed-off-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev')
| -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; |
