aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-02-01 03:17:24 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-04 14:55:45 -0500
commitd90f889e9cc76daf3a6d91120bb158b16c4af444 (patch)
treeb1d4832f4f61d9e47e196b6c6f62dd830292c113 /drivers/net/team
parentf9d96862cacd1177d76d82f70f88ac57cb05e6e0 (diff)
team: handle sending port list in the same way option list is sent
Essentially do the same thing with port list as with option list. Multipart netlink message. Side effect is that port event message can send port which is not longer in team->port_list. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/team')
-rw-r--r--drivers/net/team/team.c177
1 files changed, 93 insertions, 84 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 70d5d6bdf583..738f7445ea87 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1965,30 +1965,6 @@ static void team_nl_team_put(struct team *team)
1965 dev_put(team->dev); 1965 dev_put(team->dev);
1966} 1966}
1967 1967
1968static int team_nl_send_generic(struct genl_info *info, struct team *team,
1969 int (*fill_func)(struct sk_buff *skb,
1970 struct genl_info *info,
1971 int flags, struct team *team))
1972{
1973 struct sk_buff *skb;
1974 int err;
1975
1976 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1977 if (!skb)
1978 return -ENOMEM;
1979
1980 err = fill_func(skb, info, NLM_F_ACK, team);
1981 if (err < 0)
1982 goto err_fill;
1983
1984 err = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid);
1985 return err;
1986
1987err_fill:
1988 nlmsg_free(skb);
1989 return err;
1990}
1991
1992typedef int team_nl_send_func_t(struct sk_buff *skb, 1968typedef int team_nl_send_func_t(struct sk_buff *skb,
1993 struct team *team, u32 portid); 1969 struct team *team, u32 portid);
1994 1970
@@ -2333,16 +2309,57 @@ team_put:
2333 return err; 2309 return err;
2334} 2310}
2335 2311
2336static int team_nl_fill_port_list_get(struct sk_buff *skb, 2312static int team_nl_fill_one_port_get(struct sk_buff *skb,
2337 u32 portid, u32 seq, int flags, 2313 struct team_port *port)
2338 struct team *team, 2314{
2339 bool fillall) 2315 struct nlattr *port_item;
2316
2317 port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
2318 if (!port_item)
2319 goto nest_cancel;
2320 if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
2321 goto nest_cancel;
2322 if (port->changed) {
2323 if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED))
2324 goto nest_cancel;
2325 port->changed = false;
2326 }
2327 if ((port->removed &&
2328 nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
2329 (port->state.linkup &&
2330 nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
2331 nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
2332 nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
2333 goto nest_cancel;
2334 nla_nest_end(skb, port_item);
2335 return 0;
2336
2337nest_cancel:
2338 nla_nest_cancel(skb, port_item);
2339 return -EMSGSIZE;
2340}
2341
2342static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq,
2343 int flags, team_nl_send_func_t *send_func,
2344 struct team_port *one_port)
2340{ 2345{
2341 struct nlattr *port_list; 2346 struct nlattr *port_list;
2347 struct nlmsghdr *nlh;
2342 void *hdr; 2348 void *hdr;
2343 struct team_port *port; 2349 struct team_port *port;
2350 int err;
2351 struct sk_buff *skb = NULL;
2352 bool incomplete;
2353 int i;
2344 2354
2345 hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags, 2355 port = list_first_entry(&team->port_list, struct team_port, list);
2356
2357start_again:
2358 err = __send_and_alloc_skb(&skb, team, portid, send_func);
2359 if (err)
2360 return err;
2361
2362 hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI,
2346 TEAM_CMD_PORT_LIST_GET); 2363 TEAM_CMD_PORT_LIST_GET);
2347 if (!hdr) 2364 if (!hdr)
2348 return -EMSGSIZE; 2365 return -EMSGSIZE;
@@ -2353,47 +2370,54 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb,
2353 if (!port_list) 2370 if (!port_list)
2354 goto nla_put_failure; 2371 goto nla_put_failure;
2355 2372
2356 list_for_each_entry(port, &team->port_list, list) { 2373 i = 0;
2357 struct nlattr *port_item; 2374 incomplete = false;
2358 2375
2359 /* Include only changed ports if fill all mode is not on */ 2376 /* If one port is selected, called wants to send port list containing
2360 if (!fillall && !port->changed) 2377 * only this port. Otherwise go through all listed ports and send all
2361 continue; 2378 */
2362 port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT); 2379 if (one_port) {
2363 if (!port_item) 2380 err = team_nl_fill_one_port_get(skb, one_port);
2364 goto nla_put_failure; 2381 if (err)
2365 if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex)) 2382 goto errout;
2366 goto nla_put_failure; 2383 } else {
2367 if (port->changed) { 2384 list_for_each_entry(port, &team->port_list, list) {
2368 if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED)) 2385 err = team_nl_fill_one_port_get(skb, port);
2369 goto nla_put_failure; 2386 if (err) {
2370 port->changed = false; 2387 if (err == -EMSGSIZE) {
2388 if (!i)
2389 goto errout;
2390 incomplete = true;
2391 break;
2392 }
2393 goto errout;
2394 }
2395 i++;
2371 } 2396 }
2372 if ((port->removed &&
2373 nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
2374 (port->state.linkup &&
2375 nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
2376 nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
2377 nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
2378 goto nla_put_failure;
2379 nla_nest_end(skb, port_item);
2380 } 2397 }
2381 2398
2382 nla_nest_end(skb, port_list); 2399 nla_nest_end(skb, port_list);
2383 return genlmsg_end(skb, hdr); 2400 genlmsg_end(skb, hdr);
2401 if (incomplete)
2402 goto start_again;
2403
2404send_done:
2405 nlh = nlmsg_put(skb, portid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI);
2406 if (!nlh) {
2407 err = __send_and_alloc_skb(&skb, team, portid, send_func);
2408 if (err)
2409 goto errout;
2410 goto send_done;
2411 }
2412
2413 return send_func(skb, team, portid);
2384 2414
2385nla_put_failure: 2415nla_put_failure:
2416 err = -EMSGSIZE;
2417errout:
2386 genlmsg_cancel(skb, hdr); 2418 genlmsg_cancel(skb, hdr);
2387 return -EMSGSIZE; 2419 nlmsg_free(skb);
2388} 2420 return err;
2389
2390static int team_nl_fill_port_list_get_all(struct sk_buff *skb,
2391 struct genl_info *info, int flags,
2392 struct team *team)
2393{
2394 return team_nl_fill_port_list_get(skb, info->snd_portid,
2395 info->snd_seq, NLM_F_ACK,
2396 team, true);
2397} 2421}
2398 2422
2399static int team_nl_cmd_port_list_get(struct sk_buff *skb, 2423static int team_nl_cmd_port_list_get(struct sk_buff *skb,
@@ -2406,7 +2430,8 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
2406 if (!team) 2430 if (!team)
2407 return -EINVAL; 2431 return -EINVAL;
2408 2432
2409 err = team_nl_send_generic(info, team, team_nl_fill_port_list_get_all); 2433 err = team_nl_send_port_list_get(team, info->snd_portid, info->snd_seq,
2434 NLM_F_ACK, team_nl_send_unicast, NULL);
2410 2435
2411 team_nl_team_put(team); 2436 team_nl_team_put(team);
2412 2437
@@ -2457,27 +2482,11 @@ static int team_nl_send_event_options_get(struct team *team,
2457 sel_opt_inst_list); 2482 sel_opt_inst_list);
2458} 2483}
2459 2484
2460static int team_nl_send_event_port_list_get(struct team *team) 2485static int team_nl_send_event_port_get(struct team *team,
2486 struct team_port *port)
2461{ 2487{
2462 struct sk_buff *skb; 2488 return team_nl_send_port_list_get(team, 0, 0, 0, team_nl_send_multicast,
2463 int err; 2489 port);
2464 struct net *net = dev_net(team->dev);
2465
2466 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2467 if (!skb)
2468 return -ENOMEM;
2469
2470 err = team_nl_fill_port_list_get(skb, 0, 0, 0, team, false);
2471 if (err < 0)
2472 goto err_fill;
2473
2474 err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
2475 GFP_KERNEL);
2476 return err;
2477
2478err_fill:
2479 nlmsg_free(skb);
2480 return err;
2481} 2490}
2482 2491
2483static int team_nl_init(void) 2492static int team_nl_init(void)
@@ -2550,7 +2559,7 @@ static void __team_port_change_send(struct team_port *port, bool linkup)
2550 port->state.duplex = 0; 2559 port->state.duplex = 0;
2551 2560
2552send_event: 2561send_event:
2553 err = team_nl_send_event_port_list_get(port->team); 2562 err = team_nl_send_event_port_get(port->team, port);
2554 if (err && err != -ESRCH) 2563 if (err && err != -ESRCH)
2555 netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink (err %d)\n", 2564 netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink (err %d)\n",
2556 port->dev->name, err); 2565 port->dev->name, err);