1 |
|
|
/* $OpenBSD: rde_prefix.c,v 1.32 2010/03/26 15:41:04 claudio 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 |
|
|
|
29 |
|
|
/* |
30 |
|
|
* Prefix Table functions: |
31 |
|
|
* pt_add: create new prefix and link it into the prefix table |
32 |
|
|
* pt_remove: Checks if there is no bgp prefix linked to the prefix, |
33 |
|
|
* unlinks from the prefix table and frees the pt_entry. |
34 |
|
|
* pt_get: get a prefix/prefixlen entry. While pt_lookup searches for the |
35 |
|
|
* best matching prefix pt_get only finds the prefix/prefixlen |
36 |
|
|
* entry. The speed of pt_get is important for the bgp updates. |
37 |
|
|
* pt_getaddr: convert the address into a struct bgpd_addr. |
38 |
|
|
* pt_lookup: lookup a IP in the prefix table. Mainly for "show ip bgp". |
39 |
|
|
* pt_empty: returns true if there is no bgp prefix linked to the pt_entry. |
40 |
|
|
* pt_init: initialize prefix table. |
41 |
|
|
* pt_alloc: allocate a AF specific pt_entry. Internal function. |
42 |
|
|
* pt_free: free a pt_entry. Internal function. |
43 |
|
|
*/ |
44 |
|
|
|
45 |
|
|
/* internal prototypes */ |
46 |
|
|
static struct pt_entry *pt_alloc(struct pt_entry *); |
47 |
|
|
static void pt_free(struct pt_entry *); |
48 |
|
|
|
49 |
|
|
size_t pt_sizes[AID_MAX] = AID_PTSIZE; |
50 |
|
|
|
51 |
|
|
RB_HEAD(pt_tree, pt_entry); |
52 |
|
|
RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); |
53 |
|
|
RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); |
54 |
|
|
|
55 |
|
|
struct pt_tree pttable; |
56 |
|
|
|
57 |
|
|
void |
58 |
|
|
pt_init(void) |
59 |
|
|
{ |
60 |
|
|
RB_INIT(&pttable); |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
void |
64 |
|
|
pt_shutdown(void) |
65 |
|
|
{ |
66 |
|
|
if (!RB_EMPTY(&pttable)) |
67 |
|
|
log_debug("pt_shutdown: tree is not empty."); |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
void |
71 |
|
|
pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) |
72 |
|
|
{ |
73 |
|
|
bzero(addr, sizeof(struct bgpd_addr)); |
74 |
|
|
addr->aid = pte->aid; |
75 |
|
|
switch (addr->aid) { |
76 |
|
|
case AID_INET: |
77 |
|
|
addr->v4 = ((struct pt_entry4 *)pte)->prefix4; |
78 |
|
|
break; |
79 |
|
|
case AID_INET6: |
80 |
|
|
memcpy(&addr->v6, &((struct pt_entry6 *)pte)->prefix6, |
81 |
|
|
sizeof(addr->v6)); |
82 |
|
|
/* XXX scope_id ??? */ |
83 |
|
|
break; |
84 |
|
|
case AID_VPN_IPv4: |
85 |
|
|
addr->vpn4.addr = ((struct pt_entry_vpn4 *)pte)->prefix4; |
86 |
|
|
addr->vpn4.rd = ((struct pt_entry_vpn4 *)pte)->rd; |
87 |
|
|
addr->vpn4.labellen = ((struct pt_entry_vpn4 *)pte)->labellen; |
88 |
|
|
memcpy(addr->vpn4.labelstack, |
89 |
|
|
((struct pt_entry_vpn4 *)pte)->labelstack, |
90 |
|
|
addr->vpn4.labellen); |
91 |
|
|
break; |
92 |
|
|
default: |
93 |
|
|
fatalx("pt_getaddr: unknown af"); |
94 |
|
|
} |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
struct pt_entry * |
98 |
|
|
pt_fill(struct bgpd_addr *prefix, int prefixlen) |
99 |
|
|
{ |
100 |
|
|
static struct pt_entry4 pte4; |
101 |
|
|
static struct pt_entry6 pte6; |
102 |
|
|
static struct pt_entry_vpn4 pte_vpn4; |
103 |
|
|
in_addr_t addr_hbo; |
104 |
|
|
|
105 |
|
|
switch (prefix->aid) { |
106 |
|
|
case AID_INET: |
107 |
|
|
bzero(&pte4, sizeof(pte4)); |
108 |
|
|
pte4.aid = prefix->aid; |
109 |
|
|
if (prefixlen > 32) |
110 |
|
|
fatalx("pt_fill: bad IPv4 prefixlen"); |
111 |
|
|
addr_hbo = ntohl(prefix->v4.s_addr); |
112 |
|
|
pte4.prefix4.s_addr = htonl(addr_hbo & |
113 |
|
|
prefixlen2mask(prefixlen)); |
114 |
|
|
pte4.prefixlen = prefixlen; |
115 |
|
|
return ((struct pt_entry *)&pte4); |
116 |
|
|
case AID_INET6: |
117 |
|
|
bzero(&pte6, sizeof(pte6)); |
118 |
|
|
pte6.aid = prefix->aid; |
119 |
|
|
if (prefixlen > 128) |
120 |
|
|
fatalx("pt_get: bad IPv6 prefixlen"); |
121 |
|
|
pte6.prefixlen = prefixlen; |
122 |
|
|
inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen); |
123 |
|
|
return ((struct pt_entry *)&pte6); |
124 |
|
|
case AID_VPN_IPv4: |
125 |
|
|
bzero(&pte_vpn4, sizeof(pte_vpn4)); |
126 |
|
|
pte_vpn4.aid = prefix->aid; |
127 |
|
|
if (prefixlen > 32) |
128 |
|
|
fatalx("pt_fill: bad IPv4 prefixlen"); |
129 |
|
|
addr_hbo = ntohl(prefix->vpn4.addr.s_addr); |
130 |
|
|
pte_vpn4.prefix4.s_addr = htonl(addr_hbo & |
131 |
|
|
prefixlen2mask(prefixlen)); |
132 |
|
|
pte_vpn4.prefixlen = prefixlen; |
133 |
|
|
pte_vpn4.rd = prefix->vpn4.rd; |
134 |
|
|
pte_vpn4.labellen = prefix->vpn4.labellen; |
135 |
|
|
memcpy(pte_vpn4.labelstack, prefix->vpn4.labelstack, |
136 |
|
|
prefix->vpn4.labellen); |
137 |
|
|
return ((struct pt_entry *)&pte_vpn4); |
138 |
|
|
default: |
139 |
|
|
fatalx("pt_fill: unknown af"); |
140 |
|
|
} |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
struct pt_entry * |
144 |
|
|
pt_get(struct bgpd_addr *prefix, int prefixlen) |
145 |
|
|
{ |
146 |
|
|
struct pt_entry *pte; |
147 |
|
|
|
148 |
|
|
pte = pt_fill(prefix, prefixlen); |
149 |
|
|
return RB_FIND(pt_tree, &pttable, pte); |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
struct pt_entry * |
153 |
|
|
pt_add(struct bgpd_addr *prefix, int prefixlen) |
154 |
|
|
{ |
155 |
|
|
struct pt_entry *p = NULL; |
156 |
|
|
|
157 |
|
|
p = pt_fill(prefix, prefixlen); |
158 |
|
|
p = pt_alloc(p); |
159 |
|
|
|
160 |
|
|
if (RB_INSERT(pt_tree, &pttable, p) != NULL) |
161 |
|
|
fatalx("pt_add: insert failed"); |
162 |
|
|
|
163 |
|
|
return (p); |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
void |
167 |
|
|
pt_remove(struct pt_entry *pte) |
168 |
|
|
{ |
169 |
|
|
if (!pt_empty(pte)) |
170 |
|
|
fatalx("pt_remove: entry still holds references"); |
171 |
|
|
|
172 |
|
|
if (RB_REMOVE(pt_tree, &pttable, pte) == NULL) |
173 |
|
|
log_warnx("pt_remove: remove failed."); |
174 |
|
|
pt_free(pte); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
struct pt_entry * |
178 |
|
|
pt_lookup(struct bgpd_addr *addr) |
179 |
|
|
{ |
180 |
|
|
struct pt_entry *p; |
181 |
|
|
int i; |
182 |
|
|
|
183 |
|
|
switch (addr->aid) { |
184 |
|
|
case AID_INET: |
185 |
|
|
case AID_VPN_IPv4: |
186 |
|
|
i = 32; |
187 |
|
|
break; |
188 |
|
|
case AID_INET6: |
189 |
|
|
i = 128; |
190 |
|
|
break; |
191 |
|
|
default: |
192 |
|
|
fatalx("pt_lookup: unknown af"); |
193 |
|
|
} |
194 |
|
|
for (; i >= 0; i--) { |
195 |
|
|
p = pt_get(addr, i); |
196 |
|
|
if (p != NULL) |
197 |
|
|
return (p); |
198 |
|
|
} |
199 |
|
|
return (NULL); |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
int |
203 |
|
|
pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) |
204 |
|
|
{ |
205 |
|
|
const struct pt_entry4 *a4, *b4; |
206 |
|
|
const struct pt_entry6 *a6, *b6; |
207 |
|
|
const struct pt_entry_vpn4 *va4, *vb4; |
208 |
|
|
int i; |
209 |
|
|
|
210 |
|
|
if (a->aid > b->aid) |
211 |
|
|
return (1); |
212 |
|
|
if (a->aid < b->aid) |
213 |
|
|
return (-1); |
214 |
|
|
|
215 |
|
|
switch (a->aid) { |
216 |
|
|
case AID_INET: |
217 |
|
|
a4 = (const struct pt_entry4 *)a; |
218 |
|
|
b4 = (const struct pt_entry4 *)b; |
219 |
|
|
if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr)) |
220 |
|
|
return (1); |
221 |
|
|
if (ntohl(a4->prefix4.s_addr) < ntohl(b4->prefix4.s_addr)) |
222 |
|
|
return (-1); |
223 |
|
|
if (a4->prefixlen > b4->prefixlen) |
224 |
|
|
return (1); |
225 |
|
|
if (a4->prefixlen < b4->prefixlen) |
226 |
|
|
return (-1); |
227 |
|
|
return (0); |
228 |
|
|
case AID_INET6: |
229 |
|
|
a6 = (const struct pt_entry6 *)a; |
230 |
|
|
b6 = (const struct pt_entry6 *)b; |
231 |
|
|
|
232 |
|
|
i = memcmp(&a6->prefix6, &b6->prefix6, sizeof(struct in6_addr)); |
233 |
|
|
if (i > 0) |
234 |
|
|
return (1); |
235 |
|
|
if (i < 0) |
236 |
|
|
return (-1); |
237 |
|
|
if (a6->prefixlen < b6->prefixlen) |
238 |
|
|
return (-1); |
239 |
|
|
if (a6->prefixlen > b6->prefixlen) |
240 |
|
|
return (1); |
241 |
|
|
return (0); |
242 |
|
|
case AID_VPN_IPv4: |
243 |
|
|
va4 = (const struct pt_entry_vpn4 *)a; |
244 |
|
|
vb4 = (const struct pt_entry_vpn4 *)b; |
245 |
|
|
if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr)) |
246 |
|
|
return (1); |
247 |
|
|
if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr)) |
248 |
|
|
return (-1); |
249 |
|
|
if (va4->prefixlen > vb4->prefixlen) |
250 |
|
|
return (1); |
251 |
|
|
if (va4->prefixlen < vb4->prefixlen) |
252 |
|
|
return (-1); |
253 |
|
|
if (betoh64(va4->rd) > betoh64(vb4->rd)) |
254 |
|
|
return (1); |
255 |
|
|
if (betoh64(va4->rd) < betoh64(vb4->rd)) |
256 |
|
|
return (-1); |
257 |
|
|
return (0); |
258 |
|
|
default: |
259 |
|
|
fatalx("pt_prefix_cmp: unknown af"); |
260 |
|
|
} |
261 |
|
|
return (-1); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
/* |
265 |
|
|
* Returns a pt_entry cloned from the one passed in. |
266 |
|
|
* Function may not return on failure. |
267 |
|
|
*/ |
268 |
|
|
static struct pt_entry * |
269 |
|
|
pt_alloc(struct pt_entry *op) |
270 |
|
|
{ |
271 |
|
|
struct pt_entry *p; |
272 |
|
|
|
273 |
|
|
p = malloc(pt_sizes[op->aid]); |
274 |
|
|
if (p == NULL) |
275 |
|
|
fatal("pt_alloc"); |
276 |
|
|
rdemem.pt_cnt[op->aid]++; |
277 |
|
|
memcpy(p, op, pt_sizes[op->aid]); |
278 |
|
|
|
279 |
|
|
return (p); |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
static void |
283 |
|
|
pt_free(struct pt_entry *pte) |
284 |
|
|
{ |
285 |
|
|
rdemem.pt_cnt[pte->aid]--; |
286 |
|
|
free(pte); |
287 |
|
|
} |