Move the list of next hops from struct mlxsw_sp_rif to mlxsw_sp_crif. The reason is that eventually, next hops for mlxsw uppers should be offloaded and unoffloaded on demand as a netdevice becomes an upper, or stops being one. Currently, next hops are tracked at RIFs, but RIFs do not exist when a netdevice is not an mlxsw uppers. CRIFs are kept track of throughout the netdevice lifetime. Correspondingly, track at each next hop not its RIF, but its CRIF (from which a RIF can always be deduced). Note that now that next hops are tracked at a CRIF, it is not necessary to move each over to a new RIF when it is necessary to edit a RIF. Therefore drop mlxsw_sp_nexthop_rif_migrate() and have mlxsw_sp_rif_migrate_destroy() call mlxsw_sp_nexthop_rif_update() directly.
Unified · Split
| @@ -59,6 +59,7 @@ struct mlxsw_sp_crif { · 58 unmodified lines | ||
| 59 | 59 | struct mlxsw_sp_crif_key key; |
| 60 | 60 | struct rhash_head ht_node; |
| 61 | 61 | bool can_destroy; |
| 62 | + struct list_head nexthop_list; | |
| 62 | 63 | struct mlxsw_sp_rif *rif; |
| 63 | 64 | }; |
| 64 | 65 | |
| @@ -70,7 +71,6 @@ static const struct rhashtable_params mlxsw_sp_crif_ht_params = { · 5 unmodified lines | ||
| 70 | 71 | |
| 71 | 72 | struct mlxsw_sp_rif { |
| 72 | 73 | struct mlxsw_sp_crif *crif; /* NULL for underlay RIF */ |
| 73 | − struct list_head nexthop_list; | |
| 74 | 74 | struct list_head neigh_list; |
| 75 | 75 | struct mlxsw_sp_fid *fid; |
| 76 | 76 | unsigned char addr[ETH_ALEN]; |
| @@ -1083,6 +1083,7 @@ static void · 1006 unmodified lines | ||
| 1083 | 1083 | mlxsw_sp_crif_init(struct mlxsw_sp_crif *crif, struct net_device *dev) |
| 1084 | 1084 | { |
| 1085 | 1085 | crif->key.dev = dev; |
| 1086 | + INIT_LIST_HEAD(&crif->nexthop_list); | |
| 1086 | 1087 | } |
| 1087 | 1088 | |
| 1088 | 1089 | static struct mlxsw_sp_crif * |
| @@ -1103,6 +1104,7 @@ static void mlxsw_sp_crif_free(struct mlxsw_sp_crif *crif) · 14 unmodified lines | ||
| 1103 | 1104 | if (WARN_ON(crif->rif)) |
| 1104 | 1105 | return; |
| 1105 | 1106 | |
| 1107 | + WARN_ON(!list_empty(&crif->nexthop_list)); | |
| 1106 | 1108 | kfree(crif); |
| 1107 | 1109 | } |
| 1108 | 1110 | |
| @@ -1720,17 +1722,26 @@ static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp, · 611 unmodified lines | ||
| 1720 | 1722 | mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry); |
| 1721 | 1723 | } |
| 1722 | 1724 | |
| 1723 | −static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp, | |
| 1724 | − struct mlxsw_sp_rif *old_rif, | |
| 1725 | − struct mlxsw_sp_rif *new_rif); | |
| 1725 | +static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, | |
| 1726 | + struct mlxsw_sp_rif *rif); | |
| 1727 | + | |
| 1726 | 1728 | static void mlxsw_sp_rif_migrate_destroy(struct mlxsw_sp *mlxsw_sp, |
| 1727 | 1729 | struct mlxsw_sp_rif *old_rif, |
| 1728 | 1730 | struct mlxsw_sp_rif *new_rif, |
| 1729 | 1731 | bool migrate_nhs) |
| 1730 | 1732 | { |
| 1733 | + struct mlxsw_sp_crif *crif = old_rif->crif; | |
| 1734 | + struct mlxsw_sp_crif mock_crif = {}; | |
| 1735 | + | |
| 1731 | 1736 | if (migrate_nhs) |
| 1732 | − mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, old_rif, new_rif); | |
| 1737 | + mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif); | |
| 1733 | 1738 | |
| 1739 | + /* Plant a mock CRIF so that destroying the old RIF doesn't unoffload | |
| 1740 | + * our nexthops and IPIP tunnels, and doesn't sever the crif->rif link. | |
| 1741 | + */ | |
| 1742 | + mlxsw_sp_crif_init(&mock_crif, crif->key.dev); | |
| 1743 | + old_rif->crif = &mock_crif; | |
| 1744 | + mock_crif.rif = old_rif; | |
| 1734 | 1745 | mlxsw_sp_rif_destroy(old_rif); |
| 1735 | 1746 | } |
| 1736 | 1747 | |
| @@ -1756,9 +1767,6 @@ mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp, · 19 unmodified lines | ||
| 1756 | 1767 | return 0; |
| 1757 | 1768 | } |
| 1758 | 1769 | |
| 1759 | −static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, | |
| 1760 | − struct mlxsw_sp_rif *rif); | |
| 1761 | − | |
| 1762 | 1770 | /** |
| 1763 | 1771 | * __mlxsw_sp_ipip_entry_update_tunnel - Update offload related to IPIP entry. |
| 1764 | 1772 | * @mlxsw_sp: mlxsw_sp. |
| @@ -2987,7 +2995,7 @@ struct mlxsw_sp_nexthop_key { · 1222 unmodified lines | ||
| 2987 | 2995 | |
| 2988 | 2996 | struct mlxsw_sp_nexthop { |
| 2989 | 2997 | struct list_head neigh_list_node; /* member of neigh entry list */ |
| 2990 | − struct list_head rif_list_node; | |
| 2998 | + struct list_head crif_list_node; | |
| 2991 | 2999 | struct list_head router_list_node; |
| 2992 | 3000 | struct mlxsw_sp_nexthop_group_info *nhgi; /* pointer back to the group |
| 2993 | 3001 | * this nexthop belongs to |
| @@ -3000,7 +3008,7 @@ struct mlxsw_sp_nexthop { · 6 unmodified lines | ||
| 3000 | 3008 | int nh_weight; |
| 3001 | 3009 | int norm_nh_weight; |
| 3002 | 3010 | int num_adj_entries; |
| 3003 | − struct mlxsw_sp_rif *rif; | |
| 3011 | + struct mlxsw_sp_crif *crif; | |
| 3004 | 3012 | u8 should_offload:1, /* set indicates this nexthop should be written |
| 3005 | 3013 | * to the adjacency table. |
| 3006 | 3014 | */ |
| @@ -3023,9 +3031,9 @@ struct mlxsw_sp_nexthop { · 16 unmodified lines | ||
| 3023 | 3031 | static struct net_device * |
| 3024 | 3032 | mlxsw_sp_nexthop_dev(const struct mlxsw_sp_nexthop *nh) |
| 3025 | 3033 | { |
| 3026 | − if (nh->rif) | |
| 3027 | − return mlxsw_sp_rif_dev(nh->rif); | |
| 3028 | − return NULL; | |
| 3034 | + if (!nh->crif) | |
| 3035 | + return NULL; | |
| 3036 | + return nh->crif->key.dev; | |
| 3029 | 3037 | } |
| 3030 | 3038 | |
| 3031 | 3039 | enum mlxsw_sp_nexthop_group_type { |
| @@ -3050,7 +3058,11 @@ struct mlxsw_sp_nexthop_group_info { · 18 unmodified lines | ||
| 3050 | 3058 | static struct mlxsw_sp_rif * |
| 3051 | 3059 | mlxsw_sp_nhgi_rif(const struct mlxsw_sp_nexthop_group_info *nhgi) |
| 3052 | 3060 | { |
| 3053 | − return nhgi->nexthops[0].rif; | |
| 3061 | + struct mlxsw_sp_crif *crif = nhgi->nexthops[0].crif; | |
| 3062 | + | |
| 3063 | + if (!crif) | |
| 3064 | + return NULL; | |
| 3065 | + return crif->rif; | |
| 3054 | 3066 | } |
| 3055 | 3067 | |
| 3056 | 3068 | struct mlxsw_sp_nexthop_group_vr_key { |
| @@ -3174,7 +3186,9 @@ int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index, · 117 unmodified lines | ||
| 3174 | 3186 | |
| 3175 | 3187 | struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh) |
| 3176 | 3188 | { |
| 3177 | − return nh->rif; | |
| 3189 | + if (WARN_ON(!nh->crif)) | |
| 3190 | + return NULL; | |
| 3191 | + return nh->crif->rif; | |
| 3178 | 3192 | } |
| 3179 | 3193 | |
| 3180 | 3194 | bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh) |
| @@ -3559,11 +3573,12 @@ static int __mlxsw_sp_nexthop_eth_update(struct mlxsw_sp *mlxsw_sp, · 378 unmodified lines | ||
| 3559 | 3573 | bool force, char *ratr_pl) |
| 3560 | 3574 | { |
| 3561 | 3575 | struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry; |
| 3576 | + struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh); | |
| 3562 | 3577 | enum mlxsw_reg_ratr_op op; |
| 3563 | 3578 | u16 rif_index; |
| 3564 | 3579 | |
| 3565 | − rif_index = nh->rif ? nh->rif->rif_index : | |
| 3566 | − mlxsw_sp->router->lb_crif->rif->rif_index; | |
| 3580 | + rif_index = rif ? rif->rif_index : | |
| 3581 | + mlxsw_sp->router->lb_crif->rif->rif_index; | |
| 3567 | 3582 | op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : |
| 3568 | 3583 | MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; |
| 3569 | 3584 | mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_ETHERNET, |
| @@ -4181,23 +4196,23 @@ mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp, · 611 unmodified lines | ||
| 4181 | 4196 | } |
| 4182 | 4197 | } |
| 4183 | 4198 | |
| 4184 | −static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop *nh, | |
| 4185 | − struct mlxsw_sp_rif *rif) | |
| 4199 | +static void mlxsw_sp_nexthop_crif_init(struct mlxsw_sp_nexthop *nh, | |
| 4200 | + struct mlxsw_sp_crif *crif) | |
| 4186 | 4201 | { |
| 4187 | − if (nh->rif) | |
| 4202 | + if (nh->crif) | |
| 4188 | 4203 | return; |
| 4189 | 4204 | |
| 4190 | − nh->rif = rif; | |
| 4191 | − list_add(&nh->rif_list_node, &rif->nexthop_list); | |
| 4205 | + nh->crif = crif; | |
| 4206 | + list_add(&nh->crif_list_node, &crif->nexthop_list); | |
| 4192 | 4207 | } |
| 4193 | 4208 | |
| 4194 | −static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop *nh) | |
| 4209 | +static void mlxsw_sp_nexthop_crif_fini(struct mlxsw_sp_nexthop *nh) | |
| 4195 | 4210 | { |
| 4196 | − if (!nh->rif) | |
| 4211 | + if (!nh->crif) | |
| 4197 | 4212 | return; |
| 4198 | 4213 | |
| 4199 | − list_del(&nh->rif_list_node); | |
| 4200 | − nh->rif = NULL; | |
| 4214 | + list_del(&nh->crif_list_node); | |
| 4215 | + nh->crif = NULL; | |
| 4201 | 4216 | } |
| 4202 | 4217 | |
| 4203 | 4218 | static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, |
| @@ -4209,6 +4224,9 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, · 5 unmodified lines | ||
| 4209 | 4224 | u8 nud_state, dead; |
| 4210 | 4225 | int err; |
| 4211 | 4226 | |
| 4227 | + if (WARN_ON(!nh->crif->rif)) | |
| 4228 | + return 0; | |
| 4229 | + | |
| 4212 | 4230 | if (!nh->nhgi->gateway || nh->neigh_entry) |
| 4213 | 4231 | return 0; |
| 4214 | 4232 | dev = mlxsw_sp_nexthop_dev(nh); |
| @@ -4299,15 +4317,20 @@ static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp, · 84 unmodified lines | ||
| 4299 | 4317 | struct mlxsw_sp_nexthop *nh, |
| 4300 | 4318 | struct mlxsw_sp_ipip_entry *ipip_entry) |
| 4301 | 4319 | { |
| 4320 | + struct mlxsw_sp_crif *crif; | |
| 4302 | 4321 | bool removing; |
| 4303 | 4322 | |
| 4304 | 4323 | if (!nh->nhgi->gateway || nh->ipip_entry) |
| 4305 | 4324 | return; |
| 4306 | 4325 | |
| 4326 | + crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, ipip_entry->ol_dev); | |
| 4327 | + if (WARN_ON(!crif)) | |
| 4328 | + return; | |
| 4329 | + | |
| 4307 | 4330 | nh->ipip_entry = ipip_entry; |
| 4308 | 4331 | removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev); |
| 4309 | 4332 | __mlxsw_sp_nexthop_neigh_update(nh, removing); |
| 4310 | − mlxsw_sp_nexthop_rif_init(nh, &ipip_entry->ol_lb->common); | |
| 4333 | + mlxsw_sp_nexthop_crif_init(nh, crif); | |
| 4311 | 4334 | } |
| 4312 | 4335 | |
| 4313 | 4336 | static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp, |
| @@ -4339,7 +4362,7 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, · 25 unmodified lines | ||
| 4339 | 4362 | { |
| 4340 | 4363 | const struct mlxsw_sp_ipip_ops *ipip_ops; |
| 4341 | 4364 | struct mlxsw_sp_ipip_entry *ipip_entry; |
| 4342 | − struct mlxsw_sp_rif *rif; | |
| 4365 | + struct mlxsw_sp_crif *crif; | |
| 4343 | 4366 | int err; |
| 4344 | 4367 | |
| 4345 | 4368 | ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev); |
| @@ -4353,11 +4376,15 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, · 7 unmodified lines | ||
| 4353 | 4376 | } |
| 4354 | 4377 | |
| 4355 | 4378 | nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH; |
| 4356 | − rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); | |
| 4357 | − if (!rif) | |
| 4379 | + crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, dev); | |
| 4380 | + if (!crif) | |
| 4381 | + return 0; | |
| 4382 | + | |
| 4383 | + mlxsw_sp_nexthop_crif_init(nh, crif); | |
| 4384 | + | |
| 4385 | + if (!crif->rif) | |
| 4358 | 4386 | return 0; |
| 4359 | 4387 | |
| 4360 | − mlxsw_sp_nexthop_rif_init(nh, rif); | |
| 4361 | 4388 | err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh); |
| 4362 | 4389 | if (err) |
| 4363 | 4390 | goto err_neigh_init; |
| @@ -4365,7 +4392,7 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, · 1 unmodified line | ||
| 4365 | 4392 | return 0; |
| 4366 | 4393 | |
| 4367 | 4394 | err_neigh_init: |
| 4368 | − mlxsw_sp_nexthop_rif_fini(nh); | |
| 4395 | + mlxsw_sp_nexthop_crif_fini(nh); | |
| 4369 | 4396 | return err; |
| 4370 | 4397 | } |
| 4371 | 4398 | |
| @@ -4386,7 +4413,7 @@ static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp, · 14 unmodified lines | ||
| 4386 | 4413 | struct mlxsw_sp_nexthop *nh) |
| 4387 | 4414 | { |
| 4388 | 4415 | mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh); |
| 4389 | − mlxsw_sp_nexthop_rif_fini(nh); | |
| 4416 | + mlxsw_sp_nexthop_crif_fini(nh); | |
| 4390 | 4417 | } |
| 4391 | 4418 | |
| 4392 | 4419 | static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp, |
| @@ -4479,7 +4506,7 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, · 86 unmodified lines | ||
| 4479 | 4506 | struct mlxsw_sp_nexthop *nh; |
| 4480 | 4507 | bool removing; |
| 4481 | 4508 | |
| 4482 | − list_for_each_entry(nh, &rif->nexthop_list, rif_list_node) { | |
| 4509 | + list_for_each_entry(nh, &rif->crif->nexthop_list, crif_list_node) { | |
| 4483 | 4510 | switch (nh->type) { |
| 4484 | 4511 | case MLXSW_SP_NEXTHOP_TYPE_ETH: |
| 4485 | 4512 | removing = false; |
| @@ -4497,25 +4524,14 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, · 11 unmodified lines | ||
| 4497 | 4524 | } |
| 4498 | 4525 | } |
| 4499 | 4526 | |
| 4500 | −static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp, | |
| 4501 | − struct mlxsw_sp_rif *old_rif, | |
| 4502 | − struct mlxsw_sp_rif *new_rif) | |
| 4503 | −{ | |
| 4504 | − struct mlxsw_sp_nexthop *nh; | |
| 4505 | − | |
| 4506 | − list_splice_init(&old_rif->nexthop_list, &new_rif->nexthop_list); | |
| 4507 | − list_for_each_entry(nh, &new_rif->nexthop_list, rif_list_node) | |
| 4508 | − nh->rif = new_rif; | |
| 4509 | − mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif); | |
| 4510 | −} | |
| 4511 | − | |
| 4512 | 4527 | static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp, |
| 4513 | 4528 | struct mlxsw_sp_rif *rif) |
| 4514 | 4529 | { |
| 4515 | 4530 | struct mlxsw_sp_nexthop *nh, *tmp; |
| 4516 | 4531 | |
| 4517 | − list_for_each_entry_safe(nh, tmp, &rif->nexthop_list, rif_list_node) { | |
| 4518 | − mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh); | |
| 4532 | + list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list, | |
| 4533 | + crif_list_node) { | |
| 4534 | + mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh); | |
| 4519 | 4535 | mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp); |
| 4520 | 4536 | } |
| 4521 | 4537 | } |
| @@ -4857,13 +4873,13 @@ static void mlxsw_sp_nexthop_obj_blackhole_init(struct mlxsw_sp *mlxsw_sp, · 335 unmodified lines | ||
| 4857 | 4873 | * via an egress RIF, they still need to be programmed using a |
| 4858 | 4874 | * valid RIF, so use the loopback RIF created during init. |
| 4859 | 4875 | */ |
| 4860 | − nh->rif = mlxsw_sp->router->lb_crif->rif; | |
| 4876 | + nh->crif = mlxsw_sp->router->lb_crif; | |
| 4861 | 4877 | } |
| 4862 | 4878 | |
| 4863 | 4879 | static void mlxsw_sp_nexthop_obj_blackhole_fini(struct mlxsw_sp *mlxsw_sp, |
| 4864 | 4880 | struct mlxsw_sp_nexthop *nh) |
| 4865 | 4881 | { |
| 4866 | − nh->rif = NULL; | |
| 4882 | + nh->crif = NULL; | |
| 4867 | 4883 | nh->should_offload = 0; |
| 4868 | 4884 | } |
| 4869 | 4885 | |
| @@ -7871,6 +7887,9 @@ static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif) · 3001 unmodified lines | ||
| 7871 | 7887 | static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp, |
| 7872 | 7888 | struct mlxsw_sp_rif *rif) |
| 7873 | 7889 | { |
| 7890 | + /* Signal to nexthop cleanup that the RIF is going away. */ | |
| 7891 | + rif->crif->rif = NULL; | |
| 7892 | + | |
| 7874 | 7893 | mlxsw_sp_router_rif_disable(mlxsw_sp, rif->rif_index); |
| 7875 | 7894 | mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, rif); |
| 7876 | 7895 | mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif); |
| @@ -7989,7 +8008,6 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, · 112 unmodified lines | ||
| 7989 | 8008 | if (!rif) |
| 7990 | 8009 | return NULL; |
| 7991 | 8010 | |
| 7992 | − INIT_LIST_HEAD(&rif->nexthop_list); | |
| 7993 | 8011 | INIT_LIST_HEAD(&rif->neigh_list); |
| 7994 | 8012 | if (l3_dev) { |
| 7995 | 8013 | ether_addr_copy(rif->addr, l3_dev->dev_addr); |
| @@ -8008,7 +8026,6 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, · 12 unmodified lines | ||
| 8008 | 8026 | static void mlxsw_sp_rif_free(struct mlxsw_sp_rif *rif) |
| 8009 | 8027 | { |
| 8010 | 8028 | WARN_ON(!list_empty(&rif->neigh_list)); |
| 8011 | − WARN_ON(!list_empty(&rif->nexthop_list)); | |
| 8012 | 8029 | |
| 8013 | 8030 | if (rif->crif) |
| 8014 | 8031 | rif->crif->rif = NULL; |
| @@ -9290,7 +9307,13 @@ err_netdev_insert: · 1275 unmodified lines | ||
| 9290 | 9307 | static void mlxsw_sp_crif_unregister(struct mlxsw_sp_router *router, |
| 9291 | 9308 | struct mlxsw_sp_crif *crif) |
| 9292 | 9309 | { |
| 9310 | + struct mlxsw_sp_nexthop *nh, *tmp; | |
| 9311 | + | |
| 9293 | 9312 | mlxsw_sp_crif_remove(router, crif); |
| 9313 | + | |
| 9314 | + list_for_each_entry_safe(nh, tmp, &crif->nexthop_list, crif_list_node) | |
| 9315 | + mlxsw_sp_nexthop_type_fini(router->mlxsw_sp, nh); | |
| 9316 | + | |
| 9294 | 9317 | if (crif->rif) |
| 9295 | 9318 | crif->can_destroy = true; |
| 9296 | 9319 | else |