Skip to content

Commit c2f8f14

Browse files
rjarrychristophefontaine
authored andcommitted
nexthop: generalize reference removal
When a nexthop is destroyed, other nexthops may hold references to it. Previously, nexthop_destroy() had hardcoded logic to remove the deleted nexthop from group members. This does not scale as more nexthop types with cross-references are added. Introduce a remove_references callback in nexthop_type_ops. When destroying a nexthop, iterate through all registered types and invoke their callback if present. Move the L3 hash key removal from free to remove_references. Implement the callback for group nexthops to remove deleted members and for DNAT nexthops to clean up SNAT policies. Signed-off-by: Robin Jarry <rjarry@redhat.com> Reviewed-by: Christophe Fontaine <cfontain@redhat.com>
1 parent 4a07bf6 commit c2f8f14

File tree

5 files changed

+56
-39
lines changed

5 files changed

+56
-39
lines changed

modules/infra/control/gr_nh_control.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ struct nexthop_type_ops {
141141
int (*reconfig)(const struct gr_nexthop_config *);
142142
struct nexthop *(*lookup)(const struct gr_nexthop_base *, const void *info);
143143
// Callback that will be invoked the nexthop refcount reaches zero.
144+
void (*remove_references)(struct nexthop *);
144145
void (*free)(struct nexthop *);
145146
bool (*equal)(const struct nexthop *, const struct nexthop *);
146147
// Copy public info structure to internal info structure.

modules/infra/control/group_nexthop.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ static bool group_equal(const struct nexthop *a, const struct nexthop *b) {
2222
return true;
2323
}
2424

25+
static void remove_group_member_cb(struct nexthop *nh, void *deleted) {
26+
if (nh->type != GR_NH_T_GROUP)
27+
return;
28+
29+
struct nexthop_info_group *g = nexthop_info_group(nh);
30+
for (uint32_t i = 0; i < g->n_members; i++) {
31+
if (g->members[i].nh == deleted) {
32+
g->members[i].nh = g->members[g->n_members - 1].nh;
33+
g->members[i].weight = g->members[g->n_members - 1].weight;
34+
g->n_members--;
35+
}
36+
}
37+
}
38+
39+
static void group_remove_references(struct nexthop *nh) {
40+
nexthop_iter(remove_group_member_cb, nh);
41+
}
42+
2543
static void group_free(struct nexthop *nh) {
2644
struct nexthop_info_group *pvt = nexthop_info_group(nh);
2745

@@ -174,6 +192,7 @@ static struct gr_nexthop *group_to_api(const struct nexthop *nh, size_t *len) {
174192

175193
static struct nexthop_type_ops group_nh_ops = {
176194
.equal = group_equal,
195+
.remove_references = group_remove_references,
177196
.free = group_free,
178197
.import_info = group_import_info,
179198
.to_api = group_to_api,

modules/infra/control/l3_nexthop.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,21 @@ void nexthop_routes_cleanup(struct nexthop *nh) {
130130
}
131131
}
132132

133+
static void l3_remove_references(struct nexthop *nh) {
134+
if (nh->type == GR_NH_T_L3) {
135+
struct nexthop_info_l3 *l3 = nexthop_info_l3(nh);
136+
137+
if (l3->ipv4 != 0 || !rte_ipv6_addr_is_unspec(&l3->ipv6)) {
138+
struct nexthop_key key;
139+
set_nexthop_key(&key, l3->af, nh->vrf_id, nh->iface_id, &l3->addr);
140+
rte_hash_del_key(l3_hash, &key);
141+
}
142+
}
143+
}
144+
133145
static void l3_free(struct nexthop *nh) {
134146
struct nexthop_info_l3 *l3 = nexthop_info_l3(nh);
135147

136-
if (l3->ipv4 != 0 || !rte_ipv6_addr_is_unspec(&l3->ipv6)) {
137-
struct nexthop_key key;
138-
set_nexthop_key(&key, l3->af, nh->vrf_id, nh->iface_id, &l3->addr);
139-
rte_hash_del_key(l3_hash, &key);
140-
}
141-
142148
// Flush all held packets.
143149
struct rte_mbuf *m = l3->held_pkts_head;
144150
while (m != NULL) {
@@ -258,6 +264,7 @@ static struct gr_nexthop *l3_to_api(const struct nexthop *nh, size_t *len) {
258264
static struct nexthop_type_ops l3_nh_ops = {
259265
.reconfig = l3_reconfig,
260266
.lookup = l3_lookup,
267+
.remove_references = l3_remove_references,
261268
.free = l3_free,
262269
.equal = l3_equal,
263270
.import_info = l3_import_info,

modules/infra/control/nexthop.c

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -438,28 +438,6 @@ struct nexthop *nexthop_lookup_id(uint32_t nh_id) {
438438
return data;
439439
}
440440

441-
static void nh_groups_remove_member(const struct nexthop *nh) {
442-
struct nexthop_info_group *info;
443-
struct nexthop *group;
444-
uint32_t next = 0;
445-
const void *key;
446-
void *data;
447-
448-
while (rte_hash_iterate(hash_by_id, &key, &data, &next) >= 0) {
449-
group = data;
450-
if (group->type != GR_NH_T_GROUP)
451-
continue;
452-
info = nexthop_info_group(group);
453-
for (uint32_t i = 0; i < info->n_members; i++) {
454-
if (info->members[i].nh == nh) {
455-
info->members[i].nh = info->members[info->n_members - 1].nh;
456-
info->members[i].weight = info->members[info->n_members - 1].weight;
457-
info->n_members--;
458-
}
459-
}
460-
}
461-
}
462-
463441
static void nh_cleanup_interface_cb(struct nexthop *nh, void *priv) {
464442
if (nh->iface_id == (uintptr_t)priv) {
465443
nexthop_routes_cleanup(nh);
@@ -480,10 +458,17 @@ static struct gr_event_subscription iface_subscription = {
480458
};
481459

482460
void nexthop_destroy(struct nexthop *nh) {
461+
const struct nexthop_type_ops *ops;
462+
483463
assert(nh->ref_count == 0);
484464

485-
nh_groups_remove_member(nh);
465+
for (gr_nh_type_t t = 0; nexthop_type_valid(t); t++) {
466+
ops = type_ops[t];
467+
if (ops != NULL && ops->remove_references != NULL)
468+
ops->remove_references(nh);
469+
}
486470
nexthop_id_put(nh);
471+
487472
rte_rcu_qsbr_synchronize(gr_datapath_rcu(), RTE_QSBR_THRID_INVALID);
488473

489474
// Push NEXTHOP_DELETE event after RCU sync to ensure all datapath
@@ -494,7 +479,7 @@ void nexthop_destroy(struct nexthop *nh) {
494479
if (nh->origin != GR_NH_ORIGIN_INTERNAL)
495480
gr_event_push(GR_EVENT_NEXTHOP_DELETE, nh);
496481

497-
const struct nexthop_type_ops *ops = type_ops[nh->type];
482+
ops = type_ops[nh->type];
498483
if (ops != NULL && ops->free != NULL)
499484
ops->free(nh);
500485
rte_mempool_put(pool, nh);

modules/policy/api/dnat44.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,21 @@ static bool dnat44_nh_equal(const struct nexthop *a, const struct nexthop *b) {
3131
return ad->match == bd->match && ad->replace == bd->replace;
3232
}
3333

34+
static void dnat44_nh_remove_references(struct nexthop *nh) {
35+
if (nh->type == GR_NH_T_DNAT) {
36+
struct nexthop_info_dnat *dnat = nexthop_info_dnat(nh);
37+
struct iface *iface = iface_from_id(nh->iface_id);
38+
if (iface == NULL)
39+
return;
40+
snat44_static_policy_del(iface, dnat->replace);
41+
}
42+
}
43+
3444
static void dnat44_nh_free(struct nexthop *nh) {
3545
struct nexthop_info_dnat *dnat = nexthop_info_dnat(nh);
36-
struct iface *iface;
37-
38-
nexthop_decref(dnat->arp);
39-
40-
iface = iface_from_id(nh->iface_id);
41-
if (iface == NULL)
42-
return;
43-
44-
snat44_static_policy_del(iface, dnat->replace);
46+
if (dnat->arp)
47+
nexthop_decref(dnat->arp);
48+
dnat->arp = NULL;
4549
}
4650

4751
static int dnat44_nh_import_info(struct nexthop *nh, const void *info) {
@@ -240,6 +244,7 @@ static struct gr_api_handler list_handler = {
240244
static struct nexthop_type_ops nh_ops = {
241245
.lookup = dnat44_nh_lookup,
242246
.equal = dnat44_nh_equal,
247+
.remove_references = dnat44_nh_remove_references,
243248
.free = dnat44_nh_free,
244249
.import_info = dnat44_nh_import_info,
245250
.to_api = dnat44_nh_to_api,

0 commit comments

Comments
 (0)