File: | src/usr.sbin/ldpd/kroute.c |
Warning: | line 515, column 7 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: kroute.c,v 1.71 2023/03/08 04:43:13 guenther Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2015, 2016 Renato Westphal <renato@openbsd.org> | |||
5 | * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> | |||
6 | * Copyright (c) 2004 Esben Norby <norby@openbsd.org> | |||
7 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||
8 | * | |||
9 | * Permission to use, copy, modify, and distribute this software for any | |||
10 | * purpose with or without fee is hereby granted, provided that the above | |||
11 | * copyright notice and this permission notice appear in all copies. | |||
12 | * | |||
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
20 | */ | |||
21 | ||||
22 | #include <sys/types.h> | |||
23 | #include <sys/socket.h> | |||
24 | #include <sys/ioctl.h> | |||
25 | #include <sys/sysctl.h> | |||
26 | #include <arpa/inet.h> | |||
27 | #include <net/if_dl.h> | |||
28 | #include <net/if_types.h> | |||
29 | #include <net/route.h> | |||
30 | #include <netmpls/mpls.h> | |||
31 | #include <errno(*__errno()).h> | |||
32 | #include <stdlib.h> | |||
33 | #include <string.h> | |||
34 | #include <unistd.h> | |||
35 | #include <limits.h> | |||
36 | ||||
37 | #include "ldpd.h" | |||
38 | #include "log.h" | |||
39 | ||||
40 | struct { | |||
41 | uint32_t rtseq; | |||
42 | pid_t pid; | |||
43 | int fib_sync; | |||
44 | int fd; | |||
45 | int ioctl_fd; | |||
46 | struct event ev; | |||
47 | unsigned int rdomain; | |||
48 | } kr_state; | |||
49 | ||||
50 | struct kroute_node { | |||
51 | TAILQ_ENTRY(kroute_node)struct { struct kroute_node *tqe_next; struct kroute_node **tqe_prev ; } entry; | |||
52 | struct kroute_priority *kprio; /* back pointer */ | |||
53 | struct kroute r; | |||
54 | }; | |||
55 | ||||
56 | struct kroute_priority { | |||
57 | TAILQ_ENTRY(kroute_priority)struct { struct kroute_priority *tqe_next; struct kroute_priority **tqe_prev; } entry; | |||
58 | struct kroute_prefix *kp; /* back pointer */ | |||
59 | uint8_t priority; | |||
60 | TAILQ_HEAD(, kroute_node)struct { struct kroute_node *tqh_first; struct kroute_node ** tqh_last; } nexthops; | |||
61 | }; | |||
62 | ||||
63 | struct kroute_prefix { | |||
64 | RB_ENTRY(kroute_prefix)struct { struct kroute_prefix *rbe_left; struct kroute_prefix *rbe_right; struct kroute_prefix *rbe_parent; int rbe_color; } entry; | |||
65 | int af; | |||
66 | union ldpd_addr prefix; | |||
67 | uint8_t prefixlen; | |||
68 | TAILQ_HEAD(plist, kroute_priority)struct plist { struct kroute_priority *tqh_first; struct kroute_priority **tqh_last; } priorities; | |||
69 | }; | |||
70 | RB_HEAD(kroute_tree, kroute_prefix)struct kroute_tree { struct kroute_prefix *rbh_root; }; | |||
71 | RB_PROTOTYPE(kroute_tree, kroute_prefix, entry, kroute_compare)void kroute_tree_RB_INSERT_COLOR(struct kroute_tree *, struct kroute_prefix *); void kroute_tree_RB_REMOVE_COLOR(struct kroute_tree *, struct kroute_prefix *, struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_REMOVE(struct kroute_tree *, struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_INSERT(struct kroute_tree *, struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_FIND (struct kroute_tree *, struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_NFIND(struct kroute_tree *, struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_NEXT(struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_PREV(struct kroute_prefix *); struct kroute_prefix *kroute_tree_RB_MINMAX(struct kroute_tree *, int); | |||
72 | ||||
73 | struct kif_addr { | |||
74 | TAILQ_ENTRY(kif_addr)struct { struct kif_addr *tqe_next; struct kif_addr **tqe_prev ; } entry; | |||
75 | struct kaddr a; | |||
76 | }; | |||
77 | ||||
78 | struct kif_node { | |||
79 | RB_ENTRY(kif_node)struct { struct kif_node *rbe_left; struct kif_node *rbe_right ; struct kif_node *rbe_parent; int rbe_color; } entry; | |||
80 | TAILQ_HEAD(, kif_addr)struct { struct kif_addr *tqh_first; struct kif_addr **tqh_last ; } addrs; | |||
81 | struct kif k; | |||
82 | struct kpw *kpw; | |||
83 | }; | |||
84 | RB_HEAD(kif_tree, kif_node)struct kif_tree { struct kif_node *rbh_root; }; | |||
85 | RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)void kif_tree_RB_INSERT_COLOR(struct kif_tree *, struct kif_node *); void kif_tree_RB_REMOVE_COLOR(struct kif_tree *, struct kif_node *, struct kif_node *); struct kif_node *kif_tree_RB_REMOVE(struct kif_tree *, struct kif_node *); struct kif_node *kif_tree_RB_INSERT (struct kif_tree *, struct kif_node *); struct kif_node *kif_tree_RB_FIND (struct kif_tree *, struct kif_node *); struct kif_node *kif_tree_RB_NFIND (struct kif_tree *, struct kif_node *); struct kif_node *kif_tree_RB_NEXT (struct kif_node *); struct kif_node *kif_tree_RB_PREV(struct kif_node *); struct kif_node *kif_tree_RB_MINMAX(struct kif_tree *, int); | |||
86 | ||||
87 | static void kr_dispatch_msg(int, short, void *); | |||
88 | static void kr_redist_remove(struct kroute *); | |||
89 | static int kr_redist_eval(struct kroute *); | |||
90 | static void kr_redistribute(struct kroute_prefix *); | |||
91 | static __inline int kroute_compare(struct kroute_prefix *, | |||
92 | struct kroute_prefix *); | |||
93 | static struct kroute_prefix *kroute_find_prefix(int, union ldpd_addr *, | |||
94 | uint8_t); | |||
95 | static struct kroute_priority *kroute_find_prio(struct kroute_prefix *, | |||
96 | uint8_t); | |||
97 | static struct kroute_node *kroute_find_gw(struct kroute_priority *, | |||
98 | union ldpd_addr *); | |||
99 | static int kroute_insert(struct kroute *); | |||
100 | static int kroute_uninstall(struct kroute_node *); | |||
101 | static int kroute_remove(struct kroute *); | |||
102 | static void kroute_clear(void); | |||
103 | static __inline int kif_compare(struct kif_node *, struct kif_node *); | |||
104 | static struct kif_node *kif_find(unsigned short); | |||
105 | static struct kif_node *kif_insert(unsigned short); | |||
106 | static int kif_remove(struct kif_node *); | |||
107 | static struct kif_node *kif_update(unsigned short, int, struct if_data *, | |||
108 | struct sockaddr_dl *, int *); | |||
109 | static struct kroute_priority *kroute_match(int, union ldpd_addr *); | |||
110 | static uint8_t prefixlen_classful(in_addr_t); | |||
111 | static void get_rtaddrs(int, struct sockaddr *, | |||
112 | struct sockaddr **); | |||
113 | static void if_change(unsigned short, int, struct if_data *, | |||
114 | struct sockaddr_dl *); | |||
115 | static void if_newaddr(unsigned short, struct sockaddr *, | |||
116 | struct sockaddr *, struct sockaddr *); | |||
117 | static void if_deladdr(unsigned short, struct sockaddr *, | |||
118 | struct sockaddr *, struct sockaddr *); | |||
119 | static void if_announce(void *); | |||
120 | static int send_rtmsg(int, int, struct kroute *, int); | |||
121 | static int send_rtmsg_v4(int fd, int, struct kroute *, int); | |||
122 | static int send_rtmsg_v6(int fd, int, struct kroute *, int); | |||
123 | static int fetchtable(void); | |||
124 | static int fetchifs(void); | |||
125 | static int dispatch_rtmsg(void); | |||
126 | static int rtmsg_process(char *, size_t); | |||
127 | static int rtmsg_process_route(struct rt_msghdr *, | |||
128 | struct sockaddr *[RTAX_MAX15]); | |||
129 | static int kmpw_install(const char *, struct kpw *); | |||
130 | static int kmpw_uninstall(const char *); | |||
131 | ||||
132 | RB_GENERATE(kroute_tree, kroute_prefix, entry, kroute_compare)void kroute_tree_RB_INSERT_COLOR(struct kroute_tree *head, struct kroute_prefix *elm) { struct kroute_prefix *parent, *gparent , *tmp; while ((parent = (elm)->entry.rbe_parent) && (parent)->entry.rbe_color == 1) { gparent = (parent)-> entry.rbe_parent; if (parent == (gparent)->entry.rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp && (tmp )->entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> entry.rbe_right == elm) { do { (tmp) = (parent)->entry.rbe_right ; if (((parent)->entry.rbe_right = (tmp)->entry.rbe_left )) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)-> entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->entry.rbe_left; if (tmp && (tmp)-> entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { ( parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left ; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right )) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)-> entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } } (head-> rbh_root)->entry.rbe_color = 0; } void kroute_tree_RB_REMOVE_COLOR (struct kroute_tree *head, struct kroute_prefix *parent, struct kroute_prefix *elm) { struct kroute_prefix *tmp; while ((elm == ((void *)0) || (elm)->entry.rbe_color == 0) && elm != (head)->rbh_root) { if ((parent)->entry.rbe_left == elm) { tmp = (parent)->entry.rbe_right; if ((tmp)-> entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; ( parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent )->entry.rbe_right; if (((parent)->entry.rbe_right = (tmp )->entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->entry .rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent )->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent )->entry.rbe_parent)->entry.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent ); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp )->entry.rbe_color = 1; elm = parent; parent = (elm)->entry .rbe_parent; } else { if ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0 ) { struct kroute_prefix *oleft; if ((oleft = (tmp)->entry .rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry. rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if (( (tmp)->entry.rbe_left = (oleft)->entry.rbe_right)) { (( oleft)->entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->entry.rbe_parent = (tmp)-> entry.rbe_parent)) { if ((tmp) == ((tmp)->entry.rbe_parent )->entry.rbe_left) ((tmp)->entry.rbe_parent)->entry. rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right ; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right ) ((tmp)->entry.rbe_right)->entry.rbe_color = 0; do { ( tmp) = (parent)->entry.rbe_right; if (((parent)->entry. rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left )->entry.rbe_parent = (parent); } do {} while (0); if (((tmp )->entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left ) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = ( tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent )->entry.rbe_left; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left ; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)-> entry.rbe_left)->entry.rbe_color == 0) && ((tmp)-> entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right) ->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry.rbe_parent; } else { if ( (tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left )->entry.rbe_color == 0) { struct kroute_prefix *oright; if ((oright = (tmp)->entry.rbe_right)) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)-> entry.rbe_right; if (((tmp)->entry.rbe_right = (oright)-> entry.rbe_left)) { ((oright)->entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while (0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry .rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent) ->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent )->entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->entry.rbe_left = (tmp); (tmp)->entry .rbe_parent = (oright); do {} while (0); if (((oright)->entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> entry.rbe_left; } (tmp)->entry.rbe_color = (parent)->entry .rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry .rbe_left) ((tmp)->entry.rbe_left)->entry.rbe_color = 0 ; do { (tmp) = (parent)->entry.rbe_left; if (((parent)-> entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry .rbe_right)->entry.rbe_parent = (parent); } do {} while (0 ); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_right = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry.rbe_color = 0; } struct kroute_prefix * kroute_tree_RB_REMOVE(struct kroute_tree *head, struct kroute_prefix *elm) { struct kroute_prefix *child, *parent, *old = elm; int color; if ((elm)->entry.rbe_left == ((void *)0)) child = ( elm)->entry.rbe_right; else if ((elm)->entry.rbe_right == ((void *)0)) child = (elm)->entry.rbe_left; else { struct kroute_prefix *left; elm = (elm)->entry.rbe_right; while ( (left = (elm)->entry.rbe_left)) elm = left; child = (elm)-> entry.rbe_right; parent = (elm)->entry.rbe_parent; color = (elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left == elm ) (parent)->entry.rbe_left = child; else (parent)->entry .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->entry.rbe_parent == old) parent = elm ; (elm)->entry = (old)->entry; if ((old)->entry.rbe_parent ) { if (((old)->entry.rbe_parent)->entry.rbe_left == old ) ((old)->entry.rbe_parent)->entry.rbe_left = elm; else ((old)->entry.rbe_parent)->entry.rbe_right = elm; do { } while (0); } else (head)->rbh_root = elm; ((old)->entry .rbe_left)->entry.rbe_parent = elm; if ((old)->entry.rbe_right ) ((old)->entry.rbe_right)->entry.rbe_parent = elm; if ( parent) { left = parent; do { do {} while (0); } while ((left = (left)->entry.rbe_parent)); } goto color; } parent = (elm )->entry.rbe_parent; color = (elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left == elm) (parent)->entry.rbe_left = child; else (parent)->entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) kroute_tree_RB_REMOVE_COLOR(head, parent, child); return ( old); } struct kroute_prefix * kroute_tree_RB_INSERT(struct kroute_tree *head, struct kroute_prefix *elm) { struct kroute_prefix *tmp ; struct kroute_prefix *parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (kroute_compare )(elm, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left ; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm )->entry.rbe_left = (elm)->entry.rbe_right = ((void *)0 ); (elm)->entry.rbe_color = 1; } while (0); if (parent != ( (void *)0)) { if (comp < 0) (parent)->entry.rbe_left = elm ; else (parent)->entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; kroute_tree_RB_INSERT_COLOR( head, elm); return (((void *)0)); } struct kroute_prefix * kroute_tree_RB_FIND (struct kroute_tree *head, struct kroute_prefix *elm) { struct kroute_prefix *tmp = (head)->rbh_root; int comp; while (tmp ) { comp = kroute_compare(elm, tmp); if (comp < 0) tmp = ( tmp)->entry.rbe_left; else if (comp > 0) tmp = (tmp)-> entry.rbe_right; else return (tmp); } return (((void *)0)); } struct kroute_prefix * kroute_tree_RB_NFIND(struct kroute_tree *head, struct kroute_prefix *elm) { struct kroute_prefix *tmp = (head)->rbh_root; struct kroute_prefix *res = ((void *) 0); int comp; while (tmp) { comp = kroute_compare(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry.rbe_left; } else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } return (res); } struct kroute_prefix * kroute_tree_RB_NEXT (struct kroute_prefix *elm) { if ((elm)->entry.rbe_right) { elm = (elm)->entry.rbe_right; while ((elm)->entry.rbe_left ) elm = (elm)->entry.rbe_left; } else { if ((elm)->entry .rbe_parent && (elm == ((elm)->entry.rbe_parent)-> entry.rbe_left)) elm = (elm)->entry.rbe_parent; else { while ((elm)->entry.rbe_parent && (elm == ((elm)->entry .rbe_parent)->entry.rbe_right)) elm = (elm)->entry.rbe_parent ; elm = (elm)->entry.rbe_parent; } } return (elm); } struct kroute_prefix * kroute_tree_RB_PREV(struct kroute_prefix *elm ) { if ((elm)->entry.rbe_left) { elm = (elm)->entry.rbe_left ; while ((elm)->entry.rbe_right) elm = (elm)->entry.rbe_right ; } else { if ((elm)->entry.rbe_parent && (elm == ( (elm)->entry.rbe_parent)->entry.rbe_right)) elm = (elm) ->entry.rbe_parent; else { while ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_left )) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent ; } } return (elm); } struct kroute_prefix * kroute_tree_RB_MINMAX (struct kroute_tree *head, int val) { struct kroute_prefix *tmp = (head)->rbh_root; struct kroute_prefix *parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp )->entry.rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent); } | |||
133 | RB_GENERATE(kif_tree, kif_node, entry, kif_compare)void kif_tree_RB_INSERT_COLOR(struct kif_tree *head, struct kif_node *elm) { struct kif_node *parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent) && (parent)->entry. rbe_color == 1) { gparent = (parent)->entry.rbe_parent; if (parent == (gparent)->entry.rbe_left) { tmp = (gparent)-> entry.rbe_right; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (parent)->entry .rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0 ); elm = gparent; continue; } if ((parent)->entry.rbe_right == elm) { do { (tmp) = (parent)->entry.rbe_right; if (((parent )->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)-> entry.rbe_left)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while ( 0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)->entry.rbe_right )) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent )->entry.rbe_parent)) { if ((gparent) == ((gparent)->entry .rbe_parent)->entry.rbe_left) ((gparent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((gparent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (gparent); (gparent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); } else { tmp = (gparent)-> entry.rbe_left; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (parent)->entry. rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0) ; elm = gparent; continue; } if ((parent)->entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left; if (((parent )->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)-> entry.rbe_right)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_right = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->entry.rbe_right ; if (((gparent)->entry.rbe_right = (tmp)->entry.rbe_left )) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent )->entry.rbe_parent)) { if ((gparent) == ((gparent)->entry .rbe_parent)->entry.rbe_left) ((gparent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((gparent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_left = (gparent); (gparent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); } } (head->rbh_root)-> entry.rbe_color = 0; } void kif_tree_RB_REMOVE_COLOR(struct kif_tree *head, struct kif_node *parent, struct kif_node *elm) { struct kif_node *tmp; while ((elm == ((void *)0) || (elm)->entry .rbe_color == 0) && elm != (head)->rbh_root) { if ( (parent)->entry.rbe_left == elm) { tmp = (parent)->entry .rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)-> entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.rbe_right; if (((parent )->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)-> entry.rbe_left)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while ( 0); } while (0); tmp = (parent)->entry.rbe_right; } if ((( tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left )->entry.rbe_color == 0) && ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry.rbe_parent; } else { if ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0) { struct kif_node *oleft; if ((oleft = (tmp)->entry .rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry. rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if (( (tmp)->entry.rbe_left = (oleft)->entry.rbe_right)) { (( oleft)->entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->entry.rbe_parent = (tmp)-> entry.rbe_parent)) { if ((tmp) == ((tmp)->entry.rbe_parent )->entry.rbe_left) ((tmp)->entry.rbe_parent)->entry. rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right ; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right ) ((tmp)->entry.rbe_right)->entry.rbe_color = 0; do { ( tmp) = (parent)->entry.rbe_right; if (((parent)->entry. rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left )->entry.rbe_parent = (parent); } do {} while (0); if (((tmp )->entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left ) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = ( tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent )->entry.rbe_left; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left ; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)-> entry.rbe_left)->entry.rbe_color == 0) && ((tmp)-> entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right) ->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry.rbe_parent; } else { if ( (tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left )->entry.rbe_color == 0) { struct kif_node *oright; if ((oright = (tmp)->entry.rbe_right)) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)-> entry.rbe_right; if (((tmp)->entry.rbe_right = (oright)-> entry.rbe_left)) { ((oright)->entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while (0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry .rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent) ->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent )->entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->entry.rbe_left = (tmp); (tmp)->entry .rbe_parent = (oright); do {} while (0); if (((oright)->entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> entry.rbe_left; } (tmp)->entry.rbe_color = (parent)->entry .rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry .rbe_left) ((tmp)->entry.rbe_left)->entry.rbe_color = 0 ; do { (tmp) = (parent)->entry.rbe_left; if (((parent)-> entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry .rbe_right)->entry.rbe_parent = (parent); } do {} while (0 ); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent )) { if ((parent) == ((parent)->entry.rbe_parent)->entry .rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry .rbe_right = (parent); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry.rbe_color = 0; } struct kif_node * kif_tree_RB_REMOVE (struct kif_tree *head, struct kif_node *elm) { struct kif_node *child, *parent, *old = elm; int color; if ((elm)->entry. rbe_left == ((void *)0)) child = (elm)->entry.rbe_right; else if ((elm)->entry.rbe_right == ((void *)0)) child = (elm)-> entry.rbe_left; else { struct kif_node *left; elm = (elm)-> entry.rbe_right; while ((left = (elm)->entry.rbe_left)) elm = left; child = (elm)->entry.rbe_right; parent = (elm)-> entry.rbe_parent; color = (elm)->entry.rbe_color; if (child ) (child)->entry.rbe_parent = parent; if (parent) { if ((parent )->entry.rbe_left == elm) (parent)->entry.rbe_left = child ; else (parent)->entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)->entry.rbe_parent == old) parent = elm; (elm)->entry = (old)->entry; if ( (old)->entry.rbe_parent) { if (((old)->entry.rbe_parent )->entry.rbe_left == old) ((old)->entry.rbe_parent)-> entry.rbe_left = elm; else ((old)->entry.rbe_parent)->entry .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->entry.rbe_left)->entry.rbe_parent = elm ; if ((old)->entry.rbe_right) ((old)->entry.rbe_right)-> entry.rbe_parent = elm; if (parent) { left = parent; do { do { } while (0); } while ((left = (left)->entry.rbe_parent)); } goto color; } parent = (elm)->entry.rbe_parent; color = ( elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left == elm ) (parent)->entry.rbe_left = child; else (parent)->entry .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) kif_tree_RB_REMOVE_COLOR(head , parent, child); return (old); } struct kif_node * kif_tree_RB_INSERT (struct kif_tree *head, struct kif_node *elm) { struct kif_node *tmp; struct kif_node *parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (kif_compare )(elm, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left ; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm )->entry.rbe_left = (elm)->entry.rbe_right = ((void *)0 ); (elm)->entry.rbe_color = 1; } while (0); if (parent != ( (void *)0)) { if (comp < 0) (parent)->entry.rbe_left = elm ; else (parent)->entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; kif_tree_RB_INSERT_COLOR(head , elm); return (((void *)0)); } struct kif_node * kif_tree_RB_FIND (struct kif_tree *head, struct kif_node *elm) { struct kif_node *tmp = (head)->rbh_root; int comp; while (tmp) { comp = kif_compare (elm, tmp); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } return (((void *)0)); } struct kif_node * kif_tree_RB_NFIND (struct kif_tree *head, struct kif_node *elm) { struct kif_node *tmp = (head)->rbh_root; struct kif_node *res = ((void *) 0); int comp; while (tmp) { comp = kif_compare(elm, tmp); if ( comp < 0) { res = tmp; tmp = (tmp)->entry.rbe_left; } else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } return (res); } struct kif_node * kif_tree_RB_NEXT( struct kif_node *elm) { if ((elm)->entry.rbe_right) { elm = (elm)->entry.rbe_right; while ((elm)->entry.rbe_left) elm = (elm)->entry.rbe_left; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_left )) elm = (elm)->entry.rbe_parent; else { while ((elm)-> entry.rbe_parent && (elm == ((elm)->entry.rbe_parent )->entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent; } } return (elm); } struct kif_node * kif_tree_RB_PREV(struct kif_node *elm) { if ((elm)->entry .rbe_left) { elm = (elm)->entry.rbe_left; while ((elm)-> entry.rbe_right) elm = (elm)->entry.rbe_right; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry .rbe_parent)->entry.rbe_right)) elm = (elm)->entry.rbe_parent ; else { while ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_left)) elm = (elm )->entry.rbe_parent; elm = (elm)->entry.rbe_parent; } } return (elm); } struct kif_node * kif_tree_RB_MINMAX(struct kif_tree *head, int val) { struct kif_node *tmp = (head)->rbh_root ; struct kif_node *parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry.rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent); } | |||
134 | ||||
135 | static struct kroute_tree krt = RB_INITIALIZER(&krt){ ((void *)0) }; | |||
136 | static struct kif_tree kit = RB_INITIALIZER(&kit){ ((void *)0) }; | |||
137 | ||||
138 | int | |||
139 | kif_init(void) | |||
140 | { | |||
141 | if (fetchifs() == -1) | |||
142 | return (-1); | |||
143 | ||||
144 | if ((kr_state.ioctl_fd = socket(AF_INET2, | |||
145 | SOCK_DGRAM2 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, 0)) == -1) { | |||
146 | log_warn("%s: ioctl socket", __func__); | |||
147 | return (-1); | |||
148 | } | |||
149 | ||||
150 | return (0); | |||
151 | } | |||
152 | ||||
153 | int | |||
154 | kr_init(int fs, unsigned int rdomain) | |||
155 | { | |||
156 | int opt = 0, rcvbuf, default_rcvbuf; | |||
157 | socklen_t optlen; | |||
158 | unsigned int rtfilter; | |||
159 | ||||
160 | kr_state.fib_sync = fs; | |||
161 | kr_state.rdomain = rdomain; | |||
162 | ||||
163 | if ((kr_state.fd = socket(AF_ROUTE17, | |||
164 | SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, 0)) == -1) { | |||
165 | log_warn("%s: socket", __func__); | |||
166 | return (-1); | |||
167 | } | |||
168 | ||||
169 | /* not interested in my own messages */ | |||
170 | if (setsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_USELOOPBACK0x0040, | |||
171 | &opt, sizeof(opt)) == -1) | |||
172 | log_warn("%s: setsockopt(SO_USELOOPBACK)", __func__); | |||
173 | ||||
174 | /* filter out unwanted messages */ | |||
175 | rtfilter = ROUTE_FILTER(RTM_ADD)(1 << (0x1)) | ROUTE_FILTER(RTM_GET)(1 << (0x4)) | | |||
176 | ROUTE_FILTER(RTM_CHANGE)(1 << (0x3)) | ROUTE_FILTER(RTM_DELETE)(1 << (0x2)) | | |||
177 | ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc)) | | |||
178 | ROUTE_FILTER(RTM_DELADDR)(1 << (0xd)) | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf)); | |||
179 | ||||
180 | if (setsockopt(kr_state.fd, AF_ROUTE17, ROUTE_MSGFILTER1, | |||
181 | &rtfilter, sizeof(rtfilter)) == -1) | |||
182 | log_warn("%s: setsockopt(ROUTE_MSGFILTER)", __func__); | |||
183 | ||||
184 | /* grow receive buffer, don't wanna miss messages */ | |||
185 | optlen = sizeof(default_rcvbuf); | |||
186 | if (getsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002, | |||
187 | &default_rcvbuf, &optlen) == -1) | |||
188 | log_warn("%s: getsockopt SOL_SOCKET SO_RCVBUF", __func__); | |||
189 | else | |||
190 | for (rcvbuf = MAX_RTSOCK_BUF(2 * 1024 * 1024); | |||
191 | rcvbuf > default_rcvbuf && | |||
192 | setsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002, | |||
193 | &rcvbuf, sizeof(rcvbuf)) == -1 && errno(*__errno()) == ENOBUFS55; | |||
194 | rcvbuf /= 2) | |||
195 | ; /* nothing */ | |||
196 | ||||
197 | kr_state.pid = getpid(); | |||
198 | kr_state.rtseq = 1; | |||
199 | ||||
200 | if (fetchtable() == -1) | |||
201 | return (-1); | |||
202 | ||||
203 | event_set(&kr_state.ev, kr_state.fd, EV_READ0x02 | EV_PERSIST0x10, | |||
204 | kr_dispatch_msg, NULL((void *)0)); | |||
205 | event_add(&kr_state.ev, NULL((void *)0)); | |||
206 | ||||
207 | return (0); | |||
208 | } | |||
209 | ||||
210 | void | |||
211 | kif_redistribute(const char *ifname) | |||
212 | { | |||
213 | struct kif_node *kif; | |||
214 | struct kif_addr *ka; | |||
215 | ||||
216 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) { | |||
217 | if (kif->k.rdomain != kr_state.rdomain) | |||
218 | continue; | |||
219 | ||||
220 | if (ifname && strcmp(kif->k.ifname, ifname) != 0) | |||
221 | continue; | |||
222 | ||||
223 | TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void *)0); (ka) = ((ka)->entry.tqe_next)) | |||
224 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->a, | |||
225 | sizeof(ka->a)); | |||
226 | } | |||
227 | } | |||
228 | ||||
229 | int | |||
230 | kr_change(struct kroute *kr) | |||
231 | { | |||
232 | struct kroute_prefix *kp; | |||
233 | struct kroute_priority *kprio; | |||
234 | struct kroute_node *kn; | |||
235 | int action = RTM_ADD0x1; | |||
236 | ||||
237 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
238 | if (kp == NULL((void *)0)) | |||
239 | goto miss; | |||
240 | ||||
241 | kprio = kroute_find_prio(kp, kr->priority); | |||
242 | if (kprio == NULL((void *)0)) | |||
243 | goto miss; | |||
244 | ||||
245 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
246 | if (kn == NULL((void *)0)) | |||
247 | goto miss; | |||
248 | ||||
249 | if (kn->r.flags & F_LDPD_INSERTED0x0001) | |||
250 | action = RTM_CHANGE0x3; | |||
251 | ||||
252 | kn->r.local_label = kr->local_label; | |||
253 | kn->r.remote_label = kr->remote_label; | |||
254 | kn->r.flags = kn->r.flags | F_LDPD_INSERTED0x0001; | |||
255 | ||||
256 | /* send update */ | |||
257 | if (send_rtmsg(kr_state.fd, action, &kn->r, AF_MPLS33) == -1) | |||
258 | return (-1); | |||
259 | ||||
260 | if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && | |||
261 | kn->r.remote_label != NO_LABEL0xffffffffU) { | |||
262 | if (send_rtmsg(kr_state.fd, RTM_CHANGE0x3, &kn->r, kn->r.af) == -1) | |||
263 | return (-1); | |||
264 | } | |||
265 | ||||
266 | return (0); | |||
267 | ||||
268 | miss: | |||
269 | log_warnx("%s: lost FEC %s/%d nexthop %s", __func__, | |||
270 | log_addr(kr->af, &kr->prefix), kr->prefixlen, | |||
271 | log_addr(kr->af, &kr->nexthop)); | |||
272 | return (-1); | |||
273 | } | |||
274 | ||||
275 | int | |||
276 | kr_delete(struct kroute *kr) | |||
277 | { | |||
278 | struct kroute_prefix *kp; | |||
279 | struct kroute_priority *kprio; | |||
280 | struct kroute_node *kn; | |||
281 | int update = 0; | |||
282 | ||||
283 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
284 | if (kp == NULL((void *)0)) | |||
285 | return (0); | |||
286 | kprio = kroute_find_prio(kp, kr->priority); | |||
287 | if (kprio == NULL((void *)0)) | |||
288 | return (0); | |||
289 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
290 | if (kn == NULL((void *)0)) | |||
291 | return (0); | |||
292 | ||||
293 | if (!(kn->r.flags & F_LDPD_INSERTED0x0001)) | |||
294 | return (0); | |||
295 | if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && | |||
296 | kn->r.remote_label != NO_LABEL0xffffffffU) | |||
297 | update = 1; | |||
298 | ||||
299 | /* kill MPLS LSP */ | |||
300 | if (send_rtmsg(kr_state.fd, RTM_DELETE0x2, &kn->r, AF_MPLS33) == -1) | |||
301 | return (-1); | |||
302 | ||||
303 | kn->r.flags &= ~F_LDPD_INSERTED0x0001; | |||
304 | kn->r.local_label = NO_LABEL0xffffffffU; | |||
305 | kn->r.remote_label = NO_LABEL0xffffffffU; | |||
306 | ||||
307 | if (update && | |||
308 | send_rtmsg(kr_state.fd, RTM_CHANGE0x3, &kn->r, kn->r.af) == -1) | |||
309 | return (-1); | |||
310 | ||||
311 | return (0); | |||
312 | } | |||
313 | ||||
314 | void | |||
315 | kr_shutdown(void) | |||
316 | { | |||
317 | kr_fib_decouple(); | |||
318 | kroute_clear(); | |||
| ||||
319 | kif_clear(); | |||
320 | } | |||
321 | ||||
322 | void | |||
323 | kr_fib_couple(void) | |||
324 | { | |||
325 | struct kroute_prefix *kp; | |||
326 | struct kroute_priority *kprio; | |||
327 | struct kroute_node *kn; | |||
328 | struct kif_node *kif; | |||
329 | ||||
330 | if (kr_state.fib_sync == 1) /* already coupled */ | |||
331 | return; | |||
332 | ||||
333 | kr_state.fib_sync = 1; | |||
334 | ||||
335 | RB_FOREACH(kp, kroute_tree, &krt)for ((kp) = kroute_tree_RB_MINMAX(&krt, -1); (kp) != ((void *)0); (kp) = kroute_tree_RB_NEXT(kp)) { | |||
336 | kprio = TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first); | |||
337 | if (kprio == NULL((void *)0)) | |||
338 | continue; | |||
339 | ||||
340 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) { | |||
341 | if (!(kn->r.flags & F_LDPD_INSERTED0x0001)) | |||
342 | continue; | |||
343 | ||||
344 | send_rtmsg(kr_state.fd, RTM_ADD0x1, &kn->r, AF_MPLS33); | |||
345 | ||||
346 | if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && | |||
347 | kn->r.remote_label != NO_LABEL0xffffffffU) { | |||
348 | send_rtmsg(kr_state.fd, RTM_CHANGE0x3, | |||
349 | &kn->r, kn->r.af); | |||
350 | } | |||
351 | } | |||
352 | } | |||
353 | ||||
354 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
355 | if (kif->kpw) | |||
356 | kmpw_install(kif->k.ifname, kif->kpw); | |||
357 | ||||
358 | log_info("kernel routing table coupled"); | |||
359 | } | |||
360 | ||||
361 | void | |||
362 | kr_fib_decouple(void) | |||
363 | { | |||
364 | struct kroute_prefix *kp; | |||
365 | struct kroute_priority *kprio; | |||
366 | struct kroute_node *kn; | |||
367 | uint32_t rl; | |||
368 | struct kif_node *kif; | |||
369 | ||||
370 | if (kr_state.fib_sync == 0) /* already decoupled */ | |||
371 | return; | |||
372 | ||||
373 | RB_FOREACH(kp, kroute_tree, &krt)for ((kp) = kroute_tree_RB_MINMAX(&krt, -1); (kp) != ((void *)0); (kp) = kroute_tree_RB_NEXT(kp)) { | |||
374 | kprio = TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first); | |||
375 | if (kprio == NULL((void *)0)) | |||
376 | continue; | |||
377 | ||||
378 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) { | |||
379 | if (!(kn->r.flags & F_LDPD_INSERTED0x0001)) | |||
380 | continue; | |||
381 | ||||
382 | send_rtmsg(kr_state.fd, RTM_DELETE0x2, | |||
383 | &kn->r, AF_MPLS33); | |||
384 | ||||
385 | if (ldp_addrisset(kn->r.af, &kn->r.nexthop) && | |||
386 | kn->r.remote_label != NO_LABEL0xffffffffU) { | |||
387 | rl = kn->r.remote_label; | |||
388 | kn->r.remote_label = NO_LABEL0xffffffffU; | |||
389 | send_rtmsg(kr_state.fd, RTM_CHANGE0x3, | |||
390 | &kn->r, kn->r.af); | |||
391 | kn->r.remote_label = rl; | |||
392 | } | |||
393 | } | |||
394 | } | |||
395 | ||||
396 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
397 | if (kif->kpw) | |||
398 | kmpw_uninstall(kif->k.ifname); | |||
399 | ||||
400 | kr_state.fib_sync = 0; | |||
401 | log_info("kernel routing table decoupled"); | |||
402 | } | |||
403 | ||||
404 | void | |||
405 | kr_change_egress_label(int af, int was_implicit) | |||
406 | { | |||
407 | struct kroute_prefix *kp; | |||
408 | struct kroute_priority *kprio; | |||
409 | struct kroute_node *kn; | |||
410 | ||||
411 | RB_FOREACH(kp, kroute_tree, &krt)for ((kp) = kroute_tree_RB_MINMAX(&krt, -1); (kp) != ((void *)0); (kp) = kroute_tree_RB_NEXT(kp)) { | |||
412 | if (kp->af != af) | |||
413 | continue; | |||
414 | ||||
415 | TAILQ_FOREACH(kprio, &kp->priorities, entry)for((kprio) = ((&kp->priorities)->tqh_first); (kprio ) != ((void *)0); (kprio) = ((kprio)->entry.tqe_next)) { | |||
416 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) { | |||
417 | if (kn->r.local_label > MPLS_LABEL_RESERVED_MAX15) | |||
418 | continue; | |||
419 | ||||
420 | if (!was_implicit) { | |||
421 | kn->r.local_label = MPLS_LABEL_IMPLNULL3; | |||
422 | continue; | |||
423 | } | |||
424 | ||||
425 | switch (kn->r.af) { | |||
426 | case AF_INET2: | |||
427 | kn->r.local_label = MPLS_LABEL_IPV4NULL0; | |||
428 | break; | |||
429 | case AF_INET624: | |||
430 | kn->r.local_label = MPLS_LABEL_IPV6NULL2; | |||
431 | break; | |||
432 | default: | |||
433 | break; | |||
434 | } | |||
435 | } | |||
436 | } | |||
437 | } | |||
438 | } | |||
439 | ||||
440 | static void | |||
441 | kr_dispatch_msg(int fd, short event, void *bula) | |||
442 | { | |||
443 | if (dispatch_rtmsg() == -1) | |||
444 | event_loopexit(NULL((void *)0)); | |||
445 | } | |||
446 | ||||
447 | void | |||
448 | kr_show_route(struct imsg *imsg) | |||
449 | { | |||
450 | struct kroute_prefix *kp; | |||
451 | struct kroute_priority *kprio; | |||
452 | struct kroute_node *kn; | |||
453 | int flags; | |||
454 | struct kroute kr; | |||
455 | ||||
456 | switch (imsg->hdr.type) { | |||
457 | case IMSG_CTL_KROUTE: | |||
458 | if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(flags)) { | |||
459 | log_warnx("%s: wrong imsg len", __func__); | |||
460 | return; | |||
461 | } | |||
462 | memcpy(&flags, imsg->data, sizeof(flags)); | |||
463 | ||||
464 | RB_FOREACH(kp, kroute_tree, &krt)for ((kp) = kroute_tree_RB_MINMAX(&krt, -1); (kp) != ((void *)0); (kp) = kroute_tree_RB_NEXT(kp)) | |||
465 | TAILQ_FOREACH(kprio, &kp->priorities, entry)for((kprio) = ((&kp->priorities)->tqh_first); (kprio ) != ((void *)0); (kprio) = ((kprio)->entry.tqe_next)) | |||
466 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) { | |||
467 | if (flags && !(kn->r.flags & flags)) | |||
468 | continue; | |||
469 | ||||
470 | main_imsg_compose_ldpe(IMSG_CTL_KROUTE, | |||
471 | imsg->hdr.pid, &kn->r, | |||
472 | sizeof(kn->r)); | |||
473 | } | |||
474 | break; | |||
475 | case IMSG_CTL_KROUTE_ADDR: | |||
476 | if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(kr)) { | |||
477 | log_warnx("%s: wrong imsg len", __func__); | |||
478 | return; | |||
479 | } | |||
480 | memcpy(&kr, imsg->data, sizeof(kr)); | |||
481 | ||||
482 | kprio = kroute_match(kr.af, &kr.prefix); | |||
483 | if (kprio == NULL((void *)0)) | |||
484 | break; | |||
485 | ||||
486 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
487 | main_imsg_compose_ldpe(IMSG_CTL_KROUTE, imsg->hdr.pid, | |||
488 | &kn->r, sizeof(kn->r)); | |||
489 | break; | |||
490 | default: | |||
491 | log_debug("%s: error handling imsg", __func__); | |||
492 | break; | |||
493 | } | |||
494 | main_imsg_compose_ldpe(IMSG_CTL_END, imsg->hdr.pid, NULL((void *)0), 0); | |||
495 | } | |||
496 | ||||
497 | void | |||
498 | kr_ifinfo(char *ifname, pid_t pid) | |||
499 | { | |||
500 | struct kif_node *kif; | |||
501 | ||||
502 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
503 | if (ifname == NULL((void *)0) || !strcmp(ifname, kif->k.ifname)) { | |||
504 | main_imsg_compose_ldpe(IMSG_CTL_IFINFO, | |||
505 | pid, &kif->k, sizeof(kif->k)); | |||
506 | } | |||
507 | ||||
508 | main_imsg_compose_ldpe(IMSG_CTL_END, pid, NULL((void *)0), 0); | |||
509 | } | |||
510 | ||||
511 | static void | |||
512 | kr_redist_remove(struct kroute *kr) | |||
513 | { | |||
514 | /* was the route redistributed? */ | |||
515 | if ((kr->flags & F_REDISTRIBUTED0x0040) == 0) | |||
| ||||
516 | return; | |||
517 | ||||
518 | /* remove redistributed flag */ | |||
519 | kr->flags &= ~F_REDISTRIBUTED0x0040; | |||
520 | main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, kr, sizeof(*kr)); | |||
521 | } | |||
522 | ||||
523 | static int | |||
524 | kr_redist_eval(struct kroute *kr) | |||
525 | { | |||
526 | /* was the route redistributed? */ | |||
527 | if (kr->flags & F_REDISTRIBUTED0x0040) | |||
528 | goto dont_redistribute; | |||
529 | ||||
530 | /* Dynamic routes are not redistributable. */ | |||
531 | if (kr->flags & F_DYNAMIC0x0008) | |||
532 | goto dont_redistribute; | |||
533 | ||||
534 | /* filter-out non-redistributable addresses */ | |||
535 | if (bad_addr(kr->af, &kr->prefix) || | |||
536 | (kr->af == AF_INET624 && IN6_IS_SCOPE_EMBED(&kr->prefix.v6)(((((&kr->prefix.v6)->__u6_addr.__u6_addr8[0] == 0xfe ) && (((&kr->prefix.v6)->__u6_addr.__u6_addr8 [1] & 0xc0) == 0x80))) || ((((&kr->prefix.v6)-> __u6_addr.__u6_addr8[0] == 0xff) && (((&kr->prefix .v6)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))) || (( ((&kr->prefix.v6)->__u6_addr.__u6_addr8[0] == 0xff) && (((&kr->prefix.v6)->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x01)))))) | |||
537 | goto dont_redistribute; | |||
538 | ||||
539 | /* do not redistribute the default route */ | |||
540 | if (kr->prefixlen == 0) | |||
541 | goto dont_redistribute; | |||
542 | ||||
543 | /* | |||
544 | * Consider networks with nexthop loopback as not redistributable | |||
545 | * unless it is a reject or blackhole route. | |||
546 | */ | |||
547 | switch (kr->af) { | |||
548 | case AF_INET2: | |||
549 | if (kr->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001)))) && | |||
550 | !(kr->flags & (F_BLACKHOLE0x0020|F_REJECT0x0010))) | |||
551 | goto dont_redistribute; | |||
552 | break; | |||
553 | case AF_INET624: | |||
554 | if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop.v6)((*(const u_int32_t *)(const void *)(&(&kr->nexthop .v6)->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&kr->nexthop.v6)->__u6_addr .__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void *)(&(&kr->nexthop.v6)->__u6_addr.__u6_addr8[8] ) == 0) && (*(const u_int32_t *)(const void *)(&( &kr->nexthop.v6)->__u6_addr.__u6_addr8[12]) == (__uint32_t )(__builtin_constant_p(1) ? (__uint32_t)(((__uint32_t)(1) & 0xff) << 24 | ((__uint32_t)(1) & 0xff00) << 8 | ((__uint32_t)(1) & 0xff0000) >> 8 | ((__uint32_t )(1) & 0xff000000) >> 24) : __swap32md(1)))) && | |||
555 | !(kr->flags & (F_BLACKHOLE0x0020|F_REJECT0x0010))) | |||
556 | goto dont_redistribute; | |||
557 | break; | |||
558 | default: | |||
559 | log_debug("%s: unexpected address-family", __func__); | |||
560 | break; | |||
561 | } | |||
562 | ||||
563 | /* prefix should be redistributed */ | |||
564 | kr->flags |= F_REDISTRIBUTED0x0040; | |||
565 | main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, kr, sizeof(*kr)); | |||
566 | return (1); | |||
567 | ||||
568 | dont_redistribute: | |||
569 | return (0); | |||
570 | } | |||
571 | ||||
572 | static void | |||
573 | kr_redistribute(struct kroute_prefix *kp) | |||
574 | { | |||
575 | struct kroute_priority *kprio; | |||
576 | struct kroute_node *kn; | |||
577 | ||||
578 | TAILQ_FOREACH_REVERSE(kprio, &kp->priorities, plist, entry)for((kprio) = (*(((struct plist *)((&kp->priorities)-> tqh_last))->tqh_last)); (kprio) != ((void *)0); (kprio) = ( *(((struct plist *)((kprio)->entry.tqe_prev))->tqh_last ))) { | |||
579 | if (kprio == TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)) { | |||
580 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
581 | kr_redist_eval(&kn->r); | |||
582 | } else { | |||
583 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
584 | kr_redist_remove(&kn->r); | |||
585 | } | |||
586 | } | |||
587 | } | |||
588 | ||||
589 | /* rb-tree compare */ | |||
590 | static __inline int | |||
591 | kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b) | |||
592 | { | |||
593 | int addrcmp; | |||
594 | ||||
595 | if (a->af < b->af) | |||
596 | return (-1); | |||
597 | if (a->af > b->af) | |||
598 | return (1); | |||
599 | ||||
600 | addrcmp = ldp_addrcmp(a->af, &a->prefix, &b->prefix); | |||
601 | if (addrcmp != 0) | |||
602 | return (addrcmp); | |||
603 | ||||
604 | if (a->prefixlen < b->prefixlen) | |||
605 | return (-1); | |||
606 | if (a->prefixlen > b->prefixlen) | |||
607 | return (1); | |||
608 | ||||
609 | return (0); | |||
610 | } | |||
611 | ||||
612 | /* tree management */ | |||
613 | static struct kroute_prefix * | |||
614 | kroute_find_prefix(int af, union ldpd_addr *prefix, uint8_t prefixlen) | |||
615 | { | |||
616 | struct kroute_prefix s; | |||
617 | ||||
618 | s.af = af; | |||
619 | s.prefix = *prefix; | |||
620 | s.prefixlen = prefixlen; | |||
621 | ||||
622 | return (RB_FIND(kroute_tree, &krt, &s)kroute_tree_RB_FIND(&krt, &s)); | |||
623 | } | |||
624 | ||||
625 | static struct kroute_priority * | |||
626 | kroute_find_prio(struct kroute_prefix *kp, uint8_t prio) | |||
627 | { | |||
628 | struct kroute_priority *kprio; | |||
629 | ||||
630 | /* RTP_ANY here picks the lowest priority node */ | |||
631 | if (prio == RTP_ANY64) | |||
632 | return (TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)); | |||
633 | ||||
634 | TAILQ_FOREACH(kprio, &kp->priorities, entry)for((kprio) = ((&kp->priorities)->tqh_first); (kprio ) != ((void *)0); (kprio) = ((kprio)->entry.tqe_next)) | |||
635 | if (kprio->priority == prio) | |||
636 | return (kprio); | |||
637 | ||||
638 | return (NULL((void *)0)); | |||
639 | } | |||
640 | ||||
641 | static struct kroute_node * | |||
642 | kroute_find_gw(struct kroute_priority *kprio, union ldpd_addr *nh) | |||
643 | { | |||
644 | struct kroute_node *kn; | |||
645 | ||||
646 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
647 | if (ldp_addrcmp(kprio->kp->af, &kn->r.nexthop, nh) == 0) | |||
648 | return (kn); | |||
649 | ||||
650 | return (NULL((void *)0)); | |||
651 | } | |||
652 | ||||
653 | static int | |||
654 | kroute_insert(struct kroute *kr) | |||
655 | { | |||
656 | struct kroute_prefix *kp; | |||
657 | struct kroute_priority *kprio, *tmp; | |||
658 | struct kroute_node *kn; | |||
659 | ||||
660 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
661 | if (kp == NULL((void *)0)) { | |||
662 | kp = calloc(1, sizeof((*kp))); | |||
663 | if (kp == NULL((void *)0)) | |||
664 | fatal(__func__); | |||
665 | kp->af = kr->af; | |||
666 | kp->prefix = kr->prefix; | |||
667 | kp->prefixlen = kr->prefixlen; | |||
668 | TAILQ_INIT(&kp->priorities)do { (&kp->priorities)->tqh_first = ((void *)0); (& kp->priorities)->tqh_last = &(&kp->priorities )->tqh_first; } while (0); | |||
669 | RB_INSERT(kroute_tree, &krt, kp)kroute_tree_RB_INSERT(&krt, kp); | |||
670 | } | |||
671 | ||||
672 | kprio = kroute_find_prio(kp, kr->priority); | |||
673 | if (kprio == NULL((void *)0)) { | |||
674 | kprio = calloc(1, sizeof(*kprio)); | |||
675 | if (kprio == NULL((void *)0)) | |||
676 | fatal(__func__); | |||
677 | kprio->kp = kp; | |||
678 | kprio->priority = kr->priority; | |||
679 | TAILQ_INIT(&kprio->nexthops)do { (&kprio->nexthops)->tqh_first = ((void *)0); ( &kprio->nexthops)->tqh_last = &(&kprio-> nexthops)->tqh_first; } while (0); | |||
680 | ||||
681 | /* lower priorities first */ | |||
682 | TAILQ_FOREACH(tmp, &kp->priorities, entry)for((tmp) = ((&kp->priorities)->tqh_first); (tmp) != ((void *)0); (tmp) = ((tmp)->entry.tqe_next)) | |||
683 | if (tmp->priority > kprio->priority) | |||
684 | break; | |||
685 | if (tmp) | |||
686 | TAILQ_INSERT_BEFORE(tmp, kprio, entry)do { (kprio)->entry.tqe_prev = (tmp)->entry.tqe_prev; ( kprio)->entry.tqe_next = (tmp); *(tmp)->entry.tqe_prev = (kprio); (tmp)->entry.tqe_prev = &(kprio)->entry.tqe_next ; } while (0); | |||
687 | else | |||
688 | TAILQ_INSERT_TAIL(&kp->priorities, kprio, entry)do { (kprio)->entry.tqe_next = ((void *)0); (kprio)->entry .tqe_prev = (&kp->priorities)->tqh_last; *(&kp-> priorities)->tqh_last = (kprio); (&kp->priorities)-> tqh_last = &(kprio)->entry.tqe_next; } while (0); | |||
689 | } | |||
690 | ||||
691 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
692 | if (kn == NULL((void *)0)) { | |||
693 | kn = calloc(1, sizeof(*kn)); | |||
694 | if (kn == NULL((void *)0)) | |||
695 | fatal(__func__); | |||
696 | kn->kprio = kprio; | |||
697 | kn->r = *kr; | |||
698 | TAILQ_INSERT_TAIL(&kprio->nexthops, kn, entry)do { (kn)->entry.tqe_next = ((void *)0); (kn)->entry.tqe_prev = (&kprio->nexthops)->tqh_last; *(&kprio->nexthops )->tqh_last = (kn); (&kprio->nexthops)->tqh_last = &(kn)->entry.tqe_next; } while (0); | |||
699 | } | |||
700 | ||||
701 | kr_redistribute(kp); | |||
702 | return (0); | |||
703 | } | |||
704 | ||||
705 | static int | |||
706 | kroute_uninstall(struct kroute_node *kn) | |||
707 | { | |||
708 | /* kill MPLS LSP if one was installed */ | |||
709 | if (kn->r.flags & F_LDPD_INSERTED0x0001) | |||
710 | if (send_rtmsg(kr_state.fd, RTM_DELETE0x2, &kn->r, AF_MPLS33) == -1) | |||
711 | return (-1); | |||
712 | ||||
713 | return (0); | |||
714 | } | |||
715 | ||||
716 | static int | |||
717 | kroute_remove(struct kroute *kr) | |||
718 | { | |||
719 | struct kroute_prefix *kp; | |||
720 | struct kroute_priority *kprio; | |||
721 | struct kroute_node *kn; | |||
722 | ||||
723 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
724 | if (kp == NULL((void *)0)) | |||
725 | goto notfound; | |||
726 | kprio = kroute_find_prio(kp, kr->priority); | |||
727 | if (kprio == NULL((void *)0)) | |||
728 | goto notfound; | |||
729 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
730 | if (kn == NULL((void *)0)) | |||
731 | goto notfound; | |||
732 | ||||
733 | kr_redist_remove(&kn->r); | |||
734 | kroute_uninstall(kn); | |||
735 | ||||
736 | TAILQ_REMOVE(&kprio->nexthops, kn, entry)do { if (((kn)->entry.tqe_next) != ((void *)0)) (kn)->entry .tqe_next->entry.tqe_prev = (kn)->entry.tqe_prev; else ( &kprio->nexthops)->tqh_last = (kn)->entry.tqe_prev ; *(kn)->entry.tqe_prev = (kn)->entry.tqe_next; ; ; } while (0); | |||
737 | free(kn); | |||
738 | ||||
739 | if (TAILQ_EMPTY(&kprio->nexthops)(((&kprio->nexthops)->tqh_first) == ((void *)0))) { | |||
740 | TAILQ_REMOVE(&kp->priorities, kprio, entry)do { if (((kprio)->entry.tqe_next) != ((void *)0)) (kprio) ->entry.tqe_next->entry.tqe_prev = (kprio)->entry.tqe_prev ; else (&kp->priorities)->tqh_last = (kprio)->entry .tqe_prev; *(kprio)->entry.tqe_prev = (kprio)->entry.tqe_next ; ; ; } while (0); | |||
741 | free(kprio); | |||
742 | } | |||
743 | ||||
744 | if (TAILQ_EMPTY(&kp->priorities)(((&kp->priorities)->tqh_first) == ((void *)0))) { | |||
745 | if (RB_REMOVE(kroute_tree, &krt, kp)kroute_tree_RB_REMOVE(&krt, kp) == NULL((void *)0)) { | |||
746 | log_warnx("%s failed for %s/%u", __func__, | |||
747 | log_addr(kr->af, &kr->prefix), kp->prefixlen); | |||
748 | return (-1); | |||
749 | } | |||
750 | free(kp); | |||
751 | } else | |||
752 | kr_redistribute(kp); | |||
753 | ||||
754 | return (0); | |||
755 | ||||
756 | notfound: | |||
757 | log_warnx("%s failed to find %s/%u", __func__, | |||
758 | log_addr(kr->af, &kr->prefix), kr->prefixlen); | |||
759 | return (-1); | |||
760 | } | |||
761 | ||||
762 | static void | |||
763 | kroute_clear(void) | |||
764 | { | |||
765 | struct kroute_prefix *kp; | |||
766 | struct kroute_priority *kprio; | |||
767 | struct kroute_node *kn; | |||
768 | ||||
769 | while ((kp = RB_MIN(kroute_tree, &krt)kroute_tree_RB_MINMAX(&krt, -1)) != NULL((void *)0)) { | |||
770 | while ((kprio = TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)) != NULL((void *)0)) { | |||
771 | while ((kn = TAILQ_FIRST(&kprio->nexthops)((&kprio->nexthops)->tqh_first)) != NULL((void *)0)) { | |||
772 | kr_redist_remove(&kn->r); | |||
773 | kroute_uninstall(kn); | |||
774 | TAILQ_REMOVE(&kprio->nexthops, kn, entry)do { if (((kn)->entry.tqe_next) != ((void *)0)) (kn)->entry .tqe_next->entry.tqe_prev = (kn)->entry.tqe_prev; else ( &kprio->nexthops)->tqh_last = (kn)->entry.tqe_prev ; *(kn)->entry.tqe_prev = (kn)->entry.tqe_next; ; ; } while (0); | |||
775 | free(kn); | |||
776 | } | |||
777 | TAILQ_REMOVE(&kp->priorities, kprio, entry)do { if (((kprio)->entry.tqe_next) != ((void *)0)) (kprio) ->entry.tqe_next->entry.tqe_prev = (kprio)->entry.tqe_prev ; else (&kp->priorities)->tqh_last = (kprio)->entry .tqe_prev; *(kprio)->entry.tqe_prev = (kprio)->entry.tqe_next ; ; ; } while (0); | |||
778 | free(kprio); | |||
779 | } | |||
780 | RB_REMOVE(kroute_tree, &krt, kp)kroute_tree_RB_REMOVE(&krt, kp); | |||
781 | free(kp); | |||
782 | } | |||
783 | } | |||
784 | ||||
785 | static __inline int | |||
786 | kif_compare(struct kif_node *a, struct kif_node *b) | |||
787 | { | |||
788 | return (b->k.ifindex - a->k.ifindex); | |||
789 | } | |||
790 | ||||
791 | /* tree management */ | |||
792 | static struct kif_node * | |||
793 | kif_find(unsigned short ifindex) | |||
794 | { | |||
795 | struct kif_node s; | |||
796 | ||||
797 | memset(&s, 0, sizeof(s)); | |||
798 | s.k.ifindex = ifindex; | |||
799 | ||||
800 | return (RB_FIND(kif_tree, &kit, &s)kif_tree_RB_FIND(&kit, &s)); | |||
801 | } | |||
802 | ||||
803 | struct kif * | |||
804 | kif_findname(char *ifname) | |||
805 | { | |||
806 | struct kif_node *kif; | |||
807 | ||||
808 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
809 | if (!strcmp(ifname, kif->k.ifname)) | |||
810 | return (&kif->k); | |||
811 | ||||
812 | return (NULL((void *)0)); | |||
813 | } | |||
814 | ||||
815 | static struct kif_node * | |||
816 | kif_insert(unsigned short ifindex) | |||
817 | { | |||
818 | struct kif_node *kif; | |||
819 | ||||
820 | if ((kif = calloc(1, sizeof(struct kif_node))) == NULL((void *)0)) | |||
821 | return (NULL((void *)0)); | |||
822 | ||||
823 | kif->k.ifindex = ifindex; | |||
824 | TAILQ_INIT(&kif->addrs)do { (&kif->addrs)->tqh_first = ((void *)0); (& kif->addrs)->tqh_last = &(&kif->addrs)->tqh_first ; } while (0); | |||
825 | ||||
826 | if (RB_INSERT(kif_tree, &kit, kif)kif_tree_RB_INSERT(&kit, kif) != NULL((void *)0)) | |||
827 | fatalx("kif_insert: RB_INSERT"); | |||
828 | ||||
829 | return (kif); | |||
830 | } | |||
831 | ||||
832 | static int | |||
833 | kif_remove(struct kif_node *kif) | |||
834 | { | |||
835 | struct kif_addr *ka; | |||
836 | ||||
837 | if (RB_REMOVE(kif_tree, &kit, kif)kif_tree_RB_REMOVE(&kit, kif) == NULL((void *)0)) { | |||
838 | log_warnx("RB_REMOVE(kif_tree, &kit, kif)"); | |||
839 | return (-1); | |||
840 | } | |||
841 | ||||
842 | while ((ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first)) != NULL((void *)0)) { | |||
843 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, sizeof(ka->a)); | |||
844 | TAILQ_REMOVE(&kif->addrs, ka, entry)do { if (((ka)->entry.tqe_next) != ((void *)0)) (ka)->entry .tqe_next->entry.tqe_prev = (ka)->entry.tqe_prev; else ( &kif->addrs)->tqh_last = (ka)->entry.tqe_prev; * (ka)->entry.tqe_prev = (ka)->entry.tqe_next; ; ; } while (0); | |||
845 | free(ka); | |||
846 | } | |||
847 | free(kif); | |||
848 | return (0); | |||
849 | } | |||
850 | ||||
851 | void | |||
852 | kif_clear(void) | |||
853 | { | |||
854 | struct kif_node *kif; | |||
855 | ||||
856 | while ((kif = RB_MIN(kif_tree, &kit)kif_tree_RB_MINMAX(&kit, -1)) != NULL((void *)0)) | |||
857 | kif_remove(kif); | |||
858 | } | |||
859 | ||||
860 | static struct kif_node * | |||
861 | kif_update(unsigned short ifindex, int flags, struct if_data *ifd, | |||
862 | struct sockaddr_dl *sdl, int *link_old) | |||
863 | { | |||
864 | struct kif_node *kif; | |||
865 | ||||
866 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
867 | if ((kif = kif_insert(ifindex)) == NULL((void *)0)) | |||
868 | return (NULL((void *)0)); | |||
869 | } else | |||
870 | *link_old = (kif->k.flags & IFF_UP0x1) && | |||
871 | LINK_STATE_IS_UP(kif->k.link_state)((kif->k.link_state) >= 4 || (kif->k.link_state) == 0 ); | |||
872 | ||||
873 | kif->k.flags = flags; | |||
874 | kif->k.link_state = ifd->ifi_link_state; | |||
875 | if (sdl) | |||
876 | memcpy(kif->k.mac, LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen)), sizeof(kif->k.mac)); | |||
877 | kif->k.if_type = ifd->ifi_type; | |||
878 | kif->k.baudrate = ifd->ifi_baudrate; | |||
879 | kif->k.mtu = ifd->ifi_mtu; | |||
880 | kif->k.rdomain = ifd->ifi_rdomain; | |||
881 | ||||
882 | if (sdl && sdl->sdl_family == AF_LINK18) { | |||
883 | if (sdl->sdl_nlen >= sizeof(kif->k.ifname)) | |||
884 | memcpy(kif->k.ifname, sdl->sdl_data, | |||
885 | sizeof(kif->k.ifname) - 1); | |||
886 | else if (sdl->sdl_nlen > 0) | |||
887 | memcpy(kif->k.ifname, sdl->sdl_data, | |||
888 | sdl->sdl_nlen); | |||
889 | /* string already terminated via calloc() */ | |||
890 | } | |||
891 | ||||
892 | return (kif); | |||
893 | } | |||
894 | ||||
895 | static struct kroute_priority * | |||
896 | kroute_match(int af, union ldpd_addr *key) | |||
897 | { | |||
898 | int i, maxprefixlen; | |||
899 | struct kroute_prefix *kp; | |||
900 | struct kroute_priority *kprio; | |||
901 | union ldpd_addr addr; | |||
902 | ||||
903 | switch (af) { | |||
904 | case AF_INET2: | |||
905 | maxprefixlen = 32; | |||
906 | break; | |||
907 | case AF_INET624: | |||
908 | maxprefixlen = 128; | |||
909 | break; | |||
910 | default: | |||
911 | log_warnx("%s: unknown af", __func__); | |||
912 | return (NULL((void *)0)); | |||
913 | } | |||
914 | ||||
915 | for (i = maxprefixlen; i >= 0; i--) { | |||
916 | ldp_applymask(af, &addr, key, i); | |||
917 | ||||
918 | kp = kroute_find_prefix(af, &addr, i); | |||
919 | if (kp == NULL((void *)0)) | |||
920 | continue; | |||
921 | ||||
922 | kprio = kroute_find_prio(kp, RTP_ANY64); | |||
923 | if (kprio != NULL((void *)0)) | |||
924 | return (kprio); | |||
925 | } | |||
926 | ||||
927 | return (NULL((void *)0)); | |||
928 | } | |||
929 | ||||
930 | /* misc */ | |||
931 | static uint8_t | |||
932 | prefixlen_classful(in_addr_t ina) | |||
933 | { | |||
934 | /* it hurt to write this. */ | |||
935 | ||||
936 | if (ina >= 0xf0000000U) /* class E */ | |||
937 | return (32); | |||
938 | else if (ina >= 0xe0000000U) /* class D */ | |||
939 | return (4); | |||
940 | else if (ina >= 0xc0000000U) /* class C */ | |||
941 | return (24); | |||
942 | else if (ina >= 0x80000000U) /* class B */ | |||
943 | return (16); | |||
944 | else /* class A */ | |||
945 | return (8); | |||
946 | } | |||
947 | ||||
948 | #define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof (long)) \ | |||
949 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |||
950 | ||||
951 | static void | |||
952 | get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) | |||
953 | { | |||
954 | int i; | |||
955 | ||||
956 | for (i = 0; i < RTAX_MAX15; i++) { | |||
957 | if (addrs & (1 << i)) { | |||
958 | rti_info[i] = sa; | |||
959 | sa = (struct sockaddr *)((char *)(sa) + | |||
960 | ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long))); | |||
961 | } else | |||
962 | rti_info[i] = NULL((void *)0); | |||
963 | } | |||
964 | } | |||
965 | ||||
966 | static void | |||
967 | if_change(unsigned short ifindex, int flags, struct if_data *ifd, | |||
968 | struct sockaddr_dl *sdl) | |||
969 | { | |||
970 | struct kif_node *kif; | |||
971 | struct kif_addr *ka; | |||
972 | int link_old = 0, link_new; | |||
973 | ||||
974 | kif = kif_update(ifindex, flags, ifd, sdl, &link_old); | |||
975 | if (!kif) { | |||
976 | log_warn("%s: kif_update(%u)", __func__, ifindex); | |||
977 | return; | |||
978 | } | |||
979 | link_new = (kif->k.flags & IFF_UP0x1) && | |||
980 | LINK_STATE_IS_UP(kif->k.link_state)((kif->k.link_state) >= 4 || (kif->k.link_state) == 0 ); | |||
981 | ||||
982 | if (link_new == link_old) | |||
983 | return; | |||
984 | ||||
985 | main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif->k, sizeof(struct kif)); | |||
986 | if (link_new) { | |||
987 | TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void *)0); (ka) = ((ka)->entry.tqe_next)) | |||
988 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->a, | |||
989 | sizeof(ka->a)); | |||
990 | } else { | |||
991 | TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void *)0); (ka) = ((ka)->entry.tqe_next)) | |||
992 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, | |||
993 | sizeof(ka->a)); | |||
994 | } | |||
995 | } | |||
996 | ||||
997 | static void | |||
998 | if_newaddr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, | |||
999 | struct sockaddr *brd) | |||
1000 | { | |||
1001 | struct kif_node *kif; | |||
1002 | struct sockaddr_in *ifa4, *mask4, *brd4; | |||
1003 | struct sockaddr_in6 *ifa6, *mask6, *brd6; | |||
1004 | struct kif_addr *ka; | |||
1005 | ||||
1006 | if (ifa == NULL((void *)0)) | |||
1007 | return; | |||
1008 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
1009 | log_warnx("%s: corresponding if %d not found", __func__, | |||
1010 | ifindex); | |||
1011 | return; | |||
1012 | } | |||
1013 | ||||
1014 | switch (ifa->sa_family) { | |||
1015 | case AF_INET2: | |||
1016 | ifa4 = (struct sockaddr_in *) ifa; | |||
1017 | mask4 = (struct sockaddr_in *) mask; | |||
1018 | brd4 = (struct sockaddr_in *) brd; | |||
1019 | ||||
1020 | /* filter out unwanted addresses */ | |||
1021 | if (bad_addr_v4(ifa4->sin_addr)) | |||
1022 | return; | |||
1023 | ||||
1024 | if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void *)0)) | |||
1025 | fatal("if_newaddr"); | |||
1026 | ka->a.addr.v4 = ifa4->sin_addr; | |||
1027 | if (mask4) | |||
1028 | ka->a.prefixlen = | |||
1029 | mask2prefixlen(mask4->sin_addr.s_addr); | |||
1030 | if (brd4) | |||
1031 | ka->a.dstbrd.v4 = brd4->sin_addr; | |||
1032 | break; | |||
1033 | case AF_INET624: | |||
1034 | ifa6 = (struct sockaddr_in6 *) ifa; | |||
1035 | mask6 = (struct sockaddr_in6 *) mask; | |||
1036 | brd6 = (struct sockaddr_in6 *) brd; | |||
1037 | ||||
1038 | /* We only care about link-local and global-scope. */ | |||
1039 | if (bad_addr_v6(&ifa6->sin6_addr)) | |||
1040 | return; | |||
1041 | ||||
1042 | clearscope(&ifa6->sin6_addr); | |||
1043 | ||||
1044 | if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void *)0)) | |||
1045 | fatal("if_newaddr"); | |||
1046 | ka->a.addr.v6 = ifa6->sin6_addr; | |||
1047 | if (mask6) | |||
1048 | ka->a.prefixlen = mask2prefixlen6(mask6); | |||
1049 | if (brd6) | |||
1050 | ka->a.dstbrd.v6 = brd6->sin6_addr; | |||
1051 | break; | |||
1052 | default: | |||
1053 | return; | |||
1054 | } | |||
1055 | ||||
1056 | ka->a.ifindex = ifindex; | |||
1057 | ka->a.af = ifa->sa_family; | |||
1058 | TAILQ_INSERT_TAIL(&kif->addrs, ka, entry)do { (ka)->entry.tqe_next = ((void *)0); (ka)->entry.tqe_prev = (&kif->addrs)->tqh_last; *(&kif->addrs)-> tqh_last = (ka); (&kif->addrs)->tqh_last = &(ka )->entry.tqe_next; } while (0); | |||
1059 | ||||
1060 | /* notify ldpe about new address */ | |||
1061 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->a, sizeof(ka->a)); | |||
1062 | } | |||
1063 | ||||
1064 | static void | |||
1065 | if_deladdr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, | |||
1066 | struct sockaddr *brd) | |||
1067 | { | |||
1068 | struct kif_node *kif; | |||
1069 | struct sockaddr_in *ifa4, *mask4, *brd4; | |||
1070 | struct sockaddr_in6 *ifa6, *mask6, *brd6; | |||
1071 | struct kaddr k; | |||
1072 | struct kif_addr *ka, *nka; | |||
1073 | ||||
1074 | if (ifa == NULL((void *)0)) | |||
1075 | return; | |||
1076 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
1077 | log_warnx("%s: corresponding if %d not found", __func__, | |||
1078 | ifindex); | |||
1079 | return; | |||
1080 | } | |||
1081 | ||||
1082 | memset(&k, 0, sizeof(k)); | |||
1083 | k.af = ifa->sa_family; | |||
1084 | switch (ifa->sa_family) { | |||
1085 | case AF_INET2: | |||
1086 | ifa4 = (struct sockaddr_in *) ifa; | |||
1087 | mask4 = (struct sockaddr_in *) mask; | |||
1088 | brd4 = (struct sockaddr_in *) brd; | |||
1089 | ||||
1090 | /* filter out unwanted addresses */ | |||
1091 | if (bad_addr_v4(ifa4->sin_addr)) | |||
1092 | return; | |||
1093 | ||||
1094 | k.addr.v4 = ifa4->sin_addr; | |||
1095 | if (mask4) | |||
1096 | k.prefixlen = mask2prefixlen(mask4->sin_addr.s_addr); | |||
1097 | if (brd4) | |||
1098 | k.dstbrd.v4 = brd4->sin_addr; | |||
1099 | break; | |||
1100 | case AF_INET624: | |||
1101 | ifa6 = (struct sockaddr_in6 *) ifa; | |||
1102 | mask6 = (struct sockaddr_in6 *) mask; | |||
1103 | brd6 = (struct sockaddr_in6 *) brd; | |||
1104 | ||||
1105 | /* We only care about link-local and global-scope. */ | |||
1106 | if (bad_addr_v6(&ifa6->sin6_addr)) | |||
1107 | return; | |||
1108 | ||||
1109 | clearscope(&ifa6->sin6_addr); | |||
1110 | ||||
1111 | k.addr.v6 = ifa6->sin6_addr; | |||
1112 | if (mask6) | |||
1113 | k.prefixlen = mask2prefixlen6(mask6); | |||
1114 | if (brd6) | |||
1115 | k.dstbrd.v6 = brd6->sin6_addr; | |||
1116 | break; | |||
1117 | default: | |||
1118 | return; | |||
1119 | } | |||
1120 | ||||
1121 | for (ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first); ka != NULL((void *)0); ka = nka) { | |||
1122 | nka = TAILQ_NEXT(ka, entry)((ka)->entry.tqe_next); | |||
1123 | ||||
1124 | if (ka->a.af != k.af || | |||
1125 | ka->a.prefixlen != k.prefixlen || | |||
1126 | ldp_addrcmp(ka->a.af, &ka->a.addr, &k.addr)) | |||
1127 | continue; | |||
1128 | ||||
1129 | /* notify ldpe about removed address */ | |||
1130 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, sizeof(ka->a)); | |||
1131 | TAILQ_REMOVE(&kif->addrs, ka, entry)do { if (((ka)->entry.tqe_next) != ((void *)0)) (ka)->entry .tqe_next->entry.tqe_prev = (ka)->entry.tqe_prev; else ( &kif->addrs)->tqh_last = (ka)->entry.tqe_prev; * (ka)->entry.tqe_prev = (ka)->entry.tqe_next; ; ; } while (0); | |||
1132 | free(ka); | |||
1133 | return; | |||
1134 | } | |||
1135 | } | |||
1136 | ||||
1137 | static void | |||
1138 | if_announce(void *msg) | |||
1139 | { | |||
1140 | struct if_announcemsghdr *ifan; | |||
1141 | struct kif_node *kif; | |||
1142 | ||||
1143 | ifan = msg; | |||
1144 | ||||
1145 | switch (ifan->ifan_what) { | |||
1146 | case IFAN_ARRIVAL0: | |||
1147 | kif = kif_insert(ifan->ifan_index); | |||
1148 | if (kif) | |||
1149 | strlcpy(kif->k.ifname, ifan->ifan_name, | |||
1150 | sizeof(kif->k.ifname)); | |||
1151 | break; | |||
1152 | case IFAN_DEPARTURE1: | |||
1153 | kif = kif_find(ifan->ifan_index); | |||
1154 | if (kif) | |||
1155 | kif_remove(kif); | |||
1156 | break; | |||
1157 | } | |||
1158 | } | |||
1159 | ||||
1160 | /* rtsock */ | |||
1161 | static int | |||
1162 | send_rtmsg(int fd, int action, struct kroute *kr, int family) | |||
1163 | { | |||
1164 | switch (kr->af) { | |||
1165 | case AF_INET2: | |||
1166 | return (send_rtmsg_v4(fd, action, kr, family)); | |||
1167 | case AF_INET624: | |||
1168 | return (send_rtmsg_v6(fd, action, kr, family)); | |||
1169 | default: | |||
1170 | fatalx("send_rtmsg: unknown af"); | |||
1171 | } | |||
1172 | } | |||
1173 | ||||
1174 | static int | |||
1175 | send_rtmsg_v4(int fd, int action, struct kroute *kr, int family) | |||
1176 | { | |||
1177 | struct iovec iov[5]; | |||
1178 | struct rt_msghdr hdr; | |||
1179 | struct sockaddr_mpls label_in, label_out; | |||
1180 | struct sockaddr_in dst, mask, nexthop; | |||
1181 | int iovcnt = 0; | |||
1182 | ||||
1183 | if (kr_state.fib_sync == 0) | |||
1184 | return (0); | |||
1185 | ||||
1186 | /* | |||
1187 | * Reserved labels (implicit and explicit NULL) should not be added | |||
1188 | * to the FIB. | |||
1189 | */ | |||
1190 | if (family == AF_MPLS33 && kr->local_label < MPLS_LABEL_RESERVED_MAX15) | |||
1191 | return (0); | |||
1192 | ||||
1193 | /* initialize header */ | |||
1194 | memset(&hdr, 0, sizeof(hdr)); | |||
1195 | hdr.rtm_version = RTM_VERSION5; | |||
1196 | ||||
1197 | hdr.rtm_type = action; | |||
1198 | hdr.rtm_flags = RTF_UP0x1; | |||
1199 | hdr.rtm_fmask = RTF_MPLS0x100000; | |||
1200 | hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ | |||
1201 | hdr.rtm_msglen = sizeof(hdr); | |||
1202 | hdr.rtm_hdrlen = sizeof(struct rt_msghdr); | |||
1203 | hdr.rtm_priority = kr->priority; | |||
1204 | hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ | |||
1205 | /* adjust iovec */ | |||
1206 | iov[iovcnt].iov_base = &hdr; | |||
1207 | iov[iovcnt++].iov_len = sizeof(hdr); | |||
1208 | ||||
1209 | if (family == AF_MPLS33) { | |||
1210 | memset(&label_in, 0, sizeof(label_in)); | |||
1211 | label_in.smpls_len = sizeof(label_in); | |||
1212 | label_in.smpls_family = AF_MPLS33; | |||
1213 | label_in.smpls_label = | |||
1214 | htonl(kr->local_label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(kr->local_label << 12) ? (__uint32_t)(((__uint32_t)(kr->local_label << 12) & 0xff) << 24 | ((__uint32_t)(kr->local_label << 12) & 0xff00) << 8 | ((__uint32_t)(kr-> local_label << 12) & 0xff0000) >> 8 | ((__uint32_t )(kr->local_label << 12) & 0xff000000) >> 24 ) : __swap32md(kr->local_label << 12)); | |||
1215 | /* adjust header */ | |||
1216 | hdr.rtm_flags |= RTF_MPLS0x100000 | RTF_MPATH0x40000; | |||
1217 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1218 | hdr.rtm_msglen += sizeof(label_in); | |||
1219 | /* adjust iovec */ | |||
1220 | iov[iovcnt].iov_base = &label_in; | |||
1221 | iov[iovcnt++].iov_len = sizeof(label_in); | |||
1222 | } else { | |||
1223 | memset(&dst, 0, sizeof(dst)); | |||
1224 | dst.sin_len = sizeof(dst); | |||
1225 | dst.sin_family = AF_INET2; | |||
1226 | dst.sin_addr = kr->prefix.v4; | |||
1227 | /* adjust header */ | |||
1228 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1229 | hdr.rtm_msglen += sizeof(dst); | |||
1230 | /* adjust iovec */ | |||
1231 | iov[iovcnt].iov_base = &dst; | |||
1232 | iov[iovcnt++].iov_len = sizeof(dst); | |||
1233 | } | |||
1234 | ||||
1235 | memset(&nexthop, 0, sizeof(nexthop)); | |||
1236 | nexthop.sin_len = sizeof(nexthop); | |||
1237 | nexthop.sin_family = AF_INET2; | |||
1238 | nexthop.sin_addr = kr->nexthop.v4; | |||
1239 | /* adjust header */ | |||
1240 | hdr.rtm_flags |= RTF_GATEWAY0x2; | |||
1241 | hdr.rtm_addrs |= RTA_GATEWAY0x2; | |||
1242 | hdr.rtm_msglen += sizeof(nexthop); | |||
1243 | /* adjust iovec */ | |||
1244 | iov[iovcnt].iov_base = &nexthop; | |||
1245 | iov[iovcnt++].iov_len = sizeof(nexthop); | |||
1246 | ||||
1247 | if (family == AF_INET2) { | |||
1248 | memset(&mask, 0, sizeof(mask)); | |||
1249 | mask.sin_len = sizeof(mask); | |||
1250 | mask.sin_family = AF_INET2; | |||
1251 | mask.sin_addr.s_addr = prefixlen2mask(kr->prefixlen); | |||
1252 | /* adjust header */ | |||
1253 | hdr.rtm_addrs |= RTA_NETMASK0x4; | |||
1254 | hdr.rtm_msglen += sizeof(mask); | |||
1255 | /* adjust iovec */ | |||
1256 | iov[iovcnt].iov_base = &mask; | |||
1257 | iov[iovcnt++].iov_len = sizeof(mask); | |||
1258 | } | |||
1259 | ||||
1260 | /* If action is RTM_DELETE we have to get rid of MPLS infos */ | |||
1261 | if (kr->remote_label != NO_LABEL0xffffffffU && action != RTM_DELETE0x2) { | |||
1262 | memset(&label_out, 0, sizeof(label_out)); | |||
1263 | label_out.smpls_len = sizeof(label_out); | |||
1264 | label_out.smpls_family = AF_MPLS33; | |||
1265 | label_out.smpls_label = | |||
1266 | htonl(kr->remote_label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(kr->remote_label << 12) ? (__uint32_t)(((__uint32_t)(kr->remote_label << 12) & 0xff) << 24 | ((__uint32_t)(kr->remote_label << 12) & 0xff00) << 8 | ((__uint32_t)(kr-> remote_label << 12) & 0xff0000) >> 8 | ((__uint32_t )(kr->remote_label << 12) & 0xff000000) >> 24) : __swap32md(kr->remote_label << 12)); | |||
1267 | /* adjust header */ | |||
1268 | hdr.rtm_addrs |= RTA_SRC0x100; | |||
1269 | hdr.rtm_flags |= RTF_MPLS0x100000; | |||
1270 | hdr.rtm_msglen += sizeof(label_out); | |||
1271 | /* adjust iovec */ | |||
1272 | iov[iovcnt].iov_base = &label_out; | |||
1273 | iov[iovcnt++].iov_len = sizeof(label_out); | |||
1274 | ||||
1275 | if (kr->remote_label == MPLS_LABEL_IMPLNULL3) { | |||
1276 | if (family == AF_MPLS33) | |||
1277 | hdr.rtm_mpls = MPLS_OP_POP0x1; | |||
1278 | else | |||
1279 | return (0); | |||
1280 | } else { | |||
1281 | if (family == AF_MPLS33) | |||
1282 | hdr.rtm_mpls = MPLS_OP_SWAP0x4; | |||
1283 | else | |||
1284 | hdr.rtm_mpls = MPLS_OP_PUSH0x2; | |||
1285 | } | |||
1286 | } | |||
1287 | ||||
1288 | retry: | |||
1289 | if (writev(fd, iov, iovcnt) == -1) { | |||
1290 | if (errno(*__errno()) == ESRCH3) { | |||
1291 | if (hdr.rtm_type == RTM_CHANGE0x3 && family == AF_MPLS33) { | |||
1292 | hdr.rtm_type = RTM_ADD0x1; | |||
1293 | goto retry; | |||
1294 | } else if (hdr.rtm_type == RTM_DELETE0x2) { | |||
1295 | log_info("route %s/%u vanished before delete", | |||
1296 | inet_ntoa(kr->prefix.v4), kr->prefixlen); | |||
1297 | return (-1); | |||
1298 | } | |||
1299 | } | |||
1300 | log_warn("%s action %u, af %s, prefix %s/%u", __func__, | |||
1301 | hdr.rtm_type, af_name(family), inet_ntoa(kr->prefix.v4), | |||
1302 | kr->prefixlen); | |||
1303 | return (-1); | |||
1304 | } | |||
1305 | ||||
1306 | return (0); | |||
1307 | } | |||
1308 | ||||
1309 | static int | |||
1310 | send_rtmsg_v6(int fd, int action, struct kroute *kr, int family) | |||
1311 | { | |||
1312 | struct iovec iov[5]; | |||
1313 | struct rt_msghdr hdr; | |||
1314 | struct sockaddr_mpls label_in, label_out; | |||
1315 | struct sockaddr_in6 dst, mask, nexthop; | |||
1316 | int iovcnt = 0; | |||
1317 | ||||
1318 | if (kr_state.fib_sync == 0) | |||
1319 | return (0); | |||
1320 | ||||
1321 | /* | |||
1322 | * Reserved labels (implicit and explicit NULL) should not be added | |||
1323 | * to the FIB. | |||
1324 | */ | |||
1325 | if (family == AF_MPLS33 && kr->local_label < MPLS_LABEL_RESERVED_MAX15) | |||
1326 | return (0); | |||
1327 | ||||
1328 | /* initialize header */ | |||
1329 | memset(&hdr, 0, sizeof(hdr)); | |||
1330 | hdr.rtm_version = RTM_VERSION5; | |||
1331 | ||||
1332 | hdr.rtm_type = action; | |||
1333 | hdr.rtm_flags = RTF_UP0x1; | |||
1334 | hdr.rtm_fmask = RTF_MPLS0x100000; | |||
1335 | hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ | |||
1336 | hdr.rtm_msglen = sizeof(hdr); | |||
1337 | hdr.rtm_hdrlen = sizeof(struct rt_msghdr); | |||
1338 | hdr.rtm_priority = kr->priority; | |||
1339 | hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ | |||
1340 | /* adjust iovec */ | |||
1341 | iov[iovcnt].iov_base = &hdr; | |||
1342 | iov[iovcnt++].iov_len = sizeof(hdr); | |||
1343 | ||||
1344 | if (family == AF_MPLS33) { | |||
1345 | memset(&label_in, 0, sizeof(label_in)); | |||
1346 | label_in.smpls_len = sizeof(label_in); | |||
1347 | label_in.smpls_family = AF_MPLS33; | |||
1348 | label_in.smpls_label = | |||
1349 | htonl(kr->local_label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(kr->local_label << 12) ? (__uint32_t)(((__uint32_t)(kr->local_label << 12) & 0xff) << 24 | ((__uint32_t)(kr->local_label << 12) & 0xff00) << 8 | ((__uint32_t)(kr-> local_label << 12) & 0xff0000) >> 8 | ((__uint32_t )(kr->local_label << 12) & 0xff000000) >> 24 ) : __swap32md(kr->local_label << 12)); | |||
1350 | /* adjust header */ | |||
1351 | hdr.rtm_flags |= RTF_MPLS0x100000 | RTF_MPATH0x40000; | |||
1352 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1353 | hdr.rtm_msglen += sizeof(label_in); | |||
1354 | /* adjust iovec */ | |||
1355 | iov[iovcnt].iov_base = &label_in; | |||
1356 | iov[iovcnt++].iov_len = sizeof(label_in); | |||
1357 | } else { | |||
1358 | memset(&dst, 0, sizeof(dst)); | |||
1359 | dst.sin6_len = sizeof(dst); | |||
1360 | dst.sin6_family = AF_INET624; | |||
1361 | dst.sin6_addr = kr->prefix.v6; | |||
1362 | /* adjust header */ | |||
1363 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1364 | hdr.rtm_msglen += ROUNDUP(sizeof(dst))((sizeof(dst)) > 0 ? (1 + (((sizeof(dst)) - 1) | (sizeof(long ) - 1))) : sizeof(long)); | |||
1365 | /* adjust iovec */ | |||
1366 | iov[iovcnt].iov_base = &dst; | |||
1367 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(dst))((sizeof(dst)) > 0 ? (1 + (((sizeof(dst)) - 1) | (sizeof(long ) - 1))) : sizeof(long)); | |||
1368 | } | |||
1369 | ||||
1370 | memset(&nexthop, 0, sizeof(nexthop)); | |||
1371 | nexthop.sin6_len = sizeof(nexthop); | |||
1372 | nexthop.sin6_family = AF_INET624; | |||
1373 | nexthop.sin6_addr = kr->nexthop.v6; | |||
1374 | nexthop.sin6_scope_id = kr->ifindex; | |||
1375 | /* | |||
1376 | * XXX we should set the sin6_scope_id but the kernel | |||
1377 | * XXX does not expect it that way. It must be fiddled | |||
1378 | * XXX into the sin6_addr. Welcome to the typical | |||
1379 | * XXX IPv6 insanity and all without wine bottles. | |||
1380 | */ | |||
1381 | embedscope(&nexthop); | |||
1382 | ||||
1383 | /* adjust header */ | |||
1384 | hdr.rtm_flags |= RTF_GATEWAY0x2; | |||
1385 | hdr.rtm_addrs |= RTA_GATEWAY0x2; | |||
1386 | hdr.rtm_msglen += ROUNDUP(sizeof(nexthop))((sizeof(nexthop)) > 0 ? (1 + (((sizeof(nexthop)) - 1) | ( sizeof(long) - 1))) : sizeof(long)); | |||
1387 | /* adjust iovec */ | |||
1388 | iov[iovcnt].iov_base = &nexthop; | |||
1389 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(nexthop))((sizeof(nexthop)) > 0 ? (1 + (((sizeof(nexthop)) - 1) | ( sizeof(long) - 1))) : sizeof(long)); | |||
1390 | ||||
1391 | if (family == AF_INET624) { | |||
1392 | memset(&mask, 0, sizeof(mask)); | |||
1393 | mask.sin6_len = sizeof(mask); | |||
1394 | mask.sin6_family = AF_INET624; | |||
1395 | mask.sin6_addr = *prefixlen2mask6(kr->prefixlen); | |||
1396 | /* adjust header */ | |||
1397 | if (kr->prefixlen == 128) | |||
1398 | hdr.rtm_flags |= RTF_HOST0x4; | |||
1399 | hdr.rtm_addrs |= RTA_NETMASK0x4; | |||
1400 | hdr.rtm_msglen += ROUNDUP(sizeof(mask))((sizeof(mask)) > 0 ? (1 + (((sizeof(mask)) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1401 | /* adjust iovec */ | |||
1402 | iov[iovcnt].iov_base = &mask; | |||
1403 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(mask))((sizeof(mask)) > 0 ? (1 + (((sizeof(mask)) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1404 | } | |||
1405 | ||||
1406 | /* If action is RTM_DELETE we have to get rid of MPLS infos */ | |||
1407 | if (kr->remote_label != NO_LABEL0xffffffffU && action != RTM_DELETE0x2) { | |||
1408 | memset(&label_out, 0, sizeof(label_out)); | |||
1409 | label_out.smpls_len = sizeof(label_out); | |||
1410 | label_out.smpls_family = AF_MPLS33; | |||
1411 | label_out.smpls_label = | |||
1412 | htonl(kr->remote_label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(kr->remote_label << 12) ? (__uint32_t)(((__uint32_t)(kr->remote_label << 12) & 0xff) << 24 | ((__uint32_t)(kr->remote_label << 12) & 0xff00) << 8 | ((__uint32_t)(kr-> remote_label << 12) & 0xff0000) >> 8 | ((__uint32_t )(kr->remote_label << 12) & 0xff000000) >> 24) : __swap32md(kr->remote_label << 12)); | |||
1413 | /* adjust header */ | |||
1414 | hdr.rtm_addrs |= RTA_SRC0x100; | |||
1415 | hdr.rtm_flags |= RTF_MPLS0x100000; | |||
1416 | hdr.rtm_msglen += sizeof(label_out); | |||
1417 | /* adjust iovec */ | |||
1418 | iov[iovcnt].iov_base = &label_out; | |||
1419 | iov[iovcnt++].iov_len = sizeof(label_out); | |||
1420 | ||||
1421 | if (kr->remote_label == MPLS_LABEL_IMPLNULL3) { | |||
1422 | if (family == AF_MPLS33) | |||
1423 | hdr.rtm_mpls = MPLS_OP_POP0x1; | |||
1424 | else | |||
1425 | return (0); | |||
1426 | } else { | |||
1427 | if (family == AF_MPLS33) | |||
1428 | hdr.rtm_mpls = MPLS_OP_SWAP0x4; | |||
1429 | else | |||
1430 | hdr.rtm_mpls = MPLS_OP_PUSH0x2; | |||
1431 | } | |||
1432 | } | |||
1433 | ||||
1434 | retry: | |||
1435 | if (writev(fd, iov, iovcnt) == -1) { | |||
1436 | if (errno(*__errno()) == ESRCH3) { | |||
1437 | if (hdr.rtm_type == RTM_CHANGE0x3 && family == AF_MPLS33) { | |||
1438 | hdr.rtm_type = RTM_ADD0x1; | |||
1439 | goto retry; | |||
1440 | } else if (hdr.rtm_type == RTM_DELETE0x2) { | |||
1441 | log_info("route %s/%u vanished before delete", | |||
1442 | log_addr(kr->af, &kr->prefix), | |||
1443 | kr->prefixlen); | |||
1444 | return (-1); | |||
1445 | } | |||
1446 | } | |||
1447 | log_warn("%s action %u, af %s, prefix %s/%u", __func__, | |||
1448 | hdr.rtm_type, af_name(family), log_addr(kr->af, | |||
1449 | &kr->prefix), kr->prefixlen); | |||
1450 | return (-1); | |||
1451 | } | |||
1452 | return (0); | |||
1453 | } | |||
1454 | ||||
1455 | static int | |||
1456 | fetchtable(void) | |||
1457 | { | |||
1458 | size_t len; | |||
1459 | int mib[7]; | |||
1460 | char *buf; | |||
1461 | int rv; | |||
1462 | ||||
1463 | mib[0] = CTL_NET4; | |||
1464 | mib[1] = PF_ROUTE17; | |||
1465 | mib[2] = 0; | |||
1466 | mib[3] = 0; | |||
1467 | mib[4] = NET_RT_DUMP1; | |||
1468 | mib[5] = 0; | |||
1469 | mib[6] = kr_state.rdomain; /* rtableid */ | |||
1470 | ||||
1471 | if (sysctl(mib, 7, NULL((void *)0), &len, NULL((void *)0), 0) == -1) { | |||
1472 | log_warn("sysctl"); | |||
1473 | return (-1); | |||
1474 | } | |||
1475 | if ((buf = malloc(len)) == NULL((void *)0)) { | |||
1476 | log_warn(__func__); | |||
1477 | return (-1); | |||
1478 | } | |||
1479 | if (sysctl(mib, 7, buf, &len, NULL((void *)0), 0) == -1) { | |||
1480 | log_warn("sysctl"); | |||
1481 | free(buf); | |||
1482 | return (-1); | |||
1483 | } | |||
1484 | ||||
1485 | rv = rtmsg_process(buf, len); | |||
1486 | free(buf); | |||
1487 | ||||
1488 | return (rv); | |||
1489 | } | |||
1490 | ||||
1491 | static int | |||
1492 | fetchifs(void) | |||
1493 | { | |||
1494 | size_t len; | |||
1495 | int mib[6]; | |||
1496 | char *buf; | |||
1497 | int rv; | |||
1498 | ||||
1499 | mib[0] = CTL_NET4; | |||
1500 | mib[1] = PF_ROUTE17; | |||
1501 | mib[2] = 0; | |||
1502 | mib[3] = 0; /* wildcard */ | |||
1503 | mib[4] = NET_RT_IFLIST3; | |||
1504 | mib[5] = 0; | |||
1505 | ||||
1506 | if (sysctl(mib, 6, NULL((void *)0), &len, NULL((void *)0), 0) == -1) { | |||
1507 | log_warn("sysctl"); | |||
1508 | return (-1); | |||
1509 | } | |||
1510 | if ((buf = malloc(len)) == NULL((void *)0)) { | |||
1511 | log_warn(__func__); | |||
1512 | return (-1); | |||
1513 | } | |||
1514 | if (sysctl(mib, 6, buf, &len, NULL((void *)0), 0) == -1) { | |||
1515 | log_warn("sysctl"); | |||
1516 | free(buf); | |||
1517 | return (-1); | |||
1518 | } | |||
1519 | ||||
1520 | rv = rtmsg_process(buf, len); | |||
1521 | free(buf); | |||
1522 | ||||
1523 | return (rv); | |||
1524 | } | |||
1525 | ||||
1526 | static int | |||
1527 | dispatch_rtmsg(void) | |||
1528 | { | |||
1529 | char buf[RT_BUF_SIZE16384]; | |||
1530 | ssize_t n; | |||
1531 | ||||
1532 | if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { | |||
1533 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
1534 | return (0); | |||
1535 | log_warn("%s: read error", __func__); | |||
1536 | return (-1); | |||
1537 | } | |||
1538 | ||||
1539 | if (n == 0) { | |||
1540 | log_warnx("routing socket closed"); | |||
1541 | return (-1); | |||
1542 | } | |||
1543 | ||||
1544 | return (rtmsg_process(buf, n)); | |||
1545 | } | |||
1546 | ||||
1547 | static int | |||
1548 | rtmsg_process(char *buf, size_t len) | |||
1549 | { | |||
1550 | struct rt_msghdr *rtm; | |||
1551 | struct if_msghdr ifm; | |||
1552 | struct ifa_msghdr *ifam; | |||
1553 | struct sockaddr *sa, *rti_info[RTAX_MAX15]; | |||
1554 | size_t offset; | |||
1555 | char *next; | |||
1556 | ||||
1557 | for (offset = 0; offset < len; offset += rtm->rtm_msglen) { | |||
1558 | next = buf + offset; | |||
1559 | rtm = (struct rt_msghdr *)next; | |||
1560 | if (len < offset + sizeof(unsigned short) || | |||
1561 | len < offset + rtm->rtm_msglen) | |||
1562 | fatalx("rtmsg_process: partial rtm in buffer"); | |||
1563 | if (rtm->rtm_version != RTM_VERSION5) | |||
1564 | continue; | |||
1565 | ||||
1566 | sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); | |||
1567 | get_rtaddrs(rtm->rtm_addrs, sa, rti_info); | |||
1568 | ||||
1569 | switch (rtm->rtm_type) { | |||
1570 | case RTM_ADD0x1: | |||
1571 | case RTM_GET0x4: | |||
1572 | case RTM_CHANGE0x3: | |||
1573 | case RTM_DELETE0x2: | |||
1574 | if (rtm->rtm_errno) /* failed attempts... */ | |||
1575 | continue; | |||
1576 | ||||
1577 | if (rtm->rtm_tableid != kr_state.rdomain) | |||
1578 | continue; | |||
1579 | ||||
1580 | if (rtm->rtm_type == RTM_GET0x4 && | |||
1581 | rtm->rtm_pid != kr_state.pid) | |||
1582 | continue; | |||
1583 | ||||
1584 | /* Skip ARP/ND cache and broadcast routes. */ | |||
1585 | if (rtm->rtm_flags & (RTF_LLINFO0x400|RTF_BROADCAST0x400000)) | |||
1586 | continue; | |||
1587 | ||||
1588 | /* LDP should follow the IGP and ignore BGP routes */ | |||
1589 | if (rtm->rtm_priority == RTP_BGP48) | |||
1590 | continue; | |||
1591 | ||||
1592 | if (rtmsg_process_route(rtm, rti_info) == -1) | |||
1593 | return (-1); | |||
1594 | } | |||
1595 | ||||
1596 | switch (rtm->rtm_type) { | |||
1597 | case RTM_IFINFO0xe: | |||
1598 | memcpy(&ifm, next, sizeof(ifm)); | |||
1599 | if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data, | |||
1600 | (struct sockaddr_dl *)rti_info[RTAX_IFP4]); | |||
1601 | break; | |||
1602 | case RTM_NEWADDR0xc: | |||
1603 | ifam = (struct ifa_msghdr *)rtm; | |||
1604 | if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 | | |||
1605 | RTA_BRD0x80)) == 0) | |||
1606 | break; | |||
1607 | ||||
1608 | if_newaddr(ifam->ifam_index, | |||
1609 | (struct sockaddr *)rti_info[RTAX_IFA5], | |||
1610 | (struct sockaddr *)rti_info[RTAX_NETMASK2], | |||
1611 | (struct sockaddr *)rti_info[RTAX_BRD7]); | |||
1612 | break; | |||
1613 | case RTM_DELADDR0xd: | |||
1614 | ifam = (struct ifa_msghdr *)rtm; | |||
1615 | if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 | | |||
1616 | RTA_BRD0x80)) == 0) | |||
1617 | break; | |||
1618 | ||||
1619 | if_deladdr(ifam->ifam_index, | |||
1620 | (struct sockaddr *)rti_info[RTAX_IFA5], | |||
1621 | (struct sockaddr *)rti_info[RTAX_NETMASK2], | |||
1622 | (struct sockaddr *)rti_info[RTAX_BRD7]); | |||
1623 | break; | |||
1624 | case RTM_IFANNOUNCE0xf: | |||
1625 | if_announce(next); | |||
1626 | break; | |||
1627 | default: | |||
1628 | /* ignore for now */ | |||
1629 | break; | |||
1630 | } | |||
1631 | } | |||
1632 | ||||
1633 | return (offset); | |||
1634 | } | |||
1635 | ||||
1636 | static int | |||
1637 | rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX15]) | |||
1638 | { | |||
1639 | struct sockaddr *sa; | |||
1640 | struct sockaddr_in *sa_in; | |||
1641 | struct sockaddr_in6 *sa_in6; | |||
1642 | struct kroute kr; | |||
1643 | struct kroute_prefix *kp; | |||
1644 | struct kroute_priority *kprio; | |||
1645 | struct kroute_node *kn; | |||
1646 | ||||
1647 | if ((sa = rti_info[RTAX_DST0]) == NULL((void *)0)) | |||
1648 | return (-1); | |||
1649 | ||||
1650 | memset(&kr, 0, sizeof(kr)); | |||
1651 | kr.af = sa->sa_family; | |||
1652 | switch (kr.af) { | |||
1653 | case AF_INET2: | |||
1654 | kr.prefix.v4 = ((struct sockaddr_in *)sa)->sin_addr; | |||
1655 | sa_in = (struct sockaddr_in *) rti_info[RTAX_NETMASK2]; | |||
1656 | if (sa_in != NULL((void *)0) && sa_in->sin_len != 0) | |||
1657 | kr.prefixlen = mask2prefixlen(sa_in->sin_addr.s_addr); | |||
1658 | else if (rtm->rtm_flags & RTF_HOST0x4) | |||
1659 | kr.prefixlen = 32; | |||
1660 | else if (kr.prefix.v4.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) | |||
1661 | kr.prefixlen = 0; | |||
1662 | else | |||
1663 | kr.prefixlen = prefixlen_classful(kr.prefix.v4.s_addr); | |||
1664 | break; | |||
1665 | case AF_INET624: | |||
1666 | kr.prefix.v6 = ((struct sockaddr_in6 *)sa)->sin6_addr; | |||
1667 | sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK2]; | |||
1668 | if (sa_in6 != NULL((void *)0) && sa_in6->sin6_len != 0) | |||
1669 | kr.prefixlen = mask2prefixlen6(sa_in6); | |||
1670 | else if (rtm->rtm_flags & RTF_HOST0x4) | |||
1671 | kr.prefixlen = 128; | |||
1672 | else if (IN6_IS_ADDR_UNSPECIFIED(&kr.prefix.v6)((*(const u_int32_t *)(const void *)(&(&kr.prefix.v6) ->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&kr.prefix.v6)->__u6_addr.__u6_addr8 [4]) == 0) && (*(const u_int32_t *)(const void *)(& (&kr.prefix.v6)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *)(const void *)(&(&kr.prefix.v6) ->__u6_addr.__u6_addr8[12]) == 0))) | |||
1673 | kr.prefixlen = 0; | |||
1674 | else | |||
1675 | fatalx("in6 net addr without netmask"); | |||
1676 | break; | |||
1677 | default: | |||
1678 | return (0); | |||
1679 | } | |||
1680 | kr.ifindex = rtm->rtm_index; | |||
1681 | if ((sa = rti_info[RTAX_GATEWAY1]) != NULL((void *)0)) { | |||
1682 | switch (sa->sa_family) { | |||
1683 | case AF_INET2: | |||
1684 | kr.nexthop.v4 = ((struct sockaddr_in *)sa)->sin_addr; | |||
1685 | break; | |||
1686 | case AF_INET624: | |||
1687 | sa_in6 = (struct sockaddr_in6 *)sa; | |||
1688 | recoverscope(sa_in6); | |||
1689 | kr.nexthop.v6 = sa_in6->sin6_addr; | |||
1690 | if (sa_in6->sin6_scope_id) | |||
1691 | kr.ifindex = sa_in6->sin6_scope_id; | |||
1692 | break; | |||
1693 | case AF_LINK18: | |||
1694 | kr.flags |= F_CONNECTED0x0002; | |||
1695 | break; | |||
1696 | } | |||
1697 | } | |||
1698 | ||||
1699 | if (rtm->rtm_flags & RTF_STATIC0x800) | |||
1700 | kr.flags |= F_STATIC0x0004; | |||
1701 | if (rtm->rtm_flags & RTF_BLACKHOLE0x1000) | |||
1702 | kr.flags |= F_BLACKHOLE0x0020; | |||
1703 | if (rtm->rtm_flags & RTF_REJECT0x8) | |||
1704 | kr.flags |= F_REJECT0x0010; | |||
1705 | if (rtm->rtm_flags & RTF_DYNAMIC0x10) | |||
1706 | kr.flags |= F_DYNAMIC0x0008; | |||
1707 | /* routes attached to connected or loopback interfaces */ | |||
1708 | if (rtm->rtm_flags & RTF_CONNECTED0x800000 || | |||
1709 | ldp_addrcmp(kr.af, &kr.prefix, &kr.nexthop) == 0) | |||
1710 | kr.flags |= F_CONNECTED0x0002; | |||
1711 | kr.priority = rtm->rtm_priority; | |||
1712 | ||||
1713 | if (rtm->rtm_type == RTM_CHANGE0x3) { | |||
1714 | /* | |||
1715 | * The kernel doesn't allow RTM_CHANGE for multipath routes. | |||
1716 | * If we got this message we know that the route has only one | |||
1717 | * nexthop and we should remove it before installing the same | |||
1718 | * route with the new nexthop. | |||
1719 | */ | |||
1720 | kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); | |||
1721 | if (kp) { | |||
1722 | kprio = kroute_find_prio(kp, kr.priority); | |||
1723 | if (kprio) { | |||
1724 | kn = TAILQ_FIRST(&kprio->nexthops)((&kprio->nexthops)->tqh_first); | |||
1725 | if (kn) | |||
1726 | kroute_remove(&kn->r); | |||
1727 | } | |||
1728 | } | |||
1729 | } | |||
1730 | ||||
1731 | kn = NULL((void *)0); | |||
1732 | kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); | |||
1733 | if (kp) { | |||
1734 | kprio = kroute_find_prio(kp, kr.priority); | |||
1735 | if (kprio) | |||
1736 | kn = kroute_find_gw(kprio, &kr.nexthop); | |||
1737 | } | |||
1738 | ||||
1739 | if (rtm->rtm_type == RTM_DELETE0x2) { | |||
1740 | if (kn == NULL((void *)0)) | |||
1741 | return (0); | |||
1742 | return (kroute_remove(&kr)); | |||
1743 | } | |||
1744 | ||||
1745 | if (!ldp_addrisset(kr.af, &kr.nexthop) && !(kr.flags & F_CONNECTED0x0002)) { | |||
1746 | log_warnx("%s: no nexthop for %s/%u", __func__, | |||
1747 | log_addr(kr.af, &kr.prefix), kr.prefixlen); | |||
1748 | return (-1); | |||
1749 | } | |||
1750 | ||||
1751 | if (kn != NULL((void *)0)) { | |||
1752 | /* update route */ | |||
1753 | kn->r = kr; | |||
1754 | kr_redistribute(kp); | |||
1755 | } else { | |||
1756 | kr.local_label = NO_LABEL0xffffffffU; | |||
1757 | kr.remote_label = NO_LABEL0xffffffffU; | |||
1758 | kroute_insert(&kr); | |||
1759 | } | |||
1760 | ||||
1761 | return (0); | |||
1762 | } | |||
1763 | ||||
1764 | int | |||
1765 | kmpw_set(struct kpw *kpw) | |||
1766 | { | |||
1767 | struct kif_node *kif; | |||
1768 | ||||
1769 | kif = kif_find(kpw->ifindex); | |||
1770 | if (kif == NULL((void *)0)) { | |||
1771 | log_warnx("%s: failed to find mpw by index (%u)", __func__, | |||
1772 | kpw->ifindex); | |||
1773 | return (-1); | |||
1774 | } | |||
1775 | ||||
1776 | if (kif->kpw == NULL((void *)0)) | |||
1777 | kif->kpw = malloc(sizeof(*kif->kpw)); | |||
1778 | *kif->kpw = *kpw; | |||
1779 | ||||
1780 | return (kmpw_install(kif->k.ifname, kpw)); | |||
1781 | } | |||
1782 | ||||
1783 | int | |||
1784 | kmpw_unset(struct kpw *kpw) | |||
1785 | { | |||
1786 | struct kif_node *kif; | |||
1787 | ||||
1788 | kif = kif_find(kpw->ifindex); | |||
1789 | if (kif == NULL((void *)0)) { | |||
1790 | log_warnx("%s: failed to find mpw by index (%u)", __func__, | |||
1791 | kpw->ifindex); | |||
1792 | return (-1); | |||
1793 | } | |||
1794 | ||||
1795 | if (kif->kpw == NULL((void *)0)) { | |||
1796 | log_warnx("%s: %s is not set", __func__, kif->k.ifname); | |||
1797 | return (-1); | |||
1798 | } | |||
1799 | ||||
1800 | free(kif->kpw); | |||
1801 | kif->kpw = NULL((void *)0); | |||
1802 | return (kmpw_uninstall(kif->k.ifname)); | |||
1803 | } | |||
1804 | ||||
1805 | static int | |||
1806 | kmpw_install(const char *ifname, struct kpw *kpw) | |||
1807 | { | |||
1808 | struct ifreq ifr; | |||
1809 | struct ifmpwreq imr; | |||
1810 | ||||
1811 | memset(&imr, 0, sizeof(imr)); | |||
1812 | switch (kpw->pw_type) { | |||
1813 | case PW_TYPE_ETHERNET0x0005: | |||
1814 | imr.imr_type = IMR_TYPE_ETHERNET1; | |||
1815 | break; | |||
1816 | case PW_TYPE_ETHERNET_TAGGED0x0004: | |||
1817 | imr.imr_type = IMR_TYPE_ETHERNET_TAGGED2; | |||
1818 | break; | |||
1819 | default: | |||
1820 | log_warnx("%s: unhandled pseudowire type (%#X)", __func__, | |||
1821 | kpw->pw_type); | |||
1822 | return (-1); | |||
1823 | } | |||
1824 | ||||
1825 | if (kpw->flags & F_PW_CWORD0x08) | |||
1826 | imr.imr_flags |= IMR_FLAG_CONTROLWORD0x1; | |||
1827 | ||||
1828 | memcpy(&imr.imr_nexthop, addr2sa(kpw->af, &kpw->nexthop, 0), | |||
1829 | sizeof(imr.imr_nexthop)); | |||
1830 | ||||
1831 | imr.imr_lshim.shim_label = kpw->local_label; | |||
1832 | imr.imr_rshim.shim_label = kpw->remote_label; | |||
1833 | ||||
1834 | memset(&ifr, 0, sizeof(ifr)); | |||
1835 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); | |||
1836 | ifr.ifr_dataifr_ifru.ifru_data = (caddr_t) &imr; | |||
1837 | if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((173))), &ifr) == -1) { | |||
1838 | log_warn("ioctl SIOCSETMPWCFG"); | |||
1839 | return (-1); | |||
1840 | } | |||
1841 | ||||
1842 | return (0); | |||
1843 | } | |||
1844 | ||||
1845 | static int | |||
1846 | kmpw_uninstall(const char *ifname) | |||
1847 | { | |||
1848 | struct ifreq ifr; | |||
1849 | struct ifmpwreq imr; | |||
1850 | ||||
1851 | memset(&ifr, 0, sizeof(ifr)); | |||
1852 | memset(&imr, 0, sizeof(imr)); | |||
1853 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); | |||
1854 | ifr.ifr_dataifr_ifru.ifru_data = (caddr_t) &imr; | |||
1855 | if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((173))), &ifr) == -1) { | |||
1856 | log_warn("ioctl SIOCSETMPWCFG"); | |||
1857 | return (-1); | |||
1858 | } | |||
1859 | ||||
1860 | return (0); | |||
1861 | } | |||
1862 | ||||
1863 | int | |||
1864 | kmpw_find(const char *ifname) | |||
1865 | { | |||
1866 | struct ifreq ifr; | |||
1867 | ||||
1868 | memset(&ifr, 0, sizeof(ifr)); | |||
1869 | if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= | |||
1870 | sizeof(ifr.ifr_name)) { | |||
1871 | errno(*__errno()) = ENAMETOOLONG63; | |||
1872 | return (-1); | |||
1873 | } | |||
1874 | ||||
1875 | if (ioctl(kr_state.ioctl_fd, SIOCGPWE3(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((152))), &ifr) == -1) | |||
1876 | return (-1); | |||
1877 | ||||
1878 | if (ifr.ifr_pwe3ifr_ifru.ifru_metric != IF_PWE3_ETHERNET1) { | |||
1879 | errno(*__errno()) = EPFNOSUPPORT46; | |||
1880 | return (-1); | |||
1881 | } | |||
1882 | ||||
1883 | return (0); | |||
1884 | } |