* Creates or looks up an existing nexthop group based on @wn and @num_nhops. * * Returns referenced nhop group or NULL, passing error code in @perror. */
| 429 | * Returns referenced nhop group or NULL, passing error code in @perror. |
| 430 | */ |
| 431 | struct nhgrp_priv * |
| 432 | get_nhgrp(struct nh_control *ctl, struct weightened_nhop *wn, int num_nhops, |
| 433 | int *perror) |
| 434 | { |
| 435 | struct nhgrp_priv *key, *nhg_priv; |
| 436 | |
| 437 | if (num_nhops > RIB_MAX_MPATH_WIDTH) { |
| 438 | *perror = E2BIG; |
| 439 | return (NULL); |
| 440 | } |
| 441 | |
| 442 | if (ctl->gr_head.hash_size == 0) { |
| 443 | /* First multipath request. Bootstrap mpath datastructures. */ |
| 444 | if (nhgrp_ctl_alloc_default(ctl, M_NOWAIT) == 0) { |
| 445 | *perror = ENOMEM; |
| 446 | return (NULL); |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | /* Sort nexthops & check there are no duplicates */ |
| 451 | sort_weightened_nhops(wn, num_nhops); |
| 452 | uint32_t last_id = 0; |
| 453 | for (int i = 0; i < num_nhops; i++) { |
| 454 | if (wn[i].nh->nh_priv->nh_idx == last_id) { |
| 455 | *perror = EEXIST; |
| 456 | return (NULL); |
| 457 | } |
| 458 | last_id = wn[i].nh->nh_priv->nh_idx; |
| 459 | } |
| 460 | |
| 461 | if ((key = alloc_nhgrp(wn, num_nhops)) == NULL) { |
| 462 | *perror = ENOMEM; |
| 463 | return (NULL); |
| 464 | } |
| 465 | |
| 466 | nhg_priv = find_nhgrp(ctl, key); |
| 467 | if (nhg_priv != NULL) { |
| 468 | /* |
| 469 | * Free originally-created group. As it hasn't been linked |
| 470 | * and the dependent nexhops haven't been referenced, just free |
| 471 | * the group. |
| 472 | */ |
| 473 | destroy_nhgrp_int(key); |
| 474 | *perror = 0; |
| 475 | return (nhg_priv); |
| 476 | } else { |
| 477 | /* No existing group, try to link the new one */ |
| 478 | if (!ref_nhgrp_nhops(key)) { |
| 479 | /* |
| 480 | * Some of the nexthops have been scheduled for deletion. |
| 481 | * As the group hasn't been linked / no nexhops have been |
| 482 | * referenced, call the final destructor immediately. |
| 483 | */ |
| 484 | destroy_nhgrp_int(key); |
| 485 | *perror = EAGAIN; |
| 486 | return (NULL); |
| 487 | } |
| 488 | if (link_nhgrp(ctl, key) == 0) { |
no test coverage detected