Skip to content

Commit 9b00cf2

Browse files
Jiri Pirkodavem330
authored andcommitted
team: implement multipart netlink messages for options transfers
Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ab8250d commit 9b00cf2

File tree

1 file changed

+116
-82
lines changed

1 file changed

+116
-82
lines changed

drivers/net/team/team.c

Lines changed: 116 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,102 +1571,128 @@ static int team_nl_send_generic(struct genl_info *info, struct team *team,
15711571
return err;
15721572
}
15731573

1574+
typedef int team_nl_send_func_t(struct sk_buff *skb,
1575+
struct team *team, u32 pid);
1576+
1577+
static 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+
15741582
static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
15751583
struct team_option_inst *opt_inst)
15761584
{
15771585
struct nlattr *option_item;
15781586
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;
15801588
struct team_gsetter_ctx ctx;
15811589
int err;
15821590

1591+
ctx.info = opt_inst_info;
1592+
err = team_option_get(team, opt_inst, &ctx);
1593+
if (err)
1594+
return err;
1595+
15831596
option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
15841597
if (!option_item)
1585-
goto nla_put_failure;
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;
1598+
return -EMSGSIZE;
15951599

1596-
opt_inst_info = &opt_inst->info;
1600+
if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name))
1601+
goto nest_cancel;
15971602
if (opt_inst_info->port &&
15981603
nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX,
15991604
opt_inst_info->port->dev->ifindex))
1600-
goto nla_put_failure;
1605+
goto nest_cancel;
16011606
if (opt_inst->option->array_size &&
16021607
nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX,
16031608
opt_inst_info->array_index))
1604-
goto nla_put_failure;
1605-
ctx.info = opt_inst_info;
1609+
goto nest_cancel;
16061610

16071611
switch (option->type) {
16081612
case TEAM_OPTION_TYPE_U32:
16091613
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32))
1610-
goto nla_put_failure;
1611-
err = team_option_get(team, opt_inst, &ctx);
1612-
if (err)
1613-
goto errout;
1614+
goto nest_cancel;
16141615
if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.u32_val))
1615-
goto nla_put_failure;
1616+
goto nest_cancel;
16161617
break;
16171618
case TEAM_OPTION_TYPE_STRING:
16181619
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING))
1619-
goto nla_put_failure;
1620-
err = team_option_get(team, opt_inst, &ctx);
1621-
if (err)
1622-
goto errout;
1620+
goto nest_cancel;
16231621
if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA,
16241622
ctx.data.str_val))
1625-
goto nla_put_failure;
1623+
goto nest_cancel;
16261624
break;
16271625
case TEAM_OPTION_TYPE_BINARY:
16281626
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY))
1629-
goto nla_put_failure;
1630-
err = team_option_get(team, opt_inst, &ctx);
1631-
if (err)
1632-
goto errout;
1627+
goto nest_cancel;
16331628
if (nla_put(skb, TEAM_ATTR_OPTION_DATA, ctx.data.bin_val.len,
16341629
ctx.data.bin_val.ptr))
1635-
goto nla_put_failure;
1630+
goto nest_cancel;
16361631
break;
16371632
case TEAM_OPTION_TYPE_BOOL:
16381633
if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG))
1639-
goto nla_put_failure;
1640-
err = team_option_get(team, opt_inst, &ctx);
1641-
if (err)
1642-
goto errout;
1634+
goto nest_cancel;
16431635
if (ctx.data.bool_val &&
16441636
nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
1645-
goto nla_put_failure;
1637+
goto nest_cancel;
16461638
break;
16471639
default:
16481640
BUG();
16491641
}
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+
}
16501649
nla_nest_end(skb, option_item);
16511650
return 0;
16521651

1653-
nla_put_failure:
1654-
err = -EMSGSIZE;
1655-
errout:
1656-
return err;
1652+
nest_cancel:
1653+
nla_nest_cancel(skb, option_item);
1654+
return -EMSGSIZE;
1655+
}
1656+
1657+
static 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;
16571672
}
16581673

1659-
static int team_nl_fill_options_get(struct sk_buff *skb,
1660-
u32 pid, u32 seq, int flags,
1661-
struct team *team,
1674+
static int team_nl_send_options_get(struct team *team, u32 pid, u32 seq,
1675+
int flags, team_nl_send_func_t *send_func,
16621676
struct list_head *sel_opt_inst_list)
16631677
{
16641678
struct nlattr *option_list;
1679+
struct nlmsghdr *nlh;
16651680
void *hdr;
16661681
struct team_option_inst *opt_inst;
16671682
int err;
1683+
struct sk_buff *skb = NULL;
1684+
bool incomplete;
1685+
int i;
16681686

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+
1690+
start_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,
16701696
TEAM_CMD_OPTIONS_GET);
16711697
if (IS_ERR(hdr))
16721698
return PTR_ERR(hdr);
@@ -1677,46 +1703,62 @@ static int team_nl_fill_options_get(struct sk_buff *skb,
16771703
if (!option_list)
16781704
goto nla_put_failure;
16791705

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) {
16811709
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+
}
16831717
goto errout;
1718+
}
1719+
i++;
16841720
}
16851721

16861722
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+
1727+
send_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);
16881737

16891738
nla_put_failure:
16901739
err = -EMSGSIZE;
16911740
errout:
16921741
genlmsg_cancel(skb, hdr);
1742+
nlmsg_free(skb);
16931743
return err;
16941744
}
16951745

1696-
static 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-
17101746
static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
17111747
{
17121748
struct team *team;
1749+
struct team_option_inst *opt_inst;
17131750
int err;
1751+
LIST_HEAD(sel_opt_inst_list);
17141752

17151753
team = team_nl_team_get(info);
17161754
if (!team)
17171755
return -EINVAL;
17181756

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);
17201762

17211763
team_nl_team_put(team);
17221764

@@ -1963,28 +2005,18 @@ static struct genl_multicast_group team_change_event_mcgrp = {
19632005
.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
19642006
};
19652007

2008+
static 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+
19662015
static int team_nl_send_event_options_get(struct team *team,
19672016
struct list_head *sel_opt_inst_list)
19682017
{
1969-
struct sk_buff *skb;
1970-
int err;
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-
1985-
err_fill:
1986-
nlmsg_free(skb);
1987-
return err;
2018+
return team_nl_send_options_get(team, 0, 0, 0, team_nl_send_multicast,
2019+
sel_opt_inst_list);
19882020
}
19892021

19902022
static int team_nl_send_event_port_list_get(struct team *team)
@@ -2053,7 +2085,8 @@ static void __team_options_change_check(struct team *team)
20532085
}
20542086
err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
20552087
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);
20572090
}
20582091

20592092
static void __team_option_inst_change(struct team *team,
@@ -2066,7 +2099,8 @@ static void __team_option_inst_change(struct team *team,
20662099
list_add(&sel_opt_inst->tmp_list, &sel_opt_inst_list);
20672100
err = team_nl_send_event_options_get(team, &sel_opt_inst_list);
20682101
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);
20702104
}
20712105

20722106
/* rtnl lock is held */

0 commit comments

Comments
 (0)