Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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