| File: | src/usr.sbin/bgpd/rde_rib.c | 
| Warning: | line 254, column 29 Use of memory after it is freed | 
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rde_rib.c,v 1.224 2021/08/09 08:15:35 claudio Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | #include <sys/types.h> | |||
| 20 | #include <sys/queue.h> | |||
| 21 | ||||
| 22 | #include <limits.h> | |||
| 23 | #include <stdlib.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <siphash.h> | |||
| 26 | #include <time.h> | |||
| 27 | ||||
| 28 | #include "bgpd.h" | |||
| 29 | #include "rde.h" | |||
| 30 | #include "log.h" | |||
| 31 | ||||
| 32 | /* | |||
| 33 | * BGP RIB -- Routing Information Base | |||
| 34 | * | |||
| 35 | * The RIB is build with one aspect in mind. Speed -- actually update speed. | |||
| 36 | * Therefore one thing needs to be absolutely avoided, long table walks. | |||
| 37 | * This is achieved by heavily linking the different parts together. | |||
| 38 | */ | |||
| 39 | u_int16_t rib_size; | |||
| 40 | struct rib **ribs; | |||
| 41 | ||||
| 42 | struct rib_entry *rib_add(struct rib *, struct bgpd_addr *, int); | |||
| 43 | static inline int rib_compare(const struct rib_entry *, | |||
| 44 | const struct rib_entry *); | |||
| 45 | void rib_remove(struct rib_entry *); | |||
| 46 | int rib_empty(struct rib_entry *); | |||
| 47 | static void rib_dump_abort(u_int16_t); | |||
| 48 | ||||
| 49 | RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare)void rib_tree_RB_INSERT_COLOR(struct rib_tree *, struct rib_entry *); void rib_tree_RB_REMOVE_COLOR(struct rib_tree *, struct rib_entry *, struct rib_entry *); struct rib_entry *rib_tree_RB_REMOVE (struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_INSERT (struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_FIND (struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_NFIND (struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_NEXT (struct rib_entry *); struct rib_entry *rib_tree_RB_PREV(struct rib_entry *); struct rib_entry *rib_tree_RB_MINMAX(struct rib_tree *, int);; | |||
| 50 | RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare)void rib_tree_RB_INSERT_COLOR(struct rib_tree *head, struct rib_entry *elm) { struct rib_entry *parent, *gparent, *tmp; while ((parent = (elm)->rib_e.rbe_parent) && (parent)->rib_e. rbe_color == 1) { gparent = (parent)->rib_e.rbe_parent; if (parent == (gparent)->rib_e.rbe_left) { tmp = (gparent)-> rib_e.rbe_right; if (tmp && (tmp)->rib_e.rbe_color == 1) { (tmp)->rib_e.rbe_color = 0; do { (parent)->rib_e .rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0 ); elm = gparent; continue; } if ((parent)->rib_e.rbe_right == elm) { do { (tmp) = (parent)->rib_e.rbe_right; if (((parent )->rib_e.rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)-> rib_e.rbe_left)->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent )) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e .rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e .rbe_left = (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while ( 0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->rib_e.rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0); do { (tmp) = (gparent)->rib_e.rbe_left; if (((gparent)->rib_e.rbe_left = (tmp)->rib_e.rbe_right )) { ((tmp)->rib_e.rbe_right)->rib_e.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (gparent )->rib_e.rbe_parent)) { if ((gparent) == ((gparent)->rib_e .rbe_parent)->rib_e.rbe_left) ((gparent)->rib_e.rbe_parent )->rib_e.rbe_left = (tmp); else ((gparent)->rib_e.rbe_parent )->rib_e.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->rib_e.rbe_right = (gparent); (gparent)->rib_e .rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent )) do {} while (0); } while (0); } else { tmp = (gparent)-> rib_e.rbe_left; if (tmp && (tmp)->rib_e.rbe_color == 1) { (tmp)->rib_e.rbe_color = 0; do { (parent)->rib_e. rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0) ; elm = gparent; continue; } if ((parent)->rib_e.rbe_left == elm) { do { (tmp) = (parent)->rib_e.rbe_left; if (((parent )->rib_e.rbe_left = (tmp)->rib_e.rbe_right)) { ((tmp)-> rib_e.rbe_right)->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent )) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e .rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e .rbe_right = (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->rib_e.rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0); do { (tmp) = (gparent)->rib_e.rbe_right ; if (((gparent)->rib_e.rbe_right = (tmp)->rib_e.rbe_left )) { ((tmp)->rib_e.rbe_left)->rib_e.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (gparent )->rib_e.rbe_parent)) { if ((gparent) == ((gparent)->rib_e .rbe_parent)->rib_e.rbe_left) ((gparent)->rib_e.rbe_parent )->rib_e.rbe_left = (tmp); else ((gparent)->rib_e.rbe_parent )->rib_e.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->rib_e.rbe_left = (gparent); (gparent)->rib_e .rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent )) do {} while (0); } while (0); } } (head->rbh_root)-> rib_e.rbe_color = 0; } void rib_tree_RB_REMOVE_COLOR(struct rib_tree *head, struct rib_entry *parent, struct rib_entry *elm) { struct rib_entry *tmp; while ((elm == ((void*)0) || (elm)->rib_e .rbe_color == 0) && elm != (head)->rbh_root) { if ( (parent)->rib_e.rbe_left == elm) { tmp = (parent)->rib_e .rbe_right; if ((tmp)->rib_e.rbe_color == 1) { do { (tmp)-> rib_e.rbe_color = 0; (parent)->rib_e.rbe_color = 1; } while (0); do { (tmp) = (parent)->rib_e.rbe_right; if (((parent )->rib_e.rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)-> rib_e.rbe_left)->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent )) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e .rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e .rbe_left = (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while ( 0); } while (0); tmp = (parent)->rib_e.rbe_right; } if ((( tmp)->rib_e.rbe_left == ((void*)0) || ((tmp)->rib_e.rbe_left )->rib_e.rbe_color == 0) && ((tmp)->rib_e.rbe_right == ((void*)0) || ((tmp)->rib_e.rbe_right)->rib_e.rbe_color == 0)) { (tmp)->rib_e.rbe_color = 1; elm = parent; parent = (elm)->rib_e.rbe_parent; } else { if ((tmp)->rib_e.rbe_right == ((void*)0) || ((tmp)->rib_e.rbe_right)->rib_e.rbe_color == 0) { struct rib_entry *oleft; if ((oleft = (tmp)->rib_e .rbe_left)) (oleft)->rib_e.rbe_color = 0; (tmp)->rib_e. rbe_color = 1; do { (oleft) = (tmp)->rib_e.rbe_left; if (( (tmp)->rib_e.rbe_left = (oleft)->rib_e.rbe_right)) { (( oleft)->rib_e.rbe_right)->rib_e.rbe_parent = (tmp); } do {} while (0); if (((oleft)->rib_e.rbe_parent = (tmp)-> rib_e.rbe_parent)) { if ((tmp) == ((tmp)->rib_e.rbe_parent )->rib_e.rbe_left) ((tmp)->rib_e.rbe_parent)->rib_e. rbe_left = (oleft); else ((tmp)->rib_e.rbe_parent)->rib_e .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->rib_e.rbe_right = (tmp); (tmp)->rib_e.rbe_parent = (oleft); do {} while (0); if (((oleft)->rib_e.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->rib_e.rbe_right ; } (tmp)->rib_e.rbe_color = (parent)->rib_e.rbe_color; (parent)->rib_e.rbe_color = 0; if ((tmp)->rib_e.rbe_right ) ((tmp)->rib_e.rbe_right)->rib_e.rbe_color = 0; do { ( tmp) = (parent)->rib_e.rbe_right; if (((parent)->rib_e. rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)->rib_e.rbe_left )->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp )->rib_e.rbe_parent = (parent)->rib_e.rbe_parent)) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e.rbe_left ) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = ( tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e.rbe_left = (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent )->rib_e.rbe_left; if ((tmp)->rib_e.rbe_color == 1) { do { (tmp)->rib_e.rbe_color = 0; (parent)->rib_e.rbe_color = 1; } while (0); do { (tmp) = (parent)->rib_e.rbe_left; if (((parent)->rib_e.rbe_left = (tmp)->rib_e.rbe_right)) { ((tmp)->rib_e.rbe_right)->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (parent )->rib_e.rbe_parent)) { if ((parent) == ((parent)->rib_e .rbe_parent)->rib_e.rbe_left) ((parent)->rib_e.rbe_parent )->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent )->rib_e.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->rib_e.rbe_right = (parent); (parent)->rib_e .rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->rib_e.rbe_left ; } if (((tmp)->rib_e.rbe_left == ((void*)0) || ((tmp)-> rib_e.rbe_left)->rib_e.rbe_color == 0) && ((tmp)-> rib_e.rbe_right == ((void*)0) || ((tmp)->rib_e.rbe_right)-> rib_e.rbe_color == 0)) { (tmp)->rib_e.rbe_color = 1; elm = parent; parent = (elm)->rib_e.rbe_parent; } else { if ((tmp )->rib_e.rbe_left == ((void*)0) || ((tmp)->rib_e.rbe_left )->rib_e.rbe_color == 0) { struct rib_entry *oright; if (( oright = (tmp)->rib_e.rbe_right)) (oright)->rib_e.rbe_color = 0; (tmp)->rib_e.rbe_color = 1; do { (oright) = (tmp)-> rib_e.rbe_right; if (((tmp)->rib_e.rbe_right = (oright)-> rib_e.rbe_left)) { ((oright)->rib_e.rbe_left)->rib_e.rbe_parent = (tmp); } do {} while (0); if (((oright)->rib_e.rbe_parent = (tmp)->rib_e.rbe_parent)) { if ((tmp) == ((tmp)->rib_e .rbe_parent)->rib_e.rbe_left) ((tmp)->rib_e.rbe_parent) ->rib_e.rbe_left = (oright); else ((tmp)->rib_e.rbe_parent )->rib_e.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->rib_e.rbe_left = (tmp); (tmp)->rib_e .rbe_parent = (oright); do {} while (0); if (((oright)->rib_e .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> rib_e.rbe_left; } (tmp)->rib_e.rbe_color = (parent)->rib_e .rbe_color; (parent)->rib_e.rbe_color = 0; if ((tmp)->rib_e .rbe_left) ((tmp)->rib_e.rbe_left)->rib_e.rbe_color = 0 ; do { (tmp) = (parent)->rib_e.rbe_left; if (((parent)-> rib_e.rbe_left = (tmp)->rib_e.rbe_right)) { ((tmp)->rib_e .rbe_right)->rib_e.rbe_parent = (parent); } do {} while (0 ); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent )) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e .rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e .rbe_right = (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->rib_e.rbe_color = 0; } struct rib_entry * rib_tree_RB_REMOVE (struct rib_tree *head, struct rib_entry *elm) { struct rib_entry *child, *parent, *old = elm; int color; if ((elm)->rib_e. rbe_left == ((void*)0)) child = (elm)->rib_e.rbe_right; else if ((elm)->rib_e.rbe_right == ((void*)0)) child = (elm)-> rib_e.rbe_left; else { struct rib_entry *left; elm = (elm)-> rib_e.rbe_right; while ((left = (elm)->rib_e.rbe_left)) elm = left; child = (elm)->rib_e.rbe_right; parent = (elm)-> rib_e.rbe_parent; color = (elm)->rib_e.rbe_color; if (child ) (child)->rib_e.rbe_parent = parent; if (parent) { if ((parent )->rib_e.rbe_left == elm) (parent)->rib_e.rbe_left = child ; else (parent)->rib_e.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->rib_e.rbe_parent == old) parent = elm; (elm)->rib_e = (old)->rib_e; if ( (old)->rib_e.rbe_parent) { if (((old)->rib_e.rbe_parent )->rib_e.rbe_left == old) ((old)->rib_e.rbe_parent)-> rib_e.rbe_left = elm; else ((old)->rib_e.rbe_parent)->rib_e .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->rib_e.rbe_left)->rib_e.rbe_parent = elm ; if ((old)->rib_e.rbe_right) ((old)->rib_e.rbe_right)-> rib_e.rbe_parent = elm; if (parent) { left = parent; do { do { } while (0); } while ((left = (left)->rib_e.rbe_parent)); } goto color; } parent = (elm)->rib_e.rbe_parent; color = ( elm)->rib_e.rbe_color; if (child) (child)->rib_e.rbe_parent = parent; if (parent) { if ((parent)->rib_e.rbe_left == elm ) (parent)->rib_e.rbe_left = child; else (parent)->rib_e .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) rib_tree_RB_REMOVE_COLOR(head , parent, child); return (old); } struct rib_entry * rib_tree_RB_INSERT (struct rib_tree *head, struct rib_entry *elm) { struct rib_entry *tmp; struct rib_entry *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (rib_compare )(elm, parent); if (comp < 0) tmp = (tmp)->rib_e.rbe_left ; else if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else return (tmp); } do { (elm)->rib_e.rbe_parent = parent; (elm )->rib_e.rbe_left = (elm)->rib_e.rbe_right = ((void*)0) ; (elm)->rib_e.rbe_color = 1; } while (0); if (parent != ( (void*)0)) { if (comp < 0) (parent)->rib_e.rbe_left = elm ; else (parent)->rib_e.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; rib_tree_RB_INSERT_COLOR(head , elm); return (((void*)0)); } struct rib_entry * rib_tree_RB_FIND (struct rib_tree *head, struct rib_entry *elm) { struct rib_entry *tmp = (head)->rbh_root; int comp; while (tmp) { comp = rib_compare (elm, tmp); if (comp < 0) tmp = (tmp)->rib_e.rbe_left; else if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else return (tmp); } return (((void*)0)); } struct rib_entry * rib_tree_RB_NFIND (struct rib_tree *head, struct rib_entry *elm) { struct rib_entry *tmp = (head)->rbh_root; struct rib_entry *res = ((void*) 0); int comp; while (tmp) { comp = rib_compare(elm, tmp); if ( comp < 0) { res = tmp; tmp = (tmp)->rib_e.rbe_left; } else if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else return (tmp); } return (res); } struct rib_entry * rib_tree_RB_NEXT (struct rib_entry *elm) { if ((elm)->rib_e.rbe_right) { elm = (elm)->rib_e.rbe_right; while ((elm)->rib_e.rbe_left ) elm = (elm)->rib_e.rbe_left; } else { if ((elm)->rib_e .rbe_parent && (elm == ((elm)->rib_e.rbe_parent)-> rib_e.rbe_left)) elm = (elm)->rib_e.rbe_parent; else { while ((elm)->rib_e.rbe_parent && (elm == ((elm)->rib_e .rbe_parent)->rib_e.rbe_right)) elm = (elm)->rib_e.rbe_parent ; elm = (elm)->rib_e.rbe_parent; } } return (elm); } struct rib_entry * rib_tree_RB_PREV(struct rib_entry *elm) { if ((elm )->rib_e.rbe_left) { elm = (elm)->rib_e.rbe_left; while ((elm)->rib_e.rbe_right) elm = (elm)->rib_e.rbe_right; } else { if ((elm)->rib_e.rbe_parent && (elm == ( (elm)->rib_e.rbe_parent)->rib_e.rbe_right)) elm = (elm) ->rib_e.rbe_parent; else { while ((elm)->rib_e.rbe_parent && (elm == ((elm)->rib_e.rbe_parent)->rib_e.rbe_left )) elm = (elm)->rib_e.rbe_parent; elm = (elm)->rib_e.rbe_parent ; } } return (elm); } struct rib_entry * rib_tree_RB_MINMAX(struct rib_tree *head, int val) { struct rib_entry *tmp = (head)-> rbh_root; struct rib_entry *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->rib_e.rbe_left ; else tmp = (tmp)->rib_e.rbe_right; } return (parent); }; | |||
| 51 | ||||
| 52 | struct rib_context { | |||
| 53 | LIST_ENTRY(rib_context)struct { struct rib_context *le_next; struct rib_context **le_prev ; } entry; | |||
| 54 | struct rib_entry *ctx_re; | |||
| 55 | struct prefix *ctx_p; | |||
| 56 | u_int32_t ctx_id; | |||
| 57 | void (*ctx_rib_call)(struct rib_entry *, void *); | |||
| 58 | void (*ctx_prefix_call)(struct prefix *, void *); | |||
| 59 | void (*ctx_done)(void *, u_int8_t); | |||
| 60 | int (*ctx_throttle)(void *); | |||
| 61 | void *ctx_arg; | |||
| 62 | unsigned int ctx_count; | |||
| 63 | u_int8_t ctx_aid; | |||
| 64 | }; | |||
| 65 | LIST_HEAD(, rib_context)struct { struct rib_context *lh_first; } rib_dumps = LIST_HEAD_INITIALIZER(rib_dumps){ ((void*)0) }; | |||
| 66 | ||||
| 67 | static void prefix_dump_r(struct rib_context *); | |||
| 68 | ||||
| 69 | static inline struct rib_entry * | |||
| 70 | re_lock(struct rib_entry *re) | |||
| 71 | { | |||
| 72 | if (re->lock != 0) | |||
| 73 | log_warnx("%s: entry already locked", __func__); | |||
| 74 | re->lock = 1; | |||
| 75 | return re; | |||
| 76 | } | |||
| 77 | ||||
| 78 | static inline struct rib_entry * | |||
| 79 | re_unlock(struct rib_entry *re) | |||
| 80 | { | |||
| 81 | if (re->lock == 0) | |||
| 82 | log_warnx("%s: entry already unlocked", __func__); | |||
| 83 | re->lock = 0; | |||
| 84 | return re; | |||
| 85 | } | |||
| 86 | ||||
| 87 | static inline int | |||
| 88 | re_is_locked(struct rib_entry *re) | |||
| 89 | { | |||
| 90 | return (re->lock != 0); | |||
| 91 | } | |||
| 92 | ||||
| 93 | static inline struct prefix * | |||
| 94 | prefix_lock(struct prefix *p) | |||
| 95 | { | |||
| 96 | if (p->flags & PREFIX_FLAG_LOCKED0x80) | |||
| 97 | fatalx("%s: locking locked prefix", __func__); | |||
| 98 | p->flags |= PREFIX_FLAG_LOCKED0x80; | |||
| 99 | return p; | |||
| 100 | } | |||
| 101 | ||||
| 102 | static inline struct prefix * | |||
| 103 | prefix_unlock(struct prefix *p) | |||
| 104 | { | |||
| 105 | if ((p->flags & PREFIX_FLAG_LOCKED0x80) == 0) | |||
| 106 | fatalx("%s: unlocking unlocked prefix", __func__); | |||
| 107 | p->flags &= ~PREFIX_FLAG_LOCKED0x80; | |||
| 108 | return p; | |||
| 109 | } | |||
| 110 | ||||
| 111 | static inline int | |||
| 112 | prefix_is_locked(struct prefix *p) | |||
| 113 | { | |||
| 114 | return (p->flags & PREFIX_FLAG_LOCKED0x80) != 0; | |||
| 115 | } | |||
| 116 | ||||
| 117 | static inline int | |||
| 118 | prefix_is_dead(struct prefix *p) | |||
| 119 | { | |||
| 120 | return (p->flags & PREFIX_FLAG_DEAD0x04) != 0; | |||
| 121 | } | |||
| 122 | ||||
| 123 | static inline struct rib_tree * | |||
| 124 | rib_tree(struct rib *rib) | |||
| 125 | { | |||
| 126 | return (&rib->tree); | |||
| 127 | } | |||
| 128 | ||||
| 129 | static inline int | |||
| 130 | rib_compare(const struct rib_entry *a, const struct rib_entry *b) | |||
| 131 | { | |||
| 132 | return (pt_prefix_cmp(a->prefix, b->prefix)); | |||
| 133 | } | |||
| 134 | ||||
| 135 | /* RIB specific functions */ | |||
| 136 | struct rib * | |||
| 137 | rib_new(char *name, u_int rtableid, u_int16_t flags) | |||
| 138 | { | |||
| 139 | struct rib *new; | |||
| 140 | u_int16_t id; | |||
| 141 | ||||
| 142 | for (id = 0; id < rib_size; id++) { | |||
| 143 | if (ribs[id] == NULL((void*)0)) | |||
| 144 | break; | |||
| 145 | } | |||
| 146 | ||||
| 147 | if (id >= rib_size) { | |||
| 148 | if ((ribs = recallocarray(ribs, id, id + 8, | |||
| 149 | sizeof(struct rib))) == NULL((void*)0)) | |||
| 150 | fatal(NULL((void*)0)); | |||
| 151 | rib_size = id + 8; | |||
| 152 | } | |||
| 153 | ||||
| 154 | if ((new = calloc(1, sizeof(*new))) == NULL((void*)0)) | |||
| 155 | fatal(NULL((void*)0)); | |||
| 156 | ||||
| 157 | strlcpy(new->name, name, sizeof(new->name)); | |||
| 158 | RB_INIT(rib_tree(new))do { (rib_tree(new))->rbh_root = ((void*)0); } while (0); | |||
| 159 | new->state = RECONF_REINIT; | |||
| 160 | new->id = id; | |||
| 161 | new->flags = flags; | |||
| 162 | new->rtableid = rtableid; | |||
| 163 | ||||
| 164 | new->in_rules = calloc(1, sizeof(struct filter_head)); | |||
| 165 | if (new->in_rules == NULL((void*)0)) | |||
| 166 | fatal(NULL((void*)0)); | |||
| 167 | TAILQ_INIT(new->in_rules)do { (new->in_rules)->tqh_first = ((void*)0); (new-> in_rules)->tqh_last = &(new->in_rules)->tqh_first ; } while (0); | |||
| 168 | ||||
| 169 | ribs[id] = new; | |||
| 170 | ||||
| 171 | log_debug("%s: %s -> %u", __func__, name, id); | |||
| 172 | return (new); | |||
| 173 | } | |||
| 174 | ||||
| 175 | /* | |||
| 176 | * This function is only called when the FIB information of a RIB changed. | |||
| 177 | * It will flush the FIB if there was one previously and change the fibstate | |||
| 178 | * from RECONF_NONE (nothing to do) to either RECONF_RELOAD (reload the FIB) | |||
| 179 | * or RECONF_REINIT (rerun the route decision process for every element) | |||
| 180 | * depending on the new flags. | |||
| 181 | */ | |||
| 182 | void | |||
| 183 | rib_update(struct rib *rib) | |||
| 184 | { | |||
| 185 | /* flush fib first if there was one */ | |||
| 186 | if ((rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0) | |||
| 187 | rde_send_kroute_flush(rib); | |||
| 188 | ||||
| 189 | /* if no evaluate changes then a full reinit is needed */ | |||
| 190 | if ((rib->flags & F_RIB_NOEVALUATE0x0002) != | |||
| 191 | (rib->flags_tmp & F_RIB_NOEVALUATE0x0002)) | |||
| 192 | rib->fibstate = RECONF_REINIT; | |||
| 193 | ||||
| 194 | rib->flags = rib->flags_tmp; | |||
| 195 | rib->rtableid = rib->rtableid_tmp; | |||
| 196 | ||||
| 197 | /* reload fib if there is no reinit pending and there will be a fib */ | |||
| 198 | if (rib->fibstate != RECONF_REINIT && | |||
| 199 | (rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0) | |||
| 200 | rib->fibstate = RECONF_RELOAD; | |||
| 201 | } | |||
| 202 | ||||
| 203 | struct rib * | |||
| 204 | rib_byid(u_int16_t id) | |||
| 205 | { | |||
| 206 | if (id == RIB_NOTFOUND0xffff || id >= rib_size || ribs[id] == NULL((void*)0)) | |||
| 207 | return NULL((void*)0); | |||
| 208 | return ribs[id]; | |||
| 209 | } | |||
| 210 | ||||
| 211 | u_int16_t | |||
| 212 | rib_find(char *name) | |||
| 213 | { | |||
| 214 | u_int16_t id; | |||
| 215 | ||||
| 216 | /* no name returns the first Loc-RIB */ | |||
| 217 | if (name == NULL((void*)0) || *name == '\0') | |||
| 218 | return RIB_LOC_START1; | |||
| 219 | ||||
| 220 | for (id = 0; id < rib_size; id++) { | |||
| 221 | if (ribs[id] != NULL((void*)0) && !strcmp(ribs[id]->name, name)) | |||
| 222 | return id; | |||
| 223 | } | |||
| 224 | ||||
| 225 | return RIB_NOTFOUND0xffff; | |||
| 226 | } | |||
| 227 | ||||
| 228 | void | |||
| 229 | rib_free(struct rib *rib) | |||
| 230 | { | |||
| 231 | struct rib_entry *re, *xre; | |||
| 232 | struct prefix *p; | |||
| 233 | ||||
| 234 | rib_dump_abort(rib->id); | |||
| 235 | ||||
| 236 | /* | |||
| 237 | * flush the rib, disable route evaluation and fib sync to speed up | |||
| 238 | * the prefix removal. Nothing depends on this data anymore. | |||
| 239 | */ | |||
| 240 | if ((rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0) | |||
| 241 | rde_send_kroute_flush(rib); | |||
| 242 | rib->flags |= F_RIB_NOEVALUATE0x0002 | F_RIB_NOFIB0x0004; | |||
| 243 | ||||
| 244 | for (re = RB_MIN(rib_tree, rib_tree(rib))rib_tree_RB_MINMAX(rib_tree(rib), -1); re != NULL((void*)0); re = xre) { | |||
| 245 | xre = RB_NEXT(rib_tree, rib_tree(rib), re)rib_tree_RB_NEXT(re); | |||
| 246 | ||||
| 247 | /* | |||
| 248 | * Removing the prefixes is tricky because the last one | |||
| 249 | * will remove the rib_entry as well and because we do | |||
| 250 | * an empty check in prefix_destroy() it is not possible to | |||
| 251 | * use the default for loop. | |||
| 252 | */ | |||
| 253 | while ((p = LIST_FIRST(&re->prefix_h)((&re->prefix_h)->lh_first))) { | |||
| 254 | struct rde_aspath *asp = prefix_aspath(p); | |||
| 
 | ||||
| 255 | if (asp && asp->pftableid) | |||
| 256 | rde_pftable_del(asp->pftableid, p); | |||
| 257 | prefix_destroy(p); | |||
| 258 | } | |||
| 259 | } | |||
| 260 | if (rib->id <= RIB_LOC_START1) | |||
| 261 | return; /* never remove the default ribs */ | |||
| 262 | filterlist_free(rib->in_rules_tmp); | |||
| 263 | filterlist_free(rib->in_rules); | |||
| 264 | ribs[rib->id] = NULL((void*)0); | |||
| 265 | free(rib); | |||
| 266 | } | |||
| 267 | ||||
| 268 | void | |||
| 269 | rib_shutdown(void) | |||
| 270 | { | |||
| 271 | struct rib *rib; | |||
| 272 | u_int16_t id; | |||
| 273 | ||||
| 274 | for (id = 0; id < rib_size; id++) { | |||
| 
 | ||||
| 275 | rib = rib_byid(id); | |||
| 276 | if (rib 
 | |||
| 277 | continue; | |||
| 278 | if (!RB_EMPTY(rib_tree(ribs[id]))((rib_tree(ribs[id]))->rbh_root == ((void*)0))) { | |||
| 279 | log_warnx("%s: rib %s is not empty", __func__, | |||
| 280 | ribs[id]->name); | |||
| 281 | } | |||
| 282 | rib_free(ribs[id]); | |||
| 283 | } | |||
| 284 | for (id = 0; id <= RIB_LOC_START1; id++) { | |||
| 285 | rib = rib_byid(id); | |||
| 286 | if (rib == NULL((void*)0)) | |||
| 287 | continue; | |||
| 288 | filterlist_free(rib->in_rules_tmp); | |||
| 289 | filterlist_free(rib->in_rules); | |||
| 290 | ribs[id] = NULL((void*)0); | |||
| 291 | free(rib); | |||
| 292 | } | |||
| 293 | free(ribs); | |||
| 294 | } | |||
| 295 | ||||
| 296 | struct rib_entry * | |||
| 297 | rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) | |||
| 298 | { | |||
| 299 | struct rib_entry xre, *re; | |||
| 300 | struct pt_entry *pte; | |||
| 301 | ||||
| 302 | pte = pt_fill(prefix, prefixlen); | |||
| 303 | memset(&xre, 0, sizeof(xre)); | |||
| 304 | xre.prefix = pte; | |||
| 305 | ||||
| 306 | re = RB_FIND(rib_tree, rib_tree(rib), &xre)rib_tree_RB_FIND(rib_tree(rib), &xre); | |||
| 307 | if (re && re->rib_id != rib->id) | |||
| 308 | fatalx("%s: Unexpected RIB %u != %u.", __func__, | |||
| 309 | re->rib_id, rib->id); | |||
| 310 | return re; | |||
| 311 | } | |||
| 312 | ||||
| 313 | struct rib_entry * | |||
| 314 | rib_match(struct rib *rib, struct bgpd_addr *addr) | |||
| 315 | { | |||
| 316 | struct rib_entry *re; | |||
| 317 | int i; | |||
| 318 | ||||
| 319 | switch (addr->aid) { | |||
| 320 | case AID_INET1: | |||
| 321 | case AID_VPN_IPv43: | |||
| 322 | for (i = 32; i >= 0; i--) { | |||
| 323 | re = rib_get(rib, addr, i); | |||
| 324 | if (re != NULL((void*)0)) | |||
| 325 | return (re); | |||
| 326 | } | |||
| 327 | break; | |||
| 328 | case AID_INET62: | |||
| 329 | case AID_VPN_IPv64: | |||
| 330 | for (i = 128; i >= 0; i--) { | |||
| 331 | re = rib_get(rib, addr, i); | |||
| 332 | if (re != NULL((void*)0)) | |||
| 333 | return (re); | |||
| 334 | } | |||
| 335 | break; | |||
| 336 | default: | |||
| 337 | fatalx("%s: unknown af", __func__); | |||
| 338 | } | |||
| 339 | return (NULL((void*)0)); | |||
| 340 | } | |||
| 341 | ||||
| 342 | ||||
| 343 | struct rib_entry * | |||
| 344 | rib_add(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) | |||
| 345 | { | |||
| 346 | struct pt_entry *pte; | |||
| 347 | struct rib_entry *re; | |||
| 348 | ||||
| 349 | pte = pt_get(prefix, prefixlen); | |||
| 350 | if (pte == NULL((void*)0)) | |||
| 351 | pte = pt_add(prefix, prefixlen); | |||
| 352 | ||||
| 353 | if ((re = calloc(1, sizeof(*re))) == NULL((void*)0)) | |||
| 354 | fatal("rib_add"); | |||
| 355 | ||||
| 356 | LIST_INIT(&re->prefix_h)do { ((&re->prefix_h)->lh_first) = ((void*)0); } while (0); | |||
| 357 | re->prefix = pt_ref(pte); | |||
| 358 | re->rib_id = rib->id; | |||
| 359 | ||||
| 360 | if (RB_INSERT(rib_tree, rib_tree(rib), re)rib_tree_RB_INSERT(rib_tree(rib), re) != NULL((void*)0)) { | |||
| 361 | log_warnx("rib_add: insert failed"); | |||
| 362 | free(re); | |||
| 363 | return (NULL((void*)0)); | |||
| 364 | } | |||
| 365 | ||||
| 366 | ||||
| 367 | rdemem.rib_cnt++; | |||
| 368 | ||||
| 369 | return (re); | |||
| 370 | } | |||
| 371 | ||||
| 372 | void | |||
| 373 | rib_remove(struct rib_entry *re) | |||
| 374 | { | |||
| 375 | if (!rib_empty(re)) | |||
| 376 | fatalx("rib_remove: entry not empty"); | |||
| 377 | ||||
| 378 | if (re_is_locked(re)) | |||
| 379 | /* entry is locked, don't free it. */ | |||
| 380 | return; | |||
| 381 | ||||
| 382 | pt_unref(re->prefix); | |||
| 383 | ||||
| 384 | if (RB_REMOVE(rib_tree, rib_tree(re_rib(re)), re)rib_tree_RB_REMOVE(rib_tree(re_rib(re)), re) == NULL((void*)0)) | |||
| 385 | log_warnx("rib_remove: remove failed."); | |||
| 386 | ||||
| 387 | free(re); | |||
| 388 | rdemem.rib_cnt--; | |||
| 389 | } | |||
| 390 | ||||
| 391 | int | |||
| 392 | rib_empty(struct rib_entry *re) | |||
| 393 | { | |||
| 394 | return LIST_EMPTY(&re->prefix_h)(((&re->prefix_h)->lh_first) == ((void*)0)); | |||
| 395 | } | |||
| 396 | ||||
| 397 | static struct rib_entry * | |||
| 398 | rib_restart(struct rib_context *ctx) | |||
| 399 | { | |||
| 400 | struct rib_entry *re; | |||
| 401 | ||||
| 402 | re = re_unlock(ctx->ctx_re); | |||
| 403 | ||||
| 404 | /* find first non empty element */ | |||
| 405 | while (re && rib_empty(re)) | |||
| 406 | re = RB_NEXT(rib_tree, unused, re)rib_tree_RB_NEXT(re); | |||
| 407 | ||||
| 408 | /* free the previously locked rib element if empty */ | |||
| 409 | if (rib_empty(ctx->ctx_re)) | |||
| 410 | rib_remove(ctx->ctx_re); | |||
| 411 | ctx->ctx_re = NULL((void*)0); | |||
| 412 | return (re); | |||
| 413 | } | |||
| 414 | ||||
| 415 | static void | |||
| 416 | rib_dump_r(struct rib_context *ctx) | |||
| 417 | { | |||
| 418 | struct rib_entry *re, *next; | |||
| 419 | struct rib *rib; | |||
| 420 | unsigned int i; | |||
| 421 | ||||
| 422 | rib = rib_byid(ctx->ctx_id); | |||
| 423 | if (rib == NULL((void*)0)) | |||
| 424 | fatalx("%s: rib id %u gone", __func__, ctx->ctx_id); | |||
| 425 | ||||
| 426 | if (ctx->ctx_re == NULL((void*)0)) | |||
| 427 | re = RB_MIN(rib_tree, rib_tree(rib))rib_tree_RB_MINMAX(rib_tree(rib), -1); | |||
| 428 | else | |||
| 429 | re = rib_restart(ctx); | |||
| 430 | ||||
| 431 | for (i = 0; re != NULL((void*)0); re = next) { | |||
| 432 | next = RB_NEXT(rib_tree, unused, re)rib_tree_RB_NEXT(re); | |||
| 433 | if (re->rib_id != ctx->ctx_id) | |||
| 434 | fatalx("%s: Unexpected RIB %u != %u.", __func__, | |||
| 435 | re->rib_id, ctx->ctx_id); | |||
| 436 | if (ctx->ctx_aid != AID_UNSPEC0 && | |||
| 437 | ctx->ctx_aid != re->prefix->aid) | |||
| 438 | continue; | |||
| 439 | if (ctx->ctx_count && i++ >= ctx->ctx_count && | |||
| 440 | !re_is_locked(re)) { | |||
| 441 | /* store and lock last element */ | |||
| 442 | ctx->ctx_re = re_lock(re); | |||
| 443 | return; | |||
| 444 | } | |||
| 445 | ctx->ctx_rib_call(re, ctx->ctx_arg); | |||
| 446 | } | |||
| 447 | ||||
| 448 | if (ctx->ctx_done) | |||
| 449 | ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); | |||
| 450 | LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void*)0)) (ctx)->entry .le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)-> entry.le_prev = (ctx)->entry.le_next; ; ; } while (0); | |||
| 451 | free(ctx); | |||
| 452 | } | |||
| 453 | ||||
| 454 | int | |||
| 455 | rib_dump_pending(void) | |||
| 456 | { | |||
| 457 | struct rib_context *ctx; | |||
| 458 | ||||
| 459 | /* return true if at least one context is not throttled */ | |||
| 460 | LIST_FOREACH(ctx, &rib_dumps, entry)for((ctx) = ((&rib_dumps)->lh_first); (ctx)!= ((void*) 0); (ctx) = ((ctx)->entry.le_next)) { | |||
| 461 | if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg)) | |||
| 462 | continue; | |||
| 463 | return 1; | |||
| 464 | } | |||
| 465 | return 0; | |||
| 466 | } | |||
| 467 | ||||
| 468 | void | |||
| 469 | rib_dump_runner(void) | |||
| 470 | { | |||
| 471 | struct rib_context *ctx, *next; | |||
| 472 | ||||
| 473 | LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) && ((next) = ((ctx)->entry.le_next), 1); (ctx) = (next)) { | |||
| 474 | if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg)) | |||
| 475 | continue; | |||
| 476 | if (ctx->ctx_rib_call != NULL((void*)0)) | |||
| 477 | rib_dump_r(ctx); | |||
| 478 | else | |||
| 479 | prefix_dump_r(ctx); | |||
| 480 | } | |||
| 481 | } | |||
| 482 | ||||
| 483 | static void | |||
| 484 | rib_dump_abort(u_int16_t id) | |||
| 485 | { | |||
| 486 | struct rib_context *ctx, *next; | |||
| 487 | ||||
| 488 | LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) && ((next) = ((ctx)->entry.le_next), 1); (ctx) = (next)) { | |||
| 489 | if (id != ctx->ctx_id) | |||
| 490 | continue; | |||
| 491 | if (ctx->ctx_done) | |||
| 492 | ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); | |||
| 493 | if (ctx->ctx_re && rib_empty(re_unlock(ctx->ctx_re))) | |||
| 494 | rib_remove(ctx->ctx_re); | |||
| 495 | if (ctx->ctx_p && prefix_is_dead(prefix_unlock(ctx->ctx_p))) | |||
| 496 | prefix_adjout_destroy(ctx->ctx_p); | |||
| 497 | LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void*)0)) (ctx)->entry .le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)-> entry.le_prev = (ctx)->entry.le_next; ; ; } while (0); | |||
| 498 | free(ctx); | |||
| 499 | } | |||
| 500 | } | |||
| 501 | ||||
| 502 | void | |||
| 503 | rib_dump_terminate(void *arg) | |||
| 504 | { | |||
| 505 | struct rib_context *ctx, *next; | |||
| 506 | ||||
| 507 | LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) && ((next) = ((ctx)->entry.le_next), 1); (ctx) = (next)) { | |||
| 508 | if (ctx->ctx_arg != arg) | |||
| 509 | continue; | |||
| 510 | if (ctx->ctx_done) | |||
| 511 | ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); | |||
| 512 | if (ctx->ctx_re && rib_empty(re_unlock(ctx->ctx_re))) | |||
| 513 | rib_remove(ctx->ctx_re); | |||
| 514 | if (ctx->ctx_p && prefix_is_dead(prefix_unlock(ctx->ctx_p))) | |||
| 515 | prefix_adjout_destroy(ctx->ctx_p); | |||
| 516 | LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void*)0)) (ctx)->entry .le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)-> entry.le_prev = (ctx)->entry.le_next; ; ; } while (0); | |||
| 517 | free(ctx); | |||
| 518 | } | |||
| 519 | } | |||
| 520 | ||||
| 521 | int | |||
| 522 | rib_dump_new(u_int16_t id, u_int8_t aid, unsigned int count, void *arg, | |||
| 523 | void (*upcall)(struct rib_entry *, void *), void (*done)(void *, u_int8_t), | |||
| 524 | int (*throttle)(void *)) | |||
| 525 | { | |||
| 526 | struct rib_context *ctx; | |||
| 527 | ||||
| 528 | if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void*)0)) | |||
| 529 | return -1; | |||
| 530 | ctx->ctx_id = id; | |||
| 531 | ctx->ctx_aid = aid; | |||
| 532 | ctx->ctx_count = count; | |||
| 533 | ctx->ctx_arg = arg; | |||
| 534 | ctx->ctx_rib_call = upcall; | |||
| 535 | ctx->ctx_done = done; | |||
| 536 | ctx->ctx_throttle = throttle; | |||
| 537 | ||||
| 538 | LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first ) != ((void*)0)) (&rib_dumps)->lh_first->entry.le_prev = &(ctx)->entry.le_next; (&rib_dumps)->lh_first = (ctx); (ctx)->entry.le_prev = &(&rib_dumps)-> lh_first; } while (0); | |||
| 539 | ||||
| 540 | /* requested a sync traversal */ | |||
| 541 | if (count == 0) | |||
| 542 | rib_dump_r(ctx); | |||
| 543 | ||||
| 544 | return 0; | |||
| 545 | } | |||
| 546 | ||||
| 547 | /* path specific functions */ | |||
| 548 | ||||
| 549 | static struct rde_aspath *path_lookup(struct rde_aspath *); | |||
| 550 | static u_int64_t path_hash(struct rde_aspath *); | |||
| 551 | static void path_link(struct rde_aspath *); | |||
| 552 | static void path_unlink(struct rde_aspath *); | |||
| 553 | ||||
| 554 | struct path_table { | |||
| 555 | struct aspath_head *path_hashtbl; | |||
| 556 | u_int64_t path_hashmask; | |||
| 557 | } pathtable; | |||
| 558 | ||||
| 559 | SIPHASH_KEY pathtablekey; | |||
| 560 | ||||
| 561 | #define PATH_HASH(x)&pathtable.path_hashtbl[x & pathtable.path_hashmask] &pathtable.path_hashtbl[x & pathtable.path_hashmask] | |||
| 562 | ||||
| 563 | static inline struct rde_aspath * | |||
| 564 | path_ref(struct rde_aspath *asp) | |||
| 565 | { | |||
| 566 | if ((asp->flags & F_ATTR_LINKED0x20000) == 0) | |||
| 567 | fatalx("%s: unlinked object", __func__); | |||
| 568 | asp->refcnt++; | |||
| 569 | rdemem.path_refs++; | |||
| 570 | ||||
| 571 | return asp; | |||
| 572 | } | |||
| 573 | ||||
| 574 | static inline void | |||
| 575 | path_unref(struct rde_aspath *asp) | |||
| 576 | { | |||
| 577 | if (asp == NULL((void*)0)) | |||
| 578 | return; | |||
| 579 | if ((asp->flags & F_ATTR_LINKED0x20000) == 0) | |||
| 580 | fatalx("%s: unlinked object", __func__); | |||
| 581 | asp->refcnt--; | |||
| 582 | rdemem.path_refs--; | |||
| 583 | if (asp->refcnt <= 0) | |||
| 584 | path_unlink(asp); | |||
| 585 | } | |||
| 586 | ||||
| 587 | void | |||
| 588 | path_init(u_int32_t hashsize) | |||
| 589 | { | |||
| 590 | u_int32_t hs, i; | |||
| 591 | ||||
| 592 | for (hs = 1; hs < hashsize; hs <<= 1) | |||
| 593 | ; | |||
| 594 | pathtable.path_hashtbl = calloc(hs, sizeof(*pathtable.path_hashtbl)); | |||
| 595 | if (pathtable.path_hashtbl == NULL((void*)0)) | |||
| 596 | fatal("path_init"); | |||
| 597 | ||||
| 598 | for (i = 0; i < hs; i++) | |||
| 599 | LIST_INIT(&pathtable.path_hashtbl[i])do { ((&pathtable.path_hashtbl[i])->lh_first) = ((void *)0); } while (0); | |||
| 600 | ||||
| 601 | pathtable.path_hashmask = hs - 1; | |||
| 602 | arc4random_buf(&pathtablekey, sizeof(pathtablekey)); | |||
| 603 | } | |||
| 604 | ||||
| 605 | void | |||
| 606 | path_shutdown(void) | |||
| 607 | { | |||
| 608 | u_int32_t i; | |||
| 609 | ||||
| 610 | for (i = 0; i <= pathtable.path_hashmask; i++) | |||
| 611 | if (!LIST_EMPTY(&pathtable.path_hashtbl[i])(((&pathtable.path_hashtbl[i])->lh_first) == ((void*)0 ))) | |||
| 612 | log_warnx("path_free: free non-free table"); | |||
| 613 | ||||
| 614 | free(pathtable.path_hashtbl); | |||
| 615 | } | |||
| 616 | ||||
| 617 | void | |||
| 618 | path_hash_stats(struct rde_hashstats *hs) | |||
| 619 | { | |||
| 620 | struct rde_aspath *a; | |||
| 621 | u_int32_t i; | |||
| 622 | int64_t n; | |||
| 623 | ||||
| 624 | memset(hs, 0, sizeof(*hs)); | |||
| 625 | strlcpy(hs->name, "path hash", sizeof(hs->name)); | |||
| 626 | hs->min = LLONG_MAX9223372036854775807LL; | |||
| 627 | hs->num = pathtable.path_hashmask + 1; | |||
| 628 | ||||
| 629 | for (i = 0; i <= pathtable.path_hashmask; i++) { | |||
| 630 | n = 0; | |||
| 631 | LIST_FOREACH(a, &pathtable.path_hashtbl[i], path_l)for((a) = ((&pathtable.path_hashtbl[i])->lh_first); (a )!= ((void*)0); (a) = ((a)->path_l.le_next)) | |||
| 632 | n++; | |||
| 633 | if (n < hs->min) | |||
| 634 | hs->min = n; | |||
| 635 | if (n > hs->max) | |||
| 636 | hs->max = n; | |||
| 637 | hs->sum += n; | |||
| 638 | hs->sumq += n * n; | |||
| 639 | } | |||
| 640 | } | |||
| 641 | ||||
| 642 | int | |||
| 643 | path_compare(struct rde_aspath *a, struct rde_aspath *b) | |||
| 644 | { | |||
| 645 | int r; | |||
| 646 | ||||
| 647 | if (a == NULL((void*)0) && b == NULL((void*)0)) | |||
| 648 | return (0); | |||
| 649 | else if (b == NULL((void*)0)) | |||
| 650 | return (1); | |||
| 651 | else if (a == NULL((void*)0)) | |||
| 652 | return (-1); | |||
| 653 | if ((a->flags & ~F_ATTR_LINKED0x20000) > (b->flags & ~F_ATTR_LINKED0x20000)) | |||
| 654 | return (1); | |||
| 655 | if ((a->flags & ~F_ATTR_LINKED0x20000) < (b->flags & ~F_ATTR_LINKED0x20000)) | |||
| 656 | return (-1); | |||
| 657 | if (a->origin > b->origin) | |||
| 658 | return (1); | |||
| 659 | if (a->origin < b->origin) | |||
| 660 | return (-1); | |||
| 661 | if (a->med > b->med) | |||
| 662 | return (1); | |||
| 663 | if (a->med < b->med) | |||
| 664 | return (-1); | |||
| 665 | if (a->lpref > b->lpref) | |||
| 666 | return (1); | |||
| 667 | if (a->lpref < b->lpref) | |||
| 668 | return (-1); | |||
| 669 | if (a->weight > b->weight) | |||
| 670 | return (1); | |||
| 671 | if (a->weight < b->weight) | |||
| 672 | return (-1); | |||
| 673 | if (a->rtlabelid > b->rtlabelid) | |||
| 674 | return (1); | |||
| 675 | if (a->rtlabelid < b->rtlabelid) | |||
| 676 | return (-1); | |||
| 677 | if (a->pftableid > b->pftableid) | |||
| 678 | return (1); | |||
| 679 | if (a->pftableid < b->pftableid) | |||
| 680 | return (-1); | |||
| 681 | ||||
| 682 | r = aspath_compare(a->aspath, b->aspath); | |||
| 683 | if (r > 0) | |||
| 684 | return (1); | |||
| 685 | if (r < 0) | |||
| 686 | return (-1); | |||
| 687 | ||||
| 688 | return (attr_compare(a, b)); | |||
| 689 | } | |||
| 690 | ||||
| 691 | static u_int64_t | |||
| 692 | path_hash(struct rde_aspath *asp) | |||
| 693 | { | |||
| 694 | SIPHASH_CTX ctx; | |||
| 695 | u_int64_t hash; | |||
| 696 | ||||
| 697 | SipHash24_Init(&ctx, &pathtablekey)SipHash_Init((&ctx), (&pathtablekey)); | |||
| 698 | SipHash24_Update(&ctx, &asp->aspath_hashstart,SipHash_Update((&ctx), 2, 4, (&asp->med), ((char * )&asp->others_len - (char *)&asp->med)) | |||
| 699 | (char *)&asp->aspath_hashend - (char *)&asp->aspath_hashstart)SipHash_Update((&ctx), 2, 4, (&asp->med), ((char * )&asp->others_len - (char *)&asp->med)); | |||
| 700 | ||||
| 701 | if (asp->aspath) | |||
| 702 | SipHash24_Update(&ctx, asp->aspath->data, asp->aspath->len)SipHash_Update((&ctx), 2, 4, (asp->aspath->data), ( asp->aspath->len)); | |||
| 703 | ||||
| 704 | hash = attr_hash(asp); | |||
| 705 | SipHash24_Update(&ctx, &hash, sizeof(hash))SipHash_Update((&ctx), 2, 4, (&hash), (sizeof(hash))); | |||
| 706 | ||||
| 707 | return (SipHash24_End(&ctx)SipHash_End((&ctx), 2, 4)); | |||
| 708 | } | |||
| 709 | ||||
| 710 | static struct rde_aspath * | |||
| 711 | path_lookup(struct rde_aspath *aspath) | |||
| 712 | { | |||
| 713 | struct aspath_head *head; | |||
| 714 | struct rde_aspath *asp; | |||
| 715 | u_int64_t hash; | |||
| 716 | ||||
| 717 | hash = path_hash(aspath); | |||
| 718 | head = PATH_HASH(hash)&pathtable.path_hashtbl[hash & pathtable.path_hashmask ]; | |||
| 719 | ||||
| 720 | LIST_FOREACH(asp, head, path_l)for((asp) = ((head)->lh_first); (asp)!= ((void*)0); (asp) = ((asp)->path_l.le_next)) { | |||
| 721 | if (asp->hash == hash && path_compare(aspath, asp) == 0) | |||
| 722 | return (asp); | |||
| 723 | } | |||
| 724 | return (NULL((void*)0)); | |||
| 725 | } | |||
| 726 | ||||
| 727 | /* | |||
| 728 | * Link this aspath into the global hash table. | |||
| 729 | * The asp had to be alloced with path_get. | |||
| 730 | */ | |||
| 731 | static void | |||
| 732 | path_link(struct rde_aspath *asp) | |||
| 733 | { | |||
| 734 | struct aspath_head *head; | |||
| 735 | ||||
| 736 | asp->hash = path_hash(asp); | |||
| 737 | head = PATH_HASH(asp->hash)&pathtable.path_hashtbl[asp->hash & pathtable.path_hashmask ]; | |||
| 738 | ||||
| 739 | LIST_INSERT_HEAD(head, asp, path_l)do { if (((asp)->path_l.le_next = (head)->lh_first) != ( (void*)0)) (head)->lh_first->path_l.le_prev = &(asp )->path_l.le_next; (head)->lh_first = (asp); (asp)-> path_l.le_prev = &(head)->lh_first; } while (0); | |||
| 740 | asp->flags |= F_ATTR_LINKED0x20000; | |||
| 741 | } | |||
| 742 | ||||
| 743 | /* | |||
| 744 | * This function can only be called when all prefix have been removed first. | |||
| 745 | * Normally this happens directly out of the prefix removal functions. | |||
| 746 | */ | |||
| 747 | static void | |||
| 748 | path_unlink(struct rde_aspath *asp) | |||
| 749 | { | |||
| 750 | if (asp == NULL((void*)0)) | |||
| 751 | return; | |||
| 752 | ||||
| 753 | /* make sure no reference is hold for this rde_aspath */ | |||
| 754 | if (asp->refcnt != 0) | |||
| 755 | fatalx("%s: still holds references", __func__); | |||
| 756 | ||||
| 757 | LIST_REMOVE(asp, path_l)do { if ((asp)->path_l.le_next != ((void*)0)) (asp)->path_l .le_next->path_l.le_prev = (asp)->path_l.le_prev; *(asp )->path_l.le_prev = (asp)->path_l.le_next; ; ; } while ( 0); | |||
| 758 | asp->flags &= ~F_ATTR_LINKED0x20000; | |||
| 759 | ||||
| 760 | path_put(asp); | |||
| 761 | } | |||
| 762 | ||||
| 763 | /* | |||
| 764 | * Copy asp to a new UNLINKED aspath. | |||
| 765 | * On dst either path_get() or path_prep() had to be called before. | |||
| 766 | */ | |||
| 767 | struct rde_aspath * | |||
| 768 | path_copy(struct rde_aspath *dst, const struct rde_aspath *src) | |||
| 769 | { | |||
| 770 | dst->aspath = src->aspath; | |||
| 771 | if (dst->aspath != NULL((void*)0)) { | |||
| 772 | dst->aspath->refcnt++; | |||
| 773 | rdemem.aspath_refs++; | |||
| 774 | } | |||
| 775 | dst->hash = 0; /* not linked so no hash and no refcnt */ | |||
| 776 | dst->refcnt = 0; | |||
| 777 | dst->flags = src->flags & ~F_ATTR_LINKED0x20000; | |||
| 778 | ||||
| 779 | dst->med = src->med; | |||
| 780 | dst->lpref = src->lpref; | |||
| 781 | dst->weight = src->weight; | |||
| 782 | dst->rtlabelid = rtlabel_ref(src->rtlabelid); | |||
| 783 | dst->pftableid = pftable_ref(src->pftableid); | |||
| 784 | dst->origin = src->origin; | |||
| 785 | ||||
| 786 | attr_copy(dst, src); | |||
| 787 | ||||
| 788 | return (dst); | |||
| 789 | } | |||
| 790 | ||||
| 791 | /* initialize or pepare an aspath for use */ | |||
| 792 | struct rde_aspath * | |||
| 793 | path_prep(struct rde_aspath *asp) | |||
| 794 | { | |||
| 795 | memset(asp, 0, sizeof(*asp)); | |||
| 796 | asp->origin = ORIGIN_INCOMPLETE2; | |||
| 797 | asp->lpref = DEFAULT_LPREF100; | |||
| 798 | ||||
| 799 | return (asp); | |||
| 800 | } | |||
| 801 | ||||
| 802 | /* alloc and initialize new entry. May not fail. */ | |||
| 803 | struct rde_aspath * | |||
| 804 | path_get(void) | |||
| 805 | { | |||
| 806 | struct rde_aspath *asp; | |||
| 807 | ||||
| 808 | asp = malloc(sizeof(*asp)); | |||
| 809 | if (asp == NULL((void*)0)) | |||
| 810 | fatal("path_get"); | |||
| 811 | rdemem.path_cnt++; | |||
| 812 | ||||
| 813 | return (path_prep(asp)); | |||
| 814 | } | |||
| 815 | ||||
| 816 | /* clean up an asp after use (frees all references to sub-objects) */ | |||
| 817 | void | |||
| 818 | path_clean(struct rde_aspath *asp) | |||
| 819 | { | |||
| 820 | if (asp->flags & F_ATTR_LINKED0x20000) | |||
| 821 | fatalx("%s: linked object", __func__); | |||
| 822 | ||||
| 823 | rtlabel_unref(asp->rtlabelid); | |||
| 824 | pftable_unref(asp->pftableid); | |||
| 825 | aspath_put(asp->aspath); | |||
| 826 | attr_freeall(asp); | |||
| 827 | } | |||
| 828 | ||||
| 829 | /* free an unlinked element */ | |||
| 830 | void | |||
| 831 | path_put(struct rde_aspath *asp) | |||
| 832 | { | |||
| 833 | if (asp == NULL((void*)0)) | |||
| 834 | return; | |||
| 835 | ||||
| 836 | path_clean(asp); | |||
| 837 | ||||
| 838 | rdemem.path_cnt--; | |||
| 839 | free(asp); | |||
| 840 | } | |||
| 841 | ||||
| 842 | /* prefix specific functions */ | |||
| 843 | ||||
| 844 | static int prefix_add(struct bgpd_addr *, int, struct rib *, | |||
| 845 | struct rde_peer *, u_int32_t, struct rde_aspath *, | |||
| 846 | struct rde_community *, struct nexthop *, | |||
| 847 | u_int8_t, u_int8_t); | |||
| 848 | static int prefix_move(struct prefix *, struct rde_peer *, | |||
| 849 | struct rde_aspath *, struct rde_community *, | |||
| 850 | struct nexthop *, u_int8_t, u_int8_t); | |||
| 851 | ||||
| 852 | static void prefix_link(struct prefix *, struct rib_entry *, | |||
| 853 | struct rde_peer *, u_int32_t, struct rde_aspath *, | |||
| 854 | struct rde_community *, struct nexthop *, | |||
| 855 | u_int8_t, u_int8_t); | |||
| 856 | static void prefix_unlink(struct prefix *); | |||
| 857 | ||||
| 858 | static struct prefix *prefix_alloc(void); | |||
| 859 | static void prefix_free(struct prefix *); | |||
| 860 | ||||
| 861 | /* RB tree comparison function */ | |||
| 862 | static inline int | |||
| 863 | prefix_cmp(struct prefix *a, struct prefix *b) | |||
| 864 | { | |||
| 865 | if (a->eor != b->eor) | |||
| 866 | return a->eor - b->eor; | |||
| 867 | /* if EOR marker no need to check the rest also a->eor == b->eor */ | |||
| 868 | if (a->eor) | |||
| 869 | return 0; | |||
| 870 | ||||
| 871 | if (a->aspath != b->aspath) | |||
| 872 | return (a->aspath > b->aspath ? 1 : -1); | |||
| 873 | if (a->communities != b->communities) | |||
| 874 | return (a->communities > b->communities ? 1 : -1); | |||
| 875 | if (a->nexthop != b->nexthop) | |||
| 876 | return (a->nexthop > b->nexthop ? 1 : -1); | |||
| 877 | if (a->nhflags != b->nhflags) | |||
| 878 | return (a->nhflags > b->nhflags ? 1 : -1); | |||
| 879 | /* XXX path_id ??? */ | |||
| 880 | return pt_prefix_cmp(a->pt, b->pt); | |||
| 881 | } | |||
| 882 | ||||
| 883 | static inline int | |||
| 884 | prefix_index_cmp(struct prefix *a, struct prefix *b) | |||
| 885 | { | |||
| 886 | /* XXX path_id ??? */ | |||
| 887 | return pt_prefix_cmp(a->pt, b->pt); | |||
| 888 | } | |||
| 889 | ||||
| 890 | RB_GENERATE(prefix_tree, prefix, entry.tree.update, prefix_cmp)void prefix_tree_RB_INSERT_COLOR(struct prefix_tree *head, struct prefix *elm) { struct prefix *parent, *gparent, *tmp; while ( (parent = (elm)->entry.tree.update.rbe_parent) && ( parent)->entry.tree.update.rbe_color == 1) { gparent = (parent )->entry.tree.update.rbe_parent; if (parent == (gparent)-> entry.tree.update.rbe_left) { tmp = (gparent)->entry.tree. update.rbe_right; if (tmp && (tmp)->entry.tree.update .rbe_color == 1) { (tmp)->entry.tree.update.rbe_color = 0; do { (parent)->entry.tree.update.rbe_color = 0; (gparent) ->entry.tree.update.rbe_color = 1; } while (0); elm = gparent ; continue; } if ((parent)->entry.tree.update.rbe_right == elm) { do { (tmp) = (parent)->entry.tree.update.rbe_right ; if (((parent)->entry.tree.update.rbe_right = (tmp)->entry .tree.update.rbe_left)) { ((tmp)->entry.tree.update.rbe_left )->entry.tree.update.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.update.rbe_parent = (parent)-> entry.tree.update.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.update.rbe_parent)->entry.tree.update.rbe_left) ((parent)->entry.tree.update.rbe_parent)->entry.tree.update .rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent )->entry.tree.update.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (parent ); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.tree.update.rbe_color = 0; (gparent)-> entry.tree.update.rbe_color = 1; } while (0); do { (tmp) = (gparent )->entry.tree.update.rbe_left; if (((gparent)->entry.tree .update.rbe_left = (tmp)->entry.tree.update.rbe_right)) { ( (tmp)->entry.tree.update.rbe_right)->entry.tree.update. rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry .tree.update.rbe_parent = (gparent)->entry.tree.update.rbe_parent )) { if ((gparent) == ((gparent)->entry.tree.update.rbe_parent )->entry.tree.update.rbe_left) ((gparent)->entry.tree.update .rbe_parent)->entry.tree.update.rbe_left = (tmp); else ((gparent )->entry.tree.update.rbe_parent)->entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .tree.update.rbe_right = (gparent); (gparent)->entry.tree. update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry .tree.update.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->entry.tree.update.rbe_left; if (tmp && (tmp)->entry.tree.update.rbe_color == 1) { (tmp)->entry .tree.update.rbe_color = 0; do { (parent)->entry.tree.update .rbe_color = 0; (gparent)->entry.tree.update.rbe_color = 1 ; } while (0); elm = gparent; continue; } if ((parent)->entry .tree.update.rbe_left == elm) { do { (tmp) = (parent)->entry .tree.update.rbe_left; if (((parent)->entry.tree.update.rbe_left = (tmp)->entry.tree.update.rbe_right)) { ((tmp)->entry .tree.update.rbe_right)->entry.tree.update.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.tree.update.rbe_parent = (parent)->entry.tree.update.rbe_parent)) { if ((parent) == ((parent)->entry.tree.update.rbe_parent)->entry.tree .update.rbe_left) ((parent)->entry.tree.update.rbe_parent) ->entry.tree.update.rbe_left = (tmp); else ((parent)->entry .tree.update.rbe_parent)->entry.tree.update.rbe_right = (tmp ); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.update .rbe_right = (parent); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.tree.update.rbe_color = 0; ( gparent)->entry.tree.update.rbe_color = 1; } while (0); do { (tmp) = (gparent)->entry.tree.update.rbe_right; if (((gparent )->entry.tree.update.rbe_right = (tmp)->entry.tree.update .rbe_left)) { ((tmp)->entry.tree.update.rbe_left)->entry .tree.update.rbe_parent = (gparent); } do {} while (0); if (( (tmp)->entry.tree.update.rbe_parent = (gparent)->entry. tree.update.rbe_parent)) { if ((gparent) == ((gparent)->entry .tree.update.rbe_parent)->entry.tree.update.rbe_left) ((gparent )->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left = (tmp); else ((gparent)->entry.tree.update.rbe_parent)-> entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (gparent); ( gparent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->entry.tree.update .rbe_color = 0; } void prefix_tree_RB_REMOVE_COLOR(struct prefix_tree *head, struct prefix *parent, struct prefix *elm) { struct prefix *tmp; while ((elm == ((void*)0) || (elm)->entry.tree.update .rbe_color == 0) && elm != (head)->rbh_root) { if ( (parent)->entry.tree.update.rbe_left == elm) { tmp = (parent )->entry.tree.update.rbe_right; if ((tmp)->entry.tree.update .rbe_color == 1) { do { (tmp)->entry.tree.update.rbe_color = 0; (parent)->entry.tree.update.rbe_color = 1; } while ( 0); do { (tmp) = (parent)->entry.tree.update.rbe_right; if (((parent)->entry.tree.update.rbe_right = (tmp)->entry .tree.update.rbe_left)) { ((tmp)->entry.tree.update.rbe_left )->entry.tree.update.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.update.rbe_parent = (parent)-> entry.tree.update.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.update.rbe_parent)->entry.tree.update.rbe_left) ((parent)->entry.tree.update.rbe_parent)->entry.tree.update .rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent )->entry.tree.update.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (parent ); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.update.rbe_right ; } if (((tmp)->entry.tree.update.rbe_left == ((void*)0) || ((tmp)->entry.tree.update.rbe_left)->entry.tree.update .rbe_color == 0) && ((tmp)->entry.tree.update.rbe_right == ((void*)0) || ((tmp)->entry.tree.update.rbe_right)-> entry.tree.update.rbe_color == 0)) { (tmp)->entry.tree.update .rbe_color = 1; elm = parent; parent = (elm)->entry.tree.update .rbe_parent; } else { if ((tmp)->entry.tree.update.rbe_right == ((void*)0) || ((tmp)->entry.tree.update.rbe_right)-> entry.tree.update.rbe_color == 0) { struct prefix *oleft; if ( (oleft = (tmp)->entry.tree.update.rbe_left)) (oleft)->entry .tree.update.rbe_color = 0; (tmp)->entry.tree.update.rbe_color = 1; do { (oleft) = (tmp)->entry.tree.update.rbe_left; if (((tmp)->entry.tree.update.rbe_left = (oleft)->entry.tree .update.rbe_right)) { ((oleft)->entry.tree.update.rbe_right )->entry.tree.update.rbe_parent = (tmp); } do {} while (0) ; if (((oleft)->entry.tree.update.rbe_parent = (tmp)->entry .tree.update.rbe_parent)) { if ((tmp) == ((tmp)->entry.tree .update.rbe_parent)->entry.tree.update.rbe_left) ((tmp)-> entry.tree.update.rbe_parent)->entry.tree.update.rbe_left = (oleft); else ((tmp)->entry.tree.update.rbe_parent)->entry .tree.update.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->entry.tree.update.rbe_right = (tmp); (tmp )->entry.tree.update.rbe_parent = (oleft); do {} while (0) ; if (((oleft)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.update.rbe_right ; } (tmp)->entry.tree.update.rbe_color = (parent)->entry .tree.update.rbe_color; (parent)->entry.tree.update.rbe_color = 0; if ((tmp)->entry.tree.update.rbe_right) ((tmp)->entry .tree.update.rbe_right)->entry.tree.update.rbe_color = 0; do { (tmp) = (parent)->entry.tree.update.rbe_right; if (((parent )->entry.tree.update.rbe_right = (tmp)->entry.tree.update .rbe_left)) { ((tmp)->entry.tree.update.rbe_left)->entry .tree.update.rbe_parent = (parent); } do {} while (0); if ((( tmp)->entry.tree.update.rbe_parent = (parent)->entry.tree .update.rbe_parent)) { if ((parent) == ((parent)->entry.tree .update.rbe_parent)->entry.tree.update.rbe_left) ((parent) ->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent)-> entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (parent); (parent )->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent)->entry.tree.update.rbe_left; if ((tmp)->entry .tree.update.rbe_color == 1) { do { (tmp)->entry.tree.update .rbe_color = 0; (parent)->entry.tree.update.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.tree.update.rbe_left ; if (((parent)->entry.tree.update.rbe_left = (tmp)->entry .tree.update.rbe_right)) { ((tmp)->entry.tree.update.rbe_right )->entry.tree.update.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.update.rbe_parent = (parent)-> entry.tree.update.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.update.rbe_parent)->entry.tree.update.rbe_left) ((parent)->entry.tree.update.rbe_parent)->entry.tree.update .rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent )->entry.tree.update.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.tree.update.rbe_right = (parent ); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.update.rbe_left ; } if (((tmp)->entry.tree.update.rbe_left == ((void*)0) || ((tmp)->entry.tree.update.rbe_left)->entry.tree.update .rbe_color == 0) && ((tmp)->entry.tree.update.rbe_right == ((void*)0) || ((tmp)->entry.tree.update.rbe_right)-> entry.tree.update.rbe_color == 0)) { (tmp)->entry.tree.update .rbe_color = 1; elm = parent; parent = (elm)->entry.tree.update .rbe_parent; } else { if ((tmp)->entry.tree.update.rbe_left == ((void*)0) || ((tmp)->entry.tree.update.rbe_left)-> entry.tree.update.rbe_color == 0) { struct prefix *oright; if ((oright = (tmp)->entry.tree.update.rbe_right)) (oright)-> entry.tree.update.rbe_color = 0; (tmp)->entry.tree.update. rbe_color = 1; do { (oright) = (tmp)->entry.tree.update.rbe_right ; if (((tmp)->entry.tree.update.rbe_right = (oright)->entry .tree.update.rbe_left)) { ((oright)->entry.tree.update.rbe_left )->entry.tree.update.rbe_parent = (tmp); } do {} while (0) ; if (((oright)->entry.tree.update.rbe_parent = (tmp)-> entry.tree.update.rbe_parent)) { if ((tmp) == ((tmp)->entry .tree.update.rbe_parent)->entry.tree.update.rbe_left) ((tmp )->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left = (oright); else ((tmp)->entry.tree.update.rbe_parent)-> entry.tree.update.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->entry.tree.update.rbe_left = (tmp); (tmp)->entry.tree.update.rbe_parent = (oright); do {} while (0); if (((oright)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.update.rbe_left ; } (tmp)->entry.tree.update.rbe_color = (parent)->entry .tree.update.rbe_color; (parent)->entry.tree.update.rbe_color = 0; if ((tmp)->entry.tree.update.rbe_left) ((tmp)->entry .tree.update.rbe_left)->entry.tree.update.rbe_color = 0; do { (tmp) = (parent)->entry.tree.update.rbe_left; if (((parent )->entry.tree.update.rbe_left = (tmp)->entry.tree.update .rbe_right)) { ((tmp)->entry.tree.update.rbe_right)->entry .tree.update.rbe_parent = (parent); } do {} while (0); if ((( tmp)->entry.tree.update.rbe_parent = (parent)->entry.tree .update.rbe_parent)) { if ((parent) == ((parent)->entry.tree .update.rbe_parent)->entry.tree.update.rbe_left) ((parent) ->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent)-> entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.update.rbe_right = (parent); ( parent)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry.tree.update.rbe_color = 0; } struct prefix * prefix_tree_RB_REMOVE(struct prefix_tree *head, struct prefix *elm) { struct prefix *child, *parent, *old = elm; int color ; if ((elm)->entry.tree.update.rbe_left == ((void*)0)) child = (elm)->entry.tree.update.rbe_right; else if ((elm)-> entry.tree.update.rbe_right == ((void*)0)) child = (elm)-> entry.tree.update.rbe_left; else { struct prefix *left; elm = (elm)->entry.tree.update.rbe_right; while ((left = (elm)-> entry.tree.update.rbe_left)) elm = left; child = (elm)->entry .tree.update.rbe_right; parent = (elm)->entry.tree.update. rbe_parent; color = (elm)->entry.tree.update.rbe_color; if (child) (child)->entry.tree.update.rbe_parent = parent; if (parent) { if ((parent)->entry.tree.update.rbe_left == elm ) (parent)->entry.tree.update.rbe_left = child; else (parent )->entry.tree.update.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->entry.tree.update .rbe_parent == old) parent = elm; (elm)->entry.tree.update = (old)->entry.tree.update; if ((old)->entry.tree.update .rbe_parent) { if (((old)->entry.tree.update.rbe_parent)-> entry.tree.update.rbe_left == old) ((old)->entry.tree.update .rbe_parent)->entry.tree.update.rbe_left = elm; else ((old )->entry.tree.update.rbe_parent)->entry.tree.update.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; (( old)->entry.tree.update.rbe_left)->entry.tree.update.rbe_parent = elm; if ((old)->entry.tree.update.rbe_right) ((old)-> entry.tree.update.rbe_right)->entry.tree.update.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)->entry.tree.update.rbe_parent)); } goto color ; } parent = (elm)->entry.tree.update.rbe_parent; color = ( elm)->entry.tree.update.rbe_color; if (child) (child)-> entry.tree.update.rbe_parent = parent; if (parent) { if ((parent )->entry.tree.update.rbe_left == elm) (parent)->entry.tree .update.rbe_left = child; else (parent)->entry.tree.update .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) prefix_tree_RB_REMOVE_COLOR( head, parent, child); return (old); } struct prefix * prefix_tree_RB_INSERT (struct prefix_tree *head, struct prefix *elm) { struct prefix *tmp; struct prefix *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (prefix_cmp )(elm, parent); if (comp < 0) tmp = (tmp)->entry.tree.update .rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.update .rbe_right; else return (tmp); } do { (elm)->entry.tree.update .rbe_parent = parent; (elm)->entry.tree.update.rbe_left = ( elm)->entry.tree.update.rbe_right = ((void*)0); (elm)-> entry.tree.update.rbe_color = 1; } while (0); if (parent != ( (void*)0)) { if (comp < 0) (parent)->entry.tree.update. rbe_left = elm; else (parent)->entry.tree.update.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; prefix_tree_RB_INSERT_COLOR (head, elm); return (((void*)0)); } struct prefix * prefix_tree_RB_FIND (struct prefix_tree *head, struct prefix *elm) { struct prefix *tmp = (head)->rbh_root; int comp; while (tmp) { comp = prefix_cmp (elm, tmp); if (comp < 0) tmp = (tmp)->entry.tree.update .rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.update .rbe_right; else return (tmp); } return (((void*)0)); } struct prefix * prefix_tree_RB_NFIND(struct prefix_tree *head, struct prefix *elm) { struct prefix *tmp = (head)->rbh_root; struct prefix *res = ((void*)0); int comp; while (tmp) { comp = prefix_cmp (elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry .tree.update.rbe_left; } else if (comp > 0) tmp = (tmp)-> entry.tree.update.rbe_right; else return (tmp); } return (res ); } struct prefix * prefix_tree_RB_NEXT(struct prefix *elm) { if ((elm)->entry.tree.update.rbe_right) { elm = (elm)-> entry.tree.update.rbe_right; while ((elm)->entry.tree.update .rbe_left) elm = (elm)->entry.tree.update.rbe_left; } else { if ((elm)->entry.tree.update.rbe_parent && (elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree.update .rbe_left)) elm = (elm)->entry.tree.update.rbe_parent; else { while ((elm)->entry.tree.update.rbe_parent && ( elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree .update.rbe_right)) elm = (elm)->entry.tree.update.rbe_parent ; elm = (elm)->entry.tree.update.rbe_parent; } } return (elm ); } struct prefix * prefix_tree_RB_PREV(struct prefix *elm) { if ((elm)->entry.tree.update.rbe_left) { elm = (elm)-> entry.tree.update.rbe_left; while ((elm)->entry.tree.update .rbe_right) elm = (elm)->entry.tree.update.rbe_right; } else { if ((elm)->entry.tree.update.rbe_parent && (elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree.update .rbe_right)) elm = (elm)->entry.tree.update.rbe_parent; else { while ((elm)->entry.tree.update.rbe_parent && ( elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree .update.rbe_left)) elm = (elm)->entry.tree.update.rbe_parent ; elm = (elm)->entry.tree.update.rbe_parent; } } return (elm ); } struct prefix * prefix_tree_RB_MINMAX(struct prefix_tree *head, int val) { struct prefix *tmp = (head)->rbh_root; struct prefix *parent = ((void*)0); while (tmp) { parent = tmp; if ( val < 0) tmp = (tmp)->entry.tree.update.rbe_left; else tmp = (tmp)->entry.tree.update.rbe_right; } return (parent); } | |||
| 891 | RB_GENERATE_STATIC(prefix_index, prefix, entry.tree.index, prefix_index_cmp)__attribute__((__unused__)) static void prefix_index_RB_INSERT_COLOR (struct prefix_index *head, struct prefix *elm) { struct prefix *parent, *gparent, *tmp; while ((parent = (elm)->entry.tree .index.rbe_parent) && (parent)->entry.tree.index.rbe_color == 1) { gparent = (parent)->entry.tree.index.rbe_parent; if (parent == (gparent)->entry.tree.index.rbe_left) { tmp = ( gparent)->entry.tree.index.rbe_right; if (tmp && ( tmp)->entry.tree.index.rbe_color == 1) { (tmp)->entry.tree .index.rbe_color = 0; do { (parent)->entry.tree.index.rbe_color = 0; (gparent)->entry.tree.index.rbe_color = 1; } while ( 0); elm = gparent; continue; } if ((parent)->entry.tree.index .rbe_right == elm) { do { (tmp) = (parent)->entry.tree.index .rbe_right; if (((parent)->entry.tree.index.rbe_right = (tmp )->entry.tree.index.rbe_left)) { ((tmp)->entry.tree.index .rbe_left)->entry.tree.index.rbe_parent = (parent); } do { } while (0); if (((tmp)->entry.tree.index.rbe_parent = (parent )->entry.tree.index.rbe_parent)) { if ((parent) == ((parent )->entry.tree.index.rbe_parent)->entry.tree.index.rbe_left ) ((parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent )->entry.tree.index.rbe_color = 0; (gparent)->entry.tree .index.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.tree.index.rbe_left; if (((gparent)->entry.tree.index .rbe_left = (tmp)->entry.tree.index.rbe_right)) { ((tmp)-> entry.tree.index.rbe_right)->entry.tree.index.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.tree.index .rbe_parent = (gparent)->entry.tree.index.rbe_parent)) { if ((gparent) == ((gparent)->entry.tree.index.rbe_parent)-> entry.tree.index.rbe_left) ((gparent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_left = (tmp); else ((gparent)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree .index.rbe_right = (gparent); (gparent)->entry.tree.index. rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree .index.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->entry.tree.index.rbe_left; if (tmp && (tmp)->entry.tree.index.rbe_color == 1) { (tmp)->entry .tree.index.rbe_color = 0; do { (parent)->entry.tree.index .rbe_color = 0; (gparent)->entry.tree.index.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->entry .tree.index.rbe_left == elm) { do { (tmp) = (parent)->entry .tree.index.rbe_left; if (((parent)->entry.tree.index.rbe_left = (tmp)->entry.tree.index.rbe_right)) { ((tmp)->entry. tree.index.rbe_right)->entry.tree.index.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.tree.index.rbe_parent = (parent)->entry.tree.index.rbe_parent)) { if ((parent) == ((parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left) ((parent)->entry.tree.index.rbe_parent)->entry .tree.index.rbe_left = (tmp); else ((parent)->entry.tree.index .rbe_parent)->entry.tree.index.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_right = (parent); (parent)->entry.tree.index.rbe_parent = (tmp) ; do {} while (0); if (((tmp)->entry.tree.index.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.tree.index.rbe_color = 0; ( gparent)->entry.tree.index.rbe_color = 1; } while (0); do { (tmp) = (gparent)->entry.tree.index.rbe_right; if (((gparent )->entry.tree.index.rbe_right = (tmp)->entry.tree.index .rbe_left)) { ((tmp)->entry.tree.index.rbe_left)->entry .tree.index.rbe_parent = (gparent); } do {} while (0); if ((( tmp)->entry.tree.index.rbe_parent = (gparent)->entry.tree .index.rbe_parent)) { if ((gparent) == ((gparent)->entry.tree .index.rbe_parent)->entry.tree.index.rbe_left) ((gparent)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_left = ( tmp); else ((gparent)->entry.tree.index.rbe_parent)->entry .tree.index.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.tree.index.rbe_left = (gparent); (gparent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->entry.tree.index.rbe_color = 0; } __attribute__((__unused__)) static void prefix_index_RB_REMOVE_COLOR (struct prefix_index *head, struct prefix *parent, struct prefix *elm) { struct prefix *tmp; while ((elm == ((void*)0) || (elm )->entry.tree.index.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->entry.tree.index.rbe_left == elm) { tmp = (parent)->entry.tree.index.rbe_right; if ((tmp )->entry.tree.index.rbe_color == 1) { do { (tmp)->entry .tree.index.rbe_color = 0; (parent)->entry.tree.index.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.tree.index .rbe_right; if (((parent)->entry.tree.index.rbe_right = (tmp )->entry.tree.index.rbe_left)) { ((tmp)->entry.tree.index .rbe_left)->entry.tree.index.rbe_parent = (parent); } do { } while (0); if (((tmp)->entry.tree.index.rbe_parent = (parent )->entry.tree.index.rbe_parent)) { if ((parent) == ((parent )->entry.tree.index.rbe_parent)->entry.tree.index.rbe_left ) ((parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.index.rbe_right; } if (((tmp)->entry.tree.index.rbe_left == ((void*)0) || ((tmp )->entry.tree.index.rbe_left)->entry.tree.index.rbe_color == 0) && ((tmp)->entry.tree.index.rbe_right == (( void*)0) || ((tmp)->entry.tree.index.rbe_right)->entry. tree.index.rbe_color == 0)) { (tmp)->entry.tree.index.rbe_color = 1; elm = parent; parent = (elm)->entry.tree.index.rbe_parent ; } else { if ((tmp)->entry.tree.index.rbe_right == ((void *)0) || ((tmp)->entry.tree.index.rbe_right)->entry.tree .index.rbe_color == 0) { struct prefix *oleft; if ((oleft = ( tmp)->entry.tree.index.rbe_left)) (oleft)->entry.tree.index .rbe_color = 0; (tmp)->entry.tree.index.rbe_color = 1; do { (oleft) = (tmp)->entry.tree.index.rbe_left; if (((tmp)-> entry.tree.index.rbe_left = (oleft)->entry.tree.index.rbe_right )) { ((oleft)->entry.tree.index.rbe_right)->entry.tree. index.rbe_parent = (tmp); } do {} while (0); if (((oleft)-> entry.tree.index.rbe_parent = (tmp)->entry.tree.index.rbe_parent )) { if ((tmp) == ((tmp)->entry.tree.index.rbe_parent)-> entry.tree.index.rbe_left) ((tmp)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_left = (oleft); else ((tmp)->entry .tree.index.rbe_parent)->entry.tree.index.rbe_right = (oleft ); } else (head)->rbh_root = (oleft); (oleft)->entry.tree .index.rbe_right = (tmp); (tmp)->entry.tree.index.rbe_parent = (oleft); do {} while (0); if (((oleft)->entry.tree.index .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> entry.tree.index.rbe_right; } (tmp)->entry.tree.index.rbe_color = (parent)->entry.tree.index.rbe_color; (parent)->entry .tree.index.rbe_color = 0; if ((tmp)->entry.tree.index.rbe_right ) ((tmp)->entry.tree.index.rbe_right)->entry.tree.index .rbe_color = 0; do { (tmp) = (parent)->entry.tree.index.rbe_right ; if (((parent)->entry.tree.index.rbe_right = (tmp)->entry .tree.index.rbe_left)) { ((tmp)->entry.tree.index.rbe_left )->entry.tree.index.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.index.rbe_parent = (parent)-> entry.tree.index.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) ( (parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent)->entry.tree.index.rbe_left; if ((tmp)->entry. tree.index.rbe_color == 1) { do { (tmp)->entry.tree.index. rbe_color = 0; (parent)->entry.tree.index.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.tree.index.rbe_left ; if (((parent)->entry.tree.index.rbe_left = (tmp)->entry .tree.index.rbe_right)) { ((tmp)->entry.tree.index.rbe_right )->entry.tree.index.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.index.rbe_parent = (parent)-> entry.tree.index.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) ( (parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_right = (parent); (parent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.tree.index.rbe_left; } if (((tmp)->entry.tree.index.rbe_left == ((void*)0) || ((tmp )->entry.tree.index.rbe_left)->entry.tree.index.rbe_color == 0) && ((tmp)->entry.tree.index.rbe_right == (( void*)0) || ((tmp)->entry.tree.index.rbe_right)->entry. tree.index.rbe_color == 0)) { (tmp)->entry.tree.index.rbe_color = 1; elm = parent; parent = (elm)->entry.tree.index.rbe_parent ; } else { if ((tmp)->entry.tree.index.rbe_left == ((void* )0) || ((tmp)->entry.tree.index.rbe_left)->entry.tree.index .rbe_color == 0) { struct prefix *oright; if ((oright = (tmp) ->entry.tree.index.rbe_right)) (oright)->entry.tree.index .rbe_color = 0; (tmp)->entry.tree.index.rbe_color = 1; do { (oright) = (tmp)->entry.tree.index.rbe_right; if (((tmp)-> entry.tree.index.rbe_right = (oright)->entry.tree.index.rbe_left )) { ((oright)->entry.tree.index.rbe_left)->entry.tree. index.rbe_parent = (tmp); } do {} while (0); if (((oright)-> entry.tree.index.rbe_parent = (tmp)->entry.tree.index.rbe_parent )) { if ((tmp) == ((tmp)->entry.tree.index.rbe_parent)-> entry.tree.index.rbe_left) ((tmp)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_left = (oright); else ((tmp)->entry .tree.index.rbe_parent)->entry.tree.index.rbe_right = (oright ); } else (head)->rbh_root = (oright); (oright)->entry. tree.index.rbe_left = (tmp); (tmp)->entry.tree.index.rbe_parent = (oright); do {} while (0); if (((oright)->entry.tree.index .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> entry.tree.index.rbe_left; } (tmp)->entry.tree.index.rbe_color = (parent)->entry.tree.index.rbe_color; (parent)->entry .tree.index.rbe_color = 0; if ((tmp)->entry.tree.index.rbe_left ) ((tmp)->entry.tree.index.rbe_left)->entry.tree.index. rbe_color = 0; do { (tmp) = (parent)->entry.tree.index.rbe_left ; if (((parent)->entry.tree.index.rbe_left = (tmp)->entry .tree.index.rbe_right)) { ((tmp)->entry.tree.index.rbe_right )->entry.tree.index.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->entry.tree.index.rbe_parent = (parent)-> entry.tree.index.rbe_parent)) { if ((parent) == ((parent)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) ( (parent)->entry.tree.index.rbe_parent)->entry.tree.index .rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_right = (parent); (parent )->entry.tree.index.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree.index.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) ( elm)->entry.tree.index.rbe_color = 0; } __attribute__((__unused__ )) static struct prefix * prefix_index_RB_REMOVE(struct prefix_index *head, struct prefix *elm) { struct prefix *child, *parent, * old = elm; int color; if ((elm)->entry.tree.index.rbe_left == ((void*)0)) child = (elm)->entry.tree.index.rbe_right; else if ((elm)->entry.tree.index.rbe_right == ((void*)0)) child = (elm)->entry.tree.index.rbe_left; else { struct prefix *left; elm = (elm)->entry.tree.index.rbe_right; while ((left = (elm)->entry.tree.index.rbe_left)) elm = left; child = ( elm)->entry.tree.index.rbe_right; parent = (elm)->entry .tree.index.rbe_parent; color = (elm)->entry.tree.index.rbe_color ; if (child) (child)->entry.tree.index.rbe_parent = parent ; if (parent) { if ((parent)->entry.tree.index.rbe_left == elm) (parent)->entry.tree.index.rbe_left = child; else (parent )->entry.tree.index.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->entry.tree.index. rbe_parent == old) parent = elm; (elm)->entry.tree.index = (old)->entry.tree.index; if ((old)->entry.tree.index.rbe_parent ) { if (((old)->entry.tree.index.rbe_parent)->entry.tree .index.rbe_left == old) ((old)->entry.tree.index.rbe_parent )->entry.tree.index.rbe_left = elm; else ((old)->entry. tree.index.rbe_parent)->entry.tree.index.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->entry .tree.index.rbe_left)->entry.tree.index.rbe_parent = elm; if ((old)->entry.tree.index.rbe_right) ((old)->entry.tree .index.rbe_right)->entry.tree.index.rbe_parent = elm; if ( parent) { left = parent; do { do {} while (0); } while ((left = (left)->entry.tree.index.rbe_parent)); } goto color; } parent = (elm)->entry.tree.index.rbe_parent; color = (elm)->entry .tree.index.rbe_color; if (child) (child)->entry.tree.index .rbe_parent = parent; if (parent) { if ((parent)->entry.tree .index.rbe_left == elm) (parent)->entry.tree.index.rbe_left = child; else (parent)->entry.tree.index.rbe_right = child ; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) prefix_index_RB_REMOVE_COLOR(head, parent, child ); return (old); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_INSERT(struct prefix_index *head, struct prefix *elm) { struct prefix *tmp; struct prefix *parent = ((void*) 0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (prefix_index_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->entry.tree.index.rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.index.rbe_right; else return ( tmp); } do { (elm)->entry.tree.index.rbe_parent = parent; ( elm)->entry.tree.index.rbe_left = (elm)->entry.tree.index .rbe_right = ((void*)0); (elm)->entry.tree.index.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0 ) (parent)->entry.tree.index.rbe_left = elm; else (parent) ->entry.tree.index.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; prefix_index_RB_INSERT_COLOR(head , elm); return (((void*)0)); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_FIND(struct prefix_index *head , struct prefix *elm) { struct prefix *tmp = (head)->rbh_root ; int comp; while (tmp) { comp = prefix_index_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->entry.tree.index.rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.index.rbe_right; else return (tmp); } return (((void*)0)); } __attribute__((__unused__ )) static struct prefix * prefix_index_RB_NFIND(struct prefix_index *head, struct prefix *elm) { struct prefix *tmp = (head)-> rbh_root; struct prefix *res = ((void*)0); int comp; while (tmp ) { comp = prefix_index_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry.tree.index.rbe_left; } else if ( comp > 0) tmp = (tmp)->entry.tree.index.rbe_right; else return (tmp); } return (res); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_NEXT(struct prefix *elm) { if ((elm)->entry.tree.index.rbe_right) { elm = (elm)->entry .tree.index.rbe_right; while ((elm)->entry.tree.index.rbe_left ) elm = (elm)->entry.tree.index.rbe_left; } else { if ((elm )->entry.tree.index.rbe_parent && (elm == ((elm)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_left)) elm = (elm)->entry.tree.index.rbe_parent; else { while ((elm) ->entry.tree.index.rbe_parent && (elm == ((elm)-> entry.tree.index.rbe_parent)->entry.tree.index.rbe_right)) elm = (elm)->entry.tree.index.rbe_parent; elm = (elm)-> entry.tree.index.rbe_parent; } } return (elm); } __attribute__ ((__unused__)) static struct prefix * prefix_index_RB_PREV(struct prefix *elm) { if ((elm)->entry.tree.index.rbe_left) { elm = (elm)->entry.tree.index.rbe_left; while ((elm)->entry .tree.index.rbe_right) elm = (elm)->entry.tree.index.rbe_right ; } else { if ((elm)->entry.tree.index.rbe_parent && (elm == ((elm)->entry.tree.index.rbe_parent)->entry.tree .index.rbe_right)) elm = (elm)->entry.tree.index.rbe_parent ; else { while ((elm)->entry.tree.index.rbe_parent && (elm == ((elm)->entry.tree.index.rbe_parent)->entry.tree .index.rbe_left)) elm = (elm)->entry.tree.index.rbe_parent ; elm = (elm)->entry.tree.index.rbe_parent; } } return (elm ); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_MINMAX (struct prefix_index *head, int val) { struct prefix *tmp = ( head)->rbh_root; struct prefix *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry. tree.index.rbe_left; else tmp = (tmp)->entry.tree.index.rbe_right ; } return (parent); } | |||
| 892 | ||||
| 893 | /* | |||
| 894 | * search for specified prefix of a peer. Returns NULL if not found. | |||
| 895 | */ | |||
| 896 | struct prefix * | |||
| 897 | prefix_get(struct rib *rib, struct rde_peer *peer, u_int32_t path_id, | |||
| 898 | struct bgpd_addr *prefix, int prefixlen) | |||
| 899 | { | |||
| 900 | struct rib_entry *re; | |||
| 901 | ||||
| 902 | re = rib_get(rib, prefix, prefixlen); | |||
| 903 | if (re == NULL((void*)0)) | |||
| 904 | return (NULL((void*)0)); | |||
| 905 | return (prefix_bypeer(re, peer, path_id)); | |||
| 906 | } | |||
| 907 | ||||
| 908 | /* | |||
| 909 | * lookup prefix in the peer prefix_index. Returns NULL if not found. | |||
| 910 | */ | |||
| 911 | struct prefix * | |||
| 912 | prefix_lookup(struct rde_peer *peer, struct bgpd_addr *prefix, | |||
| 913 | int prefixlen) | |||
| 914 | { | |||
| 915 | struct prefix xp; | |||
| 916 | struct pt_entry *pte; | |||
| 917 | ||||
| 918 | memset(&xp, 0, sizeof(xp)); | |||
| 919 | pte = pt_fill(prefix, prefixlen); | |||
| 920 | xp.pt = pte; | |||
| 921 | ||||
| 922 | return RB_FIND(prefix_index, &peer->adj_rib_out, &xp)prefix_index_RB_FIND(&peer->adj_rib_out, &xp); | |||
| 923 | } | |||
| 924 | ||||
| 925 | struct prefix * | |||
| 926 | prefix_match(struct rde_peer *peer, struct bgpd_addr *addr) | |||
| 927 | { | |||
| 928 | struct prefix *p; | |||
| 929 | int i; | |||
| 930 | ||||
| 931 | switch (addr->aid) { | |||
| 932 | case AID_INET1: | |||
| 933 | case AID_VPN_IPv43: | |||
| 934 | for (i = 32; i >= 0; i--) { | |||
| 935 | p = prefix_lookup(peer, addr, i); | |||
| 936 | if (p != NULL((void*)0)) | |||
| 937 | return p; | |||
| 938 | } | |||
| 939 | break; | |||
| 940 | case AID_INET62: | |||
| 941 | case AID_VPN_IPv64: | |||
| 942 | for (i = 128; i >= 0; i--) { | |||
| 943 | p = prefix_lookup(peer, addr, i); | |||
| 944 | if (p != NULL((void*)0)) | |||
| 945 | return p; | |||
| 946 | } | |||
| 947 | break; | |||
| 948 | default: | |||
| 949 | fatalx("%s: unknown af", __func__); | |||
| 950 | } | |||
| 951 | return NULL((void*)0); | |||
| 952 | } | |||
| 953 | ||||
| 954 | /* | |||
| 955 | * Update a prefix. | |||
| 956 | * Return 1 if prefix was newly added, 0 if it was just changed. | |||
| 957 | */ | |||
| 958 | int | |||
| 959 | prefix_update(struct rib *rib, struct rde_peer *peer, u_int32_t path_id, | |||
| 960 | struct filterstate *state, struct bgpd_addr *prefix, int prefixlen, | |||
| 961 | u_int8_t vstate) | |||
| 962 | { | |||
| 963 | struct rde_aspath *asp, *nasp = &state->aspath; | |||
| 964 | struct rde_community *comm, *ncomm = &state->communities; | |||
| 965 | struct prefix *p; | |||
| 966 | ||||
| 967 | /* | |||
| 968 | * First try to find a prefix in the specified RIB. | |||
| 969 | */ | |||
| 970 | if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL((void*)0)) { | |||
| 971 | if (prefix_nexthop(p) == state->nexthop && | |||
| 972 | prefix_nhflags(p) == state->nhflags && | |||
| 973 | communities_equal(ncomm, prefix_communities(p)) && | |||
| 974 | path_compare(nasp, prefix_aspath(p)) == 0) { | |||
| 975 | /* no change, update last change */ | |||
| 976 | p->lastchange = getmonotime(); | |||
| 977 | p->validation_state = vstate; | |||
| 978 | return (0); | |||
| 979 | } | |||
| 980 | } | |||
| 981 | ||||
| 982 | /* | |||
| 983 | * Either the prefix does not exist or the path changed. | |||
| 984 | * In both cases lookup the new aspath to make sure it is not | |||
| 985 | * already in the RIB. | |||
| 986 | */ | |||
| 987 | if ((asp = path_lookup(nasp)) == NULL((void*)0)) { | |||
| 988 | /* Path not available, create and link a new one. */ | |||
| 989 | asp = path_copy(path_get(), nasp); | |||
| 990 | path_link(asp); | |||
| 991 | } | |||
| 992 | ||||
| 993 | if ((comm = communities_lookup(ncomm)) == NULL((void*)0)) { | |||
| 994 | /* Communities not available, create and link a new one. */ | |||
| 995 | comm = communities_link(ncomm); | |||
| 996 | } | |||
| 997 | ||||
| 998 | /* If the prefix was found move it else add it to the RIB. */ | |||
| 999 | if (p != NULL((void*)0)) | |||
| 1000 | return (prefix_move(p, peer, asp, comm, state->nexthop, | |||
| 1001 | state->nhflags, vstate)); | |||
| 1002 | else | |||
| 1003 | return (prefix_add(prefix, prefixlen, rib, peer, path_id, asp, | |||
| 1004 | comm, state->nexthop, state->nhflags, vstate)); | |||
| 1005 | } | |||
| 1006 | ||||
| 1007 | /* | |||
| 1008 | * Adds or updates a prefix. | |||
| 1009 | */ | |||
| 1010 | static int | |||
| 1011 | prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib, | |||
| 1012 | struct rde_peer *peer, u_int32_t path_id, struct rde_aspath *asp, | |||
| 1013 | struct rde_community *comm, struct nexthop *nexthop, u_int8_t nhflags, | |||
| 1014 | u_int8_t vstate) | |||
| 1015 | { | |||
| 1016 | struct prefix *p; | |||
| 1017 | struct rib_entry *re; | |||
| 1018 | ||||
| 1019 | re = rib_get(rib, prefix, prefixlen); | |||
| 1020 | if (re == NULL((void*)0)) | |||
| 1021 | re = rib_add(rib, prefix, prefixlen); | |||
| 1022 | ||||
| 1023 | p = prefix_alloc(); | |||
| 1024 | prefix_link(p, re, peer, path_id, asp, comm, nexthop, nhflags, vstate); | |||
| 1025 | return (1); | |||
| 1026 | } | |||
| 1027 | ||||
| 1028 | /* | |||
| 1029 | * Move the prefix to the specified as path, removes the old asp if needed. | |||
| 1030 | */ | |||
| 1031 | static int | |||
| 1032 | prefix_move(struct prefix *p, struct rde_peer *peer, | |||
| 1033 | struct rde_aspath *asp, struct rde_community *comm, | |||
| 1034 | struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate) | |||
| 1035 | { | |||
| 1036 | struct prefix *np; | |||
| 1037 | ||||
| 1038 | if (p->flags & PREFIX_FLAG_ADJOUT0x10) | |||
| 1039 | fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__); | |||
| 1040 | ||||
| 1041 | if (peer != prefix_peer(p)) | |||
| 1042 | fatalx("prefix_move: cross peer move"); | |||
| 1043 | ||||
| 1044 | /* add new prefix node */ | |||
| 1045 | np = prefix_alloc(); | |||
| 1046 | /* add reference to new AS path and communities */ | |||
| 1047 | np->aspath = path_ref(asp); | |||
| 1048 | np->communities = communities_ref(comm); | |||
| 1049 | np->peer = peer; | |||
| 1050 | np->entry.list.re = prefix_re(p); | |||
| 1051 | np->pt = p->pt; /* skip refcnt update since ref is moved */ | |||
| 1052 | np->path_id = p->path_id; | |||
| 1053 | np->validation_state = vstate; | |||
| 1054 | np->nhflags = nhflags; | |||
| 1055 | np->nexthop = nexthop_ref(nexthop); | |||
| 1056 | nexthop_link(np); | |||
| 1057 | np->lastchange = getmonotime(); | |||
| 1058 | ||||
| 1059 | /* add possible pftable reference from new aspath */ | |||
| 1060 | if (asp && asp->pftableid) | |||
| 1061 | rde_pftable_add(asp->pftableid, np); | |||
| 1062 | ||||
| 1063 | /* | |||
| 1064 | * no need to update the peer prefix count because we are only moving | |||
| 1065 | * the prefix without changing the peer. | |||
| 1066 | */ | |||
| 1067 | prefix_evaluate(prefix_re(np), np, p); | |||
| 1068 | ||||
| 1069 | /* remove possible pftable reference from old path first */ | |||
| 1070 | if (p->aspath && p->aspath->pftableid) | |||
| 1071 | rde_pftable_del(p->aspath->pftableid, p); | |||
| 1072 | ||||
| 1073 | /* remove old prefix node */ | |||
| 1074 | nexthop_unlink(p); | |||
| 1075 | nexthop_unref(p->nexthop); | |||
| 1076 | communities_unref(p->communities); | |||
| 1077 | path_unref(p->aspath); | |||
| 1078 | p->communities = NULL((void*)0); | |||
| 1079 | p->nexthop = NULL((void*)0); | |||
| 1080 | p->aspath = NULL((void*)0); | |||
| 1081 | p->peer = NULL((void*)0); | |||
| 1082 | p->pt = NULL((void*)0); | |||
| 1083 | p->entry.list.re = NULL((void*)0); | |||
| 1084 | prefix_free(p); | |||
| 1085 | ||||
| 1086 | return (0); | |||
| 1087 | } | |||
| 1088 | ||||
| 1089 | /* | |||
| 1090 | * Removes a prefix from the specified RIB. If the parent objects -- rib_entry | |||
| 1091 | * or pt_entry -- become empty remove them too. | |||
| 1092 | */ | |||
| 1093 | int | |||
| 1094 | prefix_withdraw(struct rib *rib, struct rde_peer *peer, u_int32_t path_id, | |||
| 1095 | struct bgpd_addr *prefix, int prefixlen) | |||
| 1096 | { | |||
| 1097 | struct prefix *p; | |||
| 1098 | struct rde_aspath *asp; | |||
| 1099 | ||||
| 1100 | p = prefix_get(rib, peer, path_id, prefix, prefixlen); | |||
| 1101 | if (p == NULL((void*)0)) /* Got a dummy withdrawn request. */ | |||
| 1102 | return (0); | |||
| 1103 | ||||
| 1104 | if (p->flags & PREFIX_FLAG_ADJOUT0x10) | |||
| 1105 | fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__); | |||
| 1106 | asp = prefix_aspath(p); | |||
| 1107 | if (asp && asp->pftableid) | |||
| 1108 | /* only prefixes in the local RIB were pushed into pf */ | |||
| 1109 | rde_pftable_del(asp->pftableid, p); | |||
| 1110 | ||||
| 1111 | prefix_destroy(p); | |||
| 1112 | ||||
| 1113 | return (1); | |||
| 1114 | } | |||
| 1115 | ||||
| 1116 | /* | |||
| 1117 | * Insert an End-of-RIB marker into the update queue. | |||
| 1118 | */ | |||
| 1119 | void | |||
| 1120 | prefix_add_eor(struct rde_peer *peer, u_int8_t aid) | |||
| 1121 | { | |||
| 1122 | struct prefix *p; | |||
| 1123 | ||||
| 1124 | p = prefix_alloc(); | |||
| 1125 | p->flags = PREFIX_FLAG_ADJOUT0x10 | PREFIX_FLAG_UPDATE0x02; | |||
| 1126 | p->eor = 1; | |||
| 1127 | if (RB_INSERT(prefix_tree, &peer->updates[aid], p)prefix_tree_RB_INSERT(&peer->updates[aid], p) != NULL((void*)0)) | |||
| 1128 | /* no need to add if EoR marker already present */ | |||
| 1129 | prefix_free(p); | |||
| 1130 | /* EOR marker is not inserted into the adj_rib_out index */ | |||
| 1131 | } | |||
| 1132 | ||||
| 1133 | /* | |||
| 1134 | * Put a prefix from the Adj-RIB-Out onto the update queue. | |||
| 1135 | */ | |||
| 1136 | int | |||
| 1137 | prefix_adjout_update(struct rde_peer *peer, struct filterstate *state, | |||
| 1138 | struct bgpd_addr *prefix, int prefixlen, u_int8_t vstate) | |||
| 1139 | { | |||
| 1140 | struct prefix_tree *prefix_head = NULL((void*)0); | |||
| 1141 | struct rde_aspath *asp; | |||
| 1142 | struct rde_community *comm; | |||
| 1143 | struct prefix *p; | |||
| 1144 | int created = 0; | |||
| 1145 | ||||
| 1146 | if ((p = prefix_lookup(peer, prefix, prefixlen)) != NULL((void*)0)) { | |||
| 1147 | if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0) | |||
| 1148 | fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", | |||
| 1149 | __func__); | |||
| 1150 | /* prefix is already in the Adj-RIB-Out */ | |||
| 1151 | if (p->flags & PREFIX_FLAG_WITHDRAW0x01) { | |||
| 1152 | created = 1; /* consider this a new entry */ | |||
| 1153 | peer->up_wcnt--; | |||
| 1154 | prefix_head = &peer->withdraws[prefix->aid]; | |||
| 1155 | RB_REMOVE(prefix_tree, prefix_head, p)prefix_tree_RB_REMOVE(prefix_head, p); | |||
| 1156 | } else if (p->flags & PREFIX_FLAG_DEAD0x04) { | |||
| 1157 | created = 1; /* consider this a new entry */ | |||
| 1158 | } else { | |||
| 1159 | if (prefix_nhflags(p) == state->nhflags && | |||
| 1160 | prefix_nexthop(p) == state->nexthop && | |||
| 1161 | communities_equal(&state->communities, | |||
| 1162 | prefix_communities(p)) && | |||
| 1163 | path_compare(&state->aspath, prefix_aspath(p)) == | |||
| 1164 | 0) { | |||
| 1165 | /* nothing changed */ | |||
| 1166 | p->validation_state = vstate; | |||
| 1167 | p->lastchange = getmonotime(); | |||
| 1168 | p->flags &= ~PREFIX_FLAG_STALE0x08; | |||
| 1169 | return 0; | |||
| 1170 | } | |||
| 1171 | ||||
| 1172 | if (p->flags & PREFIX_FLAG_UPDATE0x02) { | |||
| 1173 | /* created = 0 so up_nlricnt is not increased */ | |||
| 1174 | prefix_head = &peer->updates[prefix->aid]; | |||
| 1175 | RB_REMOVE(prefix_tree, prefix_head, p)prefix_tree_RB_REMOVE(prefix_head, p); | |||
| 1176 | } | |||
| 1177 | } | |||
| 1178 | /* unlink from aspath and remove nexthop ref */ | |||
| 1179 | nexthop_unref(p->nexthop); | |||
| 1180 | communities_unref(p->communities); | |||
| 1181 | path_unref(p->aspath); | |||
| 1182 | p->flags &= ~PREFIX_FLAG_MASK0x0f; | |||
| 1183 | ||||
| 1184 | /* peer and pt remain */ | |||
| 1185 | } else { | |||
| 1186 | p = prefix_alloc(); | |||
| 1187 | p->flags |= PREFIX_FLAG_ADJOUT0x10; | |||
| 1188 | created = 1; | |||
| 1189 | ||||
| 1190 | p->pt = pt_get(prefix, prefixlen); | |||
| 1191 | if (p->pt == NULL((void*)0)) | |||
| 1192 | p->pt = pt_add(prefix, prefixlen); | |||
| 1193 | pt_ref(p->pt); | |||
| 1194 | p->peer = peer; | |||
| 1195 | ||||
| 1196 | if (RB_INSERT(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_INSERT(&peer->adj_rib_out, p) != NULL((void*)0)) | |||
| 1197 | fatalx("%s: RB index invariant violated", __func__); | |||
| 1198 | } | |||
| 1199 | ||||
| 1200 | if ((asp = path_lookup(&state->aspath)) == NULL((void*)0)) { | |||
| 1201 | /* Path not available, create and link a new one. */ | |||
| 1202 | asp = path_copy(path_get(), &state->aspath); | |||
| 1203 | path_link(asp); | |||
| 1204 | } | |||
| 1205 | ||||
| 1206 | if ((comm = communities_lookup(&state->communities)) == NULL((void*)0)) { | |||
| 1207 | /* Communities not available, create and link a new one. */ | |||
| 1208 | comm = communities_link(&state->communities); | |||
| 1209 | } | |||
| 1210 | ||||
| 1211 | p->aspath = path_ref(asp); | |||
| 1212 | p->communities = communities_ref(comm); | |||
| 1213 | p->nexthop = nexthop_ref(state->nexthop); | |||
| 1214 | p->nhflags = state->nhflags; | |||
| 1215 | ||||
| 1216 | p->validation_state = vstate; | |||
| 1217 | p->lastchange = getmonotime(); | |||
| 1218 | ||||
| 1219 | if (p->flags & PREFIX_FLAG_MASK0x0f) | |||
| 1220 | fatalx("%s: bad flags %x", __func__, p->flags); | |||
| 1221 | p->flags |= PREFIX_FLAG_UPDATE0x02; | |||
| 1222 | if (RB_INSERT(prefix_tree, &peer->updates[prefix->aid], p)prefix_tree_RB_INSERT(&peer->updates[prefix->aid], p ) != NULL((void*)0)) | |||
| 1223 | fatalx("%s: RB tree invariant violated", __func__); | |||
| 1224 | ||||
| 1225 | return created; | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | /* | |||
| 1229 | * Withdraw a prefix from the Adj-RIB-Out, this unlinks the aspath but leaves | |||
| 1230 | * the prefix in the RIB linked to the peer withdraw list. | |||
| 1231 | */ | |||
| 1232 | int | |||
| 1233 | prefix_adjout_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix, | |||
| 1234 | int prefixlen) | |||
| 1235 | { | |||
| 1236 | struct prefix *p; | |||
| 1237 | ||||
| 1238 | p = prefix_lookup(peer, prefix, prefixlen); | |||
| 1239 | if (p == NULL((void*)0)) /* Got a dummy withdrawn request. */ | |||
| 1240 | return (0); | |||
| 1241 | ||||
| 1242 | if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0) | |||
| 1243 | fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__); | |||
| 1244 | ||||
| 1245 | /* already a withdraw, shortcut */ | |||
| 1246 | if (p->flags & PREFIX_FLAG_WITHDRAW0x01) { | |||
| 1247 | p->lastchange = getmonotime(); | |||
| 1248 | p->flags &= ~PREFIX_FLAG_STALE0x08; | |||
| 1249 | return (0); | |||
| 1250 | } | |||
| 1251 | /* pending update just got withdrawn */ | |||
| 1252 | if (p->flags & PREFIX_FLAG_UPDATE0x02) | |||
| 1253 | RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->updates[p->pt->aid] , p); | |||
| 1254 | /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */ | |||
| 1255 | p->flags &= ~PREFIX_FLAG_MASK0x0f; | |||
| 1256 | ||||
| 1257 | /* remove nexthop ref ... */ | |||
| 1258 | nexthop_unref(p->nexthop); | |||
| 1259 | p->nexthop = NULL((void*)0); | |||
| 1260 | p->nhflags = 0; | |||
| 1261 | ||||
| 1262 | /* unlink from aspath ...*/ | |||
| 1263 | path_unref(p->aspath); | |||
| 1264 | p->aspath = NULL((void*)0); | |||
| 1265 | ||||
| 1266 | /* ... communities ... */ | |||
| 1267 | communities_unref(p->communities); | |||
| 1268 | p->communities = NULL((void*)0); | |||
| 1269 | /* and unlink from aspath */ | |||
| 1270 | path_unref(p->aspath); | |||
| 1271 | p->aspath = NULL((void*)0); | |||
| 1272 | /* re already NULL */ | |||
| 1273 | ||||
| 1274 | p->lastchange = getmonotime(); | |||
| 1275 | ||||
| 1276 | p->flags |= PREFIX_FLAG_WITHDRAW0x01; | |||
| 1277 | if (RB_INSERT(prefix_tree, &peer->withdraws[prefix->aid], p)prefix_tree_RB_INSERT(&peer->withdraws[prefix->aid] , p) != NULL((void*)0)) | |||
| 1278 | fatalx("%s: RB tree invariant violated", __func__); | |||
| 1279 | return (1); | |||
| 1280 | } | |||
| 1281 | ||||
| 1282 | static struct prefix * | |||
| 1283 | prefix_restart(struct rib_context *ctx) | |||
| 1284 | { | |||
| 1285 | struct prefix *p; | |||
| 1286 | ||||
| 1287 | p = prefix_unlock(ctx->ctx_p); | |||
| 1288 | ||||
| 1289 | if (prefix_is_dead(p)) { | |||
| 1290 | struct prefix *next; | |||
| 1291 | ||||
| 1292 | next = RB_NEXT(prefix_index, unused, p)prefix_index_RB_NEXT(p); | |||
| 1293 | prefix_adjout_destroy(p); | |||
| 1294 | p = next; | |||
| 1295 | } | |||
| 1296 | ctx->ctx_p = NULL((void*)0); | |||
| 1297 | return p; | |||
| 1298 | } | |||
| 1299 | ||||
| 1300 | void | |||
| 1301 | prefix_adjout_destroy(struct prefix *p) | |||
| 1302 | { | |||
| 1303 | struct rde_peer *peer = prefix_peer(p); | |||
| 1304 | ||||
| 1305 | if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0) | |||
| 1306 | fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__); | |||
| 1307 | ||||
| 1308 | if (p->eor) { | |||
| 1309 | /* EOR marker is not linked in the index */ | |||
| 1310 | prefix_free(p); | |||
| 1311 | return; | |||
| 1312 | } | |||
| 1313 | ||||
| 1314 | if (p->flags & PREFIX_FLAG_WITHDRAW0x01) | |||
| 1315 | RB_REMOVE(prefix_tree, &peer->withdraws[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->withdraws[p->pt->aid ], p); | |||
| 1316 | else if (p->flags & PREFIX_FLAG_UPDATE0x02) | |||
| 1317 | RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->updates[p->pt->aid] , p); | |||
| 1318 | /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */ | |||
| 1319 | p->flags &= ~PREFIX_FLAG_MASK0x0f; | |||
| 1320 | ||||
| 1321 | ||||
| 1322 | if (prefix_is_locked(p)) { | |||
| 1323 | /* remove nexthop ref ... */ | |||
| 1324 | nexthop_unref(p->nexthop); | |||
| 1325 | p->nexthop = NULL((void*)0); | |||
| 1326 | /* ... communities ... */ | |||
| 1327 | communities_unref(p->communities); | |||
| 1328 | p->communities = NULL((void*)0); | |||
| 1329 | /* and unlink from aspath */ | |||
| 1330 | path_unref(p->aspath); | |||
| 1331 | p->aspath = NULL((void*)0); | |||
| 1332 | p->nhflags = 0; | |||
| 1333 | /* re already NULL */ | |||
| 1334 | ||||
| 1335 | /* finally mark prefix dead */ | |||
| 1336 | p->flags |= PREFIX_FLAG_DEAD0x04; | |||
| 1337 | return; | |||
| 1338 | } | |||
| 1339 | ||||
| 1340 | RB_REMOVE(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_REMOVE(&peer->adj_rib_out, p); | |||
| 1341 | ||||
| 1342 | prefix_unlink(p); | |||
| 1343 | prefix_free(p); | |||
| 1344 | } | |||
| 1345 | ||||
| 1346 | static void | |||
| 1347 | prefix_dump_r(struct rib_context *ctx) | |||
| 1348 | { | |||
| 1349 | struct prefix *p, *next; | |||
| 1350 | struct rde_peer *peer; | |||
| 1351 | unsigned int i; | |||
| 1352 | ||||
| 1353 | if ((peer = peer_get(ctx->ctx_id)) == NULL((void*)0)) | |||
| 1354 | goto done; | |||
| 1355 | ||||
| 1356 | if (ctx->ctx_p == NULL((void*)0)) | |||
| 1357 | p = RB_MIN(prefix_index, &peer->adj_rib_out)prefix_index_RB_MINMAX(&peer->adj_rib_out, -1); | |||
| 1358 | else | |||
| 1359 | p = prefix_restart(ctx); | |||
| 1360 | ||||
| 1361 | for (i = 0; p != NULL((void*)0); p = next) { | |||
| 1362 | next = RB_NEXT(prefix_index, unused, p)prefix_index_RB_NEXT(p); | |||
| 1363 | if (prefix_is_dead(p)) | |||
| 1364 | continue; | |||
| 1365 | if (ctx->ctx_aid != AID_UNSPEC0 && | |||
| 1366 | ctx->ctx_aid != p->pt->aid) | |||
| 1367 | continue; | |||
| 1368 | if (ctx->ctx_count && i++ >= ctx->ctx_count && | |||
| 1369 | !prefix_is_locked(p)) { | |||
| 1370 | /* store and lock last element */ | |||
| 1371 | ctx->ctx_p = prefix_lock(p); | |||
| 1372 | return; | |||
| 1373 | } | |||
| 1374 | ctx->ctx_prefix_call(p, ctx->ctx_arg); | |||
| 1375 | } | |||
| 1376 | ||||
| 1377 | done: | |||
| 1378 | if (ctx->ctx_done) | |||
| 1379 | ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); | |||
| 1380 | LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void*)0)) (ctx)->entry .le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)-> entry.le_prev = (ctx)->entry.le_next; ; ; } while (0); | |||
| 1381 | free(ctx); | |||
| 1382 | } | |||
| 1383 | ||||
| 1384 | int | |||
| 1385 | prefix_dump_new(struct rde_peer *peer, u_int8_t aid, unsigned int count, | |||
| 1386 | void *arg, void (*upcall)(struct prefix *, void *), | |||
| 1387 | void (*done)(void *, u_int8_t), int (*throttle)(void *)) | |||
| 1388 | { | |||
| 1389 | struct rib_context *ctx; | |||
| 1390 | ||||
| 1391 | if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void*)0)) | |||
| 1392 | return -1; | |||
| 1393 | ctx->ctx_id = peer->conf.id; | |||
| 1394 | ctx->ctx_aid = aid; | |||
| 1395 | ctx->ctx_count = count; | |||
| 1396 | ctx->ctx_arg = arg; | |||
| 1397 | ctx->ctx_prefix_call = upcall; | |||
| 1398 | ctx->ctx_done = done; | |||
| 1399 | ctx->ctx_throttle = throttle; | |||
| 1400 | ||||
| 1401 | LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first ) != ((void*)0)) (&rib_dumps)->lh_first->entry.le_prev = &(ctx)->entry.le_next; (&rib_dumps)->lh_first = (ctx); (ctx)->entry.le_prev = &(&rib_dumps)-> lh_first; } while (0); | |||
| 1402 | ||||
| 1403 | /* requested a sync traversal */ | |||
| 1404 | if (count == 0) | |||
| 1405 | prefix_dump_r(ctx); | |||
| 1406 | ||||
| 1407 | return 0; | |||
| 1408 | } | |||
| 1409 | ||||
| 1410 | /* dump a prefix into specified buffer */ | |||
| 1411 | int | |||
| 1412 | prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen, | |||
| 1413 | int withdraw) | |||
| 1414 | { | |||
| 1415 | int totlen, psize; | |||
| 1416 | ||||
| 1417 | switch (prefix->aid) { | |||
| 1418 | case AID_INET1: | |||
| 1419 | case AID_INET62: | |||
| 1420 | totlen = PREFIX_SIZE(plen)(((plen) + 7) / 8 + 1); | |||
| 1421 | ||||
| 1422 | if (totlen > len) | |||
| 1423 | return (-1); | |||
| 1424 | *buf++ = plen; | |||
| 1425 | memcpy(buf, &prefix->ba, totlen - 1); | |||
| 1426 | return (totlen); | |||
| 1427 | case AID_VPN_IPv43: | |||
| 1428 | case AID_VPN_IPv64: | |||
| 1429 | totlen = PREFIX_SIZE(plen)(((plen) + 7) / 8 + 1) + sizeof(prefix->rd); | |||
| 1430 | psize = PREFIX_SIZE(plen)(((plen) + 7) / 8 + 1) - 1; | |||
| 1431 | plen += sizeof(prefix->rd) * 8; | |||
| 1432 | if (withdraw) { | |||
| 1433 | /* withdraw have one compat label as placeholder */ | |||
| 1434 | totlen += 3; | |||
| 1435 | plen += 3 * 8; | |||
| 1436 | } else { | |||
| 1437 | totlen += prefix->labellen; | |||
| 1438 | plen += prefix->labellen * 8; | |||
| 1439 | } | |||
| 1440 | ||||
| 1441 | if (totlen > len) | |||
| 1442 | return (-1); | |||
| 1443 | *buf++ = plen; | |||
| 1444 | if (withdraw) { | |||
| 1445 | /* magic compatibility label as per rfc8277 */ | |||
| 1446 | *buf++ = 0x80; | |||
| 1447 | *buf++ = 0x0; | |||
| 1448 | *buf++ = 0x0; | |||
| 1449 | } else { | |||
| 1450 | memcpy(buf, &prefix->labelstack, | |||
| 1451 | prefix->labellen); | |||
| 1452 | buf += prefix->labellen; | |||
| 1453 | } | |||
| 1454 | memcpy(buf, &prefix->rd, sizeof(prefix->rd)); | |||
| 1455 | buf += sizeof(prefix->rd); | |||
| 1456 | memcpy(buf, &prefix->ba, psize); | |||
| 1457 | return (totlen); | |||
| 1458 | default: | |||
| 1459 | return (-1); | |||
| 1460 | } | |||
| 1461 | } | |||
| 1462 | ||||
| 1463 | int | |||
| 1464 | prefix_writebuf(struct ibuf *buf, struct bgpd_addr *prefix, u_int8_t plen) | |||
| 1465 | { | |||
| 1466 | int totlen; | |||
| 1467 | void *bptr; | |||
| 1468 | ||||
| 1469 | switch (prefix->aid) { | |||
| 1470 | case AID_INET1: | |||
| 1471 | case AID_INET62: | |||
| 1472 | totlen = PREFIX_SIZE(plen)(((plen) + 7) / 8 + 1); | |||
| 1473 | break; | |||
| 1474 | case AID_VPN_IPv43: | |||
| 1475 | case AID_VPN_IPv64: | |||
| 1476 | totlen = PREFIX_SIZE(plen)(((plen) + 7) / 8 + 1) + sizeof(prefix->rd) + | |||
| 1477 | prefix->labellen; | |||
| 1478 | break; | |||
| 1479 | default: | |||
| 1480 | return (-1); | |||
| 1481 | } | |||
| 1482 | ||||
| 1483 | if ((bptr = ibuf_reserve(buf, totlen)) == NULL((void*)0)) | |||
| 1484 | return (-1); | |||
| 1485 | if (prefix_write(bptr, totlen, prefix, plen, 0) == -1) | |||
| 1486 | return (-1); | |||
| 1487 | return (0); | |||
| 1488 | } | |||
| 1489 | ||||
| 1490 | /* | |||
| 1491 | * Searches in the prefix list of specified rib_entry for a prefix entry | |||
| 1492 | * belonging to the peer peer. Returns NULL if no match found. | |||
| 1493 | */ | |||
| 1494 | struct prefix * | |||
| 1495 | prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t path_id) | |||
| 1496 | { | |||
| 1497 | struct prefix *p; | |||
| 1498 | ||||
| 1499 | LIST_FOREACH(p, &re->prefix_h, entry.list.rib)for((p) = ((&re->prefix_h)->lh_first); (p)!= ((void *)0); (p) = ((p)->entry.list.rib.le_next)) | |||
| 1500 | if (prefix_peer(p) == peer && p->path_id == path_id) | |||
| 1501 | return (p); | |||
| 1502 | return (NULL((void*)0)); | |||
| 1503 | } | |||
| 1504 | ||||
| 1505 | static void | |||
| 1506 | prefix_evaluate_all(struct prefix *p, enum nexthop_state state, | |||
| 1507 | enum nexthop_state oldstate) | |||
| 1508 | { | |||
| 1509 | struct rib_entry *re = prefix_re(p); | |||
| 1510 | ||||
| 1511 | /* Skip non local-RIBs or RIBs that are flagged as noeval. */ | |||
| 1512 | if (re_rib(re)->flags & F_RIB_NOEVALUATE0x0002) { | |||
| 1513 | log_warnx("%s: prefix with F_RIB_NOEVALUATE hit", __func__); | |||
| 1514 | return; | |||
| 1515 | } | |||
| 1516 | ||||
| 1517 | if (oldstate == state) { | |||
| 1518 | /* | |||
| 1519 | * The state of the nexthop did not change. The only | |||
| 1520 | * thing that may have changed is the true_nexthop | |||
| 1521 | * or other internal infos. This will not change | |||
| 1522 | * the routing decision so shortcut here. | |||
| 1523 | */ | |||
| 1524 | if (state == NEXTHOP_REACH) { | |||
| 1525 | if ((re_rib(re)->flags & F_RIB_NOFIB0x0004) == 0 && | |||
| 1526 | p == re->active) | |||
| 1527 | rde_send_kroute(re_rib(re), p, NULL((void*)0)); | |||
| 1528 | } | |||
| 1529 | return; | |||
| 1530 | } | |||
| 1531 | ||||
| 1532 | /* redo the route decision */ | |||
| 1533 | prefix_evaluate(prefix_re(p), p, p); | |||
| 1534 | } | |||
| 1535 | ||||
| 1536 | /* kill a prefix. */ | |||
| 1537 | void | |||
| 1538 | prefix_destroy(struct prefix *p) | |||
| 1539 | { | |||
| 1540 | /* make route decision */ | |||
| 1541 | prefix_evaluate(prefix_re(p), NULL((void*)0), p); | |||
| 1542 | ||||
| 1543 | prefix_unlink(p); | |||
| 1544 | prefix_free(p); | |||
| 1545 | } | |||
| 1546 | ||||
| 1547 | /* | |||
| 1548 | * Link a prefix into the different parent objects. | |||
| 1549 | */ | |||
| 1550 | static void | |||
| 1551 | prefix_link(struct prefix *p, struct rib_entry *re, struct rde_peer *peer, | |||
| 1552 | u_int32_t path_id, struct rde_aspath *asp, struct rde_community *comm, | |||
| 1553 | struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate) | |||
| 1554 | { | |||
| 1555 | if (p->flags & PREFIX_FLAG_ADJOUT0x10) | |||
| 1556 | fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__); | |||
| 1557 | ||||
| 1558 | p->entry.list.re = re; | |||
| 1559 | p->aspath = path_ref(asp); | |||
| 1560 | p->communities = communities_ref(comm); | |||
| 1561 | p->peer = peer; | |||
| 1562 | p->pt = pt_ref(re->prefix); | |||
| 1563 | p->path_id = path_id; | |||
| 1564 | p->validation_state = vstate; | |||
| 1565 | p->nhflags = nhflags; | |||
| 1566 | p->nexthop = nexthop_ref(nexthop); | |||
| 1567 | nexthop_link(p); | |||
| 1568 | p->lastchange = getmonotime(); | |||
| 1569 | ||||
| 1570 | /* add possible pftable reference from aspath */ | |||
| 1571 | if (asp && asp->pftableid) | |||
| 1572 | rde_pftable_add(asp->pftableid, p); | |||
| 1573 | ||||
| 1574 | /* make route decision */ | |||
| 1575 | prefix_evaluate(re, p, NULL((void*)0)); | |||
| 1576 | } | |||
| 1577 | ||||
| 1578 | /* | |||
| 1579 | * Unlink a prefix from the different parent objects. | |||
| 1580 | */ | |||
| 1581 | static void | |||
| 1582 | prefix_unlink(struct prefix *p) | |||
| 1583 | { | |||
| 1584 | struct rib_entry *re = prefix_re(p); | |||
| 1585 | ||||
| 1586 | /* destroy all references to other objects */ | |||
| 1587 | nexthop_unlink(p); | |||
| 1588 | nexthop_unref(p->nexthop); | |||
| 1589 | communities_unref(p->communities); | |||
| 1590 | path_unref(p->aspath); | |||
| 1591 | pt_unref(p->pt); | |||
| 1592 | p->communities = NULL((void*)0); | |||
| 1593 | p->nexthop = NULL((void*)0); | |||
| 1594 | p->aspath = NULL((void*)0); | |||
| 1595 | p->peer = NULL((void*)0); | |||
| 1596 | p->pt = NULL((void*)0); | |||
| 1597 | ||||
| 1598 | if (re && rib_empty(re)) | |||
| 1599 | rib_remove(re); | |||
| 1600 | ||||
| 1601 | /* | |||
| 1602 | * It's the caller's duty to do accounting and remove empty aspath | |||
| 1603 | * structures. Also freeing the unlinked prefix is the caller's duty. | |||
| 1604 | */ | |||
| 1605 | } | |||
| 1606 | ||||
| 1607 | /* alloc and zero new entry. May not fail. */ | |||
| 1608 | static struct prefix * | |||
| 1609 | prefix_alloc(void) | |||
| 1610 | { | |||
| 1611 | struct prefix *p; | |||
| 1612 | ||||
| 1613 | p = calloc(1, sizeof(*p)); | |||
| 1614 | if (p == NULL((void*)0)) | |||
| 1615 | fatal("prefix_alloc"); | |||
| 1616 | rdemem.prefix_cnt++; | |||
| 1617 | return p; | |||
| 1618 | } | |||
| 1619 | ||||
| 1620 | /* free a unlinked entry */ | |||
| 1621 | static void | |||
| 1622 | prefix_free(struct prefix *p) | |||
| 1623 | { | |||
| 1624 | rdemem.prefix_cnt--; | |||
| 1625 | free(p); | |||
| 1626 | } | |||
| 1627 | ||||
| 1628 | /* | |||
| 1629 | * nexthop functions | |||
| 1630 | */ | |||
| 1631 | struct nexthop_head *nexthop_hash(struct bgpd_addr *); | |||
| 1632 | struct nexthop *nexthop_lookup(struct bgpd_addr *); | |||
| 1633 | ||||
| 1634 | /* | |||
| 1635 | * In BGP there exist two nexthops: the exit nexthop which was announced via | |||
| 1636 | * BGP and the true nexthop which is used in the FIB -- forward information | |||
| 1637 | * base a.k.a kernel routing table. When sending updates it is even more | |||
| 1638 | * confusing. In IBGP we pass the unmodified exit nexthop to the neighbors | |||
| 1639 | * while in EBGP normally the address of the router is sent. The exit nexthop | |||
| 1640 | * may be passed to the external neighbor if the neighbor and the exit nexthop | |||
| 1641 | * reside in the same subnet -- directly connected. | |||
| 1642 | */ | |||
| 1643 | struct nexthop_table { | |||
| 1644 | LIST_HEAD(nexthop_head, nexthop)struct nexthop_head { struct nexthop *lh_first; } *nexthop_hashtbl; | |||
| 1645 | u_int32_t nexthop_hashmask; | |||
| 1646 | } nexthoptable; | |||
| 1647 | ||||
| 1648 | SIPHASH_KEY nexthoptablekey; | |||
| 1649 | ||||
| 1650 | TAILQ_HEAD(nexthop_queue, nexthop)struct nexthop_queue { struct nexthop *tqh_first; struct nexthop **tqh_last; } nexthop_runners; | |||
| 1651 | ||||
| 1652 | void | |||
| 1653 | nexthop_init(u_int32_t hashsize) | |||
| 1654 | { | |||
| 1655 | u_int32_t hs, i; | |||
| 1656 | ||||
| 1657 | for (hs = 1; hs < hashsize; hs <<= 1) | |||
| 1658 | ; | |||
| 1659 | nexthoptable.nexthop_hashtbl = calloc(hs, sizeof(struct nexthop_head)); | |||
| 1660 | if (nexthoptable.nexthop_hashtbl == NULL((void*)0)) | |||
| 1661 | fatal("nextop_init"); | |||
| 1662 | ||||
| 1663 | TAILQ_INIT(&nexthop_runners)do { (&nexthop_runners)->tqh_first = ((void*)0); (& nexthop_runners)->tqh_last = &(&nexthop_runners)-> tqh_first; } while (0); | |||
| 1664 | for (i = 0; i < hs; i++) | |||
| 1665 | LIST_INIT(&nexthoptable.nexthop_hashtbl[i])do { ((&nexthoptable.nexthop_hashtbl[i])->lh_first) = ( (void*)0); } while (0); | |||
| 1666 | arc4random_buf(&nexthoptablekey, sizeof(nexthoptablekey)); | |||
| 1667 | ||||
| 1668 | nexthoptable.nexthop_hashmask = hs - 1; | |||
| 1669 | } | |||
| 1670 | ||||
| 1671 | void | |||
| 1672 | nexthop_shutdown(void) | |||
| 1673 | { | |||
| 1674 | u_int32_t i; | |||
| 1675 | struct nexthop *nh, *nnh; | |||
| 1676 | ||||
| 1677 | for (i = 0; i <= nexthoptable.nexthop_hashmask; i++) { | |||
| 1678 | for (nh = LIST_FIRST(&nexthoptable.nexthop_hashtbl[i])((&nexthoptable.nexthop_hashtbl[i])->lh_first); | |||
| 1679 | nh != NULL((void*)0); nh = nnh) { | |||
| 1680 | nnh = LIST_NEXT(nh, nexthop_l)((nh)->nexthop_l.le_next); | |||
| 1681 | nh->state = NEXTHOP_UNREACH; | |||
| 1682 | nexthop_unref(nh); | |||
| 1683 | } | |||
| 1684 | if (!LIST_EMPTY(&nexthoptable.nexthop_hashtbl[i])(((&nexthoptable.nexthop_hashtbl[i])->lh_first) == ((void *)0))) { | |||
| 1685 | nh = LIST_FIRST(&nexthoptable.nexthop_hashtbl[i])((&nexthoptable.nexthop_hashtbl[i])->lh_first); | |||
| 1686 | log_warnx("nexthop_shutdown: non-free table, " | |||
| 1687 | "nexthop %s refcnt %d", | |||
| 1688 | log_addr(&nh->exit_nexthop), nh->refcnt); | |||
| 1689 | } | |||
| 1690 | } | |||
| 1691 | ||||
| 1692 | free(nexthoptable.nexthop_hashtbl); | |||
| 1693 | } | |||
| 1694 | ||||
| 1695 | int | |||
| 1696 | nexthop_pending(void) | |||
| 1697 | { | |||
| 1698 | return !TAILQ_EMPTY(&nexthop_runners)(((&nexthop_runners)->tqh_first) == ((void*)0)); | |||
| 1699 | } | |||
| 1700 | ||||
| 1701 | void | |||
| 1702 | nexthop_runner(void) | |||
| 1703 | { | |||
| 1704 | struct nexthop *nh; | |||
| 1705 | struct prefix *p; | |||
| 1706 | u_int32_t j; | |||
| 1707 | ||||
| 1708 | nh = TAILQ_FIRST(&nexthop_runners)((&nexthop_runners)->tqh_first); | |||
| 1709 | if (nh == NULL((void*)0)) | |||
| 1710 | return; | |||
| 1711 | ||||
| 1712 | /* remove from runnner queue */ | |||
| 1713 | TAILQ_REMOVE(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next) != ((void*)0)) (nh)-> runner_l.tqe_next->runner_l.tqe_prev = (nh)->runner_l.tqe_prev ; else (&nexthop_runners)->tqh_last = (nh)->runner_l .tqe_prev; *(nh)->runner_l.tqe_prev = (nh)->runner_l.tqe_next ; ; ; } while (0); | |||
| 1714 | ||||
| 1715 | p = nh->next_prefix; | |||
| 1716 | for (j = 0; p != NULL((void*)0) && j < RDE_RUNNER_ROUNDS100; j++) { | |||
| 1717 | prefix_evaluate_all(p, nh->state, nh->oldstate); | |||
| 1718 | p = LIST_NEXT(p, entry.list.nexthop)((p)->entry.list.nexthop.le_next); | |||
| 1719 | } | |||
| 1720 | ||||
| 1721 | /* prep for next run, if not finished readd to tail of queue */ | |||
| 1722 | nh->next_prefix = p; | |||
| 1723 | if (p != NULL((void*)0)) | |||
| 1724 | TAILQ_INSERT_TAIL(&nexthop_runners, nh, runner_l)do { (nh)->runner_l.tqe_next = ((void*)0); (nh)->runner_l .tqe_prev = (&nexthop_runners)->tqh_last; *(&nexthop_runners )->tqh_last = (nh); (&nexthop_runners)->tqh_last = & (nh)->runner_l.tqe_next; } while (0); | |||
| 1725 | else | |||
| 1726 | log_debug("nexthop %s update finished", | |||
| 1727 | log_addr(&nh->exit_nexthop)); | |||
| 1728 | } | |||
| 1729 | ||||
| 1730 | void | |||
| 1731 | nexthop_update(struct kroute_nexthop *msg) | |||
| 1732 | { | |||
| 1733 | struct nexthop *nh; | |||
| 1734 | ||||
| 1735 | nh = nexthop_lookup(&msg->nexthop); | |||
| 1736 | if (nh == NULL((void*)0)) { | |||
| 1737 | log_warnx("nexthop_update: non-existent nexthop %s", | |||
| 1738 | log_addr(&msg->nexthop)); | |||
| 1739 | return; | |||
| 1740 | } | |||
| 1741 | ||||
| 1742 | nh->oldstate = nh->state; | |||
| 1743 | if (msg->valid) | |||
| 1744 | nh->state = NEXTHOP_REACH; | |||
| 1745 | else | |||
| 1746 | nh->state = NEXTHOP_UNREACH; | |||
| 1747 | ||||
| 1748 | if (nh->oldstate == NEXTHOP_LOOKUP) | |||
| 1749 | /* drop reference which was hold during the lookup */ | |||
| 1750 | if (nexthop_unref(nh)) | |||
| 1751 | return; /* nh lost last ref, no work left */ | |||
| 1752 | ||||
| 1753 | if (nh->next_prefix) { | |||
| 1754 | /* | |||
| 1755 | * If nexthop_runner() is not finished with this nexthop | |||
| 1756 | * then ensure that all prefixes are updated by setting | |||
| 1757 | * the oldstate to NEXTHOP_FLAPPED. | |||
| 1758 | */ | |||
| 1759 | nh->oldstate = NEXTHOP_FLAPPED; | |||
| 1760 | TAILQ_REMOVE(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next) != ((void*)0)) (nh)-> runner_l.tqe_next->runner_l.tqe_prev = (nh)->runner_l.tqe_prev ; else (&nexthop_runners)->tqh_last = (nh)->runner_l .tqe_prev; *(nh)->runner_l.tqe_prev = (nh)->runner_l.tqe_next ; ; ; } while (0); | |||
| 1761 | } | |||
| 1762 | ||||
| 1763 | if (msg->connected) { | |||
| 1764 | nh->flags |= NEXTHOP_CONNECTED0x01; | |||
| 1765 | memcpy(&nh->true_nexthop, &nh->exit_nexthop, | |||
| 1766 | sizeof(nh->true_nexthop)); | |||
| 1767 | } else | |||
| 1768 | memcpy(&nh->true_nexthop, &msg->gateway, | |||
| 1769 | sizeof(nh->true_nexthop)); | |||
| 1770 | ||||
| 1771 | memcpy(&nh->nexthop_net, &msg->net, | |||
| 1772 | sizeof(nh->nexthop_net)); | |||
| 1773 | nh->nexthop_netlen = msg->netlen; | |||
| 1774 | ||||
| 1775 | nh->next_prefix = LIST_FIRST(&nh->prefix_h)((&nh->prefix_h)->lh_first); | |||
| 1776 | if (nh->next_prefix != NULL((void*)0)) { | |||
| 1777 | TAILQ_INSERT_HEAD(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next = (&nexthop_runners) ->tqh_first) != ((void*)0)) (&nexthop_runners)->tqh_first ->runner_l.tqe_prev = &(nh)->runner_l.tqe_next; else (&nexthop_runners)->tqh_last = &(nh)->runner_l .tqe_next; (&nexthop_runners)->tqh_first = (nh); (nh)-> runner_l.tqe_prev = &(&nexthop_runners)->tqh_first ; } while (0); | |||
| 1778 | log_debug("nexthop %s update starting", | |||
| 1779 | log_addr(&nh->exit_nexthop)); | |||
| 1780 | } | |||
| 1781 | } | |||
| 1782 | ||||
| 1783 | void | |||
| 1784 | nexthop_modify(struct nexthop *setnh, enum action_types type, u_int8_t aid, | |||
| 1785 | struct nexthop **nexthop, u_int8_t *flags) | |||
| 1786 | { | |||
| 1787 | switch (type) { | |||
| 1788 | case ACTION_SET_NEXTHOP_REJECT: | |||
| 1789 | *flags = NEXTHOP_REJECT0x02; | |||
| 1790 | break; | |||
| 1791 | case ACTION_SET_NEXTHOP_BLACKHOLE: | |||
| 1792 | *flags = NEXTHOP_BLACKHOLE0x04; | |||
| 1793 | break; | |||
| 1794 | case ACTION_SET_NEXTHOP_NOMODIFY: | |||
| 1795 | *flags = NEXTHOP_NOMODIFY0x08; | |||
| 1796 | break; | |||
| 1797 | case ACTION_SET_NEXTHOP_SELF: | |||
| 1798 | *flags = NEXTHOP_SELF0x01; | |||
| 1799 | break; | |||
| 1800 | case ACTION_SET_NEXTHOP_REF: | |||
| 1801 | /* | |||
| 1802 | * it is possible that a prefix matches but has the wrong | |||
| 1803 | * address family for the set nexthop. In this case ignore it. | |||
| 1804 | */ | |||
| 1805 | if (aid != setnh->exit_nexthop.aid) | |||
| 1806 | break; | |||
| 1807 | nexthop_unref(*nexthop); | |||
| 1808 | *nexthop = nexthop_ref(setnh); | |||
| 1809 | *flags = 0; | |||
| 1810 | break; | |||
| 1811 | default: | |||
| 1812 | break; | |||
| 1813 | } | |||
| 1814 | } | |||
| 1815 | ||||
| 1816 | void | |||
| 1817 | nexthop_link(struct prefix *p) | |||
| 1818 | { | |||
| 1819 | if (p->nexthop == NULL((void*)0)) | |||
| 1820 | return; | |||
| 1821 | ||||
| 1822 | /* no need to link prefixes in RIBs that have no decision process */ | |||
| 1823 | if (re_rib(prefix_re(p))->flags & F_RIB_NOEVALUATE0x0002) | |||
| 1824 | return; | |||
| 1825 | ||||
| 1826 | p->flags |= PREFIX_NEXTHOP_LINKED0x40; | |||
| 1827 | LIST_INSERT_HEAD(&p->nexthop->prefix_h, p, entry.list.nexthop)do { if (((p)->entry.list.nexthop.le_next = (&p->nexthop ->prefix_h)->lh_first) != ((void*)0)) (&p->nexthop ->prefix_h)->lh_first->entry.list.nexthop.le_prev = & (p)->entry.list.nexthop.le_next; (&p->nexthop->prefix_h )->lh_first = (p); (p)->entry.list.nexthop.le_prev = & (&p->nexthop->prefix_h)->lh_first; } while (0); | |||
| 1828 | } | |||
| 1829 | ||||
| 1830 | void | |||
| 1831 | nexthop_unlink(struct prefix *p) | |||
| 1832 | { | |||
| 1833 | if (p->nexthop == NULL((void*)0) || (p->flags & PREFIX_NEXTHOP_LINKED0x40) == 0) | |||
| 1834 | return; | |||
| 1835 | ||||
| 1836 | if (p == p->nexthop->next_prefix) { | |||
| 1837 | p->nexthop->next_prefix = LIST_NEXT(p, entry.list.nexthop)((p)->entry.list.nexthop.le_next); | |||
| 1838 | /* remove nexthop from list if no prefixes left to update */ | |||
| 1839 | if (p->nexthop->next_prefix == NULL((void*)0)) { | |||
| 1840 | TAILQ_REMOVE(&nexthop_runners, p->nexthop, runner_l)do { if (((p->nexthop)->runner_l.tqe_next) != ((void*)0 )) (p->nexthop)->runner_l.tqe_next->runner_l.tqe_prev = (p->nexthop)->runner_l.tqe_prev; else (&nexthop_runners )->tqh_last = (p->nexthop)->runner_l.tqe_prev; *(p-> nexthop)->runner_l.tqe_prev = (p->nexthop)->runner_l .tqe_next; ; ; } while (0); | |||
| 1841 | log_debug("nexthop %s update finished", | |||
| 1842 | log_addr(&p->nexthop->exit_nexthop)); | |||
| 1843 | } | |||
| 1844 | } | |||
| 1845 | ||||
| 1846 | p->flags &= ~PREFIX_NEXTHOP_LINKED0x40; | |||
| 1847 | LIST_REMOVE(p, entry.list.nexthop)do { if ((p)->entry.list.nexthop.le_next != ((void*)0)) (p )->entry.list.nexthop.le_next->entry.list.nexthop.le_prev = (p)->entry.list.nexthop.le_prev; *(p)->entry.list.nexthop .le_prev = (p)->entry.list.nexthop.le_next; ; ; } while (0 ); | |||
| 1848 | } | |||
| 1849 | ||||
| 1850 | struct nexthop * | |||
| 1851 | nexthop_get(struct bgpd_addr *nexthop) | |||
| 1852 | { | |||
| 1853 | struct nexthop *nh; | |||
| 1854 | ||||
| 1855 | nh = nexthop_lookup(nexthop); | |||
| 1856 | if (nh == NULL((void*)0)) { | |||
| 1857 | nh = calloc(1, sizeof(*nh)); | |||
| 1858 | if (nh == NULL((void*)0)) | |||
| 1859 | fatal("nexthop_alloc"); | |||
| 1860 | rdemem.nexthop_cnt++; | |||
| 1861 | ||||
| 1862 | LIST_INIT(&nh->prefix_h)do { ((&nh->prefix_h)->lh_first) = ((void*)0); } while (0); | |||
| 1863 | nh->state = NEXTHOP_LOOKUP; | |||
| 1864 | nexthop_ref(nh); /* take reference for lookup */ | |||
| 1865 | nh->exit_nexthop = *nexthop; | |||
| 1866 | LIST_INSERT_HEAD(nexthop_hash(nexthop), nh,do { if (((nh)->nexthop_l.le_next = (nexthop_hash(nexthop) )->lh_first) != ((void*)0)) (nexthop_hash(nexthop))->lh_first ->nexthop_l.le_prev = &(nh)->nexthop_l.le_next; (nexthop_hash (nexthop))->lh_first = (nh); (nh)->nexthop_l.le_prev = & (nexthop_hash(nexthop))->lh_first; } while (0) | |||
| 1867 | nexthop_l)do { if (((nh)->nexthop_l.le_next = (nexthop_hash(nexthop) )->lh_first) != ((void*)0)) (nexthop_hash(nexthop))->lh_first ->nexthop_l.le_prev = &(nh)->nexthop_l.le_next; (nexthop_hash (nexthop))->lh_first = (nh); (nh)->nexthop_l.le_prev = & (nexthop_hash(nexthop))->lh_first; } while (0); | |||
| 1868 | ||||
| 1869 | rde_send_nexthop(&nh->exit_nexthop, 1); | |||
| 1870 | } | |||
| 1871 | ||||
| 1872 | return nexthop_ref(nh); | |||
| 1873 | } | |||
| 1874 | ||||
| 1875 | struct nexthop * | |||
| 1876 | nexthop_ref(struct nexthop *nexthop) | |||
| 1877 | { | |||
| 1878 | if (nexthop) | |||
| 1879 | nexthop->refcnt++; | |||
| 1880 | return (nexthop); | |||
| 1881 | } | |||
| 1882 | ||||
| 1883 | int | |||
| 1884 | nexthop_unref(struct nexthop *nh) | |||
| 1885 | { | |||
| 1886 | if (nh == NULL((void*)0)) | |||
| 1887 | return (0); | |||
| 1888 | if (--nh->refcnt > 0) | |||
| 1889 | return (0); | |||
| 1890 | ||||
| 1891 | /* sanity check */ | |||
| 1892 | if (!LIST_EMPTY(&nh->prefix_h)(((&nh->prefix_h)->lh_first) == ((void*)0)) || nh->state == NEXTHOP_LOOKUP) | |||
| 1893 | fatalx("%s: refcnt error", __func__); | |||
| 1894 | ||||
| 1895 | /* is nexthop update running? impossible, that is a refcnt error */ | |||
| 1896 | if (nh->next_prefix) | |||
| 1897 | fatalx("%s: next_prefix not NULL", __func__); | |||
| 1898 | ||||
| 1899 | LIST_REMOVE(nh, nexthop_l)do { if ((nh)->nexthop_l.le_next != ((void*)0)) (nh)->nexthop_l .le_next->nexthop_l.le_prev = (nh)->nexthop_l.le_prev; * (nh)->nexthop_l.le_prev = (nh)->nexthop_l.le_next; ; ; } while (0); | |||
| 1900 | rde_send_nexthop(&nh->exit_nexthop, 0); | |||
| 1901 | ||||
| 1902 | rdemem.nexthop_cnt--; | |||
| 1903 | free(nh); | |||
| 1904 | return (1); | |||
| 1905 | } | |||
| 1906 | ||||
| 1907 | int | |||
| 1908 | nexthop_compare(struct nexthop *na, struct nexthop *nb) | |||
| 1909 | { | |||
| 1910 | struct bgpd_addr *a, *b; | |||
| 1911 | ||||
| 1912 | if (na == nb) | |||
| 1913 | return (0); | |||
| 1914 | if (na == NULL((void*)0)) | |||
| 1915 | return (-1); | |||
| 1916 | if (nb == NULL((void*)0)) | |||
| 1917 | return (1); | |||
| 1918 | ||||
| 1919 | a = &na->exit_nexthop; | |||
| 1920 | b = &nb->exit_nexthop; | |||
| 1921 | ||||
| 1922 | if (a->aid != b->aid) | |||
| 1923 | return (a->aid - b->aid); | |||
| 1924 | ||||
| 1925 | switch (a->aid) { | |||
| 1926 | case AID_INET1: | |||
| 1927 | if (ntohl(a->v4.s_addr)(__uint32_t)(__builtin_constant_p(a->ba.v4.s_addr) ? (__uint32_t )(((__uint32_t)(a->ba.v4.s_addr) & 0xff) << 24 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff00) << 8 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff000000) >> 24) : __swap32md(a->ba.v4.s_addr)) > ntohl(b->v4.s_addr)(__uint32_t)(__builtin_constant_p(b->ba.v4.s_addr) ? (__uint32_t )(((__uint32_t)(b->ba.v4.s_addr) & 0xff) << 24 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff00) << 8 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff000000) >> 24) : __swap32md(b->ba.v4.s_addr))) | |||
| 1928 | return (1); | |||
| 1929 | if (ntohl(a->v4.s_addr)(__uint32_t)(__builtin_constant_p(a->ba.v4.s_addr) ? (__uint32_t )(((__uint32_t)(a->ba.v4.s_addr) & 0xff) << 24 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff00) << 8 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(a->ba.v4.s_addr) & 0xff000000) >> 24) : __swap32md(a->ba.v4.s_addr)) < ntohl(b->v4.s_addr)(__uint32_t)(__builtin_constant_p(b->ba.v4.s_addr) ? (__uint32_t )(((__uint32_t)(b->ba.v4.s_addr) & 0xff) << 24 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff00) << 8 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(b->ba.v4.s_addr) & 0xff000000) >> 24) : __swap32md(b->ba.v4.s_addr))) | |||
| 1930 | return (-1); | |||
| 1931 | return (0); | |||
| 1932 | case AID_INET62: | |||
| 1933 | return (memcmp(&a->v6ba.v6, &b->v6ba.v6, sizeof(struct in6_addr))); | |||
| 1934 | default: | |||
| 1935 | fatalx("nexthop_cmp: unknown af"); | |||
| 1936 | } | |||
| 1937 | return (-1); | |||
| 1938 | } | |||
| 1939 | ||||
| 1940 | struct nexthop * | |||
| 1941 | nexthop_lookup(struct bgpd_addr *nexthop) | |||
| 1942 | { | |||
| 1943 | struct nexthop *nh; | |||
| 1944 | ||||
| 1945 | LIST_FOREACH(nh, nexthop_hash(nexthop), nexthop_l)for((nh) = ((nexthop_hash(nexthop))->lh_first); (nh)!= ((void *)0); (nh) = ((nh)->nexthop_l.le_next)) { | |||
| 1946 | if (memcmp(&nh->exit_nexthop, nexthop, | |||
| 1947 | sizeof(struct bgpd_addr)) == 0) | |||
| 1948 | return (nh); | |||
| 1949 | } | |||
| 1950 | return (NULL((void*)0)); | |||
| 1951 | } | |||
| 1952 | ||||
| 1953 | struct nexthop_head * | |||
| 1954 | nexthop_hash(struct bgpd_addr *nexthop) | |||
| 1955 | { | |||
| 1956 | u_int32_t h = 0; | |||
| 1957 | ||||
| 1958 | switch (nexthop->aid) { | |||
| 1959 | case AID_INET1: | |||
| 1960 | h = SipHash24(&nexthoptablekey, &nexthop->v4.s_addr,SipHash((&nexthoptablekey), 2, 4, (&nexthop->ba.v4 .s_addr), (sizeof(nexthop->ba.v4.s_addr))) | |||
| 1961 | sizeof(nexthop->v4.s_addr))SipHash((&nexthoptablekey), 2, 4, (&nexthop->ba.v4 .s_addr), (sizeof(nexthop->ba.v4.s_addr))); | |||
| 1962 | break; | |||
| 1963 | case AID_INET62: | |||
| 1964 | h = SipHash24(&nexthoptablekey, &nexthop->v6,SipHash((&nexthoptablekey), 2, 4, (&nexthop->ba.v6 ), (sizeof(struct in6_addr))) | |||
| 1965 | sizeof(struct in6_addr))SipHash((&nexthoptablekey), 2, 4, (&nexthop->ba.v6 ), (sizeof(struct in6_addr))); | |||
| 1966 | break; | |||
| 1967 | default: | |||
| 1968 | fatalx("nexthop_hash: unsupported AID %d", nexthop->aid); | |||
| 1969 | } | |||
| 1970 | return (&nexthoptable.nexthop_hashtbl[h & nexthoptable.nexthop_hashmask]); | |||
| 1971 | } |