Bug Summary

File:src/usr.sbin/ospfd/kroute.c
Warning:line 1169, column 3
Null pointer passed as 1st argument to string copy function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name kroute.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -I /usr/src/usr.sbin/ospfd -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/ospfd/kroute.c
1/* $OpenBSD: kroute.c,v 1.117 2023/03/08 04:43:14 guenther 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(void)
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
458void
459kr_dispatch_msg(int fd, short event, void *bula)
460{
461 /* XXX this is stupid */
462 if (dispatch_rtmsg() == -1)
463 event_loopexit(NULL((void *)0));
464}
465
466void
467kr_show_route(struct imsg *imsg)
468{
469 struct kroute_node *kr;
470 struct kroute_node *kn;
471 int flags;
472 struct in_addr addr;
473
474 switch (imsg->hdr.type) {
475 case IMSG_CTL_KROUTE:
476 if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(flags)) {
477 log_warnx("kr_show_route: wrong imsg len");
478 return;
479 }
480 memcpy(&flags, imsg->data, sizeof(flags));
481 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
482 if (!flags || kr->r.flags & flags) {
483 kn = kr;
484 do {
485 main_imsg_compose_ospfe(IMSG_CTL_KROUTE,
486 imsg->hdr.pid,
487 &kn->r, sizeof(kn->r));
488 } while ((kn = kn->next) != NULL((void *)0));
489 }
490 break;
491 case IMSG_CTL_KROUTE_ADDR:
492 if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) +
493 sizeof(struct in_addr)) {
494 log_warnx("kr_show_route: wrong imsg len");
495 return;
496 }
497 memcpy(&addr, imsg->data, sizeof(addr));
498 kr = NULL((void *)0);
499 kr = kroute_match(addr.s_addr);
500 if (kr != NULL((void *)0))
501 main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid,
502 &kr->r, sizeof(kr->r));
503 break;
504 default:
505 log_debug("kr_show_route: error handling imsg");
506 break;
507 }
508
509 main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL((void *)0), 0);
510}
511
512void
513kr_ifinfo(char *ifname, pid_t pid)
514{
515 struct kif_node *kif;
516
517 RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void
*)0); (kif) = kif_tree_RB_NEXT(kif))
518 if (ifname == NULL((void *)0) || !strcmp(ifname, kif->k.ifname)) {
519 main_imsg_compose_ospfe(IMSG_CTL_IFINFO,
520 pid, &kif->k, sizeof(kif->k));
521 }
522
523 main_imsg_compose_ospfe(IMSG_CTL_END, pid, NULL((void *)0), 0);
524}
525
526void
527kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn)
528{
529 struct kroute *kr;
530
531 /* was the route redistributed? */
532 if ((kn->r.flags & F_REDISTRIBUTED0x0100) == 0)
533 return;
534
535 /* remove redistributed flag */
536 kn->r.flags &= ~F_REDISTRIBUTED0x0100;
537 kr = &kn->r;
538
539 /* probably inform the RDE (check if no other path is redistributed) */
540 for (kn = kh; kn; kn = kn->next)
541 if (kn->r.flags & F_REDISTRIBUTED0x0100)
542 break;
543
544 if (kn == NULL((void *)0))
545 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr,
546 sizeof(struct kroute));
547}
548
549int
550kr_redist_eval(struct kroute *kr, struct kroute *new_kr)
551{
552 u_int32_t a, metric = 0;
553
554 /* Only non-ospfd routes are considered for redistribution. */
555 if (!(kr->flags & F_KERNEL0x0002))
556 goto dont_redistribute;
557
558 /* Dynamic routes are not redistributable. */
559 if (kr->flags & F_DYNAMIC0x0010)
560 goto dont_redistribute;
561
562 /* interface is not up and running so don't announce */
563 if (kr->flags & F_DOWN0x0020)
564 goto dont_redistribute;
565
566 /*
567 * We consider the loopback net and multicast addresses
568 * as not redistributable.
569 */
570 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))
;
571 if (IN_MULTICAST(a)(((u_int32_t)(a) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
|| (a >> IN_CLASSA_NSHIFT24) == IN_LOOPBACKNET127)
572 goto dont_redistribute;
573 /*
574 * Consider networks with nexthop loopback as not redistributable
575 * unless it is a reject or blackhole route.
576 */
577 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))))
&&
578 !(kr->flags & (F_BLACKHOLE0x0080|F_REJECT0x0040)))
579 goto dont_redistribute;
580
581 /* Should we redistribute this route? */
582 if (!ospf_redistribute(kr, &metric))
583 goto dont_redistribute;
584
585 /* prefix should be redistributed */
586 kr->flags |= F_REDISTRIBUTED0x0100;
587 /*
588 * only one of all multipath routes can be redistributed so
589 * redistribute the best one.
590 */
591 if (new_kr->metric > metric) {
592 *new_kr = *kr;
593 new_kr->metric = metric;
594 }
595
596 return (1);
597
598dont_redistribute:
599 /* was the route redistributed? */
600 if ((kr->flags & F_REDISTRIBUTED0x0100) == 0)
601 return (0);
602
603 kr->flags &= ~F_REDISTRIBUTED0x0100;
604 return (1);
605}
606
607void
608kr_redistribute(struct kroute_node *kh)
609{
610 struct kroute_node *kn;
611 struct kroute kr;
612 int redistribute = 0;
613
614 /* only the highest prio route can be redistributed */
615 if (kroute_find(kh->r.prefix.s_addr, kh->r.prefixlen, RTP_ANY64) != kh)
616 return;
617
618 bzero(&kr, sizeof(kr));
619 kr.metric = UINT_MAX0xffffffffU;
620 for (kn = kh; kn; kn = kn->next)
621 if (kr_redist_eval(&kn->r, &kr))
622 redistribute = 1;
623
624 if (!redistribute)
625 return;
626
627 if (kr.flags & F_REDISTRIBUTED0x0100) {
628 main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &kr,
629 sizeof(struct kroute));
630 } else {
631 kr = kh->r;
632 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &kr,
633 sizeof(struct kroute));
634 }
635}
636
637void
638kr_reload(int redis_label_or_prefix)
639{
640 struct kroute_node *kr, *kn;
641 u_int32_t dummy;
642 int r;
643 int filter_prio = kr_state.fib_prio;
644
645 /* update the priority filter */
646 if (redis_label_or_prefix) {
647 filter_prio = 0;
648 log_info("%s: priority filter disabled", __func__);
649 } else
650 log_debug("%s: priority filter enabled", __func__);
651
652 if (setsockopt(kr_state.fd, AF_ROUTE17, ROUTE_PRIOFILTER3, &filter_prio,
653 sizeof(filter_prio)) == -1) {
654 log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__);
655 /* not fatal */
656 }
657
658 /* update redistribute lists */
659 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
{
660 for (kn = kr; kn; kn = kn->next) {
661 r = ospf_redistribute(&kn->r, &dummy);
662 /*
663 * if it is redistributed, redistribute again metric
664 * may have changed.
665 */
666 if ((kn->r.flags & F_REDISTRIBUTED0x0100 && !r) || r)
667 break;
668 }
669 if (kn) {
670 /*
671 * kr_redistribute copes with removes and RDE with
672 * duplicates
673 */
674 kr_redistribute(kr);
675 }
676 }
677}
678
679/* rb-tree compare */
680int
681kroute_compare(struct kroute_node *a, struct kroute_node *b)
682{
683 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))
)
684 return (-1);
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 (a->r.prefixlen < b->r.prefixlen)
688 return (-1);
689 if (a->r.prefixlen > b->r.prefixlen)
690 return (1);
691
692 /* if the priority is RTP_ANY finish on the first address hit */
693 if (a->r.priority == RTP_ANY64 || b->r.priority == RTP_ANY64)
694 return (0);
695 if (a->r.priority < b->r.priority)
696 return (-1);
697 if (a->r.priority > b->r.priority)
698 return (1);
699 return (0);
700}
701
702int
703kif_compare(struct kif_node *a, struct kif_node *b)
704{
705 return (b->k.ifindex - a->k.ifindex);
706}
707
708/* tree management */
709struct kroute_node *
710kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
711{
712 struct kroute_node s;
713 struct kroute_node *kn, *tmp;
714
715 s.r.prefix.s_addr = prefix;
716 s.r.prefixlen = prefixlen;
717 s.r.priority = prio;
718
719 kn = RB_FIND(kroute_tree, &krt, &s)kroute_tree_RB_FIND(&krt, &s);
720 if (kn && prio == RTP_ANY64) {
721 tmp = RB_PREV(kroute_tree, &krt, kn)kroute_tree_RB_PREV(kn);
722 while (tmp) {
723 if (kroute_compare(&s, tmp) == 0)
724 kn = tmp;
725 else
726 break;
727 tmp = RB_PREV(kroute_tree, &krt, kn)kroute_tree_RB_PREV(kn);
728 }
729 }
730 return (kn);
731}
732
733struct kroute_node *
734kroute_matchgw(struct kroute_node *kr, struct in_addr nh)
735{
736 in_addr_t nexthop;
737
738 nexthop = nh.s_addr;
739
740 while (kr) {
741 if (kr->r.nexthop.s_addr == nexthop)
742 return (kr);
743 kr = kr->next;
744 }
745
746 return (NULL((void *)0));
747}
748
749int
750kroute_insert(struct kroute_node *kr)
751{
752 struct kroute_node *krm, *krh;
753
754 kr->serial = kr_state.fib_serial;
755
756 if ((krh = RB_INSERT(kroute_tree, &krt, kr)kroute_tree_RB_INSERT(&krt, kr)) != NULL((void *)0)) {
757 /*
758 * Multipath route, add at end of list.
759 */
760 krm = krh;
761 while (krm->next != NULL((void *)0))
762 krm = krm->next;
763 krm->next = kr;
764 kr->next = NULL((void *)0); /* to be sure */
765 } else
766 krh = kr;
767
768 if (!(kr->r.flags & F_KERNEL0x0002)) {
769 /* don't validate or redistribute ospf route */
770 kr->r.flags &= ~F_DOWN0x0020;
771 return (0);
772 }
773
774 if (kif_validate(kr->r.ifindex))
775 kr->r.flags &= ~F_DOWN0x0020;
776 else
777 kr->r.flags |= F_DOWN0x0020;
778
779 kr_redistribute(krh);
780 return (0);
781}
782
783int
784kroute_remove(struct kroute_node *kr)
785{
786 struct kroute_node *krm;
787
788 if ((krm = RB_FIND(kroute_tree, &krt, kr)kroute_tree_RB_FIND(&krt, kr)) == NULL((void *)0)) {
789 log_warnx("kroute_remove failed to find %s/%u",
790 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
791 return (-1);
792 }
793
794 if (krm == kr) {
795 /* head element */
796 if (RB_REMOVE(kroute_tree, &krt, kr)kroute_tree_RB_REMOVE(&krt, kr) == NULL((void *)0)) {
797 log_warnx("kroute_remove failed for %s/%u",
798 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
799 return (-1);
800 }
801 if (kr->next != NULL((void *)0)) {
802 if (RB_INSERT(kroute_tree, &krt, kr->next)kroute_tree_RB_INSERT(&krt, kr->next) != NULL((void *)0)) {
803 log_warnx("kroute_remove failed to add %s/%u",
804 inet_ntoa(kr->r.prefix), kr->r.prefixlen);
805 return (-1);
806 }
807 }
808 } else {
809 /* somewhere in the list */
810 while (krm->next != kr && krm->next != NULL((void *)0))
811 krm = krm->next;
812 if (krm->next == NULL((void *)0)) {
813 log_warnx("kroute_remove multipath list corrupted "
814 "for %s/%u", inet_ntoa(kr->r.prefix),
815 kr->r.prefixlen);
816 return (-1);
817 }
818 krm->next = kr->next;
819 }
820
821 kr_redist_remove(krm, kr);
822 rtlabel_unref(kr->r.rtlabel);
823
824 free(kr);
825 return (0);
826}
827
828void
829kroute_clear(void)
830{
831 struct kroute_node *kr;
832
833 while ((kr = RB_MIN(kroute_tree, &krt)kroute_tree_RB_MINMAX(&krt, -1)) != NULL((void *)0))
834 kroute_remove(kr);
835}
836
837struct kif_node *
838kif_find(u_short ifindex)
839{
840 struct kif_node s;
841
842 bzero(&s, sizeof(s));
843 s.k.ifindex = ifindex;
844
845 return (RB_FIND(kif_tree, &kit, &s)kif_tree_RB_FIND(&kit, &s));
846}
847
848struct kif *
849kif_findname(char *ifname, struct in_addr addr, struct kif_addr **kap)
850{
851 struct kif_node *kif;
852 struct kif_addr *ka;
853
854 RB_FOREACH(kif, kif_tree, &kit)for ((kif) = kif_tree_RB_MINMAX(&kit, -1); (kif) != ((void
*)0); (kif) = kif_tree_RB_NEXT(kif))
855 if (!strcmp(ifname, kif->k.ifname)) {
856 ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first);
857 if (addr.s_addr != 0) {
858 TAILQ_FOREACH(ka, &kif->addrs, entry)for((ka) = ((&kif->addrs)->tqh_first); (ka) != ((void
*)0); (ka) = ((ka)->entry.tqe_next))
{
859 if (addr.s_addr == ka->addr.s_addr)
860 break;
861 }
862 }
863 if (kap != NULL((void *)0))
864 *kap = ka;
865 return (&kif->k);
866 }
867
868 return (NULL((void *)0));
869}
870
871struct kif_node *
872kif_insert(u_short ifindex)
873{
874 struct kif_node *kif;
875
876 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL((void *)0))
877 return (NULL((void *)0));
878
879 kif->k.ifindex = ifindex;
880 TAILQ_INIT(&kif->addrs)do { (&kif->addrs)->tqh_first = ((void *)0); (&
kif->addrs)->tqh_last = &(&kif->addrs)->tqh_first
; } while (0)
;
881
882 if (RB_INSERT(kif_tree, &kit, kif)kif_tree_RB_INSERT(&kit, kif) != NULL((void *)0))
883 fatalx("kif_insert: RB_INSERT");
884
885 return (kif);
886}
887
888int
889kif_remove(struct kif_node *kif)
890{
891 struct kif_addr *ka;
892
893 if (RB_REMOVE(kif_tree, &kit, kif)kif_tree_RB_REMOVE(&kit, kif) == NULL((void *)0)) {
894 log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
895 return (-1);
896 }
897
898 while ((ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first)) != NULL((void *)0)) {
899 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)
;
900 free(ka);
901 }
902 free(kif);
903 return (0);
904}
905
906void
907kif_clear(void)
908{
909 struct kif_node *kif;
910
911 while ((kif = RB_MIN(kif_tree, &kit)kif_tree_RB_MINMAX(&kit, -1)) != NULL((void *)0))
912 kif_remove(kif);
913}
914
915struct kif *
916kif_update(u_short ifindex, int flags, struct if_data *ifd,
917 struct sockaddr_dl *sdl)
918{
919 struct kif_node *kif;
920
921 if ((kif = kif_find(ifindex)) == NULL((void *)0)) {
922 if ((kif = kif_insert(ifindex)) == NULL((void *)0))
923 return (NULL((void *)0));
924 kif->k.nh_reachable = (flags & IFF_UP0x1) &&
925 LINK_STATE_IS_UP(ifd->ifi_link_state)((ifd->ifi_link_state) >= 4 || (ifd->ifi_link_state)
== 0)
;
926 }
927
928 kif->k.flags = flags;
929 kif->k.link_state = ifd->ifi_link_state;
930 kif->k.if_type = ifd->ifi_type;
931 kif->k.baudrate = ifd->ifi_baudrate;
932 kif->k.mtu = ifd->ifi_mtu;
933 kif->k.rdomain = ifd->ifi_rdomain;
934
935 if (sdl && sdl->sdl_family == AF_LINK18) {
936 if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
937 memcpy(kif->k.ifname, sdl->sdl_data,
938 sizeof(kif->k.ifname) - 1);
939 else if (sdl->sdl_nlen > 0)
940 memcpy(kif->k.ifname, sdl->sdl_data,
941 sdl->sdl_nlen);
942 /* string already terminated via calloc() */
943 }
944
945 return (&kif->k);
946}
947
948int
949kif_validate(u_short ifindex)
950{
951 struct kif_node *kif;
952
953 if ((kif = kif_find(ifindex)) == NULL((void *)0)) {
954 log_warnx("interface with index %u not found", ifindex);
955 return (1);
956 }
957
958 return (kif->k.nh_reachable);
959}
960
961struct kroute_node *
962kroute_match(in_addr_t key)
963{
964 int i;
965 struct kroute_node *kr;
966
967 /* we will never match the default route */
968 for (i = 32; i > 0; i--)
969 if ((kr = kroute_find(key & prefixlen2mask(i), i,
970 RTP_ANY64)) != NULL((void *)0))
971 return (kr);
972
973 /* if we don't have a match yet, try to find a default route */
974 if ((kr = kroute_find(0, 0, RTP_ANY64)) != NULL((void *)0))
975 return (kr);
976
977 return (NULL((void *)0));
978}
979
980/* misc */
981int
982protect_lo(void)
983{
984 struct kroute_node *kr;
985
986 /* special protection for 127/8 */
987 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL((void *)0)) {
988 log_warn("protect_lo");
989 return (-1);
990 }
991 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))))
;
992 kr->r.prefixlen = 8;
993 kr->r.flags = F_KERNEL0x0002|F_CONNECTED0x0004;
994
995 if (RB_INSERT(kroute_tree, &krt, kr)kroute_tree_RB_INSERT(&krt, kr) != NULL((void *)0))
996 free(kr); /* kernel route already there, no problem */
997
998 return (0);
999}
1000
1001u_int8_t
1002prefixlen_classful(in_addr_t ina)
1003{
1004 /* it hurt to write this. */
1005
1006 if (ina >= 0xf0000000U) /* class E */
1007 return (32);
1008 else if (ina >= 0xe0000000U) /* class D */
1009 return (4);
1010 else if (ina >= 0xc0000000U) /* class C */
1011 return (24);
1012 else if (ina >= 0x80000000U) /* class B */
1013 return (16);
1014 else /* class A */
1015 return (8);
1016}
1017
1018u_int8_t
1019mask2prefixlen(in_addr_t ina)
1020{
1021 if (ina == 0)
1022 return (0);
1023 else
1024 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))
));
1025}
1026
1027in_addr_t
1028prefixlen2mask(u_int8_t prefixlen)
1029{
1030 if (prefixlen == 0)
1031 return (0);
1032
1033 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)))
);
1034}
1035
1036#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
1037 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1038
1039void
1040get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1041{
1042 int i;
1043
1044 for (i = 0; i < RTAX_MAX15; i++) {
1045 if (addrs & (1 << i)) {
1046 rti_info[i] = sa;
1047 sa = (struct sockaddr *)((char *)(sa) +
1048 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
1049 } else
1050 rti_info[i] = NULL((void *)0);
1051 }
1052}
1053
1054void
1055if_change(u_short ifindex, int flags, struct if_data *ifd,
1056 struct sockaddr_dl *sdl)
1057{
1058 struct kroute_node *kr, *tkr;
1059 struct kif *kif;
1060 u_int8_t reachable;
1061
1062 if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL((void *)0)) {
1063 log_warn("if_change: kif_update(%u)", ifindex);
1064 return;
1065 }
1066
1067 /* notify ospfe about interface link state */
1068 main_imsg_compose_ospfe(IMSG_IFINFO, 0, kif, sizeof(struct kif));
1069
1070 reachable = (kif->flags & IFF_UP0x1) &&
1071 LINK_STATE_IS_UP(kif->link_state)((kif->link_state) >= 4 || (kif->link_state) == 0);
1072
1073 if (reachable == kif->nh_reachable)
1074 return; /* nothing changed wrt nexthop validity */
1075
1076 kif->nh_reachable = reachable;
1077
1078 /* update redistribute list */
1079 RB_FOREACH(kr, kroute_tree, &krt)for ((kr) = kroute_tree_RB_MINMAX(&krt, -1); (kr) != ((void
*)0); (kr) = kroute_tree_RB_NEXT(kr))
{
1080 for (tkr = kr; tkr != NULL((void *)0); tkr = tkr->next) {
1081 if (tkr->r.ifindex == ifindex) {
1082 if (reachable)
1083 tkr->r.flags &= ~F_DOWN0x0020;
1084 else
1085 tkr->r.flags |= F_DOWN0x0020;
1086
1087 }
1088 }
1089 kr_redistribute(kr);
1090 }
1091}
1092
1093void
1094if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1095 struct sockaddr_in *brd)
1096{
1097 struct kif_node *kif;
1098 struct kif_addr *ka;
1099 struct ifaddrchange ifn;
1100
1101 if (ifa == NULL((void *)0) || ifa->sin_family != AF_INET2)
1102 return;
1103 if ((kif = kif_find(ifindex)) == NULL((void *)0)) {
1104 log_warnx("if_newaddr: corresponding if %d not found", ifindex);
1105 return;
1106 }
1107 if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL((void *)0))
1108 fatal("if_newaddr");
1109 ka->addr = ifa->sin_addr;
1110 if (mask)
1111 ka->mask = mask->sin_addr;
1112 else
1113 ka->mask.s_addr = INADDR_NONE((u_int32_t)(0xffffffff));
1114 if (brd)
1115 ka->dstbrd = brd->sin_addr;
1116 else
1117 ka->dstbrd.s_addr = INADDR_NONE((u_int32_t)(0xffffffff));
1118
1119 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)
;
1120
1121 ifn.addr = ka->addr;
1122 ifn.mask = ka->mask;
1123 ifn.dst = ka->dstbrd;
1124 ifn.ifindex = ifindex;
1125 main_imsg_compose_ospfe(IMSG_IFADDRADD, 0, &ifn, sizeof(ifn));
1126}
1127
1128void
1129if_deladdr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1130 struct sockaddr_in *brd)
1131{
1132 struct kif_node *kif;
1133 struct kif_addr *ka, *nka;
1134 struct ifaddrchange ifc;
1135
1136 if (ifa == NULL((void *)0) || ifa->sin_family != AF_INET2)
1137 return;
1138 if ((kif = kif_find(ifindex)) == NULL((void *)0)) {
1139 log_warnx("if_deladdr: corresponding if %d not found", ifindex);
1140 return;
1141 }
1142
1143 for (ka = TAILQ_FIRST(&kif->addrs)((&kif->addrs)->tqh_first); ka != NULL((void *)0); ka = nka) {
1144 nka = TAILQ_NEXT(ka, entry)((ka)->entry.tqe_next);
1145
1146 if (ka->addr.s_addr == ifa->sin_addr.s_addr) {
1147 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)
;
1148 ifc.addr = ifa->sin_addr;
1149 ifc.ifindex = ifindex;
1150 main_imsg_compose_ospfe(IMSG_IFADDRDEL, 0, &ifc,
1151 sizeof(ifc));
1152 free(ka);
1153 return;
1154 }
1155 }
1156}
1157
1158void
1159if_announce(void *msg)
1160{
1161 struct if_announcemsghdr *ifan;
1162 struct kif_node *kif;
1163
1164 ifan = msg;
1165
1166 switch (ifan->ifan_what) {
11
Control jumps to 'case 0:' at line 1167
1167 case IFAN_ARRIVAL0:
1168 kif = kif_insert(ifan->ifan_index);
1169 strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
12
Null pointer passed as 1st argument to string copy function
1170 break;
1171 case IFAN_DEPARTURE1:
1172 kif = kif_find(ifan->ifan_index);
1173 kif_remove(kif);
1174 break;
1175 }
1176}
1177
1178/* rtsock */
1179int
1180send_rtmsg(int fd, int action, struct kroute *kroute)
1181{
1182 struct iovec iov[5];
1183 struct rt_msghdr hdr;
1184 struct sockaddr_in prefix;
1185 struct sockaddr_in nexthop;
1186 struct sockaddr_in mask;
1187 struct sockaddr_rtlabel sa_rl;
1188 int iovcnt = 0;
1189 const char *label;
1190
1191 if (kr_state.fib_sync == 0)
1192 return (0);
1193
1194 /* initialize header */
1195 bzero(&hdr, sizeof(hdr));
1196 hdr.rtm_version = RTM_VERSION5;
1197 hdr.rtm_type = action;
1198 hdr.rtm_priority = kr_state.fib_prio;
1199 hdr.rtm_tableid = kr_state.rdomain; /* rtableid */
1200 if (action == RTM_CHANGE0x3)
1201 hdr.rtm_fmask = RTF_REJECT0x8|RTF_BLACKHOLE0x1000;
1202 else
1203 hdr.rtm_flags = RTF_MPATH0x40000;
1204 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
1205 hdr.rtm_msglen = sizeof(hdr);
1206 /* adjust iovec */
1207 iov[iovcnt].iov_base = &hdr;
1208 iov[iovcnt++].iov_len = sizeof(hdr);
1209
1210 bzero(&prefix, sizeof(prefix));
1211 prefix.sin_len = sizeof(prefix);
1212 prefix.sin_family = AF_INET2;
1213 prefix.sin_addr.s_addr = kroute->prefix.s_addr;
1214 /* adjust header */
1215 hdr.rtm_addrs |= RTA_DST0x1;
1216 hdr.rtm_msglen += sizeof(prefix);
1217 /* adjust iovec */
1218 iov[iovcnt].iov_base = &prefix;
1219 iov[iovcnt++].iov_len = sizeof(prefix);
1220
1221 if (kroute->nexthop.s_addr != 0) {
1222 bzero(&nexthop, sizeof(nexthop));
1223 nexthop.sin_len = sizeof(nexthop);
1224 nexthop.sin_family = AF_INET2;
1225 nexthop.sin_addr.s_addr = kroute->nexthop.s_addr;
1226 /* adjust header */
1227 hdr.rtm_flags |= RTF_GATEWAY0x2;
1228 hdr.rtm_addrs |= RTA_GATEWAY0x2;
1229 hdr.rtm_msglen += sizeof(nexthop);
1230 /* adjust iovec */
1231 iov[iovcnt].iov_base = &nexthop;
1232 iov[iovcnt++].iov_len = sizeof(nexthop);
1233 }
1234
1235 bzero(&mask, sizeof(mask));
1236 mask.sin_len = sizeof(mask);
1237 mask.sin_family = AF_INET2;
1238 mask.sin_addr.s_addr = prefixlen2mask(kroute->prefixlen);
1239 /* adjust header */
1240 hdr.rtm_addrs |= RTA_NETMASK0x4;
1241 hdr.rtm_msglen += sizeof(mask);
1242 /* adjust iovec */
1243 iov[iovcnt].iov_base = &mask;
1244 iov[iovcnt++].iov_len = sizeof(mask);
1245
1246 if (kroute->rtlabel != 0) {
1247 sa_rl.sr_len = sizeof(sa_rl);
1248 sa_rl.sr_family = AF_UNSPEC0;
1249 label = rtlabel_id2name(kroute->rtlabel);
1250 if (strlcpy(sa_rl.sr_label, label,
1251 sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) {
1252 log_warnx("send_rtmsg: invalid rtlabel");
1253 return (-1);
1254 }
1255 /* adjust header */
1256 hdr.rtm_addrs |= RTA_LABEL0x400;
1257 hdr.rtm_msglen += sizeof(sa_rl);
1258 /* adjust iovec */
1259 iov[iovcnt].iov_base = &sa_rl;
1260 iov[iovcnt++].iov_len = sizeof(sa_rl);
1261 }
1262
1263retry:
1264 if (writev(fd, iov, iovcnt) == -1) {
1265 if (errno(*__errno()) == ESRCH3) {
1266 if (hdr.rtm_type == RTM_CHANGE0x3) {
1267 hdr.rtm_type = RTM_ADD0x1;
1268 goto retry;
1269 } else if (hdr.rtm_type == RTM_DELETE0x2) {
1270 log_info("route %s/%u vanished before delete",
1271 inet_ntoa(kroute->prefix),
1272 kroute->prefixlen);
1273 return (0);
1274 }
1275 }
1276 log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type,
1277 inet_ntoa(kroute->prefix), kroute->prefixlen);
1278 return (0);
1279 }
1280
1281 return (0);
1282}
1283
1284int
1285fetchtable(void)
1286{
1287 size_t len;
1288 int mib[7];
1289 char *buf;
1290 int rv;
1291
1292 mib[0] = CTL_NET4;
1293 mib[1] = PF_ROUTE17;
1294 mib[2] = 0;
1295 mib[3] = AF_INET2;
1296 mib[4] = NET_RT_DUMP1;
1297 mib[5] = 0;
1298 mib[6] = kr_state.rdomain; /* rtableid */
1299
1300 if (sysctl(mib, 7, NULL((void *)0), &len, NULL((void *)0), 0) == -1) {
1301 log_warn("sysctl");
1302 return (-1);
1303 }
1304 if ((buf = malloc(len)) == NULL((void *)0)) {
1305 log_warn("fetchtable");
1306 return (-1);
1307 }
1308 if (sysctl(mib, 7, buf, &len, NULL((void *)0), 0) == -1) {
1309 log_warn("sysctl");
1310 free(buf);
1311 return (-1);
1312 }
1313
1314 rv = rtmsg_process(buf, len);
1315 free(buf);
1316
1317 return (rv);
1318}
1319
1320int
1321fetchifs(u_short ifindex)
1322{
1323 size_t len;
1324 int mib[6];
1325 char *buf;
1326 int rv;
1327
1328 mib[0] = CTL_NET4;
1329 mib[1] = PF_ROUTE17;
1330 mib[2] = 0;
1331 mib[3] = AF_INET2;
1332 mib[4] = NET_RT_IFLIST3;
1333 mib[5] = ifindex;
1334
1335 if (sysctl(mib, 6, NULL((void *)0), &len, NULL((void *)0), 0) == -1) {
1336 log_warn("sysctl");
1337 return (-1);
1338 }
1339 if ((buf = malloc(len)) == NULL((void *)0)) {
1340 log_warn("fetchif");
1341 return (-1);
1342 }
1343 if (sysctl(mib, 6, buf, &len, NULL((void *)0), 0) == -1) {
1344 log_warn("sysctl");
1345 free(buf);
1346 return (-1);
1347 }
1348
1349 rv = rtmsg_process(buf, len);
1350 free(buf);
1351
1352 return (rv);
1353}
1354
1355int
1356dispatch_rtmsg(void)
1357{
1358 char buf[RT_BUF_SIZE16384];
1359 ssize_t n;
1360
1361 if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1362 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
1363 return (0);
1364 log_warn("dispatch_rtmsg: read error");
1365 return (-1);
1366 }
1367
1368 if (n == 0) {
1369 log_warnx("routing socket closed");
1370 return (-1);
1371 }
1372
1373 return (rtmsg_process(buf, n));
1374}
1375
1376int
1377rtmsg_process(char *buf, size_t len)
1378{
1379 struct rt_msghdr *rtm;
1380 struct if_msghdr ifm;
1381 struct ifa_msghdr *ifam;
1382 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1383 struct sockaddr_in *sa_in;
1384 struct sockaddr_rtlabel *label;
1385 struct kroute_node *kr, *okr;
1386 struct in_addr prefix, nexthop;
1387 u_int8_t prefixlen, prio;
1388 int flags, mpath;
1389 u_short ifindex = 0;
1390 int rv, delay;
1391
1392 size_t offset;
1393 char *next;
1394
1395 for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
1
Assuming 'offset' is < 'len'
2
Loop condition is true. Entering loop body
1396 next = buf + offset;
1397 rtm = (struct rt_msghdr *)next;
1398 if (len < offset + sizeof(u_short) ||
3
Assuming the condition is false
5
Taking false branch
1399 len < offset + rtm->rtm_msglen)
4
Assuming the condition is false
1400 fatalx("%s: partial rtm in buffer", __func__);
1401 if (rtm->rtm_version != RTM_VERSION5)
6
Assuming field 'rtm_version' is equal to RTM_VERSION
7
Taking false branch
1402 continue;
1403
1404 prefix.s_addr = 0;
1405 prefixlen = 0;
1406 nexthop.s_addr = 0;
1407 mpath = 0;
1408 prio = 0;
1409 flags = F_KERNEL0x0002;
1410
1411 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1412 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1413
1414 switch (rtm->rtm_type) {
1415 case RTM_ADD0x1:
1416 case RTM_GET0x4:
1417 case RTM_CHANGE0x3:
1418 case RTM_DELETE0x2:
1419 if (rtm->rtm_errno) /* failed attempts... */
1420 continue;
1421
1422 if (rtm->rtm_tableid != kr_state.rdomain)
1423 continue;
1424
1425 if (rtm->rtm_type == RTM_GET0x4 &&
1426 rtm->rtm_pid != kr_state.pid)
1427 continue;
1428
1429 if ((sa = rti_info[RTAX_DST0]) == NULL((void *)0))
1430 continue;
1431
1432 /* Skip ARP/ND cache and broadcast routes. */
1433 if (rtm->rtm_flags & (RTF_LLINFO0x400|RTF_BROADCAST0x400000))
1434 continue;
1435
1436 if (rtm->rtm_flags & RTF_MPATH0x40000)
1437 mpath = 1;
1438 prio = rtm->rtm_priority;
1439 flags = (prio == kr_state.fib_prio) ?
1440 F_OSPFD_INSERTED0x0001 : F_KERNEL0x0002;
1441
1442 switch (sa->sa_family) {
1443 case AF_INET2:
1444 prefix.s_addr =
1445 ((struct sockaddr_in *)sa)->sin_addr.s_addr;
1446 sa_in = (struct sockaddr_in *)
1447 rti_info[RTAX_NETMASK2];
1448 if (sa_in != NULL((void *)0)) {
1449 if (sa_in->sin_len != 0)
1450 prefixlen = mask2prefixlen(
1451 sa_in->sin_addr.s_addr);
1452 } else if (rtm->rtm_flags & RTF_HOST0x4)
1453 prefixlen = 32;
1454 else
1455 prefixlen =
1456 prefixlen_classful(prefix.s_addr);
1457 if (rtm->rtm_flags & RTF_STATIC0x800)
1458 flags |= F_STATIC0x0008;
1459 if (rtm->rtm_flags & RTF_BLACKHOLE0x1000)
1460 flags |= F_BLACKHOLE0x0080;
1461 if (rtm->rtm_flags & RTF_REJECT0x8)
1462 flags |= F_REJECT0x0040;
1463 if (rtm->rtm_flags & RTF_DYNAMIC0x10)
1464 flags |= F_DYNAMIC0x0010;
1465 break;
1466 default:
1467 continue;
1468 }
1469
1470 ifindex = rtm->rtm_index;
1471 if ((sa = rti_info[RTAX_GATEWAY1]) != NULL((void *)0)) {
1472 switch (sa->sa_family) {
1473 case AF_INET2:
1474 if (rtm->rtm_flags & RTF_CONNECTED0x800000)
1475 flags |= F_CONNECTED0x0004;
1476
1477 nexthop.s_addr = ((struct
1478 sockaddr_in *)sa)->sin_addr.s_addr;
1479 break;
1480 case AF_LINK18:
1481 /*
1482 * Traditional BSD connected routes have
1483 * a gateway of type AF_LINK.
1484 */
1485 flags |= F_CONNECTED0x0004;
1486 break;
1487 }
1488 }
1489 }
1490
1491 switch (rtm->rtm_type) {
8
'Default' branch taken. Execution continues on line 1491
9
Control jumps to 'case 15:' at line 1621
1492 case RTM_ADD0x1:
1493 case RTM_GET0x4:
1494 case RTM_CHANGE0x3:
1495 if (nexthop.s_addr == 0 && !(flags & F_CONNECTED0x0004)) {
1496 log_warnx("no nexthop for %s/%u",
1497 inet_ntoa(prefix), prefixlen);
1498 continue;
1499 }
1500
1501 if ((okr = kroute_find(prefix.s_addr, prefixlen, prio))
1502 != NULL((void *)0)) {
1503 /* get the correct route */
1504 kr = okr;
1505 if ((mpath || prio == kr_state.fib_prio) &&
1506 (kr = kroute_matchgw(okr, nexthop)) ==
1507 NULL((void *)0)) {
1508 log_warnx("%s: mpath route not found",
1509 __func__);
1510 /* add routes we missed out earlier */
1511 goto add;
1512 }
1513
1514 if (kr->r.flags & F_REDISTRIBUTED0x0100)
1515 flags |= F_REDISTRIBUTED0x0100;
1516 kr->r.nexthop.s_addr = nexthop.s_addr;
1517 kr->r.flags = flags;
1518 kr->r.ifindex = ifindex;
1519
1520 rtlabel_unref(kr->r.rtlabel);
1521 kr->r.rtlabel = 0;
1522 kr->r.ext_tag = 0;
1523 if ((label = (struct sockaddr_rtlabel *)
1524 rti_info[RTAX_LABEL10]) != NULL((void *)0)) {
1525 kr->r.rtlabel =
1526 rtlabel_name2id(label->sr_label);
1527 kr->r.ext_tag =
1528 rtlabel_id2tag(kr->r.rtlabel);
1529 }
1530
1531 if (kif_validate(kr->r.ifindex))
1532 kr->r.flags &= ~F_DOWN0x0020;
1533 else
1534 kr->r.flags |= F_DOWN0x0020;
1535
1536 /* just readd, the RDE will care */
1537 kr->serial = kr_state.fib_serial;
1538 kr_redistribute(okr);
1539 } else {
1540add:
1541 if ((kr = calloc(1,
1542 sizeof(struct kroute_node))) == NULL((void *)0)) {
1543 log_warn("%s: calloc", __func__);
1544 return (-1);
1545 }
1546
1547 kr->r.prefix.s_addr = prefix.s_addr;
1548 kr->r.prefixlen = prefixlen;
1549 kr->r.nexthop.s_addr = nexthop.s_addr;
1550 kr->r.flags = flags;
1551 kr->r.ifindex = ifindex;
1552 kr->r.priority = prio;
1553
1554 if (rtm->rtm_priority == kr_state.fib_prio) {
1555 log_warnx("alien OSPF route %s/%d",
1556 inet_ntoa(prefix), prefixlen);
1557 rv = send_rtmsg(kr_state.fd,
1558 RTM_DELETE0x2, &kr->r);
1559 free(kr);
1560 if (rv == -1)
1561 return (-1);
1562 } else {
1563 if ((label = (struct sockaddr_rtlabel *)
1564 rti_info[RTAX_LABEL10]) != NULL((void *)0)) {
1565 kr->r.rtlabel =
1566 rtlabel_name2id(
1567 label->sr_label);
1568 kr->r.ext_tag =
1569 rtlabel_id2tag(
1570 kr->r.rtlabel);
1571 }
1572
1573 kroute_insert(kr);
1574 }
1575 }
1576 break;
1577 case RTM_DELETE0x2:
1578 if ((kr = kroute_find(prefix.s_addr, prefixlen, prio))
1579 == NULL((void *)0))
1580 continue;
1581 if (!(kr->r.flags & F_KERNEL0x0002))
1582 continue;
1583 /* get the correct route */
1584 okr = kr;
1585 if (mpath &&
1586 (kr = kroute_matchgw(kr, nexthop)) == NULL((void *)0)) {
1587 log_warnx("%s: mpath route not found",
1588 __func__);
1589 return (-1);
1590 }
1591 if (kroute_remove(kr) == -1)
1592 return (-1);
1593 break;
1594 case RTM_IFINFO0xe:
1595 memcpy(&ifm, next, sizeof(ifm));
1596 if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
1597 (struct sockaddr_dl *)rti_info[RTAX_IFP4]);
1598 break;
1599 case RTM_NEWADDR0xc:
1600 ifam = (struct ifa_msghdr *)rtm;
1601 if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 |
1602 RTA_BRD0x80)) == 0)
1603 break;
1604
1605 if_newaddr(ifam->ifam_index,
1606 (struct sockaddr_in *)rti_info[RTAX_IFA5],
1607 (struct sockaddr_in *)rti_info[RTAX_NETMASK2],
1608 (struct sockaddr_in *)rti_info[RTAX_BRD7]);
1609 break;
1610 case RTM_DELADDR0xd:
1611 ifam = (struct ifa_msghdr *)rtm;
1612 if ((ifam->ifam_addrs & (RTA_NETMASK0x4 | RTA_IFA0x20 |
1613 RTA_BRD0x80)) == 0)
1614 break;
1615
1616 if_deladdr(ifam->ifam_index,
1617 (struct sockaddr_in *)rti_info[RTAX_IFA5],
1618 (struct sockaddr_in *)rti_info[RTAX_NETMASK2],
1619 (struct sockaddr_in *)rti_info[RTAX_BRD7]);
1620 break;
1621 case RTM_IFANNOUNCE0xf:
1622 if_announce(next);
10
Calling 'if_announce'
1623 break;
1624 case RTM_DESYNC0x10:
1625 /*
1626 * We lost some routing packets. Schedule a reload
1627 * of the kernel route/interface information.
1628 */
1629 if (kr_state.reload_state == KR_RELOAD_IDLE0) {
1630 delay = KR_RELOAD_TIMER250;
1631 log_info("desync; scheduling fib reload");
1632 } else {
1633 delay = KR_RELOAD_HOLD_TIMER5000;
1634 log_debug("desync during KR_RELOAD_%s",
1635 kr_state.reload_state ==
1636 KR_RELOAD_FETCH1 ? "FETCH" : "HOLD");
1637 }
1638 kr_state.reload_state = KR_RELOAD_FETCH1;
1639 kr_fib_reload_arm_timer(delay);
1640 break;
1641 default:
1642 /* ignore for now */
1643 break;
1644 }
1645 }
1646
1647 return (offset);
1648}