Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Routing Information Base header
4 : * Copyright (C) 1997 Kunihiro Ishiguro
5 : */
6 :
7 : #ifndef _ZEBRA_RIB_H
8 : #define _ZEBRA_RIB_H
9 :
10 : #include "zebra.h"
11 : #include "memory.h"
12 : #include "hook.h"
13 : #include "typesafe.h"
14 : #include "linklist.h"
15 : #include "prefix.h"
16 : #include "table.h"
17 : #include "queue.h"
18 : #include "nexthop.h"
19 : #include "nexthop_group.h"
20 : #include "vrf.h"
21 : #include "if.h"
22 : #include "mpls.h"
23 : #include "srcdest_table.h"
24 : #include "zebra/zebra_nhg.h"
25 :
26 : #ifdef __cplusplus
27 : extern "C" {
28 : #endif
29 :
30 : DECLARE_MGROUP(ZEBRA);
31 :
32 : DECLARE_MTYPE(RE);
33 :
34 : PREDECL_LIST(rnh_list);
35 :
36 : /* Nexthop structure. */
37 : struct rnh {
38 : uint8_t flags;
39 :
40 : #define ZEBRA_NHT_CONNECTED 0x1
41 : #define ZEBRA_NHT_DELETED 0x2
42 : #define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x4
43 :
44 : /* VRF identifier. */
45 : vrf_id_t vrf_id;
46 :
47 : afi_t afi;
48 : safi_t safi;
49 :
50 : uint32_t seqno;
51 :
52 : struct route_entry *state;
53 : struct prefix resolved_route;
54 : struct list *client_list;
55 :
56 : /* pseudowires dependent on this nh */
57 : struct list *zebra_pseudowire_list;
58 :
59 : struct route_node *node;
60 :
61 : /*
62 : * if this has been filtered for the client
63 : */
64 : int filtered[ZEBRA_ROUTE_MAX];
65 :
66 : struct rnh_list_item rnh_list_item;
67 : };
68 :
69 : #define DISTANCE_INFINITY 255
70 : #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
71 :
72 : PREDECL_LIST(re_list);
73 :
74 : struct re_opaque {
75 : uint16_t length;
76 : uint8_t data[];
77 : };
78 :
79 : struct route_entry {
80 : /* Link list. */
81 : struct re_list_item next;
82 :
83 : /* Nexthop group, shared/refcounted, based on the nexthop(s)
84 : * provided by the owner of the route
85 : */
86 : struct nhg_hash_entry *nhe;
87 :
88 : /* Nexthop group from FIB (optional), reflecting what is actually
89 : * installed in the FIB if that differs. The 'backup' group is used
90 : * when backup nexthops are present in the route's nhg.
91 : */
92 : struct nexthop_group fib_ng;
93 : struct nexthop_group fib_backup_ng;
94 :
95 : /* Nexthop group hash entry IDs. The "installed" id is the id
96 : * used in linux/netlink, if available.
97 : */
98 : uint32_t nhe_id;
99 : uint32_t nhe_installed_id;
100 :
101 : /* Tag */
102 : route_tag_t tag;
103 :
104 : /* Uptime. */
105 : time_t uptime;
106 :
107 : /* Type of this route. */
108 : int type;
109 :
110 : /* VRF identifier. */
111 : vrf_id_t vrf_id;
112 :
113 : /* Which routing table */
114 : uint32_t table;
115 :
116 : /* Metric */
117 : uint32_t metric;
118 :
119 : /* MTU */
120 : uint32_t mtu;
121 : uint32_t nexthop_mtu;
122 :
123 : /* Flags of this route.
124 : * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed
125 : * to clients via Zserv
126 : */
127 : uint32_t flags;
128 :
129 : /* RIB internal status */
130 : uint32_t status;
131 : #define ROUTE_ENTRY_REMOVED 0x1
132 : /* The Route Entry has changed */
133 : #define ROUTE_ENTRY_CHANGED 0x2
134 : /* The Label has changed on the Route entry */
135 : #define ROUTE_ENTRY_LABELS_CHANGED 0x4
136 : /* Route is queued for Installation into the Data Plane */
137 : #define ROUTE_ENTRY_QUEUED 0x8
138 : /* Route is installed into the Data Plane */
139 : #define ROUTE_ENTRY_INSTALLED 0x10
140 : /* Route has Failed installation into the Data Plane in some manner */
141 : #define ROUTE_ENTRY_FAILED 0x20
142 : /* Route has a 'fib' set of nexthops, probably because the installed set
143 : * differs from the rib/normal set of nexthops.
144 : */
145 : #define ROUTE_ENTRY_USE_FIB_NHG 0x40
146 : /*
147 : * Route entries that are going to the dplane for a Route Replace
148 : * let's note the fact that this is happening. This will
149 : * be useful when zebra is determing if a route can be
150 : * used for nexthops
151 : */
152 : #define ROUTE_ENTRY_ROUTE_REPLACING 0x80
153 :
154 : /* Sequence value incremented for each dataplane operation */
155 : uint32_t dplane_sequence;
156 :
157 : /* Source protocol instance */
158 : uint16_t instance;
159 :
160 : /* Distance. */
161 : uint8_t distance;
162 :
163 : struct re_opaque *opaque;
164 : };
165 :
166 : #define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type)
167 :
168 : #define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
169 :
170 : /* Define route types that are equivalent to "connected". */
171 : #define RIB_CONNECTED_ROUTE(R) \
172 : ((R)->type == ZEBRA_ROUTE_CONNECT || (R)->type == ZEBRA_ROUTE_NHRP)
173 :
174 : /* meta-queue structure:
175 : * sub-queue 0: nexthop group objects
176 : * sub-queue 1: EVPN/VxLAN objects
177 : * sub-queue 2: Early Route Processing
178 : * sub-queue 3: Early Label Processing
179 : * sub-queue 4: connected
180 : * sub-queue 5: kernel
181 : * sub-queue 6: static
182 : * sub-queue 7: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP
183 : * sub-queue 8: iBGP, eBGP
184 : * sub-queue 9: any other origin (if any) typically those that
185 : * don't generate routes
186 : */
187 : #define MQ_SIZE 11
188 :
189 : /* For checking that an object has already queued in some sub-queue */
190 : #define MQ_BIT_MASK ((1 << MQ_SIZE) - 1)
191 :
192 : struct meta_queue {
193 : struct list *subq[MQ_SIZE];
194 : uint32_t size; /* sum of lengths of all subqueues */
195 : };
196 :
197 : /*
198 : * Structure that represents a single destination (prefix).
199 : */
200 : typedef struct rib_dest_t_ {
201 :
202 : /*
203 : * Back pointer to the route node for this destination. This helps
204 : * us get to the prefix that this structure is for.
205 : */
206 : struct route_node *rnode;
207 :
208 : /*
209 : * Doubly-linked list of routes for this prefix.
210 : */
211 : struct re_list_head routes;
212 :
213 : struct route_entry *selected_fib;
214 :
215 : /*
216 : * Flags, see below.
217 : */
218 : uint32_t flags;
219 :
220 : /*
221 : * The list of nht prefixes that have ended up
222 : * depending on this route node.
223 : * After route processing is returned from
224 : * the data plane we will run evaluate_rnh
225 : * on these prefixes.
226 : */
227 : struct rnh_list_head nht;
228 :
229 : /*
230 : * Linkage to put dest on the FPM processing queue.
231 : */
232 : TAILQ_ENTRY(rib_dest_t_) fpm_q_entries;
233 :
234 : } rib_dest_t;
235 :
236 125 : DECLARE_LIST(rnh_list, struct rnh, rnh_list_item);
237 1628 : DECLARE_LIST(re_list, struct route_entry, next);
238 :
239 : #define RIB_ROUTE_QUEUED(x) (1 << (x))
240 : // If MQ_SIZE is modified this value needs to be updated.
241 : #define RIB_ROUTE_ANY_QUEUED 0x3F
242 :
243 : /*
244 : * The maximum qindex that can be used.
245 : */
246 : #define ZEBRA_MAX_QINDEX (MQ_SIZE - 1)
247 :
248 : /*
249 : * This flag indicates that a given prefix has been 'advertised' to
250 : * the FPM to be installed in the forwarding plane.
251 : */
252 : #define RIB_DEST_SENT_TO_FPM (1 << (ZEBRA_MAX_QINDEX + 1))
253 :
254 : /*
255 : * This flag is set when we need to send an update to the FPM about a
256 : * dest.
257 : */
258 : #define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2))
259 :
260 : #define RIB_DEST_UPDATE_LSPS (1 << (ZEBRA_MAX_QINDEX + 3))
261 :
262 : /*
263 : * Macro to iterate over each route for a destination (prefix).
264 : */
265 : #define RE_DEST_FOREACH_ROUTE(dest, re) \
266 : for ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL; (re); \
267 : (re) = re_list_next(&((dest)->routes), (re)))
268 :
269 : /*
270 : * Same as above, but allows the current node to be unlinked.
271 : */
272 : #define RE_DEST_FOREACH_ROUTE_SAFE(dest, re, next) \
273 : for ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL; \
274 : (re) && ((next) = re_list_next(&((dest)->routes), (re)), 1); \
275 : (re) = (next))
276 :
277 : #define RE_DEST_FIRST_ROUTE(dest, re) \
278 : ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL)
279 :
280 : #define RE_DEST_NEXT_ROUTE(dest, re) \
281 : ((re) = (dest) ? re_list_next(&((dest)->routes), (re)) : NULL)
282 :
283 : #define RNODE_FOREACH_RE(rn, re) \
284 : RE_DEST_FOREACH_ROUTE (rib_dest_from_rnode(rn), re)
285 :
286 : #define RNODE_FOREACH_RE_SAFE(rn, re, next) \
287 : RE_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode(rn), re, next)
288 :
289 : #define RNODE_FIRST_RE(rn, re) RE_DEST_FIRST_ROUTE(rib_dest_from_rnode(rn), re)
290 :
291 : #define RNODE_NEXT_RE(rn, re) RE_DEST_NEXT_ROUTE(rib_dest_from_rnode(rn), re)
292 :
293 : /*
294 : * rib_table_info_t
295 : *
296 : * Structure that is hung off of a route_table that holds information about
297 : * the table.
298 : */
299 : struct rib_table_info {
300 :
301 : /*
302 : * Back pointer to zebra_vrf.
303 : */
304 : struct zebra_vrf *zvrf;
305 : afi_t afi;
306 : safi_t safi;
307 : uint32_t table_id;
308 : };
309 :
310 : enum rib_tables_iter_state {
311 : RIB_TABLES_ITER_S_INIT,
312 : RIB_TABLES_ITER_S_ITERATING,
313 : RIB_TABLES_ITER_S_DONE
314 : };
315 :
316 : /*
317 : * Structure that holds state for iterating over all tables in the
318 : * Routing Information Base.
319 : */
320 : typedef struct rib_tables_iter_t_ {
321 : vrf_id_t vrf_id;
322 : int afi_safi_ix;
323 :
324 : enum rib_tables_iter_state state;
325 : } rib_tables_iter_t;
326 :
327 : /* Events/reasons triggering a RIB update. */
328 : enum rib_update_event {
329 : RIB_UPDATE_KERNEL,
330 : RIB_UPDATE_RMAP_CHANGE,
331 : RIB_UPDATE_OTHER,
332 : RIB_UPDATE_MAX
333 : };
334 : void rib_update_finish(void);
335 :
336 : int route_entry_update_nhe(struct route_entry *re,
337 : struct nhg_hash_entry *new_nhghe);
338 :
339 : /* NHG replace has happend, we have to update route_entry pointers to new one */
340 : int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
341 : struct nhg_hash_entry *new_entry);
342 :
343 : #define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
344 : extern void _route_entry_dump(const char *func, union prefixconstptr pp,
345 : union prefixconstptr src_pp,
346 : const struct route_entry *re);
347 :
348 : struct route_entry *
349 : zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, uint8_t instance,
350 : uint32_t flags, uint32_t nhe_id, uint32_t table_id,
351 : uint32_t metric, uint32_t mtu, uint8_t distance,
352 : route_tag_t tag);
353 :
354 : #define ZEBRA_RIB_LOOKUP_ERROR -1
355 : #define ZEBRA_RIB_FOUND_EXACT 0
356 : #define ZEBRA_RIB_FOUND_NOGATE 1
357 : #define ZEBRA_RIB_FOUND_CONNECTED 2
358 : #define ZEBRA_RIB_NOTFOUND 3
359 :
360 : extern int is_zebra_valid_kernel_table(uint32_t table_id);
361 : extern int is_zebra_main_routing_table(uint32_t table_id);
362 : extern int zebra_check_addr(const struct prefix *p);
363 :
364 : extern void rib_delnode(struct route_node *rn, struct route_entry *re);
365 : extern void rib_install_kernel(struct route_node *rn, struct route_entry *re,
366 : struct route_entry *old);
367 : extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re);
368 :
369 : /* NOTE:
370 : * All rib_add function will not just add prefix into RIB, but
371 : * also implicitly withdraw equal prefix of same type. */
372 : extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
373 : unsigned short instance, uint32_t flags, struct prefix *p,
374 : struct prefix_ipv6 *src_p, const struct nexthop *nh,
375 : uint32_t nhe_id, uint32_t table_id, uint32_t metric,
376 : uint32_t mtu, uint8_t distance, route_tag_t tag,
377 : bool startup);
378 : /*
379 : * Multipath route apis.
380 : */
381 : extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
382 : struct prefix_ipv6 *src_p, struct route_entry *re,
383 : struct nexthop_group *ng, bool startup);
384 : /*
385 : * -1 -> some sort of error
386 : * 0 -> an add
387 : * 1 -> an update
388 : */
389 : extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
390 : struct prefix_ipv6 *src_p,
391 : struct route_entry *re,
392 : struct nhg_hash_entry *nhe, bool startup);
393 :
394 : extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
395 : unsigned short instance, uint32_t flags,
396 : struct prefix *p, struct prefix_ipv6 *src_p,
397 : const struct nexthop *nh, uint32_t nhe_id,
398 : uint32_t table_id, uint32_t metric, uint8_t distance,
399 : bool fromkernel);
400 :
401 : extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
402 : const union g_addr *addr,
403 : struct route_node **rn_out);
404 : extern struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id,
405 : union g_addr *gaddr,
406 : struct route_node **rn_out);
407 :
408 : extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
409 : vrf_id_t vrf_id);
410 :
411 : extern void rib_update(enum rib_update_event event);
412 : extern void rib_update_table(struct route_table *table,
413 : enum rib_update_event event, int rtype);
414 : extern void rib_sweep_route(struct event *t);
415 : extern void rib_sweep_table(struct route_table *table);
416 : extern void rib_close_table(struct route_table *table);
417 : extern void rib_init(void);
418 : extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance);
419 : extern unsigned long rib_score_proto_table(uint8_t proto,
420 : unsigned short instance,
421 : struct route_table *table);
422 :
423 : extern int rib_queue_add(struct route_node *rn);
424 :
425 : struct nhg_ctx; /* Forward declaration */
426 :
427 : /* Enqueue incoming nhg from OS for processing */
428 : extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx);
429 :
430 : /* Enqueue incoming nhg from proto daemon for processing */
431 : extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe);
432 :
433 : /* Enqueue evpn route for processing */
434 : int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
435 : const struct ipaddr *vtep_ip,
436 : const struct prefix *host_prefix);
437 : int zebra_rib_queue_evpn_route_del(vrf_id_t vrf_id,
438 : const struct ipaddr *vtep_ip,
439 : const struct prefix *host_prefix);
440 : /* Enqueue EVPN remote ES for processing */
441 : int zebra_rib_queue_evpn_rem_es_add(const esi_t *esi,
442 : const struct in_addr *vtep_ip,
443 : bool esr_rxed, uint8_t df_alg,
444 : uint16_t df_pref);
445 : int zebra_rib_queue_evpn_rem_es_del(const esi_t *esi,
446 : const struct in_addr *vtep_ip);
447 : /* Enqueue EVPN remote macip update for processing */
448 : int zebra_rib_queue_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
449 : const struct ipaddr *ip,
450 : struct in_addr vtep_ip);
451 : int zebra_rib_queue_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
452 : const struct ipaddr *ipaddr,
453 : uint8_t flags, uint32_t seq,
454 : struct in_addr vtep_ip,
455 : const esi_t *esi);
456 : /* Enqueue VXLAN remote vtep update for processing */
457 : int zebra_rib_queue_evpn_rem_vtep_add(vrf_id_t vrf_id, vni_t vni,
458 : struct in_addr vtep_ip,
459 : int flood_control);
460 : int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni,
461 : struct in_addr vtep_ip);
462 :
463 : extern void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf);
464 : extern int zebra_rib_labeled_unicast(struct route_entry *re);
465 : extern struct route_table *rib_table_ipv6;
466 :
467 : extern void rib_unlink(struct route_node *rn, struct route_entry *re);
468 : extern int rib_gc_dest(struct route_node *rn);
469 : extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter);
470 :
471 : extern uint8_t route_distance(int type);
472 :
473 : extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq,
474 : bool rt_delete);
475 :
476 : /*
477 : * rib_find_rn_from_ctx
478 : *
479 : * Returns a lock increased route_node for the appropriate
480 : * table and prefix specified by the context. Developer
481 : * should unlock the node when done.
482 : */
483 : extern struct route_node *
484 : rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx);
485 :
486 : /*
487 : * Inline functions.
488 : */
489 :
490 : /*
491 : * rib_table_info
492 : */
493 166 : static inline struct rib_table_info *rib_table_info(struct route_table *table)
494 : {
495 166 : return (struct rib_table_info *)route_table_get_info(table);
496 : }
497 :
498 : /*
499 : * rib_dest_from_rnode
500 : */
501 1312 : static inline rib_dest_t *rib_dest_from_rnode(struct route_node *rn)
502 : {
503 1522 : return (rib_dest_t *)rn->info;
504 : }
505 :
506 : /*
507 : * rnode_to_ribs
508 : *
509 : * Returns a pointer to the list of routes corresponding to the given
510 : * route_node.
511 : */
512 56 : static inline struct route_entry *rnode_to_ribs(struct route_node *rn)
513 : {
514 56 : rib_dest_t *dest;
515 :
516 56 : dest = rib_dest_from_rnode(rn);
517 56 : if (!dest)
518 : return NULL;
519 :
520 56 : return re_list_first(&dest->routes);
521 : }
522 :
523 : /*
524 : * rib_dest_prefix
525 : */
526 : static inline struct prefix *rib_dest_prefix(rib_dest_t *dest)
527 : {
528 : return &dest->rnode->p;
529 : }
530 :
531 : /*
532 : * rib_dest_af
533 : *
534 : * Returns the address family that the destination is for.
535 : */
536 : static inline uint8_t rib_dest_af(rib_dest_t *dest)
537 : {
538 : return dest->rnode->p.family;
539 : }
540 :
541 : /*
542 : * rib_dest_table
543 : */
544 166 : static inline struct route_table *rib_dest_table(rib_dest_t *dest)
545 : {
546 332 : return srcdest_rnode_table(dest->rnode);
547 : }
548 :
549 : /*
550 : * rib_dest_vrf
551 : */
552 166 : static inline struct zebra_vrf *rib_dest_vrf(rib_dest_t *dest)
553 : {
554 166 : return rib_table_info(rib_dest_table(dest))->zvrf;
555 : }
556 :
557 : /*
558 : * Create the rib_dest_t and attach it to the specified node
559 : */
560 : extern rib_dest_t *zebra_rib_create_dest(struct route_node *rn);
561 :
562 : /*
563 : * rib_tables_iter_init
564 : */
565 : static inline void rib_tables_iter_init(rib_tables_iter_t *iter)
566 :
567 : {
568 : memset(iter, 0, sizeof(*iter));
569 : iter->state = RIB_TABLES_ITER_S_INIT;
570 : }
571 :
572 : /*
573 : * rib_tables_iter_started
574 : *
575 : * Returns true if this iterator has started iterating over the set of
576 : * tables.
577 : */
578 : static inline int rib_tables_iter_started(rib_tables_iter_t *iter)
579 : {
580 : return iter->state != RIB_TABLES_ITER_S_INIT;
581 : }
582 :
583 : /*
584 : * rib_tables_iter_cleanup
585 : */
586 : static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter)
587 : {
588 : iter->state = RIB_TABLES_ITER_S_DONE;
589 : }
590 :
591 : DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
592 : (rn, reason));
593 : DECLARE_HOOK(rib_shutdown, (struct route_node * rn), (rn));
594 :
595 : /*
596 : * Access installed/fib nexthops, which may be a subset of the
597 : * rib nexthops.
598 : */
599 4 : static inline struct nexthop_group *rib_get_fib_nhg(struct route_entry *re)
600 : {
601 : /* If the fib set is a subset of the active rib set,
602 : * use the dedicated fib list.
603 : */
604 4 : if (CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG))
605 0 : return &(re->fib_ng);
606 : else
607 4 : return &(re->nhe->nhg);
608 : }
609 :
610 : /*
611 : * Access backup nexthop-group that represents the installed backup nexthops;
612 : * any installed backup will be on the fib list.
613 : */
614 0 : static inline struct nexthop_group *rib_get_fib_backup_nhg(
615 : struct route_entry *re)
616 : {
617 4 : return &(re->fib_backup_ng);
618 : }
619 :
620 : extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto,
621 : uint8_t instance);
622 :
623 : extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto,
624 : uint8_t instance);
625 :
626 : extern void zebra_vty_init(void);
627 :
628 : extern pid_t pid;
629 :
630 : extern uint32_t rt_table_main_id;
631 :
632 : /* Name of hook calls */
633 : #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
634 :
635 : #ifdef __cplusplus
636 : }
637 : #endif
638 :
639 : #endif /*_ZEBRA_RIB_H */
|