diff options
author | Jiri Pirko <jpirko@redhat.com> | 2012-06-19 01:54:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-19 18:00:23 -0400 |
commit | 01048d9a293cbe9aac00fd014b9754bbc7eb136f (patch) | |
tree | e39bbe3f797a1a6bfa2c5a08480826498bfc40ef /drivers/net | |
parent | 3221c64603d9843d8a28dfd8e678e46625d5d807 (diff) |
team: allow to specify one option instance to be send to userspace
No need to walk through option instance list and look for ->changed ==
true when called knows exactly what one option instance changed.
Also use lists to pass option instances needed to be present in netlink
message.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/team/team.c | 210 |
1 files changed, 124 insertions, 86 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index e977f440c378..da72f41d3914 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -89,6 +89,7 @@ static void team_refresh_port_linkup(struct team_port *port) | |||
89 | 89 | ||
90 | struct team_option_inst { /* One for each option instance */ | 90 | struct team_option_inst { /* One for each option instance */ |
91 | struct list_head list; | 91 | struct list_head list; |
92 | struct list_head tmp_list; | ||
92 | struct team_option *option; | 93 | struct team_option *option; |
93 | struct team_option_inst_info info; | 94 | struct team_option_inst_info info; |
94 | bool changed; | 95 | bool changed; |
@@ -319,6 +320,8 @@ static void __team_options_unregister(struct team *team, | |||
319 | } | 320 | } |
320 | 321 | ||
321 | static void __team_options_change_check(struct team *team); | 322 | static void __team_options_change_check(struct team *team); |
323 | static void __team_option_inst_change(struct team *team, | ||
324 | struct team_option_inst *opt_inst); | ||
322 | 325 | ||
323 | int team_options_register(struct team *team, | 326 | int team_options_register(struct team *team, |
324 | const struct team_option *option, | 327 | const struct team_option *option, |
@@ -383,8 +386,7 @@ static int team_option_set(struct team *team, | |||
383 | if (err) | 386 | if (err) |
384 | return err; | 387 | return err; |
385 | 388 | ||
386 | opt_inst->changed = true; | 389 | __team_option_inst_change(team, opt_inst); |
387 | __team_options_change_check(team); | ||
388 | return err; | 390 | return err; |
389 | } | 391 | } |
390 | 392 | ||
@@ -1565,9 +1567,95 @@ err_fill: | |||
1565 | return err; | 1567 | return err; |
1566 | } | 1568 | } |
1567 | 1569 | ||
1570 | static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team, | ||
1571 | struct team_option_inst *opt_inst) | ||
1572 | { | ||
1573 | struct nlattr *option_item; | ||
1574 | struct team_option *option = opt_inst->option; | ||
1575 | struct team_option_inst_info *opt_inst_info; | ||
1576 | struct team_gsetter_ctx ctx; | ||
1577 | int err; | ||
1578 | |||
1579 | option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION); | ||
1580 | if (!option_item) | ||
1581 | goto nla_put_failure; | ||
1582 | if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name)) | ||
1583 | goto nla_put_failure; | ||
1584 | if (opt_inst->changed) { | ||
1585 | if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED)) | ||
1586 | goto nla_put_failure; | ||
1587 | opt_inst->changed = false; | ||
1588 | } | ||
1589 | if (opt_inst->removed && nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED)) | ||
1590 | goto nla_put_failure; | ||
1591 | |||
1592 | opt_inst_info = &opt_inst->info; | ||
1593 | if (opt_inst_info->port && | ||
1594 | nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, | ||
1595 | opt_inst_info->port->dev->ifindex)) | ||
1596 | goto nla_put_failure; | ||
1597 | if (opt_inst->option->array_size && | ||
1598 | nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, | ||
1599 | opt_inst_info->array_index)) | ||
1600 | goto nla_put_failure; | ||
1601 | ctx.info = opt_inst_info; | ||
1602 | |||
1603 | switch (option->type) { | ||
1604 | case TEAM_OPTION_TYPE_U32: | ||
1605 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) | ||
1606 | goto nla_put_failure; | ||
1607 | err = team_option_get(team, opt_inst, &ctx); | ||
1608 | if (err) | ||
1609 | goto errout; | ||
1610 | if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.u32_val)) | ||
1611 | goto nla_put_failure; | ||
1612 | break; | ||
1613 | case TEAM_OPTION_TYPE_STRING: | ||
1614 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING)) | ||
1615 | goto nla_put_failure; | ||
1616 | err = team_option_get(team, opt_inst, &ctx); | ||
1617 | if (err) | ||
1618 | goto errout; | ||
1619 | if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA, | ||
1620 | ctx.data.str_val)) | ||
1621 | goto nla_put_failure; | ||
1622 | break; | ||
1623 | case TEAM_OPTION_TYPE_BINARY: | ||
1624 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY)) | ||
1625 | goto nla_put_failure; | ||
1626 | err = team_option_get(team, opt_inst, &ctx); | ||
1627 | if (err) | ||
1628 | goto errout; | ||
1629 | if (nla_put(skb, TEAM_ATTR_OPTION_DATA, ctx.data.bin_val.len, | ||
1630 | ctx.data.bin_val.ptr)) | ||
1631 | goto nla_put_failure; | ||
1632 | break; | ||
1633 | case TEAM_OPTION_TYPE_BOOL: | ||
1634 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG)) | ||
1635 | goto nla_put_failure; | ||
1636 | err = team_option_get(team, opt_inst, &ctx); | ||
1637 | if (err) | ||
1638 | goto errout; | ||
1639 | if (ctx.data.bool_val && | ||
1640 | nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) | ||
1641 | goto nla_put_failure; | ||
1642 | break; | ||
1643 | default: | ||
1644 | BUG(); | ||
1645 | } | ||
1646 | nla_nest_end(skb, option_item); | ||
1647 | return 0; | ||
1648 | |||
1649 | nla_put_failure: | ||
1650 | err = -EMSGSIZE; | ||
1651 | errout: | ||
1652 | return err; | ||
1653 | } | ||
1654 | |||
1568 | static int team_nl_fill_options_get(struct sk_buff *skb, | 1655 | static int team_nl_fill_options_get(struct sk_buff *skb, |
1569 | u32 pid, u32 seq, int flags, | 1656 | u32 pid, u32 seq, int flags, |
1570 | struct team *team, bool fillall) | 1657 | struct team *team, |
1658 | struct list_head *sel_opt_inst_list) | ||
1571 | { | 1659 | { |
1572 | struct nlattr *option_list; | 1660 | struct nlattr *option_list; |
1573 | void *hdr; | 1661 | void *hdr; |
@@ -1585,85 +1673,10 @@ static int team_nl_fill_options_get(struct sk_buff *skb, | |||
1585 | if (!option_list) | 1673 | if (!option_list) |
1586 | goto nla_put_failure; | 1674 | goto nla_put_failure; |
1587 | 1675 | ||
1588 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { | 1676 | list_for_each_entry(opt_inst, sel_opt_inst_list, tmp_list) { |
1589 | struct nlattr *option_item; | 1677 | err = team_nl_fill_one_option_get(skb, team, opt_inst); |
1590 | struct team_option *option = opt_inst->option; | 1678 | if (err) |
1591 | struct team_option_inst_info *opt_inst_info; | 1679 | goto errout; |
1592 | struct team_gsetter_ctx ctx; | ||
1593 | |||
1594 | /* Include only changed options if fill all mode is not on */ | ||
1595 | if (!fillall && !opt_inst->changed) | ||
1596 | continue; | ||
1597 | option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION); | ||
1598 | if (!option_item) | ||
1599 | goto nla_put_failure; | ||
1600 | if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name)) | ||
1601 | goto nla_put_failure; | ||
1602 | if (opt_inst->changed) { | ||
1603 | if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED)) | ||
1604 | goto nla_put_failure; | ||
1605 | opt_inst->changed = false; | ||
1606 | } | ||
1607 | if (opt_inst->removed && | ||
1608 | nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED)) | ||
1609 | goto nla_put_failure; | ||
1610 | |||
1611 | opt_inst_info = &opt_inst->info; | ||
1612 | if (opt_inst_info->port && | ||
1613 | nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, | ||
1614 | opt_inst_info->port->dev->ifindex)) | ||
1615 | goto nla_put_failure; | ||
1616 | if (opt_inst->option->array_size && | ||
1617 | nla_put_u32(skb, TEAM_ATTR_OPTION_ARRAY_INDEX, | ||
1618 | opt_inst_info->array_index)) | ||
1619 | goto nla_put_failure; | ||
1620 | ctx.info = opt_inst_info; | ||
1621 | |||
1622 | switch (option->type) { | ||
1623 | case TEAM_OPTION_TYPE_U32: | ||
1624 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) | ||
1625 | goto nla_put_failure; | ||
1626 | err = team_option_get(team, opt_inst, &ctx); | ||
1627 | if (err) | ||
1628 | goto errout; | ||
1629 | if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, | ||
1630 | ctx.data.u32_val)) | ||
1631 | goto nla_put_failure; | ||
1632 | break; | ||
1633 | case TEAM_OPTION_TYPE_STRING: | ||
1634 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING)) | ||
1635 | goto nla_put_failure; | ||
1636 | err = team_option_get(team, opt_inst, &ctx); | ||
1637 | if (err) | ||
1638 | goto errout; | ||
1639 | if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA, | ||
1640 | ctx.data.str_val)) | ||
1641 | goto nla_put_failure; | ||
1642 | break; | ||
1643 | case TEAM_OPTION_TYPE_BINARY: | ||
1644 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY)) | ||
1645 | goto nla_put_failure; | ||
1646 | err = team_option_get(team, opt_inst, &ctx); | ||
1647 | if (err) | ||
1648 | goto errout; | ||
1649 | if (nla_put(skb, TEAM_ATTR_OPTION_DATA, | ||
1650 | ctx.data.bin_val.len, ctx.data.bin_val.ptr)) | ||
1651 | goto nla_put_failure; | ||
1652 | break; | ||
1653 | case TEAM_OPTION_TYPE_BOOL: | ||
1654 | if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG)) | ||
1655 | goto nla_put_failure; | ||
1656 | err = team_option_get(team, opt_inst, &ctx); | ||
1657 | if (err) | ||
1658 | goto errout; | ||
1659 | if (ctx.data.bool_val && | ||
1660 | nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) | ||
1661 | goto nla_put_failure; | ||
1662 | break; | ||
1663 | default: | ||
1664 | BUG(); | ||
1665 | } | ||
1666 | nla_nest_end(skb, option_item); | ||
1667 | } | 1680 | } |
1668 | 1681 | ||
1669 | nla_nest_end(skb, option_list); | 1682 | nla_nest_end(skb, option_list); |
@@ -1680,9 +1693,14 @@ static int team_nl_fill_options_get_all(struct sk_buff *skb, | |||
1680 | struct genl_info *info, int flags, | 1693 | struct genl_info *info, int flags, |
1681 | struct team *team) | 1694 | struct team *team) |
1682 | { | 1695 | { |
1696 | struct team_option_inst *opt_inst; | ||
1697 | LIST_HEAD(sel_opt_inst_list); | ||
1698 | |||
1699 | list_for_each_entry(opt_inst, &team->option_inst_list, list) | ||
1700 | list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list); | ||
1683 | return team_nl_fill_options_get(skb, info->snd_pid, | 1701 | return team_nl_fill_options_get(skb, info->snd_pid, |
1684 | info->snd_seq, NLM_F_ACK, | 1702 | info->snd_seq, NLM_F_ACK, |
1685 | team, true); | 1703 | team, &sel_opt_inst_list); |
1686 | } | 1704 | } |
1687 | 1705 | ||
1688 | static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info) | 1706 | static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info) |
@@ -1941,7 +1959,8 @@ static struct genl_multicast_group team_change_event_mcgrp = { | |||
1941 | .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, | 1959 | .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, |
1942 | }; | 1960 | }; |
1943 | 1961 | ||
1944 | static int team_nl_send_event_options_get(struct team *team) | 1962 | static int team_nl_send_event_options_get(struct team *team, |
1963 | struct list_head *sel_opt_inst_list) | ||
1945 | { | 1964 | { |
1946 | struct sk_buff *skb; | 1965 | struct sk_buff *skb; |
1947 | int err; | 1966 | int err; |
@@ -1951,7 +1970,7 @@ static int team_nl_send_event_options_get(struct team *team) | |||
1951 | if (!skb) | 1970 | if (!skb) |
1952 | return -ENOMEM; | 1971 | return -ENOMEM; |
1953 | 1972 | ||
1954 | err = team_nl_fill_options_get(skb, 0, 0, 0, team, false); | 1973 | err = team_nl_fill_options_get(skb, 0, 0, 0, team, sel_opt_inst_list); |
1955 | if (err < 0) | 1974 | if (err < 0) |
1956 | goto err_fill; | 1975 | goto err_fill; |
1957 | 1976 | ||
@@ -2021,12 +2040,31 @@ static void team_nl_fini(void) | |||
2021 | static void __team_options_change_check(struct team *team) | 2040 | static void __team_options_change_check(struct team *team) |
2022 | { | 2041 | { |
2023 | int err; | 2042 | int err; |
2043 | struct team_option_inst *opt_inst; | ||
2044 | LIST_HEAD(sel_opt_inst_list); | ||
2024 | 2045 | ||
2025 | err = team_nl_send_event_options_get(team); | 2046 | list_for_each_entry(opt_inst, &team->option_inst_list, list) { |
2047 | if (opt_inst->changed) | ||
2048 | list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list); | ||
2049 | } | ||
2050 | err = team_nl_send_event_options_get(team, &sel_opt_inst_list); | ||
2026 | if (err) | 2051 | if (err) |
2027 | netdev_warn(team->dev, "Failed to send options change via netlink\n"); | 2052 | netdev_warn(team->dev, "Failed to send options change via netlink\n"); |
2028 | } | 2053 | } |
2029 | 2054 | ||
2055 | static void __team_option_inst_change(struct team *team, | ||
2056 | struct team_option_inst *sel_opt_inst) | ||
2057 | { | ||
2058 | int err; | ||
2059 | LIST_HEAD(sel_opt_inst_list); | ||
2060 | |||
2061 | sel_opt_inst->changed = true; | ||
2062 | list_add(&sel_opt_inst->tmp_list, &sel_opt_inst_list); | ||
2063 | err = team_nl_send_event_options_get(team, &sel_opt_inst_list); | ||
2064 | if (err) | ||
2065 | netdev_warn(team->dev, "Failed to send option change via netlink\n"); | ||
2066 | } | ||
2067 | |||
2030 | /* rtnl lock is held */ | 2068 | /* rtnl lock is held */ |
2031 | static void __team_port_change_check(struct team_port *port, bool linkup) | 2069 | static void __team_port_change_check(struct team_port *port, bool linkup) |
2032 | { | 2070 | { |