1 |
|
|
/* $OpenBSD: rde_filter.c,v 1.83 2017/08/12 16:47:50 phessler Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> |
5 |
|
|
* Copyright (c) 2016 Job Snijders <job@instituut.net> |
6 |
|
|
* Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> |
7 |
|
|
* |
8 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
9 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
10 |
|
|
* copyright notice and this permission notice appear in all copies. |
11 |
|
|
* |
12 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 |
|
|
*/ |
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/queue.h> |
22 |
|
|
|
23 |
|
|
#include <limits.h> |
24 |
|
|
#include <stdlib.h> |
25 |
|
|
#include <string.h> |
26 |
|
|
|
27 |
|
|
#include "bgpd.h" |
28 |
|
|
#include "rde.h" |
29 |
|
|
#include "log.h" |
30 |
|
|
|
31 |
|
|
int rde_filter_match(struct filter_rule *, struct rde_aspath *, |
32 |
|
|
struct bgpd_addr *, u_int8_t, struct rde_peer *, struct rde_peer *); |
33 |
|
|
int filterset_equal(struct filter_set_head *, struct filter_set_head *); |
34 |
|
|
|
35 |
|
|
void |
36 |
|
|
rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh, |
37 |
|
|
u_int8_t aid, struct rde_peer *from, struct rde_peer *peer) |
38 |
|
|
{ |
39 |
|
|
struct filter_set *set; |
40 |
|
|
u_char *np; |
41 |
|
|
int as, type; |
42 |
|
|
int64_t las, ld1, ld2; |
43 |
|
|
u_int32_t prep_as; |
44 |
|
|
u_int16_t nl; |
45 |
|
|
u_int8_t prepend; |
46 |
|
|
|
47 |
|
|
if (asp == NULL) |
48 |
|
|
return; |
49 |
|
|
|
50 |
|
|
TAILQ_FOREACH(set, sh, entry) { |
51 |
|
|
switch (set->type) { |
52 |
|
|
case ACTION_SET_LOCALPREF: |
53 |
|
|
asp->lpref = set->action.metric; |
54 |
|
|
break; |
55 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
56 |
|
|
if (set->action.relative > 0) { |
57 |
|
|
if (set->action.relative + asp->lpref < |
58 |
|
|
asp->lpref) |
59 |
|
|
asp->lpref = UINT_MAX; |
60 |
|
|
else |
61 |
|
|
asp->lpref += set->action.relative; |
62 |
|
|
} else { |
63 |
|
|
if ((u_int32_t)-set->action.relative > |
64 |
|
|
asp->lpref) |
65 |
|
|
asp->lpref = 0; |
66 |
|
|
else |
67 |
|
|
asp->lpref += set->action.relative; |
68 |
|
|
} |
69 |
|
|
break; |
70 |
|
|
case ACTION_SET_MED: |
71 |
|
|
asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE; |
72 |
|
|
asp->med = set->action.metric; |
73 |
|
|
break; |
74 |
|
|
case ACTION_SET_RELATIVE_MED: |
75 |
|
|
asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE; |
76 |
|
|
if (set->action.relative > 0) { |
77 |
|
|
if (set->action.relative + asp->med < |
78 |
|
|
asp->med) |
79 |
|
|
asp->med = UINT_MAX; |
80 |
|
|
else |
81 |
|
|
asp->med += set->action.relative; |
82 |
|
|
} else { |
83 |
|
|
if ((u_int32_t)-set->action.relative > |
84 |
|
|
asp->med) |
85 |
|
|
asp->med = 0; |
86 |
|
|
else |
87 |
|
|
asp->med += set->action.relative; |
88 |
|
|
} |
89 |
|
|
break; |
90 |
|
|
case ACTION_SET_WEIGHT: |
91 |
|
|
asp->weight = set->action.metric; |
92 |
|
|
break; |
93 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
94 |
|
|
if (set->action.relative > 0) { |
95 |
|
|
if (set->action.relative + asp->weight < |
96 |
|
|
asp->weight) |
97 |
|
|
asp->weight = UINT_MAX; |
98 |
|
|
else |
99 |
|
|
asp->weight += set->action.relative; |
100 |
|
|
} else { |
101 |
|
|
if ((u_int32_t)-set->action.relative > |
102 |
|
|
asp->weight) |
103 |
|
|
asp->weight = 0; |
104 |
|
|
else |
105 |
|
|
asp->weight += set->action.relative; |
106 |
|
|
} |
107 |
|
|
break; |
108 |
|
|
case ACTION_SET_PREPEND_SELF: |
109 |
|
|
prep_as = peer->conf.local_as; |
110 |
|
|
prepend = set->action.prepend; |
111 |
|
|
np = aspath_prepend(asp->aspath, prep_as, prepend, &nl); |
112 |
|
|
aspath_put(asp->aspath); |
113 |
|
|
asp->aspath = aspath_get(np, nl); |
114 |
|
|
free(np); |
115 |
|
|
break; |
116 |
|
|
case ACTION_SET_PREPEND_PEER: |
117 |
|
|
if (from == NULL) |
118 |
|
|
break; |
119 |
|
|
prep_as = from->conf.remote_as; |
120 |
|
|
prepend = set->action.prepend; |
121 |
|
|
np = aspath_prepend(asp->aspath, prep_as, prepend, &nl); |
122 |
|
|
aspath_put(asp->aspath); |
123 |
|
|
asp->aspath = aspath_get(np, nl); |
124 |
|
|
free(np); |
125 |
|
|
break; |
126 |
|
|
case ACTION_SET_NEXTHOP: |
127 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
128 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
129 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
130 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
131 |
|
|
nexthop_modify(asp, &set->action.nexthop, set->type, |
132 |
|
|
aid); |
133 |
|
|
break; |
134 |
|
|
case ACTION_SET_COMMUNITY: |
135 |
|
|
switch (set->action.community.as) { |
136 |
|
|
case COMMUNITY_ERROR: |
137 |
|
|
case COMMUNITY_ANY: |
138 |
|
|
fatalx("rde_apply_set bad community string"); |
139 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
140 |
|
|
as = peer->conf.remote_as; |
141 |
|
|
break; |
142 |
|
|
case COMMUNITY_LOCAL_AS: |
143 |
|
|
as = peer->conf.local_as; |
144 |
|
|
break; |
145 |
|
|
default: |
146 |
|
|
as = set->action.community.as; |
147 |
|
|
break; |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
switch (set->action.community.type) { |
151 |
|
|
case COMMUNITY_ERROR: |
152 |
|
|
case COMMUNITY_ANY: |
153 |
|
|
fatalx("rde_apply_set bad community string"); |
154 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
155 |
|
|
type = peer->conf.remote_as; |
156 |
|
|
break; |
157 |
|
|
case COMMUNITY_LOCAL_AS: |
158 |
|
|
type = peer->conf.local_as; |
159 |
|
|
break; |
160 |
|
|
default: |
161 |
|
|
type = set->action.community.type; |
162 |
|
|
break; |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
community_set(asp, as, type); |
166 |
|
|
break; |
167 |
|
|
case ACTION_DEL_COMMUNITY: |
168 |
|
|
switch (set->action.community.as) { |
169 |
|
|
case COMMUNITY_ERROR: |
170 |
|
|
fatalx("rde_apply_set bad community string"); |
171 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
172 |
|
|
as = peer->conf.remote_as; |
173 |
|
|
break; |
174 |
|
|
case COMMUNITY_LOCAL_AS: |
175 |
|
|
as = peer->conf.local_as; |
176 |
|
|
break; |
177 |
|
|
case COMMUNITY_ANY: |
178 |
|
|
default: |
179 |
|
|
as = set->action.community.as; |
180 |
|
|
break; |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
switch (set->action.community.type) { |
184 |
|
|
case COMMUNITY_ERROR: |
185 |
|
|
fatalx("rde_apply_set bad community string"); |
186 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
187 |
|
|
type = peer->conf.remote_as; |
188 |
|
|
break; |
189 |
|
|
case COMMUNITY_LOCAL_AS: |
190 |
|
|
type = peer->conf.local_as; |
191 |
|
|
break; |
192 |
|
|
case COMMUNITY_ANY: |
193 |
|
|
default: |
194 |
|
|
type = set->action.community.type; |
195 |
|
|
break; |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
community_delete(asp, as, type); |
199 |
|
|
break; |
200 |
|
|
case ACTION_SET_LARGE_COMMUNITY: |
201 |
|
|
switch (set->action.large_community.as) { |
202 |
|
|
case COMMUNITY_ERROR: |
203 |
|
|
fatalx("rde_apply_set bad large community string"); |
204 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
205 |
|
|
las = peer->conf.remote_as; |
206 |
|
|
break; |
207 |
|
|
case COMMUNITY_LOCAL_AS: |
208 |
|
|
las = peer->conf.local_as; |
209 |
|
|
break; |
210 |
|
|
case COMMUNITY_ANY: |
211 |
|
|
default: |
212 |
|
|
las = set->action.large_community.as; |
213 |
|
|
break; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
switch (set->action.large_community.ld1) { |
217 |
|
|
case COMMUNITY_ERROR: |
218 |
|
|
fatalx("rde_apply_set bad large community string"); |
219 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
220 |
|
|
ld1 = peer->conf.remote_as; |
221 |
|
|
break; |
222 |
|
|
case COMMUNITY_LOCAL_AS: |
223 |
|
|
ld1 = peer->conf.local_as; |
224 |
|
|
break; |
225 |
|
|
case COMMUNITY_ANY: |
226 |
|
|
default: |
227 |
|
|
ld1 = set->action.large_community.ld1; |
228 |
|
|
break; |
229 |
|
|
} |
230 |
|
|
|
231 |
|
|
switch (set->action.large_community.ld2) { |
232 |
|
|
case COMMUNITY_ERROR: |
233 |
|
|
fatalx("rde_apply_set bad large community string"); |
234 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
235 |
|
|
ld2 = peer->conf.remote_as; |
236 |
|
|
break; |
237 |
|
|
case COMMUNITY_LOCAL_AS: |
238 |
|
|
ld2 = peer->conf.local_as; |
239 |
|
|
break; |
240 |
|
|
case COMMUNITY_ANY: |
241 |
|
|
default: |
242 |
|
|
ld2 = set->action.large_community.ld2; |
243 |
|
|
break; |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
community_large_set(asp, las, ld1, ld2); |
247 |
|
|
break; |
248 |
|
|
case ACTION_DEL_LARGE_COMMUNITY: |
249 |
|
|
switch (set->action.large_community.as) { |
250 |
|
|
case COMMUNITY_ERROR: |
251 |
|
|
fatalx("rde_apply_set bad large community string"); |
252 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
253 |
|
|
las = peer->conf.remote_as; |
254 |
|
|
break; |
255 |
|
|
case COMMUNITY_LOCAL_AS: |
256 |
|
|
las = peer->conf.local_as; |
257 |
|
|
break; |
258 |
|
|
case COMMUNITY_ANY: |
259 |
|
|
default: |
260 |
|
|
las = set->action.large_community.as; |
261 |
|
|
break; |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
switch (set->action.large_community.ld1) { |
265 |
|
|
case COMMUNITY_ERROR: |
266 |
|
|
fatalx("rde_apply_set bad large community string"); |
267 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
268 |
|
|
ld1 = peer->conf.remote_as; |
269 |
|
|
break; |
270 |
|
|
case COMMUNITY_LOCAL_AS: |
271 |
|
|
ld1 = peer->conf.local_as; |
272 |
|
|
break; |
273 |
|
|
case COMMUNITY_ANY: |
274 |
|
|
default: |
275 |
|
|
ld1 = set->action.large_community.ld1; |
276 |
|
|
break; |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
switch (set->action.large_community.ld2) { |
280 |
|
|
case COMMUNITY_ERROR: |
281 |
|
|
fatalx("rde_apply_set bad large community string"); |
282 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
283 |
|
|
ld2 = peer->conf.remote_as; |
284 |
|
|
break; |
285 |
|
|
case COMMUNITY_LOCAL_AS: |
286 |
|
|
ld2 = peer->conf.local_as; |
287 |
|
|
break; |
288 |
|
|
case COMMUNITY_ANY: |
289 |
|
|
default: |
290 |
|
|
ld2 = set->action.large_community.ld2; |
291 |
|
|
break; |
292 |
|
|
} |
293 |
|
|
|
294 |
|
|
community_large_delete(asp, las, ld1, ld2); |
295 |
|
|
break; |
296 |
|
|
case ACTION_PFTABLE: |
297 |
|
|
/* convert pftable name to an id */ |
298 |
|
|
set->action.id = pftable_name2id(set->action.pftable); |
299 |
|
|
set->type = ACTION_PFTABLE_ID; |
300 |
|
|
/* FALLTHROUGH */ |
301 |
|
|
case ACTION_PFTABLE_ID: |
302 |
|
|
pftable_unref(asp->pftableid); |
303 |
|
|
asp->pftableid = set->action.id; |
304 |
|
|
pftable_ref(asp->pftableid); |
305 |
|
|
break; |
306 |
|
|
case ACTION_RTLABEL: |
307 |
|
|
/* convert the route label to an id for faster access */ |
308 |
|
|
set->action.id = rtlabel_name2id(set->action.rtlabel); |
309 |
|
|
set->type = ACTION_RTLABEL_ID; |
310 |
|
|
/* FALLTHROUGH */ |
311 |
|
|
case ACTION_RTLABEL_ID: |
312 |
|
|
rtlabel_unref(asp->rtlabelid); |
313 |
|
|
asp->rtlabelid = set->action.id; |
314 |
|
|
rtlabel_ref(asp->rtlabelid); |
315 |
|
|
break; |
316 |
|
|
case ACTION_SET_ORIGIN: |
317 |
|
|
asp->origin = set->action.origin; |
318 |
|
|
break; |
319 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
320 |
|
|
community_ext_set(asp, &set->action.ext_community, |
321 |
|
|
peer->conf.remote_as); |
322 |
|
|
break; |
323 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
324 |
|
|
community_ext_delete(asp, &set->action.ext_community, |
325 |
|
|
peer->conf.remote_as); |
326 |
|
|
break; |
327 |
|
|
} |
328 |
|
|
} |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
int |
332 |
|
|
rde_filter_match(struct filter_rule *f, struct rde_aspath *asp, |
333 |
|
|
struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer, |
334 |
|
|
struct rde_peer *from) |
335 |
|
|
{ |
336 |
|
|
u_int32_t pas; |
337 |
|
|
int cas, type; |
338 |
|
|
int64_t las, ld1, ld2; |
339 |
|
|
|
340 |
|
|
if (asp != NULL && f->match.as.type != AS_NONE) { |
341 |
|
|
if (f->match.as.flags & AS_FLAG_NEIGHBORAS) |
342 |
|
|
pas = peer->conf.remote_as; |
343 |
|
|
else |
344 |
|
|
pas = f->match.as.as; |
345 |
|
|
if (aspath_match(asp->aspath->data, asp->aspath->len, |
346 |
|
|
&f->match.as, pas) == 0) |
347 |
|
|
return (0); |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
if (asp != NULL && f->peer.ebgp && !peer->conf.ebgp) |
351 |
|
|
return (0); |
352 |
|
|
if (asp != NULL && f->peer.ibgp && peer->conf.ebgp) |
353 |
|
|
return (0); |
354 |
|
|
|
355 |
|
|
if (asp != NULL && f->match.aslen.type != ASLEN_NONE) |
356 |
|
|
if (aspath_lenmatch(asp->aspath, f->match.aslen.type, |
357 |
|
|
f->match.aslen.aslen) == 0) |
358 |
|
|
return (0); |
359 |
|
|
|
360 |
|
|
if (asp != NULL && f->match.community.as != COMMUNITY_UNSET) { |
361 |
|
|
switch (f->match.community.as) { |
362 |
|
|
case COMMUNITY_ERROR: |
363 |
|
|
fatalx("rde_apply_set bad community string"); |
364 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
365 |
|
|
cas = peer->conf.remote_as; |
366 |
|
|
break; |
367 |
|
|
case COMMUNITY_LOCAL_AS: |
368 |
|
|
cas = peer->conf.local_as; |
369 |
|
|
break; |
370 |
|
|
default: |
371 |
|
|
cas = f->match.community.as; |
372 |
|
|
break; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
switch (f->match.community.type) { |
376 |
|
|
case COMMUNITY_ERROR: |
377 |
|
|
fatalx("rde_apply_set bad community string"); |
378 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
379 |
|
|
type = peer->conf.remote_as; |
380 |
|
|
break; |
381 |
|
|
case COMMUNITY_LOCAL_AS: |
382 |
|
|
type = peer->conf.local_as; |
383 |
|
|
break; |
384 |
|
|
default: |
385 |
|
|
type = f->match.community.type; |
386 |
|
|
break; |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
if (community_match(asp, cas, type) == 0) |
390 |
|
|
return (0); |
391 |
|
|
} |
392 |
|
|
if (asp != NULL && |
393 |
|
|
(f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID)) |
394 |
|
|
if (community_ext_match(asp, &f->match.ext_community, |
395 |
|
|
peer->conf.remote_as) == 0) |
396 |
|
|
return (0); |
397 |
|
|
if (asp != NULL && f->match.large_community.as != |
398 |
|
|
COMMUNITY_UNSET) { |
399 |
|
|
switch (f->match.large_community.as) { |
400 |
|
|
case COMMUNITY_ERROR: |
401 |
|
|
fatalx("rde_apply_set bad community string"); |
402 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
403 |
|
|
las = peer->conf.remote_as; |
404 |
|
|
break; |
405 |
|
|
case COMMUNITY_LOCAL_AS: |
406 |
|
|
las = peer->conf.local_as; |
407 |
|
|
break; |
408 |
|
|
default: |
409 |
|
|
las = f->match.large_community.as; |
410 |
|
|
break; |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
switch (f->match.large_community.ld1) { |
414 |
|
|
case COMMUNITY_ERROR: |
415 |
|
|
fatalx("rde_apply_set bad community string"); |
416 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
417 |
|
|
ld1 = peer->conf.remote_as; |
418 |
|
|
break; |
419 |
|
|
case COMMUNITY_LOCAL_AS: |
420 |
|
|
ld1 = peer->conf.local_as; |
421 |
|
|
break; |
422 |
|
|
default: |
423 |
|
|
ld1 = f->match.large_community.ld1; |
424 |
|
|
break; |
425 |
|
|
} |
426 |
|
|
|
427 |
|
|
switch (f->match.large_community.ld2) { |
428 |
|
|
case COMMUNITY_ERROR: |
429 |
|
|
fatalx("rde_apply_set bad community string"); |
430 |
|
|
case COMMUNITY_NEIGHBOR_AS: |
431 |
|
|
ld2 = peer->conf.remote_as; |
432 |
|
|
break; |
433 |
|
|
case COMMUNITY_LOCAL_AS: |
434 |
|
|
ld2 = peer->conf.local_as; |
435 |
|
|
break; |
436 |
|
|
default: |
437 |
|
|
ld2 = f->match.large_community.ld2; |
438 |
|
|
break; |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
if (community_large_match(asp, las, ld1, ld2) == 0) |
442 |
|
|
return (0); |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
if (f->match.prefix.addr.aid != 0) { |
446 |
|
|
if (f->match.prefix.addr.aid != prefix->aid) |
447 |
|
|
/* don't use IPv4 rules for IPv6 and vice versa */ |
448 |
|
|
return (0); |
449 |
|
|
|
450 |
|
|
if (prefix_compare(prefix, &f->match.prefix.addr, |
451 |
|
|
f->match.prefix.len)) |
452 |
|
|
return (0); |
453 |
|
|
|
454 |
|
|
/* test prefixlen stuff too */ |
455 |
|
|
switch (f->match.prefix.op) { |
456 |
|
|
case OP_NONE: /* perfect match */ |
457 |
|
|
return (plen == f->match.prefix.len); |
458 |
|
|
case OP_EQ: |
459 |
|
|
return (plen == f->match.prefix.len_min); |
460 |
|
|
case OP_NE: |
461 |
|
|
return (plen != f->match.prefix.len_min); |
462 |
|
|
case OP_RANGE: |
463 |
|
|
return ((plen >= f->match.prefix.len_min) && |
464 |
|
|
(plen <= f->match.prefix.len_max)); |
465 |
|
|
case OP_XRANGE: |
466 |
|
|
return ((plen < f->match.prefix.len_min) || |
467 |
|
|
(plen > f->match.prefix.len_max)); |
468 |
|
|
case OP_LE: |
469 |
|
|
return (plen <= f->match.prefix.len_min); |
470 |
|
|
case OP_LT: |
471 |
|
|
return (plen < f->match.prefix.len_min); |
472 |
|
|
case OP_GE: |
473 |
|
|
return (plen >= f->match.prefix.len_min); |
474 |
|
|
case OP_GT: |
475 |
|
|
return (plen > f->match.prefix.len_min); |
476 |
|
|
} |
477 |
|
|
/* NOTREACHED */ |
478 |
|
|
} |
479 |
|
|
if (f->match.nexthop.flags != 0) { |
480 |
|
|
struct bgpd_addr *nexthop, *cmpaddr; |
481 |
|
|
if (asp != NULL && asp->nexthop == NULL) |
482 |
|
|
/* no nexthop, skip */ |
483 |
|
|
return (0); |
484 |
|
|
nexthop = &asp->nexthop->exit_nexthop; |
485 |
|
|
if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR) |
486 |
|
|
cmpaddr = &f->match.nexthop.addr; |
487 |
|
|
else |
488 |
|
|
cmpaddr = &from->remote_addr; |
489 |
|
|
if (cmpaddr->aid != nexthop->aid) |
490 |
|
|
/* don't use IPv4 rules for IPv6 and vice versa */ |
491 |
|
|
return (0); |
492 |
|
|
|
493 |
|
|
switch (cmpaddr->aid) { |
494 |
|
|
case AID_INET: |
495 |
|
|
if (cmpaddr->v4.s_addr != nexthop->v4.s_addr) |
496 |
|
|
return (0); |
497 |
|
|
break; |
498 |
|
|
case AID_INET6: |
499 |
|
|
if (memcmp(&cmpaddr->v6, &nexthop->v6, |
500 |
|
|
sizeof(struct in6_addr))) |
501 |
|
|
return (0); |
502 |
|
|
break; |
503 |
|
|
default: |
504 |
|
|
fatalx("King Bula lost in address space"); |
505 |
|
|
} |
506 |
|
|
} |
507 |
|
|
|
508 |
|
|
/* matched somewhen or is anymatch rule */ |
509 |
|
|
return (1); |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
int |
513 |
|
|
rde_filter_equal(struct filter_head *a, struct filter_head *b, |
514 |
|
|
struct rde_peer *peer) |
515 |
|
|
{ |
516 |
|
|
struct filter_rule *fa, *fb; |
517 |
|
|
|
518 |
|
|
fa = a ? TAILQ_FIRST(a) : NULL; |
519 |
|
|
fb = b ? TAILQ_FIRST(b) : NULL; |
520 |
|
|
|
521 |
|
|
while (fa != NULL || fb != NULL) { |
522 |
|
|
/* skip all rules with wrong peer */ |
523 |
|
|
if (peer != NULL && fa != NULL && fa->peer.groupid != 0 && |
524 |
|
|
fa->peer.groupid != peer->conf.groupid) { |
525 |
|
|
fa = TAILQ_NEXT(fa, entry); |
526 |
|
|
continue; |
527 |
|
|
} |
528 |
|
|
if (peer != NULL && fa != NULL && fa->peer.peerid != 0 && |
529 |
|
|
fa->peer.peerid != peer->conf.id) { |
530 |
|
|
fa = TAILQ_NEXT(fa, entry); |
531 |
|
|
continue; |
532 |
|
|
} |
533 |
|
|
|
534 |
|
|
if (peer != NULL && fb != NULL && fb->peer.groupid != 0 && |
535 |
|
|
fb->peer.groupid != peer->conf.groupid) { |
536 |
|
|
fb = TAILQ_NEXT(fb, entry); |
537 |
|
|
continue; |
538 |
|
|
} |
539 |
|
|
if (peer != NULL && fb != NULL && fb->peer.peerid != 0 && |
540 |
|
|
fb->peer.peerid != peer->conf.id) { |
541 |
|
|
fb = TAILQ_NEXT(fb, entry); |
542 |
|
|
continue; |
543 |
|
|
} |
544 |
|
|
|
545 |
|
|
if (peer != NULL && fa != NULL && fa->peer.remote_as != 0 && |
546 |
|
|
fa->peer.remote_as != peer->conf.remote_as) { |
547 |
|
|
fa = TAILQ_NEXT(fa, entry); |
548 |
|
|
continue; |
549 |
|
|
} |
550 |
|
|
|
551 |
|
|
if (peer != NULL && fa != NULL && fa->peer.ebgp != 0 && |
552 |
|
|
fa->peer.ebgp != peer->conf.ebgp) { |
553 |
|
|
fa = TAILQ_NEXT(fa, entry); |
554 |
|
|
continue; |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
if (peer != NULL && fa != NULL && fa->peer.ibgp != 0 && |
558 |
|
|
fa->peer.ibgp != !peer->conf.ebgp) { |
559 |
|
|
fa = TAILQ_NEXT(fa, entry); |
560 |
|
|
continue; |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
/* compare the two rules */ |
564 |
|
|
if ((fa == NULL && fb != NULL) || (fa != NULL && fb == NULL)) |
565 |
|
|
/* new rule added or removed */ |
566 |
|
|
return (0); |
567 |
|
|
|
568 |
|
|
if (fa->action != fb->action || fa->quick != fb->quick) |
569 |
|
|
return (0); |
570 |
|
|
if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer))) |
571 |
|
|
return (0); |
572 |
|
|
if (memcmp(&fa->match, &fb->match, sizeof(fa->match))) |
573 |
|
|
return (0); |
574 |
|
|
if (!filterset_equal(&fa->set, &fb->set)) |
575 |
|
|
return (0); |
576 |
|
|
|
577 |
|
|
fa = TAILQ_NEXT(fa, entry); |
578 |
|
|
fb = TAILQ_NEXT(fb, entry); |
579 |
|
|
} |
580 |
|
|
return (1); |
581 |
|
|
} |
582 |
|
|
|
583 |
|
|
void |
584 |
|
|
filterlist_free(struct filter_head *fh) |
585 |
|
|
{ |
586 |
|
|
struct filter_rule *r; |
587 |
|
|
|
588 |
|
|
if (fh == NULL) |
589 |
|
|
return; |
590 |
|
|
|
591 |
|
|
while ((r = TAILQ_FIRST(fh)) != NULL) { |
592 |
|
|
TAILQ_REMOVE(fh, r, entry); |
593 |
|
|
filterset_free(&r->set); |
594 |
|
|
free(r); |
595 |
|
|
} |
596 |
|
|
free(fh); |
597 |
|
|
} |
598 |
|
|
|
599 |
|
|
/* free a filterset and take care of possible name2id references */ |
600 |
|
|
void |
601 |
|
|
filterset_free(struct filter_set_head *sh) |
602 |
|
|
{ |
603 |
|
|
struct filter_set *s; |
604 |
|
|
struct nexthop *nh; |
605 |
|
|
|
606 |
|
|
if (sh == NULL) |
607 |
|
|
return; |
608 |
|
|
|
609 |
|
|
while ((s = TAILQ_FIRST(sh)) != NULL) { |
610 |
|
|
TAILQ_REMOVE(sh, s, entry); |
611 |
|
|
if (s->type == ACTION_RTLABEL_ID) |
612 |
|
|
rtlabel_unref(s->action.id); |
613 |
|
|
else if (s->type == ACTION_PFTABLE_ID) |
614 |
|
|
pftable_unref(s->action.id); |
615 |
|
|
else if (s->type == ACTION_SET_NEXTHOP && |
616 |
|
|
bgpd_process == PROC_RDE) { |
617 |
|
|
nh = nexthop_get(&s->action.nexthop); |
618 |
|
|
--nh->refcnt; |
619 |
|
|
(void)nexthop_delete(nh); |
620 |
|
|
} |
621 |
|
|
free(s); |
622 |
|
|
} |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
/* |
626 |
|
|
* this function is a bit more complicated than a memcmp() because there are |
627 |
|
|
* types that need to be considered equal e.g. ACTION_SET_MED and |
628 |
|
|
* ACTION_SET_RELATIVE_MED. Also ACTION_SET_COMMUNITY and ACTION_SET_NEXTHOP |
629 |
|
|
* need some special care. It only checks the types and not the values so |
630 |
|
|
* it does not do a real compare. |
631 |
|
|
*/ |
632 |
|
|
int |
633 |
|
|
filterset_cmp(struct filter_set *a, struct filter_set *b) |
634 |
|
|
{ |
635 |
|
|
if (strcmp(filterset_name(a->type), filterset_name(b->type))) |
636 |
|
|
return (a->type - b->type); |
637 |
|
|
|
638 |
|
|
if (a->type == ACTION_SET_COMMUNITY || |
639 |
|
|
a->type == ACTION_DEL_COMMUNITY) { /* a->type == b->type */ |
640 |
|
|
/* compare community */ |
641 |
|
|
if (a->action.community.as - b->action.community.as != 0) |
642 |
|
|
return (a->action.community.as - |
643 |
|
|
b->action.community.as); |
644 |
|
|
return (a->action.community.type - b->action.community.type); |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
if (a->type == ACTION_SET_EXT_COMMUNITY || |
648 |
|
|
a->type == ACTION_DEL_EXT_COMMUNITY) { /* a->type == b->type */ |
649 |
|
|
return (memcmp(&a->action.ext_community, |
650 |
|
|
&b->action.ext_community, sizeof(a->action.ext_community))); |
651 |
|
|
} |
652 |
|
|
|
653 |
|
|
if (a->type == ACTION_SET_LARGE_COMMUNITY || |
654 |
|
|
a->type == ACTION_DEL_LARGE_COMMUNITY) { /* a->type == b->type */ |
655 |
|
|
/* compare community */ |
656 |
|
|
if (a->action.large_community.as - |
657 |
|
|
b->action.large_community.as != 0) |
658 |
|
|
return (a->action.large_community.as - |
659 |
|
|
b->action.large_community.as); |
660 |
|
|
if (a->action.large_community.ld1 - |
661 |
|
|
b->action.large_community.ld1 != 0) |
662 |
|
|
return (a->action.large_community.ld1 - |
663 |
|
|
b->action.large_community.ld1); |
664 |
|
|
return (a->action.large_community.ld2 - |
665 |
|
|
b->action.large_community.ld2); |
666 |
|
|
} |
667 |
|
|
|
668 |
|
|
if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) { |
669 |
|
|
/* |
670 |
|
|
* This is the only interesting case, all others are considered |
671 |
|
|
* equal. It does not make sense to e.g. set a nexthop and |
672 |
|
|
* reject it at the same time. Allow one IPv4 and one IPv6 |
673 |
|
|
* per filter set or only one of the other nexthop modifiers. |
674 |
|
|
*/ |
675 |
|
|
return (a->action.nexthop.aid - b->action.nexthop.aid); |
676 |
|
|
} |
677 |
|
|
|
678 |
|
|
/* equal */ |
679 |
|
|
return (0); |
680 |
|
|
} |
681 |
|
|
|
682 |
|
|
void |
683 |
|
|
filterset_move(struct filter_set_head *source, struct filter_set_head *dest) |
684 |
|
|
{ |
685 |
|
|
struct filter_set *s; |
686 |
|
|
|
687 |
|
|
TAILQ_INIT(dest); |
688 |
|
|
|
689 |
|
|
if (source == NULL) |
690 |
|
|
return; |
691 |
|
|
|
692 |
|
|
while ((s = TAILQ_FIRST(source)) != NULL) { |
693 |
|
|
TAILQ_REMOVE(source, s, entry); |
694 |
|
|
TAILQ_INSERT_TAIL(dest, s, entry); |
695 |
|
|
} |
696 |
|
|
} |
697 |
|
|
|
698 |
|
|
int |
699 |
|
|
filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh) |
700 |
|
|
{ |
701 |
|
|
struct filter_set *a, *b; |
702 |
|
|
const char *as, *bs; |
703 |
|
|
|
704 |
|
|
for (a = TAILQ_FIRST(ah), b = TAILQ_FIRST(bh); |
705 |
|
|
a != NULL && b != NULL; |
706 |
|
|
a = TAILQ_NEXT(a, entry), b = TAILQ_NEXT(b, entry)) { |
707 |
|
|
switch (a->type) { |
708 |
|
|
case ACTION_SET_PREPEND_SELF: |
709 |
|
|
case ACTION_SET_PREPEND_PEER: |
710 |
|
|
if (a->type == b->type && |
711 |
|
|
a->action.prepend == b->action.prepend) |
712 |
|
|
continue; |
713 |
|
|
break; |
714 |
|
|
case ACTION_SET_LOCALPREF: |
715 |
|
|
case ACTION_SET_MED: |
716 |
|
|
case ACTION_SET_WEIGHT: |
717 |
|
|
if (a->type == b->type && |
718 |
|
|
a->action.metric == b->action.metric) |
719 |
|
|
continue; |
720 |
|
|
break; |
721 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
722 |
|
|
case ACTION_SET_RELATIVE_MED: |
723 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
724 |
|
|
if (a->type == b->type && |
725 |
|
|
a->action.relative == b->action.relative) |
726 |
|
|
continue; |
727 |
|
|
break; |
728 |
|
|
case ACTION_SET_NEXTHOP: |
729 |
|
|
if (a->type == b->type && |
730 |
|
|
memcmp(&a->action.nexthop, &b->action.nexthop, |
731 |
|
|
sizeof(a->action.nexthop)) == 0) |
732 |
|
|
continue; |
733 |
|
|
break; |
734 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
735 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
736 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
737 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
738 |
|
|
if (a->type == b->type) |
739 |
|
|
continue; |
740 |
|
|
break; |
741 |
|
|
case ACTION_DEL_COMMUNITY: |
742 |
|
|
case ACTION_SET_COMMUNITY: |
743 |
|
|
if (a->type == b->type && |
744 |
|
|
memcmp(&a->action.community, &b->action.community, |
745 |
|
|
sizeof(a->action.community)) == 0) |
746 |
|
|
continue; |
747 |
|
|
break; |
748 |
|
|
case ACTION_DEL_LARGE_COMMUNITY: |
749 |
|
|
case ACTION_SET_LARGE_COMMUNITY: |
750 |
|
|
if (a->type == b->type && |
751 |
|
|
memcmp(&a->action.large_community, |
752 |
|
|
&b->action.large_community, |
753 |
|
|
sizeof(a->action.large_community)) == 0) |
754 |
|
|
continue; |
755 |
|
|
break; |
756 |
|
|
case ACTION_PFTABLE: |
757 |
|
|
case ACTION_PFTABLE_ID: |
758 |
|
|
if (b->type == ACTION_PFTABLE) |
759 |
|
|
bs = b->action.pftable; |
760 |
|
|
else if (b->type == ACTION_PFTABLE_ID) |
761 |
|
|
bs = pftable_id2name(b->action.id); |
762 |
|
|
else |
763 |
|
|
break; |
764 |
|
|
|
765 |
|
|
if (a->type == ACTION_PFTABLE) |
766 |
|
|
as = a->action.pftable; |
767 |
|
|
else |
768 |
|
|
as = pftable_id2name(a->action.id); |
769 |
|
|
|
770 |
|
|
if (strcmp(as, bs) == 0) |
771 |
|
|
continue; |
772 |
|
|
break; |
773 |
|
|
case ACTION_RTLABEL: |
774 |
|
|
case ACTION_RTLABEL_ID: |
775 |
|
|
if (b->type == ACTION_RTLABEL) |
776 |
|
|
bs = b->action.rtlabel; |
777 |
|
|
else if (b->type == ACTION_RTLABEL_ID) |
778 |
|
|
bs = rtlabel_id2name(b->action.id); |
779 |
|
|
else |
780 |
|
|
break; |
781 |
|
|
|
782 |
|
|
if (a->type == ACTION_RTLABEL) |
783 |
|
|
as = a->action.rtlabel; |
784 |
|
|
else |
785 |
|
|
as = rtlabel_id2name(a->action.id); |
786 |
|
|
|
787 |
|
|
if (strcmp(as, bs) == 0) |
788 |
|
|
continue; |
789 |
|
|
break; |
790 |
|
|
case ACTION_SET_ORIGIN: |
791 |
|
|
if (a->type == b->type && |
792 |
|
|
a->action.origin == b->action.origin) |
793 |
|
|
continue; |
794 |
|
|
break; |
795 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
796 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
797 |
|
|
if (a->type == b->type && memcmp( |
798 |
|
|
&a->action.ext_community, |
799 |
|
|
&b->action.ext_community, |
800 |
|
|
sizeof(a->action.ext_community)) == 0) |
801 |
|
|
continue; |
802 |
|
|
break; |
803 |
|
|
} |
804 |
|
|
/* compare failed */ |
805 |
|
|
return (0); |
806 |
|
|
} |
807 |
|
|
if (a != NULL || b != NULL) |
808 |
|
|
return (0); |
809 |
|
|
return (1); |
810 |
|
|
} |
811 |
|
|
|
812 |
|
|
const char * |
813 |
|
|
filterset_name(enum action_types type) |
814 |
|
|
{ |
815 |
|
|
switch (type) { |
816 |
|
|
case ACTION_SET_LOCALPREF: |
817 |
|
|
case ACTION_SET_RELATIVE_LOCALPREF: |
818 |
|
|
return ("localpref"); |
819 |
|
|
case ACTION_SET_MED: |
820 |
|
|
case ACTION_SET_RELATIVE_MED: |
821 |
|
|
return ("metric"); |
822 |
|
|
case ACTION_SET_WEIGHT: |
823 |
|
|
case ACTION_SET_RELATIVE_WEIGHT: |
824 |
|
|
return ("weight"); |
825 |
|
|
case ACTION_SET_PREPEND_SELF: |
826 |
|
|
return ("prepend-self"); |
827 |
|
|
case ACTION_SET_PREPEND_PEER: |
828 |
|
|
return ("prepend-peer"); |
829 |
|
|
case ACTION_SET_NEXTHOP: |
830 |
|
|
case ACTION_SET_NEXTHOP_REJECT: |
831 |
|
|
case ACTION_SET_NEXTHOP_BLACKHOLE: |
832 |
|
|
case ACTION_SET_NEXTHOP_NOMODIFY: |
833 |
|
|
case ACTION_SET_NEXTHOP_SELF: |
834 |
|
|
return ("nexthop"); |
835 |
|
|
case ACTION_SET_COMMUNITY: |
836 |
|
|
return ("community"); |
837 |
|
|
case ACTION_DEL_COMMUNITY: |
838 |
|
|
return ("community delete"); |
839 |
|
|
case ACTION_SET_LARGE_COMMUNITY: |
840 |
|
|
return ("large-community"); |
841 |
|
|
case ACTION_DEL_LARGE_COMMUNITY: |
842 |
|
|
return ("large-community delete"); |
843 |
|
|
case ACTION_PFTABLE: |
844 |
|
|
case ACTION_PFTABLE_ID: |
845 |
|
|
return ("pftable"); |
846 |
|
|
case ACTION_RTLABEL: |
847 |
|
|
case ACTION_RTLABEL_ID: |
848 |
|
|
return ("rtlabel"); |
849 |
|
|
case ACTION_SET_ORIGIN: |
850 |
|
|
return ("origin"); |
851 |
|
|
case ACTION_SET_EXT_COMMUNITY: |
852 |
|
|
return ("ext-community"); |
853 |
|
|
case ACTION_DEL_EXT_COMMUNITY: |
854 |
|
|
return ("ext-community delete"); |
855 |
|
|
} |
856 |
|
|
|
857 |
|
|
fatalx("filterset_name: got lost"); |
858 |
|
|
} |
859 |
|
|
|
860 |
|
|
/* |
861 |
|
|
* Copyright (c) 2001 Daniel Hartmeier |
862 |
|
|
* All rights reserved. |
863 |
|
|
* |
864 |
|
|
* Redistribution and use in source and binary forms, with or without |
865 |
|
|
* modification, are permitted provided that the following conditions |
866 |
|
|
* are met: |
867 |
|
|
* |
868 |
|
|
* - Redistributions of source code must retain the above copyright |
869 |
|
|
* notice, this list of conditions and the following disclaimer. |
870 |
|
|
* - Redistributions in binary form must reproduce the above |
871 |
|
|
* copyright notice, this list of conditions and the following |
872 |
|
|
* disclaimer in the documentation and/or other materials provided |
873 |
|
|
* with the distribution. |
874 |
|
|
* |
875 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
876 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
877 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
878 |
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
879 |
|
|
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
880 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
881 |
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
882 |
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
883 |
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
884 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
885 |
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
886 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
887 |
|
|
* |
888 |
|
|
* Effort sponsored in part by the Defense Advanced Research Projects |
889 |
|
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
890 |
|
|
* Materiel Command, USAF, under agreement number F30602-01-2-0537. |
891 |
|
|
* |
892 |
|
|
*/ |
893 |
|
|
|
894 |
|
|
#define RDE_FILTER_SET_SKIP_STEPS(i) \ |
895 |
|
|
do { \ |
896 |
|
|
while (head[i] != cur) { \ |
897 |
|
|
head[i]->skip[i].ptr = cur; \ |
898 |
|
|
head[i] = TAILQ_NEXT(head[i], entry); \ |
899 |
|
|
} \ |
900 |
|
|
} while (0) |
901 |
|
|
|
902 |
|
|
struct peer; |
903 |
|
|
void print_rule(struct peer *, struct filter_rule *); |
904 |
|
|
|
905 |
|
|
void |
906 |
|
|
rde_filter_calc_skip_steps(struct filter_head *rules) |
907 |
|
|
{ |
908 |
|
|
struct filter_rule *cur, *prev, *head[RDE_FILTER_SKIP_COUNT]; |
909 |
|
|
int i; |
910 |
|
|
|
911 |
|
|
if (rules == NULL) |
912 |
|
|
return; |
913 |
|
|
|
914 |
|
|
cur = TAILQ_FIRST(rules); |
915 |
|
|
|
916 |
|
|
prev = cur; |
917 |
|
|
for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i) |
918 |
|
|
head[i] = cur; |
919 |
|
|
while (cur != NULL) { |
920 |
|
|
if (cur->peer.groupid != prev->peer.groupid) |
921 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_GROUPID); |
922 |
|
|
if (cur->peer.remote_as != prev->peer.remote_as) |
923 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_REMOTE_AS); |
924 |
|
|
if (cur->peer.peerid != prev->peer.peerid) |
925 |
|
|
RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_PEERID); |
926 |
|
|
prev = cur; |
927 |
|
|
cur = TAILQ_NEXT(cur, entry); |
928 |
|
|
} |
929 |
|
|
for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i) |
930 |
|
|
RDE_FILTER_SET_SKIP_STEPS(i); |
931 |
|
|
|
932 |
|
|
} |
933 |
|
|
|
934 |
|
|
#define RDE_FILTER_TEST_ATTRIB(t, a) \ |
935 |
|
|
do { \ |
936 |
|
|
if (t) { \ |
937 |
|
|
f = a; \ |
938 |
|
|
goto nextrule; \ |
939 |
|
|
} \ |
940 |
|
|
} while (0) |
941 |
|
|
|
942 |
|
|
enum filter_actions |
943 |
|
|
rde_filter(struct filter_head *rules, struct rde_aspath **new, |
944 |
|
|
struct rde_peer *peer, struct rde_aspath *asp, struct bgpd_addr *prefix, |
945 |
|
|
u_int8_t prefixlen, struct rde_peer *from) |
946 |
|
|
{ |
947 |
|
|
struct filter_rule *f; |
948 |
|
|
enum filter_actions action = ACTION_ALLOW; /* default allow */ |
949 |
|
|
|
950 |
|
|
if (new != NULL) |
951 |
|
|
*new = NULL; |
952 |
|
|
|
953 |
|
|
if (asp->flags & F_ATTR_PARSE_ERR) |
954 |
|
|
/* |
955 |
|
|
* don't try to filter bad updates just deny them |
956 |
|
|
* so they act as implicit withdraws |
957 |
|
|
*/ |
958 |
|
|
return (ACTION_DENY); |
959 |
|
|
|
960 |
|
|
if (rules == NULL) |
961 |
|
|
return (action); |
962 |
|
|
|
963 |
|
|
f = TAILQ_FIRST(rules); |
964 |
|
|
while (f != NULL) { |
965 |
|
|
RDE_FILTER_TEST_ATTRIB( |
966 |
|
|
(f->peer.groupid && |
967 |
|
|
f->peer.groupid != peer->conf.groupid), |
968 |
|
|
f->skip[RDE_FILTER_SKIP_GROUPID].ptr); |
969 |
|
|
RDE_FILTER_TEST_ATTRIB( |
970 |
|
|
(f->peer.remote_as && |
971 |
|
|
f->peer.remote_as != peer->conf.remote_as), |
972 |
|
|
f->skip[RDE_FILTER_SKIP_REMOTE_AS].ptr); |
973 |
|
|
RDE_FILTER_TEST_ATTRIB( |
974 |
|
|
(f->peer.peerid && |
975 |
|
|
f->peer.peerid != peer->conf.id), |
976 |
|
|
f->skip[RDE_FILTER_SKIP_PEERID].ptr); |
977 |
|
|
if (rde_filter_match(f, asp, prefix, prefixlen, peer, from)) { |
978 |
|
|
if (asp != NULL && new != NULL) { |
979 |
|
|
/* asp may get modified so create a copy */ |
980 |
|
|
if (*new == NULL) { |
981 |
|
|
*new = path_copy(asp); |
982 |
|
|
/* ... and use the copy from now on */ |
983 |
|
|
asp = *new; |
984 |
|
|
} |
985 |
|
|
rde_apply_set(asp, &f->set, prefix->aid, |
986 |
|
|
from, peer); |
987 |
|
|
} |
988 |
|
|
if (f->action != ACTION_NONE) |
989 |
|
|
action = f->action; |
990 |
|
|
if (f->quick) |
991 |
|
|
return (action); |
992 |
|
|
} |
993 |
|
|
f = TAILQ_NEXT(f, entry); |
994 |
|
|
nextrule: ; |
995 |
|
|
} |
996 |
|
|
return (action); |
997 |
|
|
} |