1 |
|
|
/* $OpenBSD: rde_prefix.c,v 1.33 2017/01/24 04:22:42 benno Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/types.h> |
20 |
|
|
#include <sys/queue.h> |
21 |
|
|
|
22 |
|
|
#include <errno.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
|
26 |
|
|
#include "bgpd.h" |
27 |
|
|
#include "rde.h" |
28 |
|
|
#include "log.h" |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* Prefix Table functions: |
32 |
|
|
* pt_add: create new prefix and link it into the prefix table |
33 |
|
|
* pt_remove: Checks if there is no bgp prefix linked to the prefix, |
34 |
|
|
* unlinks from the prefix table and frees the pt_entry. |
35 |
|
|
* pt_get: get a prefix/prefixlen entry. While pt_lookup searches for the |
36 |
|
|
* best matching prefix pt_get only finds the prefix/prefixlen |
37 |
|
|
* entry. The speed of pt_get is important for the bgp updates. |
38 |
|
|
* pt_getaddr: convert the address into a struct bgpd_addr. |
39 |
|
|
* pt_lookup: lookup a IP in the prefix table. Mainly for "show ip bgp". |
40 |
|
|
* pt_empty: returns true if there is no bgp prefix linked to the pt_entry. |
41 |
|
|
* pt_init: initialize prefix table. |
42 |
|
|
* pt_alloc: allocate a AF specific pt_entry. Internal function. |
43 |
|
|
* pt_free: free a pt_entry. Internal function. |
44 |
|
|
*/ |
45 |
|
|
|
46 |
|
|
/* internal prototypes */ |
47 |
|
|
static struct pt_entry *pt_alloc(struct pt_entry *); |
48 |
|
|
static void pt_free(struct pt_entry *); |
49 |
|
|
|
50 |
|
|
size_t pt_sizes[AID_MAX] = AID_PTSIZE; |
51 |
|
|
|
52 |
|
|
RB_HEAD(pt_tree, pt_entry); |
53 |
|
|
RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); |
54 |
|
|
RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); |
55 |
|
|
|
56 |
|
|
struct pt_tree pttable; |
57 |
|
|
|
58 |
|
|
void |
59 |
|
|
pt_init(void) |
60 |
|
|
{ |
61 |
|
|
RB_INIT(&pttable); |
62 |
|
|
} |
63 |
|
|
|
64 |
|
|
void |
65 |
|
|
pt_shutdown(void) |
66 |
|
|
{ |
67 |
|
|
if (!RB_EMPTY(&pttable)) |
68 |
|
|
log_debug("pt_shutdown: tree is not empty."); |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
void |
72 |
|
|
pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) |
73 |
|
|
{ |
74 |
|
|
bzero(addr, sizeof(struct bgpd_addr)); |
75 |
|
|
addr->aid = pte->aid; |
76 |
|
|
switch (addr->aid) { |
77 |
|
|
case AID_INET: |
78 |
|
|
addr->v4 = ((struct pt_entry4 *)pte)->prefix4; |
79 |
|
|
break; |
80 |
|
|
case AID_INET6: |
81 |
|
|
memcpy(&addr->v6, &((struct pt_entry6 *)pte)->prefix6, |
82 |
|
|
sizeof(addr->v6)); |
83 |
|
|
/* XXX scope_id ??? */ |
84 |
|
|
break; |
85 |
|
|
case AID_VPN_IPv4: |
86 |
|
|
addr->vpn4.addr = ((struct pt_entry_vpn4 *)pte)->prefix4; |
87 |
|
|
addr->vpn4.rd = ((struct pt_entry_vpn4 *)pte)->rd; |
88 |
|
|
addr->vpn4.labellen = ((struct pt_entry_vpn4 *)pte)->labellen; |
89 |
|
|
memcpy(addr->vpn4.labelstack, |
90 |
|
|
((struct pt_entry_vpn4 *)pte)->labelstack, |
91 |
|
|
addr->vpn4.labellen); |
92 |
|
|
break; |
93 |
|
|
default: |
94 |
|
|
fatalx("pt_getaddr: unknown af"); |
95 |
|
|
} |
96 |
|
|
} |
97 |
|
|
|
98 |
|
|
struct pt_entry * |
99 |
|
|
pt_fill(struct bgpd_addr *prefix, int prefixlen) |
100 |
|
|
{ |
101 |
|
|
static struct pt_entry4 pte4; |
102 |
|
|
static struct pt_entry6 pte6; |
103 |
|
|
static struct pt_entry_vpn4 pte_vpn4; |
104 |
|
|
in_addr_t addr_hbo; |
105 |
|
|
|
106 |
|
|
switch (prefix->aid) { |
107 |
|
|
case AID_INET: |
108 |
|
|
bzero(&pte4, sizeof(pte4)); |
109 |
|
|
pte4.aid = prefix->aid; |
110 |
|
|
if (prefixlen > 32) |
111 |
|
|
fatalx("pt_fill: bad IPv4 prefixlen"); |
112 |
|
|
addr_hbo = ntohl(prefix->v4.s_addr); |
113 |
|
|
pte4.prefix4.s_addr = htonl(addr_hbo & |
114 |
|
|
prefixlen2mask(prefixlen)); |
115 |
|
|
pte4.prefixlen = prefixlen; |
116 |
|
|
return ((struct pt_entry *)&pte4); |
117 |
|
|
case AID_INET6: |
118 |
|
|
bzero(&pte6, sizeof(pte6)); |
119 |
|
|
pte6.aid = prefix->aid; |
120 |
|
|
if (prefixlen > 128) |
121 |
|
|
fatalx("pt_get: bad IPv6 prefixlen"); |
122 |
|
|
pte6.prefixlen = prefixlen; |
123 |
|
|
inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen); |
124 |
|
|
return ((struct pt_entry *)&pte6); |
125 |
|
|
case AID_VPN_IPv4: |
126 |
|
|
bzero(&pte_vpn4, sizeof(pte_vpn4)); |
127 |
|
|
pte_vpn4.aid = prefix->aid; |
128 |
|
|
if (prefixlen > 32) |
129 |
|
|
fatalx("pt_fill: bad IPv4 prefixlen"); |
130 |
|
|
addr_hbo = ntohl(prefix->vpn4.addr.s_addr); |
131 |
|
|
pte_vpn4.prefix4.s_addr = htonl(addr_hbo & |
132 |
|
|
prefixlen2mask(prefixlen)); |
133 |
|
|
pte_vpn4.prefixlen = prefixlen; |
134 |
|
|
pte_vpn4.rd = prefix->vpn4.rd; |
135 |
|
|
pte_vpn4.labellen = prefix->vpn4.labellen; |
136 |
|
|
memcpy(pte_vpn4.labelstack, prefix->vpn4.labelstack, |
137 |
|
|
prefix->vpn4.labellen); |
138 |
|
|
return ((struct pt_entry *)&pte_vpn4); |
139 |
|
|
default: |
140 |
|
|
fatalx("pt_fill: unknown af"); |
141 |
|
|
} |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
struct pt_entry * |
145 |
|
|
pt_get(struct bgpd_addr *prefix, int prefixlen) |
146 |
|
|
{ |
147 |
|
|
struct pt_entry *pte; |
148 |
|
|
|
149 |
|
|
pte = pt_fill(prefix, prefixlen); |
150 |
|
|
return RB_FIND(pt_tree, &pttable, pte); |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
struct pt_entry * |
154 |
|
|
pt_add(struct bgpd_addr *prefix, int prefixlen) |
155 |
|
|
{ |
156 |
|
|
struct pt_entry *p = NULL; |
157 |
|
|
|
158 |
|
|
p = pt_fill(prefix, prefixlen); |
159 |
|
|
p = pt_alloc(p); |
160 |
|
|
|
161 |
|
|
if (RB_INSERT(pt_tree, &pttable, p) != NULL) |
162 |
|
|
fatalx("pt_add: insert failed"); |
163 |
|
|
|
164 |
|
|
return (p); |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
void |
168 |
|
|
pt_remove(struct pt_entry *pte) |
169 |
|
|
{ |
170 |
|
|
if (!pt_empty(pte)) |
171 |
|
|
fatalx("pt_remove: entry still holds references"); |
172 |
|
|
|
173 |
|
|
if (RB_REMOVE(pt_tree, &pttable, pte) == NULL) |
174 |
|
|
log_warnx("pt_remove: remove failed."); |
175 |
|
|
pt_free(pte); |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
struct pt_entry * |
179 |
|
|
pt_lookup(struct bgpd_addr *addr) |
180 |
|
|
{ |
181 |
|
|
struct pt_entry *p; |
182 |
|
|
int i; |
183 |
|
|
|
184 |
|
|
switch (addr->aid) { |
185 |
|
|
case AID_INET: |
186 |
|
|
case AID_VPN_IPv4: |
187 |
|
|
i = 32; |
188 |
|
|
break; |
189 |
|
|
case AID_INET6: |
190 |
|
|
i = 128; |
191 |
|
|
break; |
192 |
|
|
default: |
193 |
|
|
fatalx("pt_lookup: unknown af"); |
194 |
|
|
} |
195 |
|
|
for (; i >= 0; i--) { |
196 |
|
|
p = pt_get(addr, i); |
197 |
|
|
if (p != NULL) |
198 |
|
|
return (p); |
199 |
|
|
} |
200 |
|
|
return (NULL); |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
int |
204 |
|
|
pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) |
205 |
|
|
{ |
206 |
|
|
const struct pt_entry4 *a4, *b4; |
207 |
|
|
const struct pt_entry6 *a6, *b6; |
208 |
|
|
const struct pt_entry_vpn4 *va4, *vb4; |
209 |
|
|
int i; |
210 |
|
|
|
211 |
|
|
if (a->aid > b->aid) |
212 |
|
|
return (1); |
213 |
|
|
if (a->aid < b->aid) |
214 |
|
|
return (-1); |
215 |
|
|
|
216 |
|
|
switch (a->aid) { |
217 |
|
|
case AID_INET: |
218 |
|
|
a4 = (const struct pt_entry4 *)a; |
219 |
|
|
b4 = (const struct pt_entry4 *)b; |
220 |
|
|
if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr)) |
221 |
|
|
return (1); |
222 |
|
|
if (ntohl(a4->prefix4.s_addr) < ntohl(b4->prefix4.s_addr)) |
223 |
|
|
return (-1); |
224 |
|
|
if (a4->prefixlen > b4->prefixlen) |
225 |
|
|
return (1); |
226 |
|
|
if (a4->prefixlen < b4->prefixlen) |
227 |
|
|
return (-1); |
228 |
|
|
return (0); |
229 |
|
|
case AID_INET6: |
230 |
|
|
a6 = (const struct pt_entry6 *)a; |
231 |
|
|
b6 = (const struct pt_entry6 *)b; |
232 |
|
|
|
233 |
|
|
i = memcmp(&a6->prefix6, &b6->prefix6, sizeof(struct in6_addr)); |
234 |
|
|
if (i > 0) |
235 |
|
|
return (1); |
236 |
|
|
if (i < 0) |
237 |
|
|
return (-1); |
238 |
|
|
if (a6->prefixlen < b6->prefixlen) |
239 |
|
|
return (-1); |
240 |
|
|
if (a6->prefixlen > b6->prefixlen) |
241 |
|
|
return (1); |
242 |
|
|
return (0); |
243 |
|
|
case AID_VPN_IPv4: |
244 |
|
|
va4 = (const struct pt_entry_vpn4 *)a; |
245 |
|
|
vb4 = (const struct pt_entry_vpn4 *)b; |
246 |
|
|
if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr)) |
247 |
|
|
return (1); |
248 |
|
|
if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr)) |
249 |
|
|
return (-1); |
250 |
|
|
if (va4->prefixlen > vb4->prefixlen) |
251 |
|
|
return (1); |
252 |
|
|
if (va4->prefixlen < vb4->prefixlen) |
253 |
|
|
return (-1); |
254 |
|
|
if (betoh64(va4->rd) > betoh64(vb4->rd)) |
255 |
|
|
return (1); |
256 |
|
|
if (betoh64(va4->rd) < betoh64(vb4->rd)) |
257 |
|
|
return (-1); |
258 |
|
|
return (0); |
259 |
|
|
default: |
260 |
|
|
fatalx("pt_prefix_cmp: unknown af"); |
261 |
|
|
} |
262 |
|
|
return (-1); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Returns a pt_entry cloned from the one passed in. |
267 |
|
|
* Function may not return on failure. |
268 |
|
|
*/ |
269 |
|
|
static struct pt_entry * |
270 |
|
|
pt_alloc(struct pt_entry *op) |
271 |
|
|
{ |
272 |
|
|
struct pt_entry *p; |
273 |
|
|
|
274 |
|
|
p = malloc(pt_sizes[op->aid]); |
275 |
|
|
if (p == NULL) |
276 |
|
|
fatal("pt_alloc"); |
277 |
|
|
rdemem.pt_cnt[op->aid]++; |
278 |
|
|
memcpy(p, op, pt_sizes[op->aid]); |
279 |
|
|
|
280 |
|
|
return (p); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
static void |
284 |
|
|
pt_free(struct pt_entry *pte) |
285 |
|
|
{ |
286 |
|
|
rdemem.pt_cnt[pte->aid]--; |
287 |
|
|
free(pte); |
288 |
|
|
} |