Bug Summary

File:src/usr.sbin/ospfd/kroute.c
Warning:line 1586, column 4
Value stored to 'okr' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name kroute.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/ospfd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/ospfd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ospfd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/ospfd/kroute.c
1/* $OpenBSD: kroute.c,v 1.114 2020/08/20 03:09:28 jmatthew Exp $ */
2
3/*
4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <sys/sysctl.h>
23#include <sys/tree.h>
24#include <sys/uio.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <net/if.h>
28#include <net/if_dl.h>
29#include <net/if_types.h>
30#include <net/route.h>
31#include <err.h>
32#include <errno(*__errno()).h>
33#include <fcntl.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <limits.h>
39
40#include "ospfd.h"
41#include "log.h"
42
43struct {
44 u_int32_t rtseq;
45 pid_t pid;
46 int fib_sync;
47 int fib_serial;
48 u_int8_t fib_prio;
49 int fd;
50 struct event ev;
51 struct event reload;
52 u_int rdomain;
53#define KR_RELOAD_IDLE0 0
54#define KR_RELOAD_FETCH1 1
55#define KR_RELOAD_HOLD2 2
56 int reload_state;
57} kr_state;
58
59struct kroute_node {
60 RB_ENTRY(kroute_node)struct { struct kroute_node *rbe_left; struct kroute_node *rbe_right
; struct kroute_node *rbe_parent; int rbe_color; }
entry;
61 struct kroute_node *next;
62 struct kroute r;
63 int serial;
64};
65
66struct kif_node {
67 RB_ENTRY(kif_node)struct { struct kif_node *rbe_left; struct kif_node *rbe_right
; struct kif_node *rbe_parent; int rbe_color; }
entry;
68 TAILQ_HEAD(, kif_addr)struct { struct kif_addr *tqh_first; struct kif_addr **tqh_last
; }
addrs;
69 struct kif k;
70};
71
72void kr_redist_remove(struct kroute_node *, struct kroute_node *);
73int kr_redist_eval(struct kroute *, struct kroute *);
74void kr_redistribute(struct kroute_node *);
75int kroute_compare(struct kroute_node *, struct kroute_node *);
76int kif_compare(struct kif_node *, struct kif_node *);
77int kr_change_fib(struct kroute_node *, struct kroute *, int, int);
78int kr_delete_fib(struct kroute_node *);
79
80struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t);
81struct kroute_node *kroute_matchgw(struct kroute_node *, struct in_addr);
82int kroute_insert(struct kroute_node *);
83int kroute_remove(struct kroute_node *);
84void kroute_clear(void);
85
86struct kif_node *kif_find(u_short);
87struct kif_node *kif_insert(u_short);
88int kif_remove(struct kif_node *);
89struct kif *kif_update(u_short, int, struct if_data *,
90 struct sockaddr_dl *);
91int kif_validate(u_short);
92
93struct kroute_node *kroute_match(in_addr_t);
94
95int protect_lo(void);
96u_int8_t prefixlen_classful(in_addr_t);
97void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
98void if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
99void if_newaddr(u_short, struct sockaddr_in *, struct sockaddr_in *,
100 struct sockaddr_in *);
101void if_deladdr(u_short, struct sockaddr_in *, struct sockaddr_in *,
102 struct sockaddr_in *);
103void if_announce(void *);
104
105int send_rtmsg(int, int, struct kroute *);
106int dispatch_rtmsg(void);
107int fetchtable(void);
108int fetchifs(u_short);
109int rtmsg_process(char *, size_t);
110void kr_fib_reload_timer(int, short, void *);
111void kr_fib_reload_arm_timer(int);
112
113RB_HEAD(kroute_tree, kroute_node)struct kroute_tree { struct kroute_node *rbh_root; } krt = RB_INITIALIZER(&krt){ ((void*)0) };
114RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)void kroute_tree_RB_INSERT_COLOR(struct kroute_tree *, struct
kroute_node *); void kroute_tree_RB_REMOVE_COLOR(struct kroute_tree
*, struct kroute_node *, struct kroute_node *); struct kroute_node
*kroute_tree_RB_REMOVE(struct kroute_tree *, struct kroute_node
*); struct kroute_node *kroute_tree_RB_INSERT(struct kroute_tree
*, struct kroute_node *); struct kroute_node *kroute_tree_RB_FIND
(struct kroute_tree *, struct kroute_node *); struct kroute_node
*kroute_tree_RB_NFIND(struct kroute_tree *, struct kroute_node
*); struct kroute_node *kroute_tree_RB_NEXT(struct kroute_node
*); struct kroute_node *kroute_tree_RB_PREV(struct kroute_node
*); struct kroute_node *kroute_tree_RB_MINMAX(struct kroute_tree
*, int);
115RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)void kroute_tree_RB_INSERT_COLOR(struct kroute_tree *head, struct
kroute_node *elm) { struct kroute_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 kroute_tree_RB_REMOVE_COLOR(struct
kroute_tree *head, struct kroute_node *parent, struct kroute_node
*elm) { struct kroute_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 kroute_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 kroute_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 kroute_node
* kroute_tree_RB_REMOVE(struct kroute_tree *head, struct kroute_node
*elm) { struct kroute_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 kroute_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) kroute_tree_RB_REMOVE_COLOR
(head, parent, child); return (old); } struct kroute_node * kroute_tree_RB_INSERT
(struct kroute_tree *head, struct kroute_node *elm) { struct kroute_node
*tmp; struct kroute_node *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_node * kroute_tree_RB_FIND
(struct kroute_tree *head, struct kroute_node *elm) { struct kroute_node
*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_node * kroute_tree_RB_NFIND
(struct kroute_tree *head, struct kroute_node *elm) { struct kroute_node
*tmp = (head)->rbh_root; struct kroute_node *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_node * kroute_tree_RB_NEXT
(struct kroute_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
kroute_node * kroute_tree_RB_PREV(struct kroute_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 kroute_node * kroute_tree_RB_MINMAX
(struct kroute_tree *head, int val) { struct kroute_node *tmp
= (head)->rbh_root; struct kroute_node *parent = ((void*)
0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->
entry.rbe_left; else tmp = (tmp)->entry.rbe_right; } return
(parent); }
116
117RB_HEAD(kif_tree, kif_node)struct kif_tree { struct kif_node *rbh_root; } kit = RB_INITIALIZER(&kit){ ((void*)0) };
118RB_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);
119RB_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); }
120
121int
122kif_init(void)
123{
124 if (fetchifs(0) == -1)
125 return (-1);
126
127 return (0);
128}
129
130int
131kr_init(int fs, u_int rdomain, int redis_label_or_prefix, u_int8_t fib_prio)
132{
133 int opt = 0, rcvbuf, default_rcvbuf;
134 socklen_t optlen;
135 int filter_prio = fib_prio;
136 int filter_flags = RTF_LLINFO0x400 | RTF_BROADCAST0x400000;
137
138 kr_state.fib_sync = fs;
139 kr_state.rdomain = rdomain;
140 kr_state.fib_prio = fib_prio;
141
142 if ((kr_state.fd = socket(AF_ROUTE17,
143 SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, AF_INET2)) == -1) {
144 log_warn("kr_init: socket");
145 return (-1);
146 }
147
148 /* not interested in my own messages */
149 if (setsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_USELOOPBACK0x0040,
150 &opt, sizeof(opt)) == -1)
151 log_warn("kr_init: setsockopt"); /* not fatal */
152
153 if (redis_label_or_prefix) {
154 filter_prio = 0;
155 log_info("%s: priority filter disabled", __func__);
156 } else
157 log_debug("%s: priority filter enabled", __func__);
158
159 if (setsockopt(kr_state.fd, AF_ROUTE17, ROUTE_PRIOFILTER3, &filter_prio,
160 sizeof(filter_prio)) == -1) {
161 log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__);
162 /* not fatal */
163 }
164 if (setsockopt(kr_state.fd, AF_ROUTE17, ROUTE_FLAGFILTER4, &filter_flags,
165 sizeof(filter_flags)) == -1) {
166 log_warn("%s: setsockopt AF_ROUTE ROUTE_FLAGFILTER", __func__);
167 /* not fatal */
168 }
169
170 /* grow receive buffer, don't wanna miss messages */
171 optlen = sizeof(default_rcvbuf);
172 if (getsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002,
173 &default_rcvbuf, &optlen) == -1)
174 log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
175 else
176 for (rcvbuf = MAX_RTSOCK_BUF(2 * 1024 * 1024);
177 rcvbuf > default_rcvbuf &&
178 setsockopt(kr_state.fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002,
179 &rcvbuf, sizeof(rcvbuf)) == -1 && errno(*__errno()) == ENOBUFS55;
180 rcvbuf /= 2)
181 ; /* nothing */
182
183 kr_state.pid = getpid();
184 kr_state.rtseq = 1;
185
186 if (fetchtable() == -1)
187 return (-1);
188
189 if (protect_lo() == -1)
190 return (-1);
191
192 event_set(&kr_state.ev, kr_state.fd, EV_READ0x02 | EV_PERSIST0x10,
193 kr_dispatch_msg, NULL((void*)0));
194 event_add(&kr_state.ev, NULL((void*)0));
195
196 kr_state.reload_state = KR_RELOAD_IDLE0;
197 evtimer_set(&kr_state.reload, kr_fib_reload_timer, NULL)event_set(&kr_state.reload, -1, 0, kr_fib_reload_timer, (
(void*)0))
;
198
199 return (0);
200}
201
202int
203kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int krcount,
204 int action)
205{
206 int i;
207 struct kroute_node *kn, *nkn;
208
209 if (action == RTM_ADD0x1) {
210 /*
211 * First remove all stale multipath routes.
212 * This step must be skipped when the action is RTM_CHANGE
213 * because it is already a single path route that will be
214 * changed.
215 */
216 for (kn = kr; kn != NULL((void*)0); kn = nkn) {
217 for (i = 0; i < krcount; i++) {
218 if (kn->r.nexthop.s_addr ==
219 kroute[i].nexthop.s_addr)
220 break;
221 }
222 nkn = kn->next;
223 if (i == krcount) {
224 /* stale route */
225 if (kr_delete_fib(kn) == -1)
226 log_warnx("kr_delete_fib failed");
227 /*
228 * if head element was removed we need to adjust
229 * the head
230 */
231 if (kr == kn)
232 kr = nkn;
233 }
234 }
235 }
236
237 /*
238 * now add or change the route
239 */
240 for (i = 0; i < krcount; i++) {
241 /* nexthop within 127/8 -> ignore silently */
242 if ((kroute[i].nexthop.s_addr & htonl(IN_CLASSA_NET)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0xff000000))) ?
(__uint32_t)(((__uint32_t)(((u_int32_t)(0xff000000))) & 0xff
) << 24 | ((__uint32_t)(((u_int32_t)(0xff000000))) &
0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0xff000000))
) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0xff000000
))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)(
0xff000000))))
) ==
243 htonl(INADDR_LOOPBACK & IN_CLASSA_NET)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001)) &
((u_int32_t)(0xff000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t
)(0x7f000001)) & ((u_int32_t)(0xff000000))) & 0xff) <<
24 | ((__uint32_t)(((u_int32_t)(0x7f000001)) & ((u_int32_t
)(0xff000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t
)(0x7f000001)) & ((u_int32_t)(0xff000000))) & 0xff0000
) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) & (
(u_int32_t)(0xff000000))) & 0xff000000) >> 24) : __swap32md
(((u_int32_t)(0x7f000001)) & ((u_int32_t)(0xff000000))))
)
244 continue;
245
246 if (action == RTM_ADD0x1 && kr) {
247 for (kn = kr; kn != NULL((void*)0); kn = kn->next) {
248 if (kn->r.nexthop.s_addr ==
249 kroute[i].nexthop.s_addr)
250 break;
251 }
252
253 if (kn != NULL((void*)0))
254 /* nexthop already present, skip it */
255 continue;
256 } else
257 /* modify first entry */
258 kn = kr;
259
260 /* send update */
261 if (send_rtmsg(kr_state.fd, action, &kroute[i]) == -1)
262 return (-1);
263
264 /* create new entry unless we are changing the first entry */
265 if (action == RTM_ADD0x1)
266 if ((kn = calloc(1, sizeof(*kn))) == NULL((void*)0))
267 fatal(NULL((void*)0));
268
269 kn->r.prefix.s_addr = kroute[i].prefix.s_addr;
270 kn->r.prefixlen = kroute[i].prefixlen;
271 kn->r.nexthop.s_addr = kroute[i].nexthop.s_addr;
272 kn->r.flags = kroute[i].flags | F_OSPFD_INSERTED0x0001;
273 kn->r.priority = kr_state.fib_prio;
274 kn->r.ext_tag = kroute[i].ext_tag;
275 rtlabel_unref(kn->r.rtlabel); /* for RTM_CHANGE */
276 kn->r.rtlabel = kroute[i].rtlabel;
277
278 if (action == RTM_ADD0x1)
279 if (kroute_insert(kn) == -1) {
280 log_debug("kr_update_fib: cannot insert %s",
281 inet_ntoa(kn->r.nexthop));
282 free(kn);
283 }
284 action = RTM_ADD0x1;
285 }
286 return (0);
287}
288
289int
290kr_change(struct kroute *kroute, int krcount)
291{
292 struct kroute_node *kr;
293 int action = RTM_ADD0x1;
294
295 kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag);
296
297 kr = kroute_find(kroute->prefix.s_addr, kroute->prefixlen,
298 kr_state.fib_prio);
299 if (kr != NULL((void*)0) && kr->next == NULL((void*)0) && krcount == 1)
300 /* single path OSPF route */
301 action = RTM_CHANGE0x3;
302
303 return (kr_change_fib(kr, kroute, krcount, action));
304}
305
306int
307kr_delete_fib(struct kroute_node *kr)
308{
309 if (kr->r.priority != kr_state.fib_prio)
310 log_warn("kr_delete_fib: %s/%d has wrong priority %d",
311 inet_ntoa(kr->r.prefix), kr->r.prefixlen, kr->r.priority);
312
313 if (send_rtmsg(kr_state.fd, RTM_DELETE0x2, &kr->r) == -1)
314 return (-1);
315
316 if (kroute_remove(kr) == -1)
317 return (-1);
318
319 return (0);
320}
321
322int
323kr_delete(struct kroute *kroute)
324{
325 struct kroute_node *kr, *nkr;
326
327 if ((kr = kroute_find(kroute->prefix.s_addr, kroute->prefixlen,
328 kr_state.fib_prio)) == NULL((void*)0))
329 return (0);
330
331 while (kr != NULL((void*)0)) {
332 nkr = kr->next;
333 if (kr_delete_fib(kr) == -1)
334 return (-1);
335 kr = nkr;
336 }
337 return (0);
338}
339
340void
341kr_shutdown(void)
342{
343 kr_fib_decouple();
344 kroute_clear();
345 kif_clear();
346}
347
348void
349kr_fib_couple(void)
350{
351 struct kroute_node *kr;
352 struct kroute_node *kn;
353
354 if (kr_state.fib_sync == 1) /* already coupled */
355 return;
356
357 kr_state.fib_sync = 1;
358
359 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
360 if (kr->r.priority == kr_state.fib_prio)
361 for (kn = kr; kn != NULL((void*)0); kn = kn->next)
362 send_rtmsg(kr_state.fd, RTM_ADD0x1, &kn->r);
363
364 log_info("kernel routing table coupled");
365}
366
367void
368kr_fib_decouple(void)
369{
370 struct kroute_node *kr;
371 struct kroute_node *kn;
372
373 if (kr_state.fib_sync == 0) /* already decoupled */
374 return;
375
376 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
377 if (kr->r.priority == kr_state.fib_prio)
378 for (kn = kr; kn != NULL((void*)0); kn = kn->next)
379 send_rtmsg(kr_state.fd, RTM_DELETE0x2, &kn->r);
380
381 kr_state.fib_sync = 0;
382
383 log_info("kernel routing table decoupled");
384}
385
386void
387kr_fib_reload_timer(int fd, short event, void *bula)
388{
389 if (kr_state.reload_state == KR_RELOAD_FETCH1) {
390 kr_fib_reload();
391 kr_state.reload_state = KR_RELOAD_HOLD2;
392 kr_fib_reload_arm_timer(KR_RELOAD_HOLD_TIMER5000);
393 } else {
394 kr_state.reload_state = KR_RELOAD_IDLE0;
395 }
396}
397
398void
399kr_fib_reload_arm_timer(int delay)
400{
401 struct timeval tv;
402
403 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
404 tv.tv_sec = delay / 1000;
405 tv.tv_usec = (delay % 1000) * 1000;
406
407 if (evtimer_add(&kr_state.reload, &tv)event_add(&kr_state.reload, &tv) == -1)
408 fatal("add_reload_timer");
409}
410
411void
412kr_fib_reload()
413{
414 struct kroute_node *krn, *kr, *kn;
415
416 log_info("reloading interface list and routing table");
417
418 kr_state.fib_serial++;
419
420 if (fetchifs(0) == -1 || fetchtable() == -1)
421 return;
422
423 for (kr = RB_MIN(kroute_tree, &krt)kroute_tree_RB_MINMAX(&krt, -1); kr != NULL((void*)0); kr = krn) {
424 krn = RB_NEXT(kroute_tree, &krt, kr)kroute_tree_RB_NEXT(kr);
425
426 do {
427 kn = kr->next;
428
429 if (kr->serial != kr_state.fib_serial) {
430 if (kr->r.priority == kr_state.fib_prio) {
431 kr->serial = kr_state.fib_serial;
432 if (send_rtmsg(kr_state.fd,
433 RTM_ADD0x1, &kr->r) != 0)
434 break;
435 } else
436 kroute_remove(kr);
437 }
438
439 } while ((kr = kn) != NULL((void*)0));
440 }
441}
442
443void
444kr_fib_update_prio(u_int8_t fib_prio)
445{
446 struct kroute_node *kr;
447
448 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
449 if ((kr->r.flags & F_OSPFD_INSERTED0x0001))
450 kr->r.priority = fib_prio;
451
452 log_info("fib priority changed from %hhu to %hhu",
453 kr_state.fib_prio, fib_prio);
454
455 kr_state.fib_prio = fib_prio;
456 }
457
458/* ARGSUSED */
459void
460kr_dispatch_msg(int fd, short event, void *bula)
461{
462 /* XXX this is stupid */
463 if (dispatch_rtmsg() == -1)
464 event_loopexit(NULL((void*)0));
465}
466
467void
468kr_show_route(struct imsg *imsg)
469{
470 struct kroute_node *kr;
471 struct kroute_node *kn;
472 int flags;
473 struct in_addr addr;
474
475 switch (imsg->hdr.type) {
476 case IMSG_CTL_KROUTE:
477 if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(flags)) {
478 log_warnx("kr_show_route: wrong imsg len");
479 return;
480 }
481 memcpy(&flags, imsg->data, sizeof(flags));
482 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
483 if (!flags || kr->r.flags & flags) {
484 kn = kr;
485 do {
486 main_imsg_compose_ospfe(IMSG_CTL_KROUTE,
487 imsg->hdr.pid,
488 &kn->r, sizeof(kn->r));
489 } while ((kn = kn->next) != NULL((void*)0));
490 }
491 break;
492 case IMSG_CTL_KROUTE_ADDR:
493 if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) +
494 sizeof(struct in_addr)) {
495 log_warnx("kr_show_route: wrong imsg len");
496 return;
497 }
498 memcpy(&addr, imsg->data, sizeof(addr));
499 kr = NULL((void*)0);
500 kr = kroute_match(addr.s_addr);
501 if (kr != NULL((void*)0))
502 main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid,
503 &kr->r, sizeof(kr->r));
504 break;
505 default:
506 log_debug("kr_show_route: error handling imsg");
507 break;
508 }
509
510 main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL((void*)0), 0);
511}
512
513void
514kr_ifinfo(char *ifname, pid_t pid)
515{
516 struct kif_node *kif;
517
518 RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void
*)0); (kif) = kif_tree_RB_NEXT(kif))
519 if (ifname == NULL((void*)0) || !strcmp(ifname, kif->k.ifname)) {
520 main_imsg_compose_ospfe(IMSG_CTL_IFINFO,
521 pid, &kif->k, sizeof(kif->k));
522 }
523
524 main_imsg_compose_ospfe(IMSG_CTL_END, pid, NULL((void*)0), 0);
525}
526
527void
528kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn)
529{
530 struct kroute *kr;
531
532 /* was the route redistributed? */
533 if ((kn->r.flags & F_REDISTRIBUTED0x0100) == 0)
534 return;
535
536 /* remove redistributed flag */
537 kn->r.flags &= ~F_REDISTRIBUTED0x0100;
538 kr = &kn->r;
539
540 /* probably inform the RDE (check if no other path is redistributed) */
541 for (kn = kh; kn; kn = kn->next)
542 if (kn->r.flags & F_REDISTRIBUTED0x0100)
543 break;
544
545 if (kn == NULL((void*)0))
546 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr,
547 sizeof(struct kroute));
548}
549
550int
551kr_redist_eval(struct kroute *kr, struct kroute *new_kr)
552{
553 u_int32_t a, metric = 0;
554
555 /* Only non-ospfd routes are considered for redistribution. */
556 if (!(kr->flags & F_KERNEL0x0002))
557 goto dont_redistribute;
558
559 /* Dynamic routes are not redistributable. */
560 if (kr->flags & F_DYNAMIC0x0010)
561 goto dont_redistribute;
562
563 /* interface is not up and running so don't announce */
564 if (kr->flags & F_DOWN0x0020)
565 goto dont_redistribute;
566
567 /*
568 * We consider the loopback net, multicast and experimental addresses
569 * as not redistributable.
570 */
571 a = ntohl(kr->prefix.s_addr)(__uint32_t)(__builtin_constant_p(kr->prefix.s_addr) ? (__uint32_t
)(((__uint32_t)(kr->prefix.s_addr) & 0xff) << 24
| ((__uint32_t)(kr->prefix.s_addr) & 0xff00) <<
8 | ((__uint32_t)(kr->prefix.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(kr->prefix.s_addr) & 0xff000000) >>
24) : __swap32md(kr->prefix.s_addr))
;
572 if (IN_MULTICAST(a)(((u_int32_t)(a) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
|| IN_BADCLASS(a)(((u_int32_t)(a) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xf0000000)))
||
573 (a >> IN_CLASSA_NSHIFT24) == IN_LOOPBACKNET127)
574 goto dont_redistribute;
575 /*
576 * Consider networks with nexthop loopback as not redistributable
577 * unless it is a reject or blackhole route.
578 */
579 if (kr->nexthop.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))))
&&
580 !(kr->flags & (F_BLACKHOLE0x0080|F_REJECT0x0040)))
581 goto dont_redistribute;
582
583 /* Should we redistribute this route? */
584 if (!ospf_redistribute(kr, &metric))
585 goto dont_redistribute;
586
587 /* prefix should be redistributed */
588 kr->flags |= F_REDISTRIBUTED0x0100;
589 /*
590 * only one of all multipath routes can be redistributed so
591 * redistribute the best one.
592 */
593 if (new_kr->metric > metric) {
594 *new_kr = *kr;
595 new_kr->metric = metric;
596 }
597
598 return (1);
599
600dont_redistribute:
601 /* was the route redistributed? */
602 if ((kr->flags & F_REDISTRIBUTED0x0100) == 0)
603 return (0);
604
605 kr->flags &= ~F_REDISTRIBUTED0x0100;
606 return (1);
607}
608
609void
610kr_redistribute(struct kroute_node *kh)
611{
612 struct kroute_node *kn;
613 struct kroute kr;
614 int redistribute = 0;
615
616 /* only the highest prio route can be redistributed */
617 if (kroute_find(kh->r.prefix.s_addr, kh->r.prefixlen, RTP_ANY64) != kh)
618 return;
619
620 bzero(&kr, sizeof(kr));
621 kr.metric = UINT_MAX(2147483647 *2U +1U);
622 for (kn = kh; kn; kn = kn->next)
623 if (kr_redist_eval(&kn->r, &kr))
624 redistribute = 1;
625
626 if (!redistribute)
627 return;
628
629 if (kr.flags & F_REDISTRIBUTED0x0100) {
630 main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &kr,
631 sizeof(struct kroute));
632 } else {
633 kr = kh->r;
634 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &kr,
635 sizeof(struct kroute));
636 }
637}
638
639void
640kr_reload(int redis_label_or_prefix)
641{
642 struct kroute_node *kr, *kn;
643 u_int32_t dummy;
644 int r;
645 int filter_prio = kr_state.fib_prio;
646
647 /* update the priority filter */
648 if (redis_label_or_prefix) {
649 filter_prio = 0;
650 log_info("%s: priority filter disabled", __func__);
651 } else
652 log_debug("%s: priority filter enabled", __func__);
653
654 if (setsockopt(kr_state.fd, AF_ROUTE17, ROUTE_PRIOFILTER3, &filter_prio,
655 sizeof(filter_prio)) == -1) {
656 log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__);
657 /* not fatal */
658 }
659
660 /* update redistribute lists */
661 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
{
662 for (kn = kr; kn; kn = kn->next) {
663 r = ospf_redistribute(&kn->r, &dummy);
664 /*
665 * if it is redistributed, redistribute again metric
666 * may have changed.
667 */
668 if ((kn->r.flags & F_REDISTRIBUTED0x0100 && !r) || r)
669 break;
670 }
671 if (kn) {
672 /*
673 * kr_redistribute copes with removes and RDE with
674 * duplicates
675 */
676 kr_redistribute(kr);
677 }
678 }
679}
680
681/* rb-tree compare */
682int
683kroute_compare(struct kroute_node *a, struct kroute_node *b)
684{
685 if (ntohl(a->r.prefix.s_addr)(__uint32_t)(__builtin_constant_p(a->r.prefix.s_addr) ? (__uint32_t
)(((__uint32_t)(a->r.prefix.s_addr) & 0xff) << 24
| ((__uint32_t)(a->r.prefix.s_addr) & 0xff00) <<
8 | ((__uint32_t)(a->r.prefix.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(a->r.prefix.s_addr) & 0xff000000) >>
24) : __swap32md(a->r.prefix.s_addr))
< ntohl(b->r.prefix.s_addr)(__uint32_t)(__builtin_constant_p(b->r.prefix.s_addr) ? (__uint32_t
)(((__uint32_t)(b->r.prefix.s_addr) & 0xff) << 24
| ((__uint32_t)(b->r.prefix.s_addr) & 0xff00) <<
8 | ((__uint32_t)(b->r.prefix.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(b->r.prefix.s_addr) & 0xff000000) >>
24) : __swap32md(b->r.prefix.s_addr))
)
686 return (-1);
687 if (ntohl(a->r.prefix.s_addr)(__uint32_t)(__builtin_constant_p(a->r.prefix.s_addr) ? (__uint32_t
)(((__uint32_t)(a->r.prefix.s_addr) & 0xff) << 24
| ((__uint32_t)(a->r.prefix.s_addr) & 0xff00) <<
8 | ((__uint32_t)(a->r.prefix.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(a->r.prefix.s_addr) & 0xff000000) >>
24) : __swap32md(a->r.prefix.s_addr))
> ntohl(b->r.prefix.s_addr)(__uint32_t)(__builtin_constant_p(b->r.prefix.s_addr) ? (__uint32_t
)(((__uint32_t)(b->r.prefix.s_addr) & 0xff) << 24
| ((__uint32_t)(b->r.prefix.s_addr) & 0xff00) <<
8 | ((__uint32_t)(b->r.prefix.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(b->r.prefix.s_addr) & 0xff000000) >>
24) : __swap32md(b->r.prefix.s_addr))
)
688 return (1);
689 if (a->r.prefixlen < b->r.prefixlen)
690 return (-1);
691 if (a->r.prefixlen > b->r.prefixlen)
692 return (1);
693
694 /* if the priority is RTP_ANY finish on the first address hit */
695 if (a->r.priority == RTP_ANY64 || b->r.priority == RTP_ANY64)
696 return (0);
697 if (a->r.priority < b->r.priority)
698 return (-1);
699 if (a->r.priority > b->r.priority)
700 return (1);
701 return (0);
702}
703
704int
705kif_compare(struct kif_node *a, struct kif_node *b)
706{
707 return (b->k.ifindex - a->k.ifindex);
708}
709
710/* tree management */
711struct kroute_node *
712kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
713{
714 struct kroute_node s;
715 struct kroute_node *kn, *tmp;
716
717 s.r.prefix.s_addr = prefix;
718 s.r.prefixlen = prefixlen;
719 s.r.priority = prio;
720
721 kn = RB_FIND(kroute_tree, &krt, &s)kroute_tree_RB_FIND(&krt, &s);
722 if (kn && prio == RTP_ANY64) {
723 tmp = RB_PREV(kroute_tree, &krt, kn)kroute_tree_RB_PREV(kn);
724 while (tmp) {
725 if (kroute_compare(&s, tmp) == 0)
726 kn = tmp;
727 else
728 break;
729 tmp = RB_PREV(kroute_tree, &krt, kn)kroute_tree_RB_PREV(kn);
730 }
731 }
732 return (kn);
733}
734
735struct kroute_node *
736kroute_matchgw(struct kroute_node *kr, struct in_addr nh)
737{
738 in_addr_t nexthop;
739
740 nexthop = nh.s_addr;
741
742 while (kr) {
743 if (kr->r.nexthop.s_addr == nexthop)
744 return (kr);
745 kr = kr->next;
746 }
747
748 return (NULL((void*)0));
749}
750
751int
752kroute_insert(struct kroute_node *kr)
753{
754 struct kroute_node *krm, *krh;
755
756 kr->serial = kr_state.fib_serial;
757
758 if ((krh = RB_INSERT(kroute_tree, &krt, kr)kroute_tree_RB_INSERT(&krt, kr)) != NULL((void*)0)) {
759 /*
760 * Multipath route, add at end of list.
761 */
762 krm = krh;
763 while (krm->next != NULL((void*)0))
764 krm = krm->next;
765 krm->next = kr;
766 kr->next = NULL((void*)0); /* to be sure */
767 } else
768 krh = kr;
769
770 if (!(kr->r.flags & F_KERNEL0x0002)) {
771 /* don't validate or redistribute ospf route */
772 kr->r.flags &= ~F_DOWN0x0020;
773 return (0);
774 }
775
776 if (kif_validate(kr->r.ifindex))
777 kr->r.flags &= ~F_DOWN0x0020;
778 else
779 kr->r.flags |= F_DOWN0x0020;
780
781 kr_redistribute(krh);
782 return (0);
783}
784
785int
786kroute_remove(struct kroute_node *kr)
787{
788 struct kroute_node *krm;
789
790 if ((krm = RB_FIND(kroute_tree, &krt, kr)kroute_tree_RB_FIND(&krt, kr)) == NULL((void*)0)) {
791 log_warnx("kroute_remove failed to find %s/%u",
792 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
793 return (-1);
794 }
795
796 if (krm == kr) {
797 /* head element */
798 if (RB_REMOVE(kroute_tree, &krt, kr)kroute_tree_RB_REMOVE(&krt, kr) == NULL((void*)0)) {
799 log_warnx("kroute_remove failed for %s/%u",
800 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
801 return (-1);
802 }
803 if (kr->next != NULL((void*)0)) {
804 if (RB_INSERT(kroute_tree, &krt, kr->next)kroute_tree_RB_INSERT(&krt, kr->next) != NULL((void*)0)) {
805 log_warnx("kroute_remove failed to add %s/%u",
806 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
807 return (-1);
808 }
809 }
810 } else {
811 /* somewhere in the list */
812 while (krm->next != kr && krm->next != NULL((void*)0))
813 krm = krm->next;
814 if (krm->next == NULL((void*)0)) {
815 log_warnx("kroute_remove multipath list corrupted "
816 "for %s/%u", inet_ntoa(kr->r.prefix),
817 kr->r.prefixlen);
818 return (-1);
819 }
820 krm->next = kr->next;
821 }
822
823 kr_redist_remove(krm, kr);
824 rtlabel_unref(kr->r.rtlabel);
825
826 free(kr);
827 return (0);
828}
829
830void
831kroute_clear(void)
832{
833 struct kroute_node *kr;
834
835 while ((kr = RB_MIN(kroute_tree, &krt)kroute_tree_RB_MINMAX(&krt, -1)) != NULL((void*)0))
836 kroute_remove(kr);
837}
838
839struct kif_node *
840kif_find(u_short ifindex)
841{
842 struct kif_node s;
843
844 bzero(&s, sizeof(s));
845 s.k.ifindex = ifindex;
846
847 return (RB_FIND(kif_tree, &kit, &s)kif_tree_RB_FIND(&kit, &s));
848}
849
850struct kif *
851kif_findname(char *ifname, struct in_addr addr, struct kif_addr **kap)
852{
853 struct kif_node *kif;
854 struct kif_addr *ka;
855
856 RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void
*)0); (kif) = kif_tree_RB_NEXT(kif))
857 if (!strcmp(ifname, kif->k.ifname)) {
858 ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first);
859 if (addr.s_addr != 0) {
860 TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void
*)0); (ka) = ((ka)->entry.tqe_next))
{
861 if (addr.s_addr == ka->addr.s_addr)
862 break;
863 }
864 }
865 if (kap != NULL((void*)0))
866 *kap = ka;
867 return (&kif->k);
868 }
869
870 return (NULL((void*)0));
871}
872
873struct kif_node *
874kif_insert(u_short ifindex)
875{
876 struct kif_node *kif;
877
878 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL((void*)0))
879 return (NULL((void*)0));
880
881 kif->k.ifindex = ifindex;
882 TAILQ_INIT(&kif->addrs)do { (&kif->addrs)->tqh_first = ((void*)0); (&kif
->addrs)->tqh_last = &(&kif->addrs)->tqh_first
; } while (0)
;
883
884 if (RB_INSERT(kif_tree, &kit, kif)kif_tree_RB_INSERT(&kit, kif) != NULL((void*)0))
885 fatalx("kif_insert: RB_INSERT");
886
887 return (kif);
888}
889
890int
891kif_remove(struct kif_node *kif)
892{
893 struct kif_addr *ka;
894
895 if (RB_REMOVE(kif_tree, &kit, kif)kif_tree_RB_REMOVE(&kit, kif) == NULL((void*)0)) {
896 log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
897 return (-1);
898 }
899
900 while ((ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first)) != NULL((void*)0)) {
901 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)
;
902 free(ka);
903 }
904 free(kif);
905 return (0);
906}
907
908void
909kif_clear(void)
910{
911 struct kif_node *kif;
912
913 while ((kif = RB_MIN(kif_tree, &kit)kif_tree_RB_MINMAX(&kit, -1)) != NULL((void*)0))
914 kif_remove(kif);
915}
916
917struct kif *
918kif_update(u_short ifindex, int flags, struct if_data *ifd,
919 struct sockaddr_dl *sdl)
920{
921 struct kif_node *kif;
922
923 if ((kif = kif_find(ifindex)) == NULL((void*)0)) {
924 if ((kif = kif_insert(ifindex)) == NULL((void*)0))
925 return (NULL((void*)0));
926 kif->k.nh_reachable = (flags & IFF_UP0x1) &&
927 LINK_STATE_IS_UP(ifd->ifi_link_state)((ifd->ifi_link_state) >= 4 || (ifd->ifi_link_state)
== 0)
;
928 }
929
930 kif->k.flags = flags;
931 kif->k.link_state = ifd->ifi_link_state;
932 kif->k.if_type = ifd->ifi_type;
933 kif->k.baudrate = ifd->ifi_baudrate;
934 kif->k.mtu = ifd->ifi_mtu;
935 kif->k.rdomain = ifd->ifi_rdomain;
936
937 if (sdl && sdl->sdl_family == AF_LINK18) {
938 if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
939 memcpy(kif->k.ifname, sdl->sdl_data,
940 sizeof(kif->k.ifname) - 1);
941 else if (sdl->sdl_nlen > 0)
942 memcpy(kif->k.ifname, sdl->sdl_data,
943 sdl->sdl_nlen);
944 /* string already terminated via calloc() */
945 }
946
947 return (&kif->k);
948}
949
950int
951kif_validate(u_short ifindex)
952{
953 struct kif_node *kif;
954
955 if ((kif = kif_find(ifindex)) == NULL((void*)0)) {
956 log_warnx("interface with index %u not found", ifindex);
957 return (1);
958 }
959
960 return (kif->k.nh_reachable);
961}
962
963struct kroute_node *
964kroute_match(in_addr_t key)
965{
966 int i;
967 struct kroute_node *kr;
968
969 /* we will never match the default route */
970 for (i = 32; i > 0; i--)
971 if ((kr = kroute_find(key & prefixlen2mask(i), i,
972 RTP_ANY64)) != NULL((void*)0))
973 return (kr);
974
975 /* if we don't have a match yet, try to find a default route */
976 if ((kr = kroute_find(0, 0, RTP_ANY64)) != NULL((void*)0))
977 return (kr);
978
979 return (NULL((void*)0));
980}
981
982/* misc */
983int
984protect_lo(void)
985{
986 struct kroute_node *kr;
987
988 /* special protection for 127/8 */
989 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL((void*)0)) {
990 log_warn("protect_lo");
991 return (-1);
992 }
993 kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001)) &
((u_int32_t)(0xff000000))) ? (__uint32_t)(((__uint32_t)(((u_int32_t
)(0x7f000001)) & ((u_int32_t)(0xff000000))) & 0xff) <<
24 | ((__uint32_t)(((u_int32_t)(0x7f000001)) & ((u_int32_t
)(0xff000000))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t
)(0x7f000001)) & ((u_int32_t)(0xff000000))) & 0xff0000
) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) & (
(u_int32_t)(0xff000000))) & 0xff000000) >> 24) : __swap32md
(((u_int32_t)(0x7f000001)) & ((u_int32_t)(0xff000000))))
;
994 kr->r.prefixlen = 8;
995 kr->r.flags = F_KERNEL0x0002|F_CONNECTED0x0004;
996
997 if (RB_INSERT(kroute_tree, &krt, kr)kroute_tree_RB_INSERT(&krt, kr) != NULL((void*)0))
998 free(kr); /* kernel route already there, no problem */
999
1000 return (0);
1001}
1002
1003u_int8_t
1004prefixlen_classful(in_addr_t ina)
1005{
1006 /* it hurt to write this. */
1007
1008 if (ina >= 0xf0000000U) /* class E */
1009 return (32);
1010 else if (ina >= 0xe0000000U) /* class D */
1011 return (4);
1012 else if (ina >= 0xc0000000U) /* class C */
1013 return (24);
1014 else if (ina >= 0x80000000U) /* class B */
1015 return (16);
1016 else /* class A */
1017 return (8);
1018}
1019
1020u_int8_t
1021mask2prefixlen(in_addr_t ina)
1022{
1023 if (ina == 0)
1024 return (0);
1025 else
1026 return (33 - ffs(ntohl(ina)(__uint32_t)(__builtin_constant_p(ina) ? (__uint32_t)(((__uint32_t
)(ina) & 0xff) << 24 | ((__uint32_t)(ina) & 0xff00
) << 8 | ((__uint32_t)(ina) & 0xff0000) >> 8 |
((__uint32_t)(ina) & 0xff000000) >> 24) : __swap32md
(ina))
));
1027}
1028
1029in_addr_t
1030prefixlen2mask(u_int8_t prefixlen)
1031{
1032 if (prefixlen == 0)
1033 return (0);
1034
1035 return (htonl(0xffffffff << (32 - prefixlen))(__uint32_t)(__builtin_constant_p(0xffffffff << (32 - prefixlen
)) ? (__uint32_t)(((__uint32_t)(0xffffffff << (32 - prefixlen
)) & 0xff) << 24 | ((__uint32_t)(0xffffffff <<
(32 - prefixlen)) & 0xff00) << 8 | ((__uint32_t)(0xffffffff
<< (32 - prefixlen)) & 0xff0000) >> 8 | ((__uint32_t
)(0xffffffff << (32 - prefixlen)) & 0xff000000) >>
24) : __swap32md(0xffffffff << (32 - prefixlen)))
);
1036}
1037
1038#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
1039 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1040
1041void
1042get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1043{
1044 int i;
1045
1046 for (i = 0; i < RTAX_MAX15; i++) {
1047 if (addrs & (1 << i)) {
1048 rti_info[i] = sa;
1049 sa = (struct sockaddr *)((char *)(sa) +
1050 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
1051 } else
1052 rti_info[i] = NULL((void*)0);
1053 }
1054}
1055
1056void
1057if_change(u_short ifindex, int flags, struct if_data *ifd,
1058 struct sockaddr_dl *sdl)
1059{
1060 struct kroute_node *kr, *tkr;
1061 struct kif *kif;
1062 u_int8_t reachable;
1063
1064 if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL((void*)0)) {
1065 log_warn("if_change: kif_update(%u)", ifindex);
1066 return;
1067 }
1068
1069 /* notify ospfe about interface link state */
1070 main_imsg_compose_ospfe(IMSG_IFINFO, 0, kif, sizeof(struct kif));
1071
1072 reachable = (kif->flags & IFF_UP0x1) &&
1073 LINK_STATE_IS_UP(kif->link_state)((kif->link_state) >= 4 || (kif->link_state) == 0);
1074
1075 if (reachable == kif->nh_reachable)
1076 return; /* nothing changed wrt nexthop validity */
1077
1078 kif->nh_reachable = reachable;
1079
1080 /* update redistribute list */
1081 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
{
1082 for (tkr = kr; tkr != NULL((void*)0); tkr = tkr->next) {
1083 if (tkr->r.ifindex == ifindex) {
1084 if (reachable)
1085 tkr->r.flags &= ~F_DOWN0x0020;
1086 else
1087 tkr->r.flags |= F_DOWN0x0020;
1088
1089 }
1090 }
1091 kr_redistribute(kr);
1092 }
1093}
1094
1095void
1096if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1097 struct sockaddr_in *brd)
1098{
1099 struct kif_node *kif;
1100 struct kif_addr *ka;
1101 struct ifaddrchange ifn;
1102
1103 if (ifa == NULL((void*)0) || ifa->sin_family != AF_INET2)
1104 return;
1105 if ((kif = kif_find(ifindex)) == NULL((void*)0)) {
1106 log_warnx("if_newaddr: corresponding if %d not found", ifindex);
1107 return;
1108 }
1109 if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void*)0))
1110 fatal("if_newaddr");
1111 ka->addr = ifa->sin_addr;
1112 if (mask)
1113 ka->mask = mask->sin_addr;
1114 else
1115 ka->mask.s_addr = INADDR_NONE((u_int32_t)(0xffffffff));
1116 if (brd)
1117 ka->dstbrd = brd->sin_addr;
1118 else
1119 ka->dstbrd.s_addr = INADDR_NONE((u_int32_t)(0xffffffff));
1120
1121 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)
;
1122
1123 ifn.addr = ka->addr;
1124 ifn.mask = ka->mask;
1125 ifn.dst = ka->dstbrd;
1126 ifn.ifindex = ifindex;
1127 main_imsg_compose_ospfe(IMSG_IFADDRADD, 0, &ifn, sizeof(ifn));
1128}
1129
1130void
1131if_deladdr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1132 struct sockaddr_in *brd)
1133{
1134 struct kif_node *kif;
1135 struct kif_addr *ka, *nka;
1136 struct ifaddrchange ifc;
1137
1138 if (ifa == NULL((void*)0) || ifa->sin_family != AF_INET2)
1139 return;
1140 if ((kif = kif_find(ifindex)) == NULL((void*)0)) {
1141 log_warnx("if_deladdr: corresponding if %d not found", ifindex);
1142 return;
1143 }
1144
1145 for (ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first); ka != NULL((void*)0); ka = nka) {
1146 nka = TAILQ_NEXT(ka, entry)((ka)->entry.tqe_next);
1147
1148 if (ka->addr.s_addr == ifa->sin_addr.s_addr) {
1149 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)
;
1150 ifc.addr = ifa->sin_addr;
1151 ifc.ifindex = ifindex;
1152 main_imsg_compose_ospfe(IMSG_IFADDRDEL, 0, &ifc,
1153 sizeof(ifc));
1154 free(ka);
1155 return;
1156 }
1157 }
1158}
1159
1160void
1161if_announce(void *msg)
1162{
1163 struct if_announcemsghdr *ifan;
1164 struct kif_node *kif;
1165
1166 ifan = msg;
1167
1168 switch (ifan->ifan_what) {
1169 case IFAN_ARRIVAL0:
1170 kif = kif_insert(ifan->ifan_index);
1171 strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
1172 break;
1173 case IFAN_DEPARTURE1:
1174 kif = kif_find(ifan->ifan_index);
1175 kif_remove(kif);
1176 break;
1177 }
1178}
1179
1180/* rtsock */
1181int
1182send_rtmsg(int fd, int action, struct kroute *kroute)
1183{
1184 struct iovec iov[5];
1185 struct rt_msghdr hdr;
1186 struct sockaddr_in prefix;
1187 struct sockaddr_in nexthop;
1188 struct sockaddr_in mask;
1189 struct sockaddr_rtlabel sa_rl;
1190 int iovcnt = 0;
1191 const char *label;
1192
1193 if (kr_state.fib_sync == 0)
1194 return (0);
1195
1196 /* initialize header */
1197 bzero(&hdr, sizeof(hdr));
1198 hdr.rtm_version = RTM_VERSION5;
1199 hdr.rtm_type = action;
1200 hdr.rtm_priority = kr_state.fib_prio;
1201 hdr.rtm_tableid = kr_state.rdomain; /* rtableid */
1202 if (action == RTM_CHANGE0x3)
1203 hdr.rtm_fmask = RTF_REJECT0x8|RTF_BLACKHOLE0x1000;
1204 else
1205 hdr.rtm_flags = RTF_MPATH0x40000;
1206 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
1207 hdr.rtm_msglen = sizeof(hdr);
1208 /* adjust iovec */
1209 iov[iovcnt].iov_base = &hdr;
1210 iov[iovcnt++].iov_len = sizeof(hdr);
1211
1212 bzero(&prefix, sizeof(prefix));
1213 prefix.sin_len = sizeof(prefix);
1214 prefix.sin_family = AF_INET2;
1215 prefix.sin_addr.s_addr = kroute->prefix.s_addr;
1216 /* adjust header */
1217 hdr.rtm_addrs |= RTA_DST0x1;
1218 hdr.rtm_msglen += sizeof(prefix);
1219 /* adjust iovec */
1220 iov[iovcnt].iov_base = &prefix;
1221 iov[iovcnt++].iov_len = sizeof(prefix);
1222
1223 if (kroute->nexthop.s_addr != 0) {
1224 bzero(&nexthop, sizeof(nexthop));
1225 nexthop.sin_len = sizeof(nexthop);
1226 nexthop.sin_family = AF_INET2;
1227 nexthop.sin_addr.s_addr = kroute->nexthop.s_addr;
1228 /* adjust header */
1229 hdr.rtm_flags |= RTF_GATEWAY0x2;
1230 hdr.rtm_addrs |= RTA_GATEWAY0x2;
1231 hdr.rtm_msglen += sizeof(nexthop);
1232 /* adjust iovec */
1233 iov[iovcnt].iov_base = &nexthop;
1234 iov[iovcnt++].iov_len = sizeof(nexthop);
1235 }
1236
1237 bzero(&mask, sizeof(mask));
1238 mask.sin_len = sizeof(mask);
1239 mask.sin_family = AF_INET2;
1240 mask.sin_addr.s_addr = prefixlen2mask(kroute->prefixlen);
1241 /* adjust header */
1242 hdr.rtm_addrs |= RTA_NETMASK0x4;
1243 hdr.rtm_msglen += sizeof(mask);
1244 /* adjust iovec */
1245 iov[iovcnt].iov_base = &mask;
1246 iov[iovcnt++].iov_len = sizeof(mask);
1247
1248 if (kroute->rtlabel != 0) {
1249 sa_rl.sr_len = sizeof(sa_rl);
1250 sa_rl.sr_family = AF_UNSPEC0;
1251 label = rtlabel_id2name(kroute->rtlabel);
1252 if (strlcpy(sa_rl.sr_label, label,
1253 sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) {
1254 log_warnx("send_rtmsg: invalid rtlabel");
1255 return (-1);
1256 }
1257 /* adjust header */
1258 hdr.rtm_addrs |= RTA_LABEL0x400;
1259 hdr.rtm_msglen += sizeof(sa_rl);
1260 /* adjust iovec */
1261 iov[iovcnt].iov_base = &sa_rl;
1262 iov[iovcnt++].iov_len = sizeof(sa_rl);
1263 }
1264
1265retry:
1266 if (writev(fd, iov, iovcnt) == -1) {
1267 if (errno(*__errno()) == ESRCH3) {
1268 if (hdr.rtm_type == RTM_CHANGE0x3) {
1269 hdr.rtm_type = RTM_ADD0x1;
1270 goto retry;
1271 } else if (hdr.rtm_type == RTM_DELETE0x2) {
1272 log_info("route %s/%u vanished before delete",
1273 inet_ntoa(kroute->prefix),
1274 kroute->prefixlen);
1275 return (0);
1276 }
1277 }
1278 log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type,
1279 inet_ntoa(kroute->prefix), kroute->prefixlen);
1280 return (0);
1281 }
1282
1283 return (0);
1284}
1285
1286int
1287fetchtable(void)
1288{
1289 size_t len;
1290 int mib[7];
1291 char *buf;
1292 int rv;
1293
1294 mib[0] = CTL_NET4;
1295 mib[1] = PF_ROUTE17;
1296 mib[2] = 0;
1297 mib[3] = AF_INET2;
1298 mib[4] = NET_RT_DUMP1;
1299 mib[5] = 0;
1300 mib[6] = kr_state.rdomain; /* rtableid */
1301
1302 if (sysctl(mib, 7, NULL((void*)0), &len, NULL((void*)0), 0) == -1) {
1303 log_warn("sysctl");
1304 return (-1);
1305 }
1306 if ((buf = malloc(len)) == NULL((void*)0)) {
1307 log_warn("fetchtable");
1308 return (-1);
1309 }
1310 if (sysctl(mib, 7, buf, &len, NULL((void*)0), 0) == -1) {
1311 log_warn("sysctl");
1312 free(buf);
1313 return (-1);
1314 }
1315
1316 rv = rtmsg_process(buf, len);
1317 free(buf);
1318
1319 return (rv);
1320}
1321
1322int
1323fetchifs(u_short ifindex)
1324{
1325 size_t len;
1326 int mib[6];
1327 char *buf;
1328 int rv;
1329
1330 mib[0] = CTL_NET4;
1331 mib[1] = PF_ROUTE17;
1332 mib[2] = 0;
1333 mib[3] = AF_INET2;
1334 mib[4] = NET_RT_IFLIST3;
1335 mib[5] = ifindex;
1336
1337 if (sysctl(mib, 6, NULL((void*)0), &len, NULL((void*)0), 0) == -1) {
1338 log_warn("sysctl");
1339 return (-1);
1340 }
1341 if ((buf = malloc(len)) == NULL((void*)0)) {
1342 log_warn("fetchif");
1343 return (-1);
1344 }
1345 if (sysctl(mib, 6, buf, &len, NULL((void*)0), 0) == -1) {
1346 log_warn("sysctl");
1347 free(buf);
1348 return (-1);
1349 }
1350
1351 rv = rtmsg_process(buf, len);
1352 free(buf);
1353
1354 return (rv);
1355}
1356
1357int
1358dispatch_rtmsg(void)
1359{
1360 char buf[RT_BUF_SIZE16384];
1361 ssize_t n;
1362
1363 if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1364 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
1365 return (0);
1366 log_warn("dispatch_rtmsg: read error");
1367 return (-1);
1368 }
1369
1370 if (n == 0) {
1371 log_warnx("routing socket closed");
1372 return (-1);
1373 }
1374
1375 return (rtmsg_process(buf, n));
1376}
1377
1378int
1379rtmsg_process(char *buf, size_t len)
1380{
1381 struct rt_msghdr *rtm;
1382 struct if_msghdr ifm;
1383 struct ifa_msghdr *ifam;
1384 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1385 struct sockaddr_in *sa_in;
1386 struct sockaddr_rtlabel *label;
1387 struct kroute_node *kr, *okr;
1388 struct in_addr prefix, nexthop;
1389 u_int8_t prefixlen, prio;
1390 int flags, mpath;
1391 u_short ifindex = 0;
1392 int rv, delay;
1393
1394 size_t offset;
1395 char *next;
1396
1397 for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
1398 next = buf + offset;
1399 rtm = (struct rt_msghdr *)next;
1400 if (len < offset + sizeof(u_short) ||
1401 len < offset + rtm->rtm_msglen)
1402 fatalx("%s: partial rtm in buffer", __func__);
1403 if (rtm->rtm_version != RTM_VERSION5)
1404 continue;
1405
1406 prefix.s_addr = 0;
1407 prefixlen = 0;
1408 nexthop.s_addr = 0;
1409 mpath = 0;
1410 prio = 0;
1411 flags = F_KERNEL0x0002;
1412
1413 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1414 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1415
1416 switch (rtm->rtm_type) {
1417 case RTM_ADD0x1:
1418 case RTM_GET0x4:
1419 case RTM_CHANGE0x3:
1420 case RTM_DELETE0x2:
1421 if (rtm->rtm_errno) /* failed attempts... */
1422 continue;
1423
1424 if (rtm->rtm_tableid != kr_state.rdomain)
1425 continue;
1426
1427 if (rtm->rtm_type == RTM_GET0x4 &&
1428 rtm->rtm_pid != kr_state.pid)
1429 continue;
1430
1431 if ((sa = rti_info[RTAX_DST0]) == NULL((void*)0))
1432 continue;
1433
1434 /* Skip ARP/ND cache and broadcast routes. */
1435 if (rtm->rtm_flags & (RTF_LLINFO0x400|RTF_BROADCAST0x400000))
1436 continue;
1437
1438 if (rtm->rtm_flags & RTF_MPATH0x40000)
1439 mpath = 1;
1440 prio = rtm->rtm_priority;
1441 flags = (prio == kr_state.fib_prio) ?
1442 F_OSPFD_INSERTED0x0001 : F_KERNEL0x0002;
1443
1444 switch (sa->sa_family) {
1445 case AF_INET2:
1446 prefix.s_addr =
1447 ((struct sockaddr_in *)sa)->sin_addr.s_addr;
1448 sa_in = (struct sockaddr_in *)
1449 rti_info[RTAX_NETMASK2];
1450 if (sa_in != NULL((void*)0)) {
1451 if (sa_in->sin_len != 0)
1452 prefixlen = mask2prefixlen(
1453 sa_in->sin_addr.s_addr);
1454 } else if (rtm->rtm_flags & RTF_HOST0x4)
1455 prefixlen = 32;
1456 else
1457 prefixlen =
1458 prefixlen_classful(prefix.s_addr);
1459 if (rtm->rtm_flags & RTF_STATIC0x800)
1460 flags |= F_STATIC0x0008;
1461 if (rtm->rtm_flags & RTF_BLACKHOLE0x1000)
1462 flags |= F_BLACKHOLE0x0080;
1463 if (rtm->rtm_flags & RTF_REJECT0x8)
1464 flags |= F_REJECT0x0040;
1465 if (rtm->rtm_flags & RTF_DYNAMIC0x10)
1466 flags |= F_DYNAMIC0x0010;
1467 break;
1468 default:
1469 continue;
1470 }
1471
1472 ifindex = rtm->rtm_index;
1473 if ((sa = rti_info[RTAX_GATEWAY1]) != NULL((void*)0)) {
1474 switch (sa->sa_family) {
1475 case AF_INET2:
1476 if (rtm->rtm_flags & RTF_CONNECTED0x800000)
1477 flags |= F_CONNECTED0x0004;
1478
1479 nexthop.s_addr = ((struct
1480 sockaddr_in *)sa)->sin_addr.s_addr;
1481 break;
1482 case AF_LINK18:
1483 /*
1484 * Traditional BSD connected routes have
1485 * a gateway of type AF_LINK.
1486 */
1487 flags |= F_CONNECTED0x0004;
1488 break;
1489 }
1490 }
1491 }
1492
1493 switch (rtm->rtm_type) {
1494 case RTM_ADD0x1:
1495 case RTM_GET0x4:
1496 case RTM_CHANGE0x3:
1497 if (nexthop.s_addr == 0 && !(flags & F_CONNECTED0x0004)) {
1498 log_warnx("no nexthop for %s/%u",
1499 inet_ntoa(prefix), prefixlen);
1500 continue;
1501 }
1502
1503 if ((okr = kroute_find(prefix.s_addr, prefixlen, prio))
1504 != NULL((void*)0)) {
1505 /* get the correct route */
1506 kr = okr;
1507 if ((mpath || prio == kr_state.fib_prio) &&
1508 (kr = kroute_matchgw(okr, nexthop)) ==
1509 NULL((void*)0)) {
1510 log_warnx("%s: mpath route not found",
1511 __func__);
1512 /* add routes we missed out earlier */
1513 goto add;
1514 }
1515
1516 if (kr->r.flags & F_REDISTRIBUTED0x0100)
1517 flags |= F_REDISTRIBUTED0x0100;
1518 kr->r.nexthop.s_addr = nexthop.s_addr;
1519 kr->r.flags = flags;
1520 kr->r.ifindex = ifindex;
1521
1522 rtlabel_unref(kr->r.rtlabel);
1523 kr->r.rtlabel = 0;
1524 kr->r.ext_tag = 0;
1525 if ((label = (struct sockaddr_rtlabel *)
1526 rti_info[RTAX_LABEL10]) != NULL((void*)0)) {
1527 kr->r.rtlabel =
1528 rtlabel_name2id(label->sr_label);
1529 kr->r.ext_tag =
1530 rtlabel_id2tag(kr->r.rtlabel);
1531 }
1532
1533 if (kif_validate(kr->r.ifindex))
1534 kr->r.flags &= ~F_DOWN0x0020;
1535 else
1536 kr->r.flags |= F_DOWN0x0020;
1537
1538 /* just readd, the RDE will care */
1539 kr->serial = kr_state.fib_serial;
1540 kr_redistribute(okr);
1541 } else {
1542add:
1543 if ((kr = calloc(1,
1544 sizeof(struct kroute_node))) == NULL((void*)0)) {
1545 log_warn("%s: calloc", __func__);
1546 return (-1);
1547 }
1548
1549 kr->r.prefix.s_addr = prefix.s_addr;
1550 kr->r.prefixlen = prefixlen;
1551 kr->r.nexthop.s_addr = nexthop.s_addr;
1552 kr->r.flags = flags;
1553 kr->r.ifindex = ifindex;
1554 kr->r.priority = prio;
1555
1556 if (rtm->rtm_priority == kr_state.fib_prio) {
1557 log_warnx("alien OSPF route %s/%d",
1558 inet_ntoa(prefix), prefixlen);
1559 rv = send_rtmsg(kr_state.fd,
1560 RTM_DELETE0x2, &kr->r);
1561 free(kr);
1562 if (rv == -1)
1563 return (-1);
1564 } else {
1565 if ((label = (struct sockaddr_rtlabel *)
1566 rti_info[RTAX_LABEL10]) != NULL((void*)0)) {
1567 kr->r.rtlabel =
1568 rtlabel_name2id(
1569 label->sr_label);
1570 kr->r.ext_tag =
1571 rtlabel_id2tag(
1572 kr->r.rtlabel);
1573 }
1574
1575 kroute_insert(kr);
1576 }
1577 }
1578 break;
1579 case RTM_DELETE0x2:
1580 if ((kr = kroute_find(prefix.s_addr, prefixlen, prio))
1581 == NULL((void*)0))
1582 continue;
1583 if (!(kr->r.flags & F_KERNEL0x0002))
1584 continue;
1585 /* get the correct route */
1586 okr = kr;
Value stored to 'okr' is never read
1587 if (mpath &&
1588 (kr = kroute_matchgw(kr, nexthop)) == NULL((void*)0)) {
1589 log_warnx("%s: mpath route not found",
1590 __func__);
1591 return (-1);
1592 }
1593 if (kroute_remove(kr) == -1)
1594 return (-1);
1595 break;
1596 case RTM_IFINFO0xe:
1597 memcpy(&ifm, next, sizeof(ifm));
1598 if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
1599 (struct sockaddr_dl *)rti_info[RTAX_IFP4]);
1600 break;
1601 case RTM_NEWADDR0xc:
1602 ifam = (struct ifa_msghdr *)rtm;
1603 if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 |
1604 RTA_BRD0x80)) == 0)
1605 break;
1606
1607 if_newaddr(ifam->ifam_index,
1608 (struct sockaddr_in *)rti_info[RTAX_IFA5],
1609 (struct sockaddr_in *)rti_info[RTAX_NETMASK2],
1610 (struct sockaddr_in *)rti_info[RTAX_BRD7]);
1611 break;
1612 case RTM_DELADDR0xd:
1613 ifam = (struct ifa_msghdr *)rtm;
1614 if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 |
1615 RTA_BRD0x80)) == 0)
1616 break;
1617
1618 if_deladdr(ifam->ifam_index,
1619 (struct sockaddr_in *)rti_info[RTAX_IFA5],
1620 (struct sockaddr_in *)rti_info[RTAX_NETMASK2],
1621 (struct sockaddr_in *)rti_info[RTAX_BRD7]);
1622 break;
1623 case RTM_IFANNOUNCE0xf:
1624 if_announce(next);
1625 break;
1626 case RTM_DESYNC0x10:
1627 /*
1628 * We lost some routing packets. Schedule a reload
1629 * of the kernel route/interface information.
1630 */
1631 if (kr_state.reload_state == KR_RELOAD_IDLE0) {
1632 delay = KR_RELOAD_TIMER250;
1633 log_info("desync; scheduling fib reload");
1634 } else {
1635 delay = KR_RELOAD_HOLD_TIMER5000;
1636 log_debug("desync during KR_RELOAD_%s",
1637 kr_state.reload_state ==
1638 KR_RELOAD_FETCH1 ? "FETCH" : "HOLD");
1639 }
1640 kr_state.reload_state = KR_RELOAD_FETCH1;
1641 kr_fib_reload_arm_timer(delay);
1642 break;
1643 default:
1644 /* ignore for now */
1645 break;
1646 }
1647 }
1648
1649 return (offset);
1650}