aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/team/team.c')
-rw-r--r--drivers/net/team/team.c198
1 files changed, 116 insertions, 82 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index bc76f946e071..9e9d3e57a2f6 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1571,102 +1571,128 @@ err_fill:
1571 return err; 1571 return err;
1572} 1572}
1573 1573
1574typedef int team_nl_send_func_t(struct sk_buff *skb,
1575 struct team *team, u32 pid);
1576
1577static int team_nl_send_unicast(struct sk_buff *skb, struct team *team, u32 pid)
1578{
1579 return genlmsg_unicast(dev_net(team->dev), skb, pid);
1580}
1581
1574static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team, 1582static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
1575 struct team_option_inst *opt_inst) 1583 struct team_option_inst *opt_inst)
1576{ 1584{
1577 struct nlattr *option_item; 1585 struct nlattr *option_item;
1578 struct team_option *option = opt_inst->option; 1586 struct team_option *option = opt_inst->option;
1579 struct team_option_inst_info *opt_inst_info; 1587 struct team_option_inst_info *opt_inst_info = &opt_inst->info;
1580 struct team_gsetter_ctx ctx; 1588 struct team_gsetter_ctx ctx;
1581 int err; 1589 int err;
1582 1590
1591 ctx.info = opt_inst_info;
1592 err = team_option_get(team, opt_inst, &ctx);
1593 if (err)
1594 return err;
1595
1583 option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION); 1596 option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
1584 if (!option_item) 1597 if (!option_item)
1585 goto nla_put_failure; 1598 return -EMSGSIZE;
1586 if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
1587 goto nla_put_failure;
1588 if (opt_inst->changed) {
1589 if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
1590 goto nla_put_failure;
1591 opt_inst->changed = false;
1592 }
1593 if (opt_inst->removed && nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
1594 goto nla_put_failure;
1595 1599
1596 opt_inst_info = &opt_inst->info; 1600 if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
1601 goto nest_cancel;
1597 if (opt_inst_info->port && 1602 if (opt_inst_info->port &&
1598 nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, 1603 nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
1599 opt_inst_info->port->dev->ifindex)) 1604 opt_inst_info->port->dev->ifindex))
1600 goto nla_put_failure; 1605 goto nest_cancel;
1601 if (opt_inst->option->array_size && 1606 if (opt_inst->option->array_size &&
1602 nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, 1607 nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
1603 opt_inst_info->array_index)) 1608 opt_inst_info->array_index))
1604 goto nla_put_failure; 1609 goto nest_cancel;
1605 ctx.info = opt_inst_info;
1606 1610
1607 switch (option->type) { 1611 switch (option->type) {
1608 case TEAM_OPTION_TYPE_U32: 1612 case TEAM_OPTION_TYPE_U32:
1609 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) 1613 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
1610 goto nla_put_failure; 1614 goto nest_cancel;
1611 err = team_option_get(team, opt_inst, &ctx);
1612 if (err)
1613 goto errout;
1614 if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.u32_val)) 1615 if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.u32_val))
1615 goto nla_put_failure; 1616 goto nest_cancel;
1616 break; 1617 break;
1617 case TEAM_OPTION_TYPE_STRING: 1618 case TEAM_OPTION_TYPE_STRING:
1618 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING)) 1619 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING))
1619 goto nla_put_failure; 1620 goto nest_cancel;
1620 err = team_option_get(team, opt_inst, &ctx);
1621 if (err)
1622 goto errout;
1623 if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA, 1621 if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
1624 ctx.data.str_val)) 1622 ctx.data.str_val))
1625 goto nla_put_failure; 1623 goto nest_cancel;
1626 break; 1624 break;
1627 case TEAM_OPTION_TYPE_BINARY: 1625 case TEAM_OPTION_TYPE_BINARY:
1628 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY)) 1626 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY))
1629 goto nla_put_failure; 1627 goto nest_cancel;
1630 err = team_option_get(team, opt_inst, &ctx);
1631 if (err)
1632 goto errout;
1633 if (nla_put(skb, TEAM_ATTR_OPTION_DATA, ctx.data.bin_val.len, 1628 if (nla_put(skb, TEAM_ATTR_OPTION_DATA, ctx.data.bin_val.len,
1634 ctx.data.bin_val.ptr)) 1629 ctx.data.bin_val.ptr))
1635 goto nla_put_failure; 1630 goto nest_cancel;
1636 break; 1631 break;
1637 case TEAM_OPTION_TYPE_BOOL: 1632 case TEAM_OPTION_TYPE_BOOL:
1638 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG)) 1633 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG))
1639 goto nla_put_failure; 1634 goto nest_cancel;
1640 err = team_option_get(team, opt_inst, &ctx);
1641 if (err)
1642 goto errout;
1643 if (ctx.data.bool_val && 1635 if (ctx.data.bool_val &&
1644 nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) 1636 nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
1645 goto nla_put_failure; 1637 goto nest_cancel;
1646 break; 1638 break;
1647 default: 1639 default:
1648 BUG(); 1640 BUG();
1649 } 1641 }
1642 if (opt_inst->removed && nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED))
1643 goto nest_cancel;
1644 if (opt_inst->changed) {
1645 if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED))
1646 goto nest_cancel;
1647 opt_inst->changed = false;
1648 }
1650 nla_nest_end(skb, option_item); 1649 nla_nest_end(skb, option_item);
1651 return 0; 1650 return 0;
1652 1651
1653nla_put_failure: 1652nest_cancel:
1654 err = -EMSGSIZE; 1653 nla_nest_cancel(skb, option_item);
1655errout: 1654 return -EMSGSIZE;
1656 return err; 1655}
1656
1657static int __send_and_alloc_skb(struct sk_buff **pskb,
1658 struct team *team, u32 pid,
1659 team_nl_send_func_t *send_func)
1660{
1661 int err;
1662
1663 if (*pskb) {
1664 err = send_func(*pskb, team, pid);
1665 if (err)
1666 return err;
1667 }
1668 *pskb = genlmsg_new(NLMSG_DEFAULT_SIZE - GENL_HDRLEN, GFP_KERNEL);
1669 if (!*pskb)
1670 return -ENOMEM;
1671 return 0;
1657} 1672}
1658 1673
1659static int team_nl_fill_options_get(struct sk_buff *skb, 1674static int team_nl_send_options_get(struct team *team, u32 pid, u32 seq,
1660 u32 pid, u32 seq, int flags, 1675 int flags, team_nl_send_func_t *send_func,
1661 struct team *team,
1662 struct list_head *sel_opt_inst_list) 1676 struct list_head *sel_opt_inst_list)
1663{ 1677{
1664 struct nlattr *option_list; 1678 struct nlattr *option_list;
1679 struct nlmsghdr *nlh;
1665 void *hdr; 1680 void *hdr;
1666 struct team_option_inst *opt_inst; 1681 struct team_option_inst *opt_inst;
1667 int err; 1682 int err;
1683 struct sk_buff *skb = NULL;
1684 bool incomplete;
1685 int i;
1668 1686
1669 hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags, 1687 opt_inst = list_first_entry(sel_opt_inst_list,
1688 struct team_option_inst, tmp_list);
1689
1690start_again:
1691 err = __send_and_alloc_skb(&skb, team, pid, send_func);
1692 if (err)
1693 return err;
1694
1695 hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags | NLM_F_MULTI,
1670 TEAM_CMD_OPTIONS_GET); 1696 TEAM_CMD_OPTIONS_GET);
1671 if (IS_ERR(hdr)) 1697 if (IS_ERR(hdr))
1672 return PTR_ERR(hdr); 1698 return PTR_ERR(hdr);
@@ -1677,46 +1703,62 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
1677 if (!option_list) 1703 if (!option_list)
1678 goto nla_put_failure; 1704 goto nla_put_failure;
1679 1705
1680 list_for_each_entry(opt_inst, sel_opt_inst_list, tmp_list) { 1706 i = 0;
1707 incomplete = false;
1708 list_for_each_entry_from(opt_inst, sel_opt_inst_list, tmp_list) {
1681 err = team_nl_fill_one_option_get(skb, team, opt_inst); 1709 err = team_nl_fill_one_option_get(skb, team, opt_inst);
1682 if (err) 1710 if (err) {
1711 if (err == -EMSGSIZE) {
1712 if (!i)
1713 goto errout;
1714 incomplete = true;
1715 break;
1716 }
1683 goto errout; 1717 goto errout;
1718 }
1719 i++;
1684 } 1720 }
1685 1721
1686 nla_nest_end(skb, option_list); 1722 nla_nest_end(skb, option_list);
1687 return genlmsg_end(skb, hdr); 1723 genlmsg_end(skb, hdr);
1724 if (incomplete)
1725 goto start_again;
1726
1727send_done:
1728 nlh = nlmsg_put(skb, pid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI);
1729 if (!nlh) {
1730 err = __send_and_alloc_skb(&skb, team, pid, send_func);
1731 if (err)
1732 goto errout;
1733 goto send_done;
1734 }
1735
1736 return send_func(skb, team, pid);
1688 1737
1689nla_put_failure: 1738nla_put_failure:
1690 err = -EMSGSIZE; 1739 err = -EMSGSIZE;
1691errout: 1740errout:
1692 genlmsg_cancel(skb, hdr); 1741 genlmsg_cancel(skb, hdr);
1742 nlmsg_free(skb);
1693 return err; 1743 return err;
1694} 1744}
1695 1745
1696static int team_nl_fill_options_get_all(struct sk_buff *skb,
1697 struct genl_info *info, int flags,
1698 struct team *team)
1699{
1700 struct team_option_inst *opt_inst;
1701 LIST_HEAD(sel_opt_inst_list);
1702
1703 list_for_each_entry(opt_inst, &team->option_inst_list, list)
1704 list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
1705 return team_nl_fill_options_get(skb, info->snd_pid,
1706 info->snd_seq, NLM_F_ACK,
1707 team, &sel_opt_inst_list);
1708}
1709
1710static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info) 1746static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
1711{ 1747{
1712 struct team *team; 1748 struct team *team;
1749 struct team_option_inst *opt_inst;
1713 int err; 1750 int err;
1751 LIST_HEAD(sel_opt_inst_list);
1714 1752
1715 team = team_nl_team_get(info); 1753 team = team_nl_team_get(info);
1716 if (!team) 1754 if (!team)
1717 return -EINVAL; 1755 return -EINVAL;
1718 1756
1719 err = team_nl_send_generic(info, team, team_nl_fill_options_get_all); 1757 list_for_each_entry(opt_inst, &team->option_inst_list, list)
1758 list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
1759 err = team_nl_send_options_get(team, info->snd_pid, info->snd_seq,
1760 NLM_F_ACK, team_nl_send_unicast,
1761 &sel_opt_inst_list);
1720 1762
1721 team_nl_team_put(team); 1763 team_nl_team_put(team);
1722 1764
@@ -1963,28 +2005,18 @@ static struct genl_multicast_group team_change_event_mcgrp = {
1963 .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, 2005 .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
1964}; 2006};
1965 2007
2008static int team_nl_send_multicast(struct sk_buff *skb,
2009 struct team *team, u32 pid)
2010{
2011 return genlmsg_multicast_netns(dev_net(team->dev), skb, 0,
2012 team_change_event_mcgrp.id, GFP_KERNEL);
2013}
2014
1966static int team_nl_send_event_options_get(struct team *team, 2015static int team_nl_send_event_options_get(struct team *team,
1967 struct list_head *sel_opt_inst_list) 2016 struct list_head *sel_opt_inst_list)
1968{ 2017{
1969 struct sk_buff *skb; 2018 return team_nl_send_options_get(team, 0, 0, 0, team_nl_send_multicast,
1970 int err; 2019 sel_opt_inst_list);
1971 struct net *net = dev_net(team->dev);
1972
1973 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1974 if (!skb)
1975 return -ENOMEM;
1976
1977 err = team_nl_fill_options_get(skb, 0, 0, 0, team, sel_opt_inst_list);
1978 if (err < 0)
1979 goto err_fill;
1980
1981 err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
1982 GFP_KERNEL);
1983 return err;
1984
1985err_fill:
1986 nlmsg_free(skb);
1987 return err;
1988} 2020}
1989 2021
1990static int team_nl_send_event_port_list_get(struct team *team) 2022static int team_nl_send_event_port_list_get(struct team *team)
@@ -2053,7 +2085,8 @@ static void __team_options_change_check(struct team *team)
2053 } 2085 }
2054 err = team_nl_send_event_options_get(team, &sel_opt_inst_list); 2086 err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
2055 if (err) 2087 if (err)
2056 netdev_warn(team->dev, "Failed to send options change via netlink\n"); 2088 netdev_warn(team->dev, "Failed to send options change via netlink (err %d)\n",
2089 err);
2057} 2090}
2058 2091
2059static void __team_option_inst_change(struct team *team, 2092static void __team_option_inst_change(struct team *team,
@@ -2066,7 +2099,8 @@ static void __team_option_inst_change(struct team *team,
2066 list_add(&sel_opt_inst->tmp_list, &sel_opt_inst_list); 2099 list_add(&sel_opt_inst->tmp_list, &sel_opt_inst_list);
2067 err = team_nl_send_event_options_get(team, &sel_opt_inst_list); 2100 err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
2068 if (err) 2101 if (err)
2069 netdev_warn(team->dev, "Failed to send option change via netlink\n"); 2102 netdev_warn(team->dev, "Failed to send option change via netlink (err %d)\n",
2103 err);
2070} 2104}
2071 2105
2072/* rtnl lock is held */ 2106/* rtnl lock is held */