Bug Summary

File:src/usr.sbin/ldpd/kroute.c
Warning:line 515, column 7
Use of memory after it is freed

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