File: | src/usr.sbin/ldpd/kroute.c |
Warning: | line 516, column 7 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: kroute.c,v 1.70 2019/06/28 13:32:48 deraadt 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 | /* ARGSUSED */ | |||
441 | static void | |||
442 | kr_dispatch_msg(int fd, short event, void *bula) | |||
443 | { | |||
444 | if (dispatch_rtmsg() == -1) | |||
445 | event_loopexit(NULL((void *)0)); | |||
446 | } | |||
447 | ||||
448 | void | |||
449 | kr_show_route(struct imsg *imsg) | |||
450 | { | |||
451 | struct kroute_prefix *kp; | |||
452 | struct kroute_priority *kprio; | |||
453 | struct kroute_node *kn; | |||
454 | int flags; | |||
455 | struct kroute kr; | |||
456 | ||||
457 | switch (imsg->hdr.type) { | |||
458 | case IMSG_CTL_KROUTE: | |||
459 | if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(flags)) { | |||
460 | log_warnx("%s: wrong imsg len", __func__); | |||
461 | return; | |||
462 | } | |||
463 | memcpy(&flags, imsg->data, sizeof(flags)); | |||
464 | ||||
465 | RB_FOREACH(kp, kroute_tree, &krt)for ((kp) = kroute_tree_RB_MINMAX(&krt, -1); (kp) != ((void *)0); (kp) = kroute_tree_RB_NEXT(kp)) | |||
466 | TAILQ_FOREACH(kprio, &kp->priorities, entry)for((kprio) = ((&kp->priorities)->tqh_first); (kprio ) != ((void *)0); (kprio) = ((kprio)->entry.tqe_next)) | |||
467 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) { | |||
468 | if (flags && !(kn->r.flags & flags)) | |||
469 | continue; | |||
470 | ||||
471 | main_imsg_compose_ldpe(IMSG_CTL_KROUTE, | |||
472 | imsg->hdr.pid, &kn->r, | |||
473 | sizeof(kn->r)); | |||
474 | } | |||
475 | break; | |||
476 | case IMSG_CTL_KROUTE_ADDR: | |||
477 | if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(kr)) { | |||
478 | log_warnx("%s: wrong imsg len", __func__); | |||
479 | return; | |||
480 | } | |||
481 | memcpy(&kr, imsg->data, sizeof(kr)); | |||
482 | ||||
483 | kprio = kroute_match(kr.af, &kr.prefix); | |||
484 | if (kprio == NULL((void *)0)) | |||
485 | break; | |||
486 | ||||
487 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
488 | main_imsg_compose_ldpe(IMSG_CTL_KROUTE, imsg->hdr.pid, | |||
489 | &kn->r, sizeof(kn->r)); | |||
490 | break; | |||
491 | default: | |||
492 | log_debug("%s: error handling imsg", __func__); | |||
493 | break; | |||
494 | } | |||
495 | main_imsg_compose_ldpe(IMSG_CTL_END, imsg->hdr.pid, NULL((void *)0), 0); | |||
496 | } | |||
497 | ||||
498 | void | |||
499 | kr_ifinfo(char *ifname, pid_t pid) | |||
500 | { | |||
501 | struct kif_node *kif; | |||
502 | ||||
503 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
504 | if (ifname == NULL((void *)0) || !strcmp(ifname, kif->k.ifname)) { | |||
505 | main_imsg_compose_ldpe(IMSG_CTL_IFINFO, | |||
506 | pid, &kif->k, sizeof(kif->k)); | |||
507 | } | |||
508 | ||||
509 | main_imsg_compose_ldpe(IMSG_CTL_END, pid, NULL((void *)0), 0); | |||
510 | } | |||
511 | ||||
512 | static void | |||
513 | kr_redist_remove(struct kroute *kr) | |||
514 | { | |||
515 | /* was the route redistributed? */ | |||
516 | if ((kr->flags & F_REDISTRIBUTED0x0040) == 0) | |||
| ||||
517 | return; | |||
518 | ||||
519 | /* remove redistributed flag */ | |||
520 | kr->flags &= ~F_REDISTRIBUTED0x0040; | |||
521 | main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, kr, sizeof(*kr)); | |||
522 | } | |||
523 | ||||
524 | static int | |||
525 | kr_redist_eval(struct kroute *kr) | |||
526 | { | |||
527 | /* was the route redistributed? */ | |||
528 | if (kr->flags & F_REDISTRIBUTED0x0040) | |||
529 | goto dont_redistribute; | |||
530 | ||||
531 | /* Dynamic routes are not redistributable. */ | |||
532 | if (kr->flags & F_DYNAMIC0x0008) | |||
533 | goto dont_redistribute; | |||
534 | ||||
535 | /* filter-out non-redistributable addresses */ | |||
536 | if (bad_addr(kr->af, &kr->prefix) || | |||
537 | (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)))))) | |||
538 | goto dont_redistribute; | |||
539 | ||||
540 | /* do not redistribute the default route */ | |||
541 | if (kr->prefixlen == 0) | |||
542 | goto dont_redistribute; | |||
543 | ||||
544 | /* | |||
545 | * Consider networks with nexthop loopback as not redistributable | |||
546 | * unless it is a reject or blackhole route. | |||
547 | */ | |||
548 | switch (kr->af) { | |||
549 | case AF_INET2: | |||
550 | 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)))) && | |||
551 | !(kr->flags & (F_BLACKHOLE0x0020|F_REJECT0x0010))) | |||
552 | goto dont_redistribute; | |||
553 | break; | |||
554 | case AF_INET624: | |||
555 | 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)))) && | |||
556 | !(kr->flags & (F_BLACKHOLE0x0020|F_REJECT0x0010))) | |||
557 | goto dont_redistribute; | |||
558 | break; | |||
559 | default: | |||
560 | log_debug("%s: unexpected address-family", __func__); | |||
561 | break; | |||
562 | } | |||
563 | ||||
564 | /* prefix should be redistributed */ | |||
565 | kr->flags |= F_REDISTRIBUTED0x0040; | |||
566 | main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, kr, sizeof(*kr)); | |||
567 | return (1); | |||
568 | ||||
569 | dont_redistribute: | |||
570 | return (0); | |||
571 | } | |||
572 | ||||
573 | static void | |||
574 | kr_redistribute(struct kroute_prefix *kp) | |||
575 | { | |||
576 | struct kroute_priority *kprio; | |||
577 | struct kroute_node *kn; | |||
578 | ||||
579 | 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 ))) { | |||
580 | if (kprio == TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)) { | |||
581 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
582 | kr_redist_eval(&kn->r); | |||
583 | } else { | |||
584 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
585 | kr_redist_remove(&kn->r); | |||
586 | } | |||
587 | } | |||
588 | } | |||
589 | ||||
590 | /* rb-tree compare */ | |||
591 | static __inline int | |||
592 | kroute_compare(struct kroute_prefix *a, struct kroute_prefix *b) | |||
593 | { | |||
594 | int addrcmp; | |||
595 | ||||
596 | if (a->af < b->af) | |||
597 | return (-1); | |||
598 | if (a->af > b->af) | |||
599 | return (1); | |||
600 | ||||
601 | addrcmp = ldp_addrcmp(a->af, &a->prefix, &b->prefix); | |||
602 | if (addrcmp != 0) | |||
603 | return (addrcmp); | |||
604 | ||||
605 | if (a->prefixlen < b->prefixlen) | |||
606 | return (-1); | |||
607 | if (a->prefixlen > b->prefixlen) | |||
608 | return (1); | |||
609 | ||||
610 | return (0); | |||
611 | } | |||
612 | ||||
613 | /* tree management */ | |||
614 | static struct kroute_prefix * | |||
615 | kroute_find_prefix(int af, union ldpd_addr *prefix, uint8_t prefixlen) | |||
616 | { | |||
617 | struct kroute_prefix s; | |||
618 | ||||
619 | s.af = af; | |||
620 | s.prefix = *prefix; | |||
621 | s.prefixlen = prefixlen; | |||
622 | ||||
623 | return (RB_FIND(kroute_tree, &krt, &s)kroute_tree_RB_FIND(&krt, &s)); | |||
624 | } | |||
625 | ||||
626 | static struct kroute_priority * | |||
627 | kroute_find_prio(struct kroute_prefix *kp, uint8_t prio) | |||
628 | { | |||
629 | struct kroute_priority *kprio; | |||
630 | ||||
631 | /* RTP_ANY here picks the lowest priority node */ | |||
632 | if (prio == RTP_ANY64) | |||
633 | return (TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)); | |||
634 | ||||
635 | TAILQ_FOREACH(kprio, &kp->priorities, entry)for((kprio) = ((&kp->priorities)->tqh_first); (kprio ) != ((void *)0); (kprio) = ((kprio)->entry.tqe_next)) | |||
636 | if (kprio->priority == prio) | |||
637 | return (kprio); | |||
638 | ||||
639 | return (NULL((void *)0)); | |||
640 | } | |||
641 | ||||
642 | static struct kroute_node * | |||
643 | kroute_find_gw(struct kroute_priority *kprio, union ldpd_addr *nh) | |||
644 | { | |||
645 | struct kroute_node *kn; | |||
646 | ||||
647 | TAILQ_FOREACH(kn, &kprio->nexthops, entry)for((kn) = ((&kprio->nexthops)->tqh_first); (kn) != ((void *)0); (kn) = ((kn)->entry.tqe_next)) | |||
648 | if (ldp_addrcmp(kprio->kp->af, &kn->r.nexthop, nh) == 0) | |||
649 | return (kn); | |||
650 | ||||
651 | return (NULL((void *)0)); | |||
652 | } | |||
653 | ||||
654 | static int | |||
655 | kroute_insert(struct kroute *kr) | |||
656 | { | |||
657 | struct kroute_prefix *kp; | |||
658 | struct kroute_priority *kprio, *tmp; | |||
659 | struct kroute_node *kn; | |||
660 | ||||
661 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
662 | if (kp == NULL((void *)0)) { | |||
663 | kp = calloc(1, sizeof((*kp))); | |||
664 | if (kp == NULL((void *)0)) | |||
665 | fatal(__func__); | |||
666 | kp->af = kr->af; | |||
667 | kp->prefix = kr->prefix; | |||
668 | kp->prefixlen = kr->prefixlen; | |||
669 | TAILQ_INIT(&kp->priorities)do { (&kp->priorities)->tqh_first = ((void *)0); (& kp->priorities)->tqh_last = &(&kp->priorities )->tqh_first; } while (0); | |||
670 | RB_INSERT(kroute_tree, &krt, kp)kroute_tree_RB_INSERT(&krt, kp); | |||
671 | } | |||
672 | ||||
673 | kprio = kroute_find_prio(kp, kr->priority); | |||
674 | if (kprio == NULL((void *)0)) { | |||
675 | kprio = calloc(1, sizeof(*kprio)); | |||
676 | if (kprio == NULL((void *)0)) | |||
677 | fatal(__func__); | |||
678 | kprio->kp = kp; | |||
679 | kprio->priority = kr->priority; | |||
680 | TAILQ_INIT(&kprio->nexthops)do { (&kprio->nexthops)->tqh_first = ((void *)0); ( &kprio->nexthops)->tqh_last = &(&kprio-> nexthops)->tqh_first; } while (0); | |||
681 | ||||
682 | /* lower priorities first */ | |||
683 | TAILQ_FOREACH(tmp, &kp->priorities, entry)for((tmp) = ((&kp->priorities)->tqh_first); (tmp) != ((void *)0); (tmp) = ((tmp)->entry.tqe_next)) | |||
684 | if (tmp->priority > kprio->priority) | |||
685 | break; | |||
686 | if (tmp) | |||
687 | 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); | |||
688 | else | |||
689 | 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); | |||
690 | } | |||
691 | ||||
692 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
693 | if (kn == NULL((void *)0)) { | |||
694 | kn = calloc(1, sizeof(*kn)); | |||
695 | if (kn == NULL((void *)0)) | |||
696 | fatal(__func__); | |||
697 | kn->kprio = kprio; | |||
698 | kn->r = *kr; | |||
699 | 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); | |||
700 | } | |||
701 | ||||
702 | kr_redistribute(kp); | |||
703 | return (0); | |||
704 | } | |||
705 | ||||
706 | static int | |||
707 | kroute_uninstall(struct kroute_node *kn) | |||
708 | { | |||
709 | /* kill MPLS LSP if one was installed */ | |||
710 | if (kn->r.flags & F_LDPD_INSERTED0x0001) | |||
711 | if (send_rtmsg(kr_state.fd, RTM_DELETE0x2, &kn->r, AF_MPLS33) == -1) | |||
712 | return (-1); | |||
713 | ||||
714 | return (0); | |||
715 | } | |||
716 | ||||
717 | static int | |||
718 | kroute_remove(struct kroute *kr) | |||
719 | { | |||
720 | struct kroute_prefix *kp; | |||
721 | struct kroute_priority *kprio; | |||
722 | struct kroute_node *kn; | |||
723 | ||||
724 | kp = kroute_find_prefix(kr->af, &kr->prefix, kr->prefixlen); | |||
725 | if (kp == NULL((void *)0)) | |||
726 | goto notfound; | |||
727 | kprio = kroute_find_prio(kp, kr->priority); | |||
728 | if (kprio == NULL((void *)0)) | |||
729 | goto notfound; | |||
730 | kn = kroute_find_gw(kprio, &kr->nexthop); | |||
731 | if (kn == NULL((void *)0)) | |||
732 | goto notfound; | |||
733 | ||||
734 | kr_redist_remove(&kn->r); | |||
735 | kroute_uninstall(kn); | |||
736 | ||||
737 | 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); | |||
738 | free(kn); | |||
739 | ||||
740 | if (TAILQ_EMPTY(&kprio->nexthops)(((&kprio->nexthops)->tqh_first) == ((void *)0))) { | |||
741 | 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); | |||
742 | free(kprio); | |||
743 | } | |||
744 | ||||
745 | if (TAILQ_EMPTY(&kp->priorities)(((&kp->priorities)->tqh_first) == ((void *)0))) { | |||
746 | if (RB_REMOVE(kroute_tree, &krt, kp)kroute_tree_RB_REMOVE(&krt, kp) == NULL((void *)0)) { | |||
747 | log_warnx("%s failed for %s/%u", __func__, | |||
748 | log_addr(kr->af, &kr->prefix), kp->prefixlen); | |||
749 | return (-1); | |||
750 | } | |||
751 | free(kp); | |||
752 | } else | |||
753 | kr_redistribute(kp); | |||
754 | ||||
755 | return (0); | |||
756 | ||||
757 | notfound: | |||
758 | log_warnx("%s failed to find %s/%u", __func__, | |||
759 | log_addr(kr->af, &kr->prefix), kr->prefixlen); | |||
760 | return (-1); | |||
761 | } | |||
762 | ||||
763 | static void | |||
764 | kroute_clear(void) | |||
765 | { | |||
766 | struct kroute_prefix *kp; | |||
767 | struct kroute_priority *kprio; | |||
768 | struct kroute_node *kn; | |||
769 | ||||
770 | while ((kp = RB_MIN(kroute_tree, &krt)kroute_tree_RB_MINMAX(&krt, -1)) != NULL((void *)0)) { | |||
771 | while ((kprio = TAILQ_FIRST(&kp->priorities)((&kp->priorities)->tqh_first)) != NULL((void *)0)) { | |||
772 | while ((kn = TAILQ_FIRST(&kprio->nexthops)((&kprio->nexthops)->tqh_first)) != NULL((void *)0)) { | |||
773 | kr_redist_remove(&kn->r); | |||
774 | kroute_uninstall(kn); | |||
775 | 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); | |||
776 | free(kn); | |||
777 | } | |||
778 | 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); | |||
779 | free(kprio); | |||
780 | } | |||
781 | RB_REMOVE(kroute_tree, &krt, kp)kroute_tree_RB_REMOVE(&krt, kp); | |||
782 | free(kp); | |||
783 | } | |||
784 | } | |||
785 | ||||
786 | static __inline int | |||
787 | kif_compare(struct kif_node *a, struct kif_node *b) | |||
788 | { | |||
789 | return (b->k.ifindex - a->k.ifindex); | |||
790 | } | |||
791 | ||||
792 | /* tree management */ | |||
793 | static struct kif_node * | |||
794 | kif_find(unsigned short ifindex) | |||
795 | { | |||
796 | struct kif_node s; | |||
797 | ||||
798 | memset(&s, 0, sizeof(s)); | |||
799 | s.k.ifindex = ifindex; | |||
800 | ||||
801 | return (RB_FIND(kif_tree, &kit, &s)kif_tree_RB_FIND(&kit, &s)); | |||
802 | } | |||
803 | ||||
804 | struct kif * | |||
805 | kif_findname(char *ifname) | |||
806 | { | |||
807 | struct kif_node *kif; | |||
808 | ||||
809 | RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void *)0); (kif) = kif_tree_RB_NEXT(kif)) | |||
810 | if (!strcmp(ifname, kif->k.ifname)) | |||
811 | return (&kif->k); | |||
812 | ||||
813 | return (NULL((void *)0)); | |||
814 | } | |||
815 | ||||
816 | static struct kif_node * | |||
817 | kif_insert(unsigned short ifindex) | |||
818 | { | |||
819 | struct kif_node *kif; | |||
820 | ||||
821 | if ((kif = calloc(1, sizeof(struct kif_node))) == NULL((void *)0)) | |||
822 | return (NULL((void *)0)); | |||
823 | ||||
824 | kif->k.ifindex = ifindex; | |||
825 | TAILQ_INIT(&kif->addrs)do { (&kif->addrs)->tqh_first = ((void *)0); (& kif->addrs)->tqh_last = &(&kif->addrs)->tqh_first ; } while (0); | |||
826 | ||||
827 | if (RB_INSERT(kif_tree, &kit, kif)kif_tree_RB_INSERT(&kit, kif) != NULL((void *)0)) | |||
828 | fatalx("kif_insert: RB_INSERT"); | |||
829 | ||||
830 | return (kif); | |||
831 | } | |||
832 | ||||
833 | static int | |||
834 | kif_remove(struct kif_node *kif) | |||
835 | { | |||
836 | struct kif_addr *ka; | |||
837 | ||||
838 | if (RB_REMOVE(kif_tree, &kit, kif)kif_tree_RB_REMOVE(&kit, kif) == NULL((void *)0)) { | |||
839 | log_warnx("RB_REMOVE(kif_tree, &kit, kif)"); | |||
840 | return (-1); | |||
841 | } | |||
842 | ||||
843 | while ((ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first)) != NULL((void *)0)) { | |||
844 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, sizeof(ka->a)); | |||
845 | 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); | |||
846 | free(ka); | |||
847 | } | |||
848 | free(kif); | |||
849 | return (0); | |||
850 | } | |||
851 | ||||
852 | void | |||
853 | kif_clear(void) | |||
854 | { | |||
855 | struct kif_node *kif; | |||
856 | ||||
857 | while ((kif = RB_MIN(kif_tree, &kit)kif_tree_RB_MINMAX(&kit, -1)) != NULL((void *)0)) | |||
858 | kif_remove(kif); | |||
859 | } | |||
860 | ||||
861 | static struct kif_node * | |||
862 | kif_update(unsigned short ifindex, int flags, struct if_data *ifd, | |||
863 | struct sockaddr_dl *sdl, int *link_old) | |||
864 | { | |||
865 | struct kif_node *kif; | |||
866 | ||||
867 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
868 | if ((kif = kif_insert(ifindex)) == NULL((void *)0)) | |||
869 | return (NULL((void *)0)); | |||
870 | } else | |||
871 | *link_old = (kif->k.flags & IFF_UP0x1) && | |||
872 | LINK_STATE_IS_UP(kif->k.link_state)((kif->k.link_state) >= 4 || (kif->k.link_state) == 0 ); | |||
873 | ||||
874 | kif->k.flags = flags; | |||
875 | kif->k.link_state = ifd->ifi_link_state; | |||
876 | if (sdl) | |||
877 | memcpy(kif->k.mac, LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen)), sizeof(kif->k.mac)); | |||
878 | kif->k.if_type = ifd->ifi_type; | |||
879 | kif->k.baudrate = ifd->ifi_baudrate; | |||
880 | kif->k.mtu = ifd->ifi_mtu; | |||
881 | kif->k.rdomain = ifd->ifi_rdomain; | |||
882 | ||||
883 | if (sdl && sdl->sdl_family == AF_LINK18) { | |||
884 | if (sdl->sdl_nlen >= sizeof(kif->k.ifname)) | |||
885 | memcpy(kif->k.ifname, sdl->sdl_data, | |||
886 | sizeof(kif->k.ifname) - 1); | |||
887 | else if (sdl->sdl_nlen > 0) | |||
888 | memcpy(kif->k.ifname, sdl->sdl_data, | |||
889 | sdl->sdl_nlen); | |||
890 | /* string already terminated via calloc() */ | |||
891 | } | |||
892 | ||||
893 | return (kif); | |||
894 | } | |||
895 | ||||
896 | static struct kroute_priority * | |||
897 | kroute_match(int af, union ldpd_addr *key) | |||
898 | { | |||
899 | int i, maxprefixlen; | |||
900 | struct kroute_prefix *kp; | |||
901 | struct kroute_priority *kprio; | |||
902 | union ldpd_addr addr; | |||
903 | ||||
904 | switch (af) { | |||
905 | case AF_INET2: | |||
906 | maxprefixlen = 32; | |||
907 | break; | |||
908 | case AF_INET624: | |||
909 | maxprefixlen = 128; | |||
910 | break; | |||
911 | default: | |||
912 | log_warnx("%s: unknown af", __func__); | |||
913 | return (NULL((void *)0)); | |||
914 | } | |||
915 | ||||
916 | for (i = maxprefixlen; i >= 0; i--) { | |||
917 | ldp_applymask(af, &addr, key, i); | |||
918 | ||||
919 | kp = kroute_find_prefix(af, &addr, i); | |||
920 | if (kp == NULL((void *)0)) | |||
921 | continue; | |||
922 | ||||
923 | kprio = kroute_find_prio(kp, RTP_ANY64); | |||
924 | if (kprio != NULL((void *)0)) | |||
925 | return (kprio); | |||
926 | } | |||
927 | ||||
928 | return (NULL((void *)0)); | |||
929 | } | |||
930 | ||||
931 | /* misc */ | |||
932 | static uint8_t | |||
933 | prefixlen_classful(in_addr_t ina) | |||
934 | { | |||
935 | /* it hurt to write this. */ | |||
936 | ||||
937 | if (ina >= 0xf0000000U) /* class E */ | |||
938 | return (32); | |||
939 | else if (ina >= 0xe0000000U) /* class D */ | |||
940 | return (4); | |||
941 | else if (ina >= 0xc0000000U) /* class C */ | |||
942 | return (24); | |||
943 | else if (ina >= 0x80000000U) /* class B */ | |||
944 | return (16); | |||
945 | else /* class A */ | |||
946 | return (8); | |||
947 | } | |||
948 | ||||
949 | #define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof (long)) \ | |||
950 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |||
951 | ||||
952 | static void | |||
953 | get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) | |||
954 | { | |||
955 | int i; | |||
956 | ||||
957 | for (i = 0; i < RTAX_MAX15; i++) { | |||
958 | if (addrs & (1 << i)) { | |||
959 | rti_info[i] = sa; | |||
960 | sa = (struct sockaddr *)((char *)(sa) + | |||
961 | ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long))); | |||
962 | } else | |||
963 | rti_info[i] = NULL((void *)0); | |||
964 | } | |||
965 | } | |||
966 | ||||
967 | static void | |||
968 | if_change(unsigned short ifindex, int flags, struct if_data *ifd, | |||
969 | struct sockaddr_dl *sdl) | |||
970 | { | |||
971 | struct kif_node *kif; | |||
972 | struct kif_addr *ka; | |||
973 | int link_old = 0, link_new; | |||
974 | ||||
975 | kif = kif_update(ifindex, flags, ifd, sdl, &link_old); | |||
976 | if (!kif) { | |||
977 | log_warn("%s: kif_update(%u)", __func__, ifindex); | |||
978 | return; | |||
979 | } | |||
980 | link_new = (kif->k.flags & IFF_UP0x1) && | |||
981 | LINK_STATE_IS_UP(kif->k.link_state)((kif->k.link_state) >= 4 || (kif->k.link_state) == 0 ); | |||
982 | ||||
983 | if (link_new == link_old) | |||
984 | return; | |||
985 | ||||
986 | main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif->k, sizeof(struct kif)); | |||
987 | if (link_new) { | |||
988 | TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void *)0); (ka) = ((ka)->entry.tqe_next)) | |||
989 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->a, | |||
990 | sizeof(ka->a)); | |||
991 | } else { | |||
992 | TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void *)0); (ka) = ((ka)->entry.tqe_next)) | |||
993 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, | |||
994 | sizeof(ka->a)); | |||
995 | } | |||
996 | } | |||
997 | ||||
998 | static void | |||
999 | if_newaddr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, | |||
1000 | struct sockaddr *brd) | |||
1001 | { | |||
1002 | struct kif_node *kif; | |||
1003 | struct sockaddr_in *ifa4, *mask4, *brd4; | |||
1004 | struct sockaddr_in6 *ifa6, *mask6, *brd6; | |||
1005 | struct kif_addr *ka; | |||
1006 | ||||
1007 | if (ifa == NULL((void *)0)) | |||
1008 | return; | |||
1009 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
1010 | log_warnx("%s: corresponding if %d not found", __func__, | |||
1011 | ifindex); | |||
1012 | return; | |||
1013 | } | |||
1014 | ||||
1015 | switch (ifa->sa_family) { | |||
1016 | case AF_INET2: | |||
1017 | ifa4 = (struct sockaddr_in *) ifa; | |||
1018 | mask4 = (struct sockaddr_in *) mask; | |||
1019 | brd4 = (struct sockaddr_in *) brd; | |||
1020 | ||||
1021 | /* filter out unwanted addresses */ | |||
1022 | if (bad_addr_v4(ifa4->sin_addr)) | |||
1023 | return; | |||
1024 | ||||
1025 | if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void *)0)) | |||
1026 | fatal("if_newaddr"); | |||
1027 | ka->a.addr.v4 = ifa4->sin_addr; | |||
1028 | if (mask4) | |||
1029 | ka->a.prefixlen = | |||
1030 | mask2prefixlen(mask4->sin_addr.s_addr); | |||
1031 | if (brd4) | |||
1032 | ka->a.dstbrd.v4 = brd4->sin_addr; | |||
1033 | break; | |||
1034 | case AF_INET624: | |||
1035 | ifa6 = (struct sockaddr_in6 *) ifa; | |||
1036 | mask6 = (struct sockaddr_in6 *) mask; | |||
1037 | brd6 = (struct sockaddr_in6 *) brd; | |||
1038 | ||||
1039 | /* We only care about link-local and global-scope. */ | |||
1040 | if (bad_addr_v6(&ifa6->sin6_addr)) | |||
1041 | return; | |||
1042 | ||||
1043 | clearscope(&ifa6->sin6_addr); | |||
1044 | ||||
1045 | if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void *)0)) | |||
1046 | fatal("if_newaddr"); | |||
1047 | ka->a.addr.v6 = ifa6->sin6_addr; | |||
1048 | if (mask6) | |||
1049 | ka->a.prefixlen = mask2prefixlen6(mask6); | |||
1050 | if (brd6) | |||
1051 | ka->a.dstbrd.v6 = brd6->sin6_addr; | |||
1052 | break; | |||
1053 | default: | |||
1054 | return; | |||
1055 | } | |||
1056 | ||||
1057 | ka->a.ifindex = ifindex; | |||
1058 | ka->a.af = ifa->sa_family; | |||
1059 | 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); | |||
1060 | ||||
1061 | /* notify ldpe about new address */ | |||
1062 | main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka->a, sizeof(ka->a)); | |||
1063 | } | |||
1064 | ||||
1065 | static void | |||
1066 | if_deladdr(unsigned short ifindex, struct sockaddr *ifa, struct sockaddr *mask, | |||
1067 | struct sockaddr *brd) | |||
1068 | { | |||
1069 | struct kif_node *kif; | |||
1070 | struct sockaddr_in *ifa4, *mask4, *brd4; | |||
1071 | struct sockaddr_in6 *ifa6, *mask6, *brd6; | |||
1072 | struct kaddr k; | |||
1073 | struct kif_addr *ka, *nka; | |||
1074 | ||||
1075 | if (ifa == NULL((void *)0)) | |||
1076 | return; | |||
1077 | if ((kif = kif_find(ifindex)) == NULL((void *)0)) { | |||
1078 | log_warnx("%s: corresponding if %d not found", __func__, | |||
1079 | ifindex); | |||
1080 | return; | |||
1081 | } | |||
1082 | ||||
1083 | memset(&k, 0, sizeof(k)); | |||
1084 | k.af = ifa->sa_family; | |||
1085 | switch (ifa->sa_family) { | |||
1086 | case AF_INET2: | |||
1087 | ifa4 = (struct sockaddr_in *) ifa; | |||
1088 | mask4 = (struct sockaddr_in *) mask; | |||
1089 | brd4 = (struct sockaddr_in *) brd; | |||
1090 | ||||
1091 | /* filter out unwanted addresses */ | |||
1092 | if (bad_addr_v4(ifa4->sin_addr)) | |||
1093 | return; | |||
1094 | ||||
1095 | k.addr.v4 = ifa4->sin_addr; | |||
1096 | if (mask4) | |||
1097 | k.prefixlen = mask2prefixlen(mask4->sin_addr.s_addr); | |||
1098 | if (brd4) | |||
1099 | k.dstbrd.v4 = brd4->sin_addr; | |||
1100 | break; | |||
1101 | case AF_INET624: | |||
1102 | ifa6 = (struct sockaddr_in6 *) ifa; | |||
1103 | mask6 = (struct sockaddr_in6 *) mask; | |||
1104 | brd6 = (struct sockaddr_in6 *) brd; | |||
1105 | ||||
1106 | /* We only care about link-local and global-scope. */ | |||
1107 | if (bad_addr_v6(&ifa6->sin6_addr)) | |||
1108 | return; | |||
1109 | ||||
1110 | clearscope(&ifa6->sin6_addr); | |||
1111 | ||||
1112 | k.addr.v6 = ifa6->sin6_addr; | |||
1113 | if (mask6) | |||
1114 | k.prefixlen = mask2prefixlen6(mask6); | |||
1115 | if (brd6) | |||
1116 | k.dstbrd.v6 = brd6->sin6_addr; | |||
1117 | break; | |||
1118 | default: | |||
1119 | return; | |||
1120 | } | |||
1121 | ||||
1122 | for (ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first); ka != NULL((void *)0); ka = nka) { | |||
1123 | nka = TAILQ_NEXT(ka, entry)((ka)->entry.tqe_next); | |||
1124 | ||||
1125 | if (ka->a.af != k.af || | |||
1126 | ka->a.prefixlen != k.prefixlen || | |||
1127 | ldp_addrcmp(ka->a.af, &ka->a.addr, &k.addr)) | |||
1128 | continue; | |||
1129 | ||||
1130 | /* notify ldpe about removed address */ | |||
1131 | main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka->a, sizeof(ka->a)); | |||
1132 | 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); | |||
1133 | free(ka); | |||
1134 | return; | |||
1135 | } | |||
1136 | } | |||
1137 | ||||
1138 | static void | |||
1139 | if_announce(void *msg) | |||
1140 | { | |||
1141 | struct if_announcemsghdr *ifan; | |||
1142 | struct kif_node *kif; | |||
1143 | ||||
1144 | ifan = msg; | |||
1145 | ||||
1146 | switch (ifan->ifan_what) { | |||
1147 | case IFAN_ARRIVAL0: | |||
1148 | kif = kif_insert(ifan->ifan_index); | |||
1149 | if (kif) | |||
1150 | strlcpy(kif->k.ifname, ifan->ifan_name, | |||
1151 | sizeof(kif->k.ifname)); | |||
1152 | break; | |||
1153 | case IFAN_DEPARTURE1: | |||
1154 | kif = kif_find(ifan->ifan_index); | |||
1155 | if (kif) | |||
1156 | kif_remove(kif); | |||
1157 | break; | |||
1158 | } | |||
1159 | } | |||
1160 | ||||
1161 | /* rtsock */ | |||
1162 | static int | |||
1163 | send_rtmsg(int fd, int action, struct kroute *kr, int family) | |||
1164 | { | |||
1165 | switch (kr->af) { | |||
1166 | case AF_INET2: | |||
1167 | return (send_rtmsg_v4(fd, action, kr, family)); | |||
1168 | case AF_INET624: | |||
1169 | return (send_rtmsg_v6(fd, action, kr, family)); | |||
1170 | default: | |||
1171 | fatalx("send_rtmsg: unknown af"); | |||
1172 | } | |||
1173 | } | |||
1174 | ||||
1175 | static int | |||
1176 | send_rtmsg_v4(int fd, int action, struct kroute *kr, int family) | |||
1177 | { | |||
1178 | struct iovec iov[5]; | |||
1179 | struct rt_msghdr hdr; | |||
1180 | struct sockaddr_mpls label_in, label_out; | |||
1181 | struct sockaddr_in dst, mask, nexthop; | |||
1182 | int iovcnt = 0; | |||
1183 | ||||
1184 | if (kr_state.fib_sync == 0) | |||
1185 | return (0); | |||
1186 | ||||
1187 | /* | |||
1188 | * Reserved labels (implicit and explicit NULL) should not be added | |||
1189 | * to the FIB. | |||
1190 | */ | |||
1191 | if (family == AF_MPLS33 && kr->local_label < MPLS_LABEL_RESERVED_MAX15) | |||
1192 | return (0); | |||
1193 | ||||
1194 | /* initialize header */ | |||
1195 | memset(&hdr, 0, sizeof(hdr)); | |||
1196 | hdr.rtm_version = RTM_VERSION5; | |||
1197 | ||||
1198 | hdr.rtm_type = action; | |||
1199 | hdr.rtm_flags = RTF_UP0x1; | |||
1200 | hdr.rtm_fmask = RTF_MPLS0x100000; | |||
1201 | hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ | |||
1202 | hdr.rtm_msglen = sizeof(hdr); | |||
1203 | hdr.rtm_hdrlen = sizeof(struct rt_msghdr); | |||
1204 | hdr.rtm_priority = kr->priority; | |||
1205 | hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ | |||
1206 | /* adjust iovec */ | |||
1207 | iov[iovcnt].iov_base = &hdr; | |||
1208 | iov[iovcnt++].iov_len = sizeof(hdr); | |||
1209 | ||||
1210 | if (family == AF_MPLS33) { | |||
1211 | memset(&label_in, 0, sizeof(label_in)); | |||
1212 | label_in.smpls_len = sizeof(label_in); | |||
1213 | label_in.smpls_family = AF_MPLS33; | |||
1214 | label_in.smpls_label = | |||
1215 | 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)); | |||
1216 | /* adjust header */ | |||
1217 | hdr.rtm_flags |= RTF_MPLS0x100000 | RTF_MPATH0x40000; | |||
1218 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1219 | hdr.rtm_msglen += sizeof(label_in); | |||
1220 | /* adjust iovec */ | |||
1221 | iov[iovcnt].iov_base = &label_in; | |||
1222 | iov[iovcnt++].iov_len = sizeof(label_in); | |||
1223 | } else { | |||
1224 | memset(&dst, 0, sizeof(dst)); | |||
1225 | dst.sin_len = sizeof(dst); | |||
1226 | dst.sin_family = AF_INET2; | |||
1227 | dst.sin_addr = kr->prefix.v4; | |||
1228 | /* adjust header */ | |||
1229 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1230 | hdr.rtm_msglen += sizeof(dst); | |||
1231 | /* adjust iovec */ | |||
1232 | iov[iovcnt].iov_base = &dst; | |||
1233 | iov[iovcnt++].iov_len = sizeof(dst); | |||
1234 | } | |||
1235 | ||||
1236 | memset(&nexthop, 0, sizeof(nexthop)); | |||
1237 | nexthop.sin_len = sizeof(nexthop); | |||
1238 | nexthop.sin_family = AF_INET2; | |||
1239 | nexthop.sin_addr = kr->nexthop.v4; | |||
1240 | /* adjust header */ | |||
1241 | hdr.rtm_flags |= RTF_GATEWAY0x2; | |||
1242 | hdr.rtm_addrs |= RTA_GATEWAY0x2; | |||
1243 | hdr.rtm_msglen += sizeof(nexthop); | |||
1244 | /* adjust iovec */ | |||
1245 | iov[iovcnt].iov_base = &nexthop; | |||
1246 | iov[iovcnt++].iov_len = sizeof(nexthop); | |||
1247 | ||||
1248 | if (family == AF_INET2) { | |||
1249 | memset(&mask, 0, sizeof(mask)); | |||
1250 | mask.sin_len = sizeof(mask); | |||
1251 | mask.sin_family = AF_INET2; | |||
1252 | mask.sin_addr.s_addr = prefixlen2mask(kr->prefixlen); | |||
1253 | /* adjust header */ | |||
1254 | hdr.rtm_addrs |= RTA_NETMASK0x4; | |||
1255 | hdr.rtm_msglen += sizeof(mask); | |||
1256 | /* adjust iovec */ | |||
1257 | iov[iovcnt].iov_base = &mask; | |||
1258 | iov[iovcnt++].iov_len = sizeof(mask); | |||
1259 | } | |||
1260 | ||||
1261 | /* If action is RTM_DELETE we have to get rid of MPLS infos */ | |||
1262 | if (kr->remote_label != NO_LABEL0xffffffffU && action != RTM_DELETE0x2) { | |||
1263 | memset(&label_out, 0, sizeof(label_out)); | |||
1264 | label_out.smpls_len = sizeof(label_out); | |||
1265 | label_out.smpls_family = AF_MPLS33; | |||
1266 | label_out.smpls_label = | |||
1267 | 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)); | |||
1268 | /* adjust header */ | |||
1269 | hdr.rtm_addrs |= RTA_SRC0x100; | |||
1270 | hdr.rtm_flags |= RTF_MPLS0x100000; | |||
1271 | hdr.rtm_msglen += sizeof(label_out); | |||
1272 | /* adjust iovec */ | |||
1273 | iov[iovcnt].iov_base = &label_out; | |||
1274 | iov[iovcnt++].iov_len = sizeof(label_out); | |||
1275 | ||||
1276 | if (kr->remote_label == MPLS_LABEL_IMPLNULL3) { | |||
1277 | if (family == AF_MPLS33) | |||
1278 | hdr.rtm_mpls = MPLS_OP_POP0x1; | |||
1279 | else | |||
1280 | return (0); | |||
1281 | } else { | |||
1282 | if (family == AF_MPLS33) | |||
1283 | hdr.rtm_mpls = MPLS_OP_SWAP0x4; | |||
1284 | else | |||
1285 | hdr.rtm_mpls = MPLS_OP_PUSH0x2; | |||
1286 | } | |||
1287 | } | |||
1288 | ||||
1289 | retry: | |||
1290 | if (writev(fd, iov, iovcnt) == -1) { | |||
1291 | if (errno(*__errno()) == ESRCH3) { | |||
1292 | if (hdr.rtm_type == RTM_CHANGE0x3 && family == AF_MPLS33) { | |||
1293 | hdr.rtm_type = RTM_ADD0x1; | |||
1294 | goto retry; | |||
1295 | } else if (hdr.rtm_type == RTM_DELETE0x2) { | |||
1296 | log_info("route %s/%u vanished before delete", | |||
1297 | inet_ntoa(kr->prefix.v4), kr->prefixlen); | |||
1298 | return (-1); | |||
1299 | } | |||
1300 | } | |||
1301 | log_warn("%s action %u, af %s, prefix %s/%u", __func__, | |||
1302 | hdr.rtm_type, af_name(family), inet_ntoa(kr->prefix.v4), | |||
1303 | kr->prefixlen); | |||
1304 | return (-1); | |||
1305 | } | |||
1306 | ||||
1307 | return (0); | |||
1308 | } | |||
1309 | ||||
1310 | static int | |||
1311 | send_rtmsg_v6(int fd, int action, struct kroute *kr, int family) | |||
1312 | { | |||
1313 | struct iovec iov[5]; | |||
1314 | struct rt_msghdr hdr; | |||
1315 | struct sockaddr_mpls label_in, label_out; | |||
1316 | struct sockaddr_in6 dst, mask, nexthop; | |||
1317 | int iovcnt = 0; | |||
1318 | ||||
1319 | if (kr_state.fib_sync == 0) | |||
1320 | return (0); | |||
1321 | ||||
1322 | /* | |||
1323 | * Reserved labels (implicit and explicit NULL) should not be added | |||
1324 | * to the FIB. | |||
1325 | */ | |||
1326 | if (family == AF_MPLS33 && kr->local_label < MPLS_LABEL_RESERVED_MAX15) | |||
1327 | return (0); | |||
1328 | ||||
1329 | /* initialize header */ | |||
1330 | memset(&hdr, 0, sizeof(hdr)); | |||
1331 | hdr.rtm_version = RTM_VERSION5; | |||
1332 | ||||
1333 | hdr.rtm_type = action; | |||
1334 | hdr.rtm_flags = RTF_UP0x1; | |||
1335 | hdr.rtm_fmask = RTF_MPLS0x100000; | |||
1336 | hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ | |||
1337 | hdr.rtm_msglen = sizeof(hdr); | |||
1338 | hdr.rtm_hdrlen = sizeof(struct rt_msghdr); | |||
1339 | hdr.rtm_priority = kr->priority; | |||
1340 | hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ | |||
1341 | /* adjust iovec */ | |||
1342 | iov[iovcnt].iov_base = &hdr; | |||
1343 | iov[iovcnt++].iov_len = sizeof(hdr); | |||
1344 | ||||
1345 | if (family == AF_MPLS33) { | |||
1346 | memset(&label_in, 0, sizeof(label_in)); | |||
1347 | label_in.smpls_len = sizeof(label_in); | |||
1348 | label_in.smpls_family = AF_MPLS33; | |||
1349 | label_in.smpls_label = | |||
1350 | 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)); | |||
1351 | /* adjust header */ | |||
1352 | hdr.rtm_flags |= RTF_MPLS0x100000 | RTF_MPATH0x40000; | |||
1353 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1354 | hdr.rtm_msglen += sizeof(label_in); | |||
1355 | /* adjust iovec */ | |||
1356 | iov[iovcnt].iov_base = &label_in; | |||
1357 | iov[iovcnt++].iov_len = sizeof(label_in); | |||
1358 | } else { | |||
1359 | memset(&dst, 0, sizeof(dst)); | |||
1360 | dst.sin6_len = sizeof(dst); | |||
1361 | dst.sin6_family = AF_INET624; | |||
1362 | dst.sin6_addr = kr->prefix.v6; | |||
1363 | /* adjust header */ | |||
1364 | hdr.rtm_addrs |= RTA_DST0x1; | |||
1365 | hdr.rtm_msglen += ROUNDUP(sizeof(dst))((sizeof(dst)) > 0 ? (1 + (((sizeof(dst)) - 1) | (sizeof(long ) - 1))) : sizeof(long)); | |||
1366 | /* adjust iovec */ | |||
1367 | iov[iovcnt].iov_base = &dst; | |||
1368 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(dst))((sizeof(dst)) > 0 ? (1 + (((sizeof(dst)) - 1) | (sizeof(long ) - 1))) : sizeof(long)); | |||
1369 | } | |||
1370 | ||||
1371 | memset(&nexthop, 0, sizeof(nexthop)); | |||
1372 | nexthop.sin6_len = sizeof(nexthop); | |||
1373 | nexthop.sin6_family = AF_INET624; | |||
1374 | nexthop.sin6_addr = kr->nexthop.v6; | |||
1375 | nexthop.sin6_scope_id = kr->ifindex; | |||
1376 | /* | |||
1377 | * XXX we should set the sin6_scope_id but the kernel | |||
1378 | * XXX does not expect it that way. It must be fiddled | |||
1379 | * XXX into the sin6_addr. Welcome to the typical | |||
1380 | * XXX IPv6 insanity and all without wine bottles. | |||
1381 | */ | |||
1382 | embedscope(&nexthop); | |||
1383 | ||||
1384 | /* adjust header */ | |||
1385 | hdr.rtm_flags |= RTF_GATEWAY0x2; | |||
1386 | hdr.rtm_addrs |= RTA_GATEWAY0x2; | |||
1387 | hdr.rtm_msglen += ROUNDUP(sizeof(nexthop))((sizeof(nexthop)) > 0 ? (1 + (((sizeof(nexthop)) - 1) | ( sizeof(long) - 1))) : sizeof(long)); | |||
1388 | /* adjust iovec */ | |||
1389 | iov[iovcnt].iov_base = &nexthop; | |||
1390 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(nexthop))((sizeof(nexthop)) > 0 ? (1 + (((sizeof(nexthop)) - 1) | ( sizeof(long) - 1))) : sizeof(long)); | |||
1391 | ||||
1392 | if (family == AF_INET624) { | |||
1393 | memset(&mask, 0, sizeof(mask)); | |||
1394 | mask.sin6_len = sizeof(mask); | |||
1395 | mask.sin6_family = AF_INET624; | |||
1396 | mask.sin6_addr = *prefixlen2mask6(kr->prefixlen); | |||
1397 | /* adjust header */ | |||
1398 | if (kr->prefixlen == 128) | |||
1399 | hdr.rtm_flags |= RTF_HOST0x4; | |||
1400 | hdr.rtm_addrs |= RTA_NETMASK0x4; | |||
1401 | hdr.rtm_msglen += ROUNDUP(sizeof(mask))((sizeof(mask)) > 0 ? (1 + (((sizeof(mask)) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1402 | /* adjust iovec */ | |||
1403 | iov[iovcnt].iov_base = &mask; | |||
1404 | iov[iovcnt++].iov_len = ROUNDUP(sizeof(mask))((sizeof(mask)) > 0 ? (1 + (((sizeof(mask)) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1405 | } | |||
1406 | ||||
1407 | /* If action is RTM_DELETE we have to get rid of MPLS infos */ | |||
1408 | if (kr->remote_label != NO_LABEL0xffffffffU && action != RTM_DELETE0x2) { | |||
1409 | memset(&label_out, 0, sizeof(label_out)); | |||
1410 | label_out.smpls_len = sizeof(label_out); | |||
1411 | label_out.smpls_family = AF_MPLS33; | |||
1412 | label_out.smpls_label = | |||
1413 | 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)); | |||
1414 | /* adjust header */ | |||
1415 | hdr.rtm_addrs |= RTA_SRC0x100; | |||
1416 | hdr.rtm_flags |= RTF_MPLS0x100000; | |||
1417 | hdr.rtm_msglen += sizeof(label_out); | |||
1418 | /* adjust iovec */ | |||
1419 | iov[iovcnt].iov_base = &label_out; | |||
1420 | iov[iovcnt++].iov_len = sizeof(label_out); | |||
1421 | ||||
1422 | if (kr->remote_label == MPLS_LABEL_IMPLNULL3) { | |||
1423 | if (family == AF_MPLS33) | |||
1424 | hdr.rtm_mpls = MPLS_OP_POP0x1; | |||
1425 | else | |||
1426 | return (0); | |||
1427 | } else { | |||
1428 | if (family == AF_MPLS33) | |||
1429 | hdr.rtm_mpls = MPLS_OP_SWAP0x4; | |||
1430 | else | |||
1431 | hdr.rtm_mpls = MPLS_OP_PUSH0x2; | |||
1432 | } | |||
1433 | } | |||
1434 | ||||
1435 | retry: | |||
1436 | if (writev(fd, iov, iovcnt) == -1) { | |||
1437 | if (errno(*__errno()) == ESRCH3) { | |||
1438 | if (hdr.rtm_type == RTM_CHANGE0x3 && family == AF_MPLS33) { | |||
1439 | hdr.rtm_type = RTM_ADD0x1; | |||
1440 | goto retry; | |||
1441 | } else if (hdr.rtm_type == RTM_DELETE0x2) { | |||
1442 | log_info("route %s/%u vanished before delete", | |||
1443 | log_addr(kr->af, &kr->prefix), | |||
1444 | kr->prefixlen); | |||
1445 | return (-1); | |||
1446 | } | |||
1447 | } | |||
1448 | log_warn("%s action %u, af %s, prefix %s/%u", __func__, | |||
1449 | hdr.rtm_type, af_name(family), log_addr(kr->af, | |||
1450 | &kr->prefix), kr->prefixlen); | |||
1451 | return (-1); | |||
1452 | } | |||
1453 | return (0); | |||
1454 | } | |||
1455 | ||||
1456 | static int | |||
1457 | fetchtable(void) | |||
1458 | { | |||
1459 | size_t len; | |||
1460 | int mib[7]; | |||
1461 | char *buf; | |||
1462 | int rv; | |||
1463 | ||||
1464 | mib[0] = CTL_NET4; | |||
1465 | mib[1] = PF_ROUTE17; | |||
1466 | mib[2] = 0; | |||
1467 | mib[3] = 0; | |||
1468 | mib[4] = NET_RT_DUMP1; | |||
1469 | mib[5] = 0; | |||
1470 | mib[6] = kr_state.rdomain; /* rtableid */ | |||
1471 | ||||
1472 | if (sysctl(mib, 7, NULL((void *)0), &len, NULL((void *)0), 0) == -1) { | |||
1473 | log_warn("sysctl"); | |||
1474 | return (-1); | |||
1475 | } | |||
1476 | if ((buf = malloc(len)) == NULL((void *)0)) { | |||
1477 | log_warn(__func__); | |||
1478 | return (-1); | |||
1479 | } | |||
1480 | if (sysctl(mib, 7, buf, &len, NULL((void *)0), 0) == -1) { | |||
1481 | log_warn("sysctl"); | |||
1482 | free(buf); | |||
1483 | return (-1); | |||
1484 | } | |||
1485 | ||||
1486 | rv = rtmsg_process(buf, len); | |||
1487 | free(buf); | |||
1488 | ||||
1489 | return (rv); | |||
1490 | } | |||
1491 | ||||
1492 | static int | |||
1493 | fetchifs(void) | |||
1494 | { | |||
1495 | size_t len; | |||
1496 | int mib[6]; | |||
1497 | char *buf; | |||
1498 | int rv; | |||
1499 | ||||
1500 | mib[0] = CTL_NET4; | |||
1501 | mib[1] = PF_ROUTE17; | |||
1502 | mib[2] = 0; | |||
1503 | mib[3] = 0; /* wildcard */ | |||
1504 | mib[4] = NET_RT_IFLIST3; | |||
1505 | mib[5] = 0; | |||
1506 | ||||
1507 | if (sysctl(mib, 6, NULL((void *)0), &len, NULL((void *)0), 0) == -1) { | |||
1508 | log_warn("sysctl"); | |||
1509 | return (-1); | |||
1510 | } | |||
1511 | if ((buf = malloc(len)) == NULL((void *)0)) { | |||
1512 | log_warn(__func__); | |||
1513 | return (-1); | |||
1514 | } | |||
1515 | if (sysctl(mib, 6, buf, &len, NULL((void *)0), 0) == -1) { | |||
1516 | log_warn("sysctl"); | |||
1517 | free(buf); | |||
1518 | return (-1); | |||
1519 | } | |||
1520 | ||||
1521 | rv = rtmsg_process(buf, len); | |||
1522 | free(buf); | |||
1523 | ||||
1524 | return (rv); | |||
1525 | } | |||
1526 | ||||
1527 | static int | |||
1528 | dispatch_rtmsg(void) | |||
1529 | { | |||
1530 | char buf[RT_BUF_SIZE16384]; | |||
1531 | ssize_t n; | |||
1532 | ||||
1533 | if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { | |||
1534 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
1535 | return (0); | |||
1536 | log_warn("%s: read error", __func__); | |||
1537 | return (-1); | |||
1538 | } | |||
1539 | ||||
1540 | if (n == 0) { | |||
1541 | log_warnx("routing socket closed"); | |||
1542 | return (-1); | |||
1543 | } | |||
1544 | ||||
1545 | return (rtmsg_process(buf, n)); | |||
1546 | } | |||
1547 | ||||
1548 | static int | |||
1549 | rtmsg_process(char *buf, size_t len) | |||
1550 | { | |||
1551 | struct rt_msghdr *rtm; | |||
1552 | struct if_msghdr ifm; | |||
1553 | struct ifa_msghdr *ifam; | |||
1554 | struct sockaddr *sa, *rti_info[RTAX_MAX15]; | |||
1555 | size_t offset; | |||
1556 | char *next; | |||
1557 | ||||
1558 | for (offset = 0; offset < len; offset += rtm->rtm_msglen) { | |||
1559 | next = buf + offset; | |||
1560 | rtm = (struct rt_msghdr *)next; | |||
1561 | if (len < offset + sizeof(unsigned short) || | |||
1562 | len < offset + rtm->rtm_msglen) | |||
1563 | fatalx("rtmsg_process: partial rtm in buffer"); | |||
1564 | if (rtm->rtm_version != RTM_VERSION5) | |||
1565 | continue; | |||
1566 | ||||
1567 | sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); | |||
1568 | get_rtaddrs(rtm->rtm_addrs, sa, rti_info); | |||
1569 | ||||
1570 | switch (rtm->rtm_type) { | |||
1571 | case RTM_ADD0x1: | |||
1572 | case RTM_GET0x4: | |||
1573 | case RTM_CHANGE0x3: | |||
1574 | case RTM_DELETE0x2: | |||
1575 | if (rtm->rtm_errno) /* failed attempts... */ | |||
1576 | continue; | |||
1577 | ||||
1578 | if (rtm->rtm_tableid != kr_state.rdomain) | |||
1579 | continue; | |||
1580 | ||||
1581 | if (rtm->rtm_type == RTM_GET0x4 && | |||
1582 | rtm->rtm_pid != kr_state.pid) | |||
1583 | continue; | |||
1584 | ||||
1585 | /* Skip ARP/ND cache and broadcast routes. */ | |||
1586 | if (rtm->rtm_flags & (RTF_LLINFO0x400|RTF_BROADCAST0x400000)) | |||
1587 | continue; | |||
1588 | ||||
1589 | /* LDP should follow the IGP and ignore BGP routes */ | |||
1590 | if (rtm->rtm_priority == RTP_BGP48) | |||
1591 | continue; | |||
1592 | ||||
1593 | if (rtmsg_process_route(rtm, rti_info) == -1) | |||
1594 | return (-1); | |||
1595 | } | |||
1596 | ||||
1597 | switch (rtm->rtm_type) { | |||
1598 | case RTM_IFINFO0xe: | |||
1599 | memcpy(&ifm, next, sizeof(ifm)); | |||
1600 | if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data, | |||
1601 | (struct sockaddr_dl *)rti_info[RTAX_IFP4]); | |||
1602 | break; | |||
1603 | case RTM_NEWADDR0xc: | |||
1604 | ifam = (struct ifa_msghdr *)rtm; | |||
1605 | if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 | | |||
1606 | RTA_BRD0x80)) == 0) | |||
1607 | break; | |||
1608 | ||||
1609 | if_newaddr(ifam->ifam_index, | |||
1610 | (struct sockaddr *)rti_info[RTAX_IFA5], | |||
1611 | (struct sockaddr *)rti_info[RTAX_NETMASK2], | |||
1612 | (struct sockaddr *)rti_info[RTAX_BRD7]); | |||
1613 | break; | |||
1614 | case RTM_DELADDR0xd: | |||
1615 | ifam = (struct ifa_msghdr *)rtm; | |||
1616 | if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 | | |||
1617 | RTA_BRD0x80)) == 0) | |||
1618 | break; | |||
1619 | ||||
1620 | if_deladdr(ifam->ifam_index, | |||
1621 | (struct sockaddr *)rti_info[RTAX_IFA5], | |||
1622 | (struct sockaddr *)rti_info[RTAX_NETMASK2], | |||
1623 | (struct sockaddr *)rti_info[RTAX_BRD7]); | |||
1624 | break; | |||
1625 | case RTM_IFANNOUNCE0xf: | |||
1626 | if_announce(next); | |||
1627 | break; | |||
1628 | default: | |||
1629 | /* ignore for now */ | |||
1630 | break; | |||
1631 | } | |||
1632 | } | |||
1633 | ||||
1634 | return (offset); | |||
1635 | } | |||
1636 | ||||
1637 | static int | |||
1638 | rtmsg_process_route(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX15]) | |||
1639 | { | |||
1640 | struct sockaddr *sa; | |||
1641 | struct sockaddr_in *sa_in; | |||
1642 | struct sockaddr_in6 *sa_in6; | |||
1643 | struct kroute kr; | |||
1644 | struct kroute_prefix *kp; | |||
1645 | struct kroute_priority *kprio; | |||
1646 | struct kroute_node *kn; | |||
1647 | ||||
1648 | if ((sa = rti_info[RTAX_DST0]) == NULL((void *)0)) | |||
1649 | return (-1); | |||
1650 | ||||
1651 | memset(&kr, 0, sizeof(kr)); | |||
1652 | kr.af = sa->sa_family; | |||
1653 | switch (kr.af) { | |||
1654 | case AF_INET2: | |||
1655 | kr.prefix.v4 = ((struct sockaddr_in *)sa)->sin_addr; | |||
1656 | sa_in = (struct sockaddr_in *) rti_info[RTAX_NETMASK2]; | |||
1657 | if (sa_in != NULL((void *)0) && sa_in->sin_len != 0) | |||
1658 | kr.prefixlen = mask2prefixlen(sa_in->sin_addr.s_addr); | |||
1659 | else if (rtm->rtm_flags & RTF_HOST0x4) | |||
1660 | kr.prefixlen = 32; | |||
1661 | else if (kr.prefix.v4.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) | |||
1662 | kr.prefixlen = 0; | |||
1663 | else | |||
1664 | kr.prefixlen = prefixlen_classful(kr.prefix.v4.s_addr); | |||
1665 | break; | |||
1666 | case AF_INET624: | |||
1667 | kr.prefix.v6 = ((struct sockaddr_in6 *)sa)->sin6_addr; | |||
1668 | sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK2]; | |||
1669 | if (sa_in6 != NULL((void *)0) && sa_in6->sin6_len != 0) | |||
1670 | kr.prefixlen = mask2prefixlen6(sa_in6); | |||
1671 | else if (rtm->rtm_flags & RTF_HOST0x4) | |||
1672 | kr.prefixlen = 128; | |||
1673 | 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))) | |||
1674 | kr.prefixlen = 0; | |||
1675 | else | |||
1676 | fatalx("in6 net addr without netmask"); | |||
1677 | break; | |||
1678 | default: | |||
1679 | return (0); | |||
1680 | } | |||
1681 | kr.ifindex = rtm->rtm_index; | |||
1682 | if ((sa = rti_info[RTAX_GATEWAY1]) != NULL((void *)0)) { | |||
1683 | switch (sa->sa_family) { | |||
1684 | case AF_INET2: | |||
1685 | kr.nexthop.v4 = ((struct sockaddr_in *)sa)->sin_addr; | |||
1686 | break; | |||
1687 | case AF_INET624: | |||
1688 | sa_in6 = (struct sockaddr_in6 *)sa; | |||
1689 | recoverscope(sa_in6); | |||
1690 | kr.nexthop.v6 = sa_in6->sin6_addr; | |||
1691 | if (sa_in6->sin6_scope_id) | |||
1692 | kr.ifindex = sa_in6->sin6_scope_id; | |||
1693 | break; | |||
1694 | case AF_LINK18: | |||
1695 | kr.flags |= F_CONNECTED0x0002; | |||
1696 | break; | |||
1697 | } | |||
1698 | } | |||
1699 | ||||
1700 | if (rtm->rtm_flags & RTF_STATIC0x800) | |||
1701 | kr.flags |= F_STATIC0x0004; | |||
1702 | if (rtm->rtm_flags & RTF_BLACKHOLE0x1000) | |||
1703 | kr.flags |= F_BLACKHOLE0x0020; | |||
1704 | if (rtm->rtm_flags & RTF_REJECT0x8) | |||
1705 | kr.flags |= F_REJECT0x0010; | |||
1706 | if (rtm->rtm_flags & RTF_DYNAMIC0x10) | |||
1707 | kr.flags |= F_DYNAMIC0x0008; | |||
1708 | /* routes attached to connected or loopback interfaces */ | |||
1709 | if (rtm->rtm_flags & RTF_CONNECTED0x800000 || | |||
1710 | ldp_addrcmp(kr.af, &kr.prefix, &kr.nexthop) == 0) | |||
1711 | kr.flags |= F_CONNECTED0x0002; | |||
1712 | kr.priority = rtm->rtm_priority; | |||
1713 | ||||
1714 | if (rtm->rtm_type == RTM_CHANGE0x3) { | |||
1715 | /* | |||
1716 | * The kernel doesn't allow RTM_CHANGE for multipath routes. | |||
1717 | * If we got this message we know that the route has only one | |||
1718 | * nexthop and we should remove it before installing the same | |||
1719 | * route with the new nexthop. | |||
1720 | */ | |||
1721 | kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); | |||
1722 | if (kp) { | |||
1723 | kprio = kroute_find_prio(kp, kr.priority); | |||
1724 | if (kprio) { | |||
1725 | kn = TAILQ_FIRST(&kprio->nexthops)((&kprio->nexthops)->tqh_first); | |||
1726 | if (kn) | |||
1727 | kroute_remove(&kn->r); | |||
1728 | } | |||
1729 | } | |||
1730 | } | |||
1731 | ||||
1732 | kn = NULL((void *)0); | |||
1733 | kp = kroute_find_prefix(kr.af, &kr.prefix, kr.prefixlen); | |||
1734 | if (kp) { | |||
1735 | kprio = kroute_find_prio(kp, kr.priority); | |||
1736 | if (kprio) | |||
1737 | kn = kroute_find_gw(kprio, &kr.nexthop); | |||
1738 | } | |||
1739 | ||||
1740 | if (rtm->rtm_type == RTM_DELETE0x2) { | |||
1741 | if (kn == NULL((void *)0)) | |||
1742 | return (0); | |||
1743 | return (kroute_remove(&kr)); | |||
1744 | } | |||
1745 | ||||
1746 | if (!ldp_addrisset(kr.af, &kr.nexthop) && !(kr.flags & F_CONNECTED0x0002)) { | |||
1747 | log_warnx("%s: no nexthop for %s/%u", __func__, | |||
1748 | log_addr(kr.af, &kr.prefix), kr.prefixlen); | |||
1749 | return (-1); | |||
1750 | } | |||
1751 | ||||
1752 | if (kn != NULL((void *)0)) { | |||
1753 | /* update route */ | |||
1754 | kn->r = kr; | |||
1755 | kr_redistribute(kp); | |||
1756 | } else { | |||
1757 | kr.local_label = NO_LABEL0xffffffffU; | |||
1758 | kr.remote_label = NO_LABEL0xffffffffU; | |||
1759 | kroute_insert(&kr); | |||
1760 | } | |||
1761 | ||||
1762 | return (0); | |||
1763 | } | |||
1764 | ||||
1765 | int | |||
1766 | kmpw_set(struct kpw *kpw) | |||
1767 | { | |||
1768 | struct kif_node *kif; | |||
1769 | ||||
1770 | kif = kif_find(kpw->ifindex); | |||
1771 | if (kif == NULL((void *)0)) { | |||
1772 | log_warnx("%s: failed to find mpw by index (%u)", __func__, | |||
1773 | kpw->ifindex); | |||
1774 | return (-1); | |||
1775 | } | |||
1776 | ||||
1777 | if (kif->kpw == NULL((void *)0)) | |||
1778 | kif->kpw = malloc(sizeof(*kif->kpw)); | |||
1779 | *kif->kpw = *kpw; | |||
1780 | ||||
1781 | return (kmpw_install(kif->k.ifname, kpw)); | |||
1782 | } | |||
1783 | ||||
1784 | int | |||
1785 | kmpw_unset(struct kpw *kpw) | |||
1786 | { | |||
1787 | struct kif_node *kif; | |||
1788 | ||||
1789 | kif = kif_find(kpw->ifindex); | |||
1790 | if (kif == NULL((void *)0)) { | |||
1791 | log_warnx("%s: failed to find mpw by index (%u)", __func__, | |||
1792 | kpw->ifindex); | |||
1793 | return (-1); | |||
1794 | } | |||
1795 | ||||
1796 | if (kif->kpw == NULL((void *)0)) { | |||
1797 | log_warnx("%s: %s is not set", __func__, kif->k.ifname); | |||
1798 | return (-1); | |||
1799 | } | |||
1800 | ||||
1801 | free(kif->kpw); | |||
1802 | kif->kpw = NULL((void *)0); | |||
1803 | return (kmpw_uninstall(kif->k.ifname)); | |||
1804 | } | |||
1805 | ||||
1806 | static int | |||
1807 | kmpw_install(const char *ifname, struct kpw *kpw) | |||
1808 | { | |||
1809 | struct ifreq ifr; | |||
1810 | struct ifmpwreq imr; | |||
1811 | ||||
1812 | memset(&imr, 0, sizeof(imr)); | |||
1813 | switch (kpw->pw_type) { | |||
1814 | case PW_TYPE_ETHERNET0x0005: | |||
1815 | imr.imr_type = IMR_TYPE_ETHERNET1; | |||
1816 | break; | |||
1817 | case PW_TYPE_ETHERNET_TAGGED0x0004: | |||
1818 | imr.imr_type = IMR_TYPE_ETHERNET_TAGGED2; | |||
1819 | break; | |||
1820 | default: | |||
1821 | log_warnx("%s: unhandled pseudowire type (%#X)", __func__, | |||
1822 | kpw->pw_type); | |||
1823 | return (-1); | |||
1824 | } | |||
1825 | ||||
1826 | if (kpw->flags & F_PW_CWORD0x08) | |||
1827 | imr.imr_flags |= IMR_FLAG_CONTROLWORD0x1; | |||
1828 | ||||
1829 | memcpy(&imr.imr_nexthop, addr2sa(kpw->af, &kpw->nexthop, 0), | |||
1830 | sizeof(imr.imr_nexthop)); | |||
1831 | ||||
1832 | imr.imr_lshim.shim_label = kpw->local_label; | |||
1833 | imr.imr_rshim.shim_label = kpw->remote_label; | |||
1834 | ||||
1835 | memset(&ifr, 0, sizeof(ifr)); | |||
1836 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); | |||
1837 | ifr.ifr_dataifr_ifru.ifru_data = (caddr_t) &imr; | |||
1838 | if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((173))), &ifr) == -1) { | |||
1839 | log_warn("ioctl SIOCSETMPWCFG"); | |||
1840 | return (-1); | |||
1841 | } | |||
1842 | ||||
1843 | return (0); | |||
1844 | } | |||
1845 | ||||
1846 | static int | |||
1847 | kmpw_uninstall(const char *ifname) | |||
1848 | { | |||
1849 | struct ifreq ifr; | |||
1850 | struct ifmpwreq imr; | |||
1851 | ||||
1852 | memset(&ifr, 0, sizeof(ifr)); | |||
1853 | memset(&imr, 0, sizeof(imr)); | |||
1854 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); | |||
1855 | ifr.ifr_dataifr_ifru.ifru_data = (caddr_t) &imr; | |||
1856 | if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((173))), &ifr) == -1) { | |||
1857 | log_warn("ioctl SIOCSETMPWCFG"); | |||
1858 | return (-1); | |||
1859 | } | |||
1860 | ||||
1861 | return (0); | |||
1862 | } | |||
1863 | ||||
1864 | int | |||
1865 | kmpw_find(const char *ifname) | |||
1866 | { | |||
1867 | struct ifreq ifr; | |||
1868 | ||||
1869 | memset(&ifr, 0, sizeof(ifr)); | |||
1870 | if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= | |||
1871 | sizeof(ifr.ifr_name)) { | |||
1872 | errno(*__errno()) = ENAMETOOLONG63; | |||
1873 | return (-1); | |||
1874 | } | |||
1875 | ||||
1876 | if (ioctl(kr_state.ioctl_fd, SIOCGPWE3(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((152))), &ifr) == -1) | |||
1877 | return (-1); | |||
1878 | ||||
1879 | if (ifr.ifr_pwe3ifr_ifru.ifru_metric != IF_PWE3_ETHERNET1) { | |||
1880 | errno(*__errno()) = EPFNOSUPPORT46; | |||
1881 | return (-1); | |||
1882 | } | |||
1883 | ||||
1884 | return (0); | |||
1885 | } |