aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team
diff options
context:
space:
mode:
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);