summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_nhg.h
blob: 4eddecb73d6ea03c5e98d53dcd764c3233718cd1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
// SPDX-License-Identifier: GPL-2.0-or-later
/* Zebra Nexthop Group header.
 * Copyright (C) 2019 Cumulus Networks, Inc.
 *                    Donald Sharp
 *                    Stephen Worley
 */
#ifndef __ZEBRA_NHG_H__
#define __ZEBRA_NHG_H__

#include "lib/nexthop.h"
#include "lib/nexthop_group.h"

#ifdef __cplusplus
extern "C" {
#endif

/* This struct is used exclusively for dataplane
 * interaction via a dataplane context.
 *
 * It is designed to mimic the netlink nexthop_grp
 * struct in include/linux/nexthop.h
 */
struct nh_grp {
	uint32_t id;
	uint8_t weight;
};

PREDECL_RBTREE_UNIQ(nhg_connected_tree);

/*
 * Hashtables containing nhg entries is in `zebra_router`.
 */
struct nhg_hash_entry {
	uint32_t id;
	afi_t afi;
	vrf_id_t vrf_id;

	/* Time since last update */
	time_t uptime;

	/* Source protocol - zebra or another daemon */
	int type;

	/* zapi instance and session id, for groups from other daemons */
	uint16_t zapi_instance;
	uint32_t zapi_session;

	struct nexthop_group nhg;

	/* If supported, a mapping of backup nexthops. */
	struct nhg_backup_info *backup_info;

	/* If this is not a group, it
	 * will be a single nexthop
	 * and must have an interface
	 * associated with it.
	 * Otherwise, this will be null.
	 */
	struct interface *ifp;

	uint32_t refcnt;
	uint32_t dplane_ref;

	uint32_t flags;

	/* Dependency trees for other entries.
	 * For instance a group with two
	 * nexthops will have two dependencies
	 * pointing to those nhg_hash_entries.
	 *
	 * Using a rb tree here to make lookups
	 * faster with ID's.
	 *
	 * nhg_depends the RB tree of entries that this
	 * group contains.
	 *
	 * nhg_dependents the RB tree of entries that
	 * this group is being used by
	 *
	 * NHG id 3 with nexthops id 1/2
	 * nhg(3)->nhg_depends has 1 and 2 in the tree
	 * nhg(3)->nhg_dependents is empty
	 *
	 * nhg(1)->nhg_depends is empty
	 * nhg(1)->nhg_dependents is 3 in the tree
	 *
	 * nhg(2)->nhg_depends is empty
	 * nhg(3)->nhg_dependents is 3 in the tree
	 */
	struct nhg_connected_tree_head nhg_depends, nhg_dependents;

	struct event *timer;

/*
 * Is this nexthop group valid, ie all nexthops are fully resolved.
 * What is fully resolved?  It's a nexthop that is either self contained
 * and correct( ie no recursive pointer ) or a nexthop that is recursively
 * resolved and correct.
 */
#define NEXTHOP_GROUP_VALID (1 << 0)
/*
 * Has this nexthop group been installed?  At this point in time, this
 * means that the data-plane has been told about this nexthop group
 * and it's possible usage by a route entry.
 */
#define NEXTHOP_GROUP_INSTALLED (1 << 1)
/*
 * Has the nexthop group been queued to be send to the FIB?
 * The NEXTHOP_GROUP_VALID flag should also be set by this point.
 */
#define NEXTHOP_GROUP_QUEUED (1 << 2)
/*
 * Is this a nexthop that is recursively resolved?
 */
#define NEXTHOP_GROUP_RECURSIVE (1 << 3)

/*
 * Backup nexthop support - identify groups that are backups for
 * another group.
 */
#define NEXTHOP_GROUP_BACKUP (1 << 4)

/*
 * The NHG has been release by an upper level protocol via the
 * `zebra_nhg_proto_del()` API.
 *
 * We use this flag to track this state in case the NHG is still being used
 * by routes therefore holding their refcnts as well. Otherwise, the NHG will
 * be removed and uninstalled.
 *
 */
#define NEXTHOP_GROUP_PROTO_RELEASED (1 << 5)

/*
 * When deleting a NHG notice that it is still installed
 * and if it is, slightly delay the actual removal to
 * the future.  So that upper level protocols might
 * be able to take advantage of some NHG's that
 * are there
 */
#define NEXTHOP_GROUP_KEEP_AROUND (1 << 6)

/*
 * Track FPM installation status..
 */
#define NEXTHOP_GROUP_FPM (1 << 7)
};

/* Upper 4 bits of the NHG are reserved for indicating the NHG type */
#define NHG_ID_TYPE_POS 28
enum nhg_type {
	NHG_TYPE_L3 = 0,
	NHG_TYPE_L2_NH, /* NHs in a L2 NHG used as a MAC/FDB dest */
	NHG_TYPE_L2,    /* L2 NHG used as a MAC/FDB dest */
};

/* Was this one we created, either this session or previously? */
#define ZEBRA_NHG_CREATED(NHE)                                                 \
	(((NHE->type) <= ZEBRA_ROUTE_MAX) && (NHE->type != ZEBRA_ROUTE_KERNEL))

/* Is this an NHE owned by zebra and not an upper level protocol? */
#define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG)

#define PROTO_OWNED(NHE) (NHE->id >= ZEBRA_NHG_PROTO_LOWER)

/*
 * Backup nexthops: this is a group object itself, so
 * that the backup nexthops can use the same code as a normal object.
 */
struct nhg_backup_info {
	struct nhg_hash_entry *nhe;
};

enum nhg_ctx_op_e {
	NHG_CTX_OP_NONE = 0,
	NHG_CTX_OP_NEW,
	NHG_CTX_OP_DEL,
};

enum nhg_ctx_status {
	NHG_CTX_NONE = 0,
	NHG_CTX_QUEUED,
	NHG_CTX_REQUEUED,
	NHG_CTX_SUCCESS,
	NHG_CTX_FAILURE,
};

/*
 * Context needed to queue nhg updates on the
 * work queue.
 */
struct nhg_ctx {

	/* Unique ID */
	uint32_t id;

	vrf_id_t vrf_id;
	afi_t afi;

	/*
	 * This should only ever be ZEBRA_ROUTE_NHG unless we get a a kernel
	 * created nexthop not made by us.
	 */
	int type;

	/* If its a group array, how many? */
	uint8_t count;

	/* Its either a single nexthop or an array of ID's */
	union {
		struct nexthop nh;
		struct nh_grp grp[MULTIPATH_NUM];
	} u;

	struct nhg_resilience resilience;
	enum nhg_ctx_op_e op;
	enum nhg_ctx_status status;
};

/* Global control to disable use of kernel nexthops, if available. We can't
 * force the kernel to support nexthop ids, of course, but we can disable
 * zebra's use of them, for testing e.g. By default, if the kernel supports
 * nexthop ids, zebra uses them.
 */
void zebra_nhg_enable_kernel_nexthops(bool set);
bool zebra_nhg_kernel_nexthops_enabled(void);

/* Global control for zebra to only use proto-owned nexthops */
void zebra_nhg_set_proto_nexthops_only(bool set);
bool zebra_nhg_proto_nexthops_only(void);

/* Global control for use of activated backups for recursive resolution. */
void zebra_nhg_set_recursive_use_backups(bool set);
bool zebra_nhg_recursive_use_backups(void);

/**
 * NHE abstracted tree functions.
 * Use these where possible instead of direct access.
 */
struct nhg_hash_entry *zebra_nhg_alloc(void);
void zebra_nhg_free(struct nhg_hash_entry *nhe);
/* In order to clear a generic hash, we need a generic api, sigh. */
void zebra_nhg_hash_free(void *p);
void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg);

