1 /* Zebra Nexthop Group header.
2  * Copyright (C) 2019 Cumulus Networks, Inc.
3  *                    Donald Sharp
4  *                    Stephen Worley
5  *
6  * This file is part of FRR.
7  *
8  * FRR is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2, or (at your option) any
11  * later version.
12  *
13  * FRR is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with FRR; see the file COPYING.  If not, write to the Free
20  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  * 02111-1307, USA.
22  */
23 #ifndef __ZEBRA_NHG_H__
24 #define __ZEBRA_NHG_H__
25 
26 #include "lib/nexthop.h"
27 #include "lib/nexthop_group.h"
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /* This struct is used exclusively for dataplane
34  * interaction via a dataplane context.
35  *
36  * It is designed to mimic the netlink nexthop_grp
37  * struct in include/linux/nexthop.h
38  */
39 struct nh_grp {
40 	uint32_t id;
41 	uint8_t weight;
42 };
43 
44 PREDECL_RBTREE_UNIQ(nhg_connected_tree);
45 
46 /*
47  * Hashtables containing nhg entries is in `zebra_router`.
48  */
49 struct nhg_hash_entry {
50 	uint32_t id;
51 	afi_t afi;
52 	vrf_id_t vrf_id;
53 	int type;
54 
55 	struct nexthop_group nhg;
56 
57 	/* If supported, a mapping of backup nexthops. */
58 	struct nhg_backup_info *backup_info;
59 
60 	/* If this is not a group, it
61 	 * will be a single nexthop
62 	 * and must have an interface
63 	 * associated with it.
64 	 * Otherwise, this will be null.
65 	 */
66 	struct interface *ifp;
67 
68 	uint32_t refcnt;
69 	uint32_t dplane_ref;
70 
71 	uint32_t flags;
72 
73 	/* Dependency tree for other entries.
74 	 * For instance a group with two
75 	 * nexthops will have two dependencies
76 	 * pointing to those nhg_hash_entries.
77 	 *
78 	 * Using a rb tree here to make lookups
79 	 * faster with ID's.
80 	 */
81 	struct nhg_connected_tree_head nhg_depends, nhg_dependents;
82 
83 /*
84  * Is this nexthop group valid, ie all nexthops are fully resolved.
85  * What is fully resolved?  It's a nexthop that is either self contained
86  * and correct( ie no recursive pointer ) or a nexthop that is recursively
87  * resolved and correct.
88  */
89 #define NEXTHOP_GROUP_VALID (1 << 0)
90 /*
91  * Has this nexthop group been installed?  At this point in time, this
92  * means that the data-plane has been told about this nexthop group
93  * and it's possible usage by a route entry.
94  */
95 #define NEXTHOP_GROUP_INSTALLED (1 << 1)
96 /*
97  * Has the nexthop group been queued to be send to the FIB?
98  * The NEXTHOP_GROUP_VALID flag should also be set by this point.
99  */
100 #define NEXTHOP_GROUP_QUEUED (1 << 2)
101 /*
102  * Is this a nexthop that is recursively resolved?
103  */
104 #define NEXTHOP_GROUP_RECURSIVE (1 << 3)
105 /*
106  * This is a nexthop group we got from the kernel, it is identical to
107  * one we already have. (The kernel allows duplicate nexthops, we don't
108  * since we hash on them). We are only tracking it in our ID table,
109  * it is unusable by our created routes but may be used by routes we get
110  * from the kernel. Therefore, it is unhashable.
111  */
112 #define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
113 
114 /*
115  * Backup nexthop support - identify groups that are backups for
116  * another group.
117  */
118 #define NEXTHOP_GROUP_BACKUP (1 << 5)
119 
120 /*
121  * Track FPM installation status..
122  */
123 #define NEXTHOP_GROUP_FPM (1 << 6)
124 };
125 
126 /* Was this one we created, either this session or previously? */
127 #define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
128 
129 /*
130  * Backup nexthops: this is a group object itself, so
131  * that the backup nexthops can use the same code as a normal object.
132  */
133 struct nhg_backup_info {
134 	struct nhg_hash_entry *nhe;
135 };
136 
137 enum nhg_ctx_op_e {
138 	NHG_CTX_OP_NONE = 0,
139 	NHG_CTX_OP_NEW,
140 	NHG_CTX_OP_DEL,
141 };
142 
143 enum nhg_ctx_status {
144 	NHG_CTX_NONE = 0,
145 	NHG_CTX_QUEUED,
146 	NHG_CTX_REQUEUED,
147 	NHG_CTX_SUCCESS,
148 	NHG_CTX_FAILURE,
149 };
150 
151 /*
152  * Context needed to queue nhg updates on the
153  * work queue.
154  */
155 struct nhg_ctx {
156 
157 	/* Unique ID */
158 	uint32_t id;
159 
160 	vrf_id_t vrf_id;
161 	afi_t afi;
162 	/*
163 	 * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel
164 	 * created nexthop not made by us.
165 	 */
166 	int type;
167 
168 	/* If its a group array, how many? */
169 	uint8_t count;
170 
171 	/* Its either a single nexthop or an array of ID's */
172 	union {
173 		struct nexthop nh;
174 		struct nh_grp grp[MULTIPATH_NUM];
175 	} u;
176 
177 	enum nhg_ctx_op_e op;
178 	enum nhg_ctx_status status;
179 };
180 
181 /* Global control to disable use of kernel nexthops, if available. We can't
182  * force the kernel to support nexthop ids, of course, but we can disable
183  * zebra's use of them, for testing e.g. By default, if the kernel supports
184  * nexthop ids, zebra uses them.
185  */
186 void zebra_nhg_enable_kernel_nexthops(bool set);
187 bool zebra_nhg_kernel_nexthops_enabled(void);
188 
189 /**
190  * NHE abstracted tree functions.
191  * Use these where possible instead of direct access.
192  */
193 struct nhg_hash_entry *zebra_nhg_alloc(void);
194 void zebra_nhg_free(struct nhg_hash_entry *nhe);
195 /* In order to clear a generic hash, we need a generic api, sigh. */
196 void zebra_nhg_hash_free(void *p);
197 
198 /* Init an nhe, for use in a hash lookup for example. There's some fuzziness
199  * if the nhe represents only a single nexthop, so we try to capture that
200  * variant also.
201  */
202 void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
203 		    const struct nexthop *nh);
204 
205 /*
206  * Shallow copy of 'orig', into new/allocated nhe.
207  */
208 struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
209 				      uint32_t id);
210 
211 /* Allocate, free backup nexthop info objects */
212 struct nhg_backup_info *zebra_nhg_backup_alloc(void);
213 void zebra_nhg_backup_free(struct nhg_backup_info **p);
214 
215 struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe);
216 
217 extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe);
218 
219 extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe);
220 extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe);
221 
222 extern unsigned int
223 zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe);
224 extern bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe);
225 
226 /* Lookup ID, doesn't create */
227 extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id);
228 
229 /* Hash functions */
230 extern uint32_t zebra_nhg_hash_key(const void *arg);
231 extern uint32_t zebra_nhg_id_key(const void *arg);
232 
233 extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2);
234 extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2);
235 
236 /*
237  * Process a context off of a queue.
238  * Specifically this should be from
239  * the rib meta queue.
240  */
241 extern int nhg_ctx_process(struct nhg_ctx *ctx);
242 
243 /* Find via kernel nh creation */
244 extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
245 				 struct nh_grp *grp, uint8_t count,
246 				 vrf_id_t vrf_id, afi_t afi, int type,
247 				 int startup);
248 /* Del via kernel */
249 extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
250 
251 /* Find an nhe based on a nexthop_group */
252 extern struct nhg_hash_entry *
253 zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
254 
255 /* Find an nhe based on a route's nhe, used during route creation */
256 struct nhg_hash_entry *
257 zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
258 
259 /* Reference counter functions */
260 extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
261 extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
262 
263 /* Check validity of nhe, if invalid will update dependents as well */
264 extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe);
265 
266 /* Convert nhe depends to a grp context that can be passed around safely */
267 extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
268 				 int size);
269 
270 /* Dataplane install/uninstall */
271 extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe);
272 extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe);
273 
274 /* Forward ref of dplane update context type */
275 struct zebra_dplane_ctx;
276 extern void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx);
277 
278 
279 /* Sweep the nhg hash tables for old entries on restart */
280 extern void zebra_nhg_sweep_table(struct hash *hash);
281 
282 /*
283  * We are shutting down but the nexthops should be kept
284  * as that -r has been specified and we don't want to delete
285  * the routes unintentionally
286  */
287 extern void zebra_nhg_mark_keep(void);
288 
289 /* Nexthop resolution processing */
290 struct route_entry; /* Forward ref to avoid circular includes */
291 extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
292 
293 #ifdef __cplusplus
294 }
295 #endif
296 
297 #endif	/* __ZEBRA_NHG_H__ */
298