/* Init an nhe, for use in a hash lookup for example. There's some fuzziness
 * if the nhe represents only a single nexthop, so we try to capture that
 * variant also.
 */
void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
		    const struct nexthop *nh);

/*
 * Shallow copy of 'orig', into new/allocated nhe.
 */
struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
				      uint32_t id);

/* Allocate, free backup nexthop info objects */
struct nhg_backup_info *zebra_nhg_backup_alloc(void);
void zebra_nhg_backup_free(struct nhg_backup_info **p);

struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe);

extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe);

extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe);
extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe);

extern unsigned int
zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe);
extern bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe);

/* Lookup ID, doesn't create */
extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id);

/* Hash functions */
extern uint32_t zebra_nhg_hash_key(const void *arg);
extern uint32_t zebra_nhg_id_key(const void *arg);

extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2);
extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2);

/*
 * Process a context off of a queue.
 * Specifically this should be from
 * the rib meta queue.
 */
extern int nhg_ctx_process(struct nhg_ctx *ctx);
void nhg_ctx_free(struct nhg_ctx **ctx);

/* Find via kernel nh creation */
extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
				 struct nh_grp *grp, uint8_t count,
				 vrf_id_t vrf_id, afi_t afi, int type,
				 int startup,
				 struct nhg_resilience *resilience);
/* Del via kernel */
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);

/* Find an nhe based on a nexthop_group */
extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
						 struct nexthop_group *nhg,
						 afi_t rt_afi, int type);

/* Find an nhe based on a route's nhe, used during route creation */
struct nhg_hash_entry *
zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);


/**
 * Functions for Add/Del/Replace via protocol NHG creation.
 *
 * The NHEs will not be hashed. They will only be present in the
 * ID table and therefore not sharable.
 *
 * It is the owning protocols job to manage these.
 */

/*
 * Add NHE. If already exists, Replace.
 *
 * Returns allocated NHE on success, otherwise NULL.
 */
struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
					   uint16_t instance, uint32_t session,
					   struct nexthop_group *nhg,
					   afi_t afi);

/*
 * Del NHE.
 *
 * Returns deleted NHE on success, otherwise NULL.
 *
 * Caller must decrement ref with zebra_nhg_decrement_ref() when done.
 */
struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id, int type);

/*
 * Remove specific by proto NHGs.
 *
 * Called after client disconnect.
 *
 */
unsigned long zebra_nhg_score_proto(int type);

/* Reference counter functions */
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);

/* Check validity of nhe, if invalid will update dependents as well */
extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe);

/* Convert nhe depends to a grp context that can be passed around safely */
extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
				 int size);

/* Dataplane install/uninstall */
extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe);
extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe);
extern void zebra_interface_nhg_reinstall(struct interface *ifp);

/* Forward ref of dplane update context type */
struct zebra_dplane_ctx;
extern void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx);


/* Sweep the nhg hash tables for old entries on restart */
extern void zebra_nhg_sweep_table(struct hash *hash);

/*
 * We are shutting down but the nexthops should be kept
 * as that -r has been specified and we don't want to delete
 * the routes unintentionally
 */
extern void zebra_nhg_mark_keep(void);

/* Nexthop resolution processing */
struct route_entry; /* Forward ref to avoid circular includes */
extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);

#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pNG" (const struct nhg_hash_entry *)
#endif

#ifdef __cplusplus
}
#endif

#endif	/* __ZEBRA_NHG_H__ */