xref: /openbsd-src/usr.sbin/bgpd/rde_filter.c (revision bc2d12c4ba4a9e3456936e0e6f61edffd2bd142b)
1*bc2d12c4Sclaudio /*	$OpenBSD: rde_filter.c,v 1.136 2023/05/09 13:11:19 claudio Exp $ */
284ff2965Sclaudio 
384ff2965Sclaudio /*
484ff2965Sclaudio  * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
5280f24a4Sphessler  * Copyright (c) 2016 Job Snijders <job@instituut.net>
6280f24a4Sphessler  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
7441aaadcSbenno  * Copyright (c) 2018 Sebastian Benoit <benno@openbsd.org>
884ff2965Sclaudio  *
984ff2965Sclaudio  * Permission to use, copy, modify, and distribute this software for any
1084ff2965Sclaudio  * purpose with or without fee is hereby granted, provided that the above
1184ff2965Sclaudio  * copyright notice and this permission notice appear in all copies.
1284ff2965Sclaudio  *
1384ff2965Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1484ff2965Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1584ff2965Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1684ff2965Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1784ff2965Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1884ff2965Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1984ff2965Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2084ff2965Sclaudio  */
2184ff2965Sclaudio #include <sys/types.h>
2284ff2965Sclaudio #include <sys/queue.h>
2384ff2965Sclaudio 
242e699b24Sclaudio #include <limits.h>
2598d902b5Sclaudio #include <stdlib.h>
26972b7d94Sdjm #include <string.h>
27972b7d94Sdjm 
2884ff2965Sclaudio #include "bgpd.h"
2984ff2965Sclaudio #include "rde.h"
305e3f6f95Sbenno #include "log.h"
3184ff2965Sclaudio 
32ff2f0a45Sclaudio int	filterset_equal(struct filter_set_head *, struct filter_set_head *);
3384ff2965Sclaudio 
3484ff2965Sclaudio void
rde_apply_set(struct filter_set_head * sh,struct rde_peer * peer,struct rde_peer * from,struct filterstate * state,uint8_t aid)35928a56d5Sclaudio rde_apply_set(struct filter_set_head *sh, struct rde_peer *peer,
3639386878Sclaudio     struct rde_peer *from, struct filterstate *state, uint8_t aid)
3798d902b5Sclaudio {
3898d902b5Sclaudio 	struct filter_set	*set;
390c88bf70Sclaudio 	u_char			*np;
4039386878Sclaudio 	uint32_t		 prep_as;
4139386878Sclaudio 	uint16_t		 nl;
4239386878Sclaudio 	uint8_t			 prepend;
43b33564f7Sclaudio 
4476630fdaSclaudio 	TAILQ_FOREACH(set, sh, entry) {
4598d902b5Sclaudio 		switch (set->type) {
4698d902b5Sclaudio 		case ACTION_SET_LOCALPREF:
47effde4cfSclaudio 			state->aspath.lpref = set->action.metric;
486d36d8acSclaudio 			break;
492704869fSclaudio 		case ACTION_SET_RELATIVE_LOCALPREF:
502704869fSclaudio 			if (set->action.relative > 0) {
51fe9add27Sclaudio 				if (state->aspath.lpref >
52fe9add27Sclaudio 				    UINT_MAX - set->action.relative)
53effde4cfSclaudio 					state->aspath.lpref = UINT_MAX;
542704869fSclaudio 				else
55effde4cfSclaudio 					state->aspath.lpref +=
56effde4cfSclaudio 					    set->action.relative;
572704869fSclaudio 			} else {
587ff9bf35Sclaudio 				if (state->aspath.lpref <
597ff9bf35Sclaudio 				    0U - set->action.relative)
60effde4cfSclaudio 					state->aspath.lpref = 0;
612704869fSclaudio 				else
62effde4cfSclaudio 					state->aspath.lpref +=
63effde4cfSclaudio 					    set->action.relative;
642704869fSclaudio 			}
652704869fSclaudio 			break;
6698d902b5Sclaudio 		case ACTION_SET_MED:
67effde4cfSclaudio 			state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
68effde4cfSclaudio 			state->aspath.med = set->action.metric;
696d36d8acSclaudio 			break;
702704869fSclaudio 		case ACTION_SET_RELATIVE_MED:
71effde4cfSclaudio 			state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
722704869fSclaudio 			if (set->action.relative > 0) {
73fe9add27Sclaudio 				if (state->aspath.med >
74fe9add27Sclaudio 				    UINT_MAX - set->action.relative)
75effde4cfSclaudio 					state->aspath.med = UINT_MAX;
762704869fSclaudio 				else
77effde4cfSclaudio 					state->aspath.med +=
78effde4cfSclaudio 					    set->action.relative;
792704869fSclaudio 			} else {
807ff9bf35Sclaudio 				if (state->aspath.med <
817ff9bf35Sclaudio 				    0U - set->action.relative)
82effde4cfSclaudio 					state->aspath.med = 0;
832704869fSclaudio 				else
84effde4cfSclaudio 					state->aspath.med +=
85effde4cfSclaudio 					    set->action.relative;
862704869fSclaudio 			}
872704869fSclaudio 			break;
88aa5d92feSclaudio 		case ACTION_SET_WEIGHT:
89effde4cfSclaudio 			state->aspath.weight = set->action.metric;
90aa5d92feSclaudio 			break;
91aa5d92feSclaudio 		case ACTION_SET_RELATIVE_WEIGHT:
92aa5d92feSclaudio 			if (set->action.relative > 0) {
93fe9add27Sclaudio 				if (state->aspath.weight >
94fe9add27Sclaudio 				    UINT_MAX - set->action.relative)
95effde4cfSclaudio 					state->aspath.weight = UINT_MAX;
96aa5d92feSclaudio 				else
97effde4cfSclaudio 					state->aspath.weight +=
98effde4cfSclaudio 					    set->action.relative;
99aa5d92feSclaudio 			} else {
1007ff9bf35Sclaudio 				if (state->aspath.weight <
1017ff9bf35Sclaudio 				    0U - set->action.relative)
102effde4cfSclaudio 					state->aspath.weight = 0;
103aa5d92feSclaudio 				else
104effde4cfSclaudio 					state->aspath.weight +=
105effde4cfSclaudio 					    set->action.relative;
106aa5d92feSclaudio 			}
107aa5d92feSclaudio 			break;
10898d902b5Sclaudio 		case ACTION_SET_PREPEND_SELF:
109f0bc600cSphessler 			prep_as = peer->conf.local_as;
11098d902b5Sclaudio 			prepend = set->action.prepend;
111effde4cfSclaudio 			np = aspath_prepend(state->aspath.aspath, prep_as,
112effde4cfSclaudio 			    prepend, &nl);
113effde4cfSclaudio 			aspath_put(state->aspath.aspath);
114effde4cfSclaudio 			state->aspath.aspath = aspath_get(np, nl);
1150c88bf70Sclaudio 			free(np);
11698d902b5Sclaudio 			break;
11798d902b5Sclaudio 		case ACTION_SET_PREPEND_PEER:
118a30e1557Sclaudio 			if (from == NULL)
119a30e1557Sclaudio 				break;
120688b3329Sclaudio 			prep_as = from->conf.remote_as;
12198d902b5Sclaudio 			prepend = set->action.prepend;
122effde4cfSclaudio 			np = aspath_prepend(state->aspath.aspath, prep_as,
123effde4cfSclaudio 			    prepend, &nl);
124effde4cfSclaudio 			aspath_put(state->aspath.aspath);
125effde4cfSclaudio 			state->aspath.aspath = aspath_get(np, nl);
1260c88bf70Sclaudio 			free(np);
12798d902b5Sclaudio 			break;
128d7a2dcd7Sclaudio 		case ACTION_SET_AS_OVERRIDE:
129d7a2dcd7Sclaudio 			if (from == NULL)
130d7a2dcd7Sclaudio 				break;
131d7a2dcd7Sclaudio 			np = aspath_override(state->aspath.aspath,
132d7a2dcd7Sclaudio 			    from->conf.remote_as, from->conf.local_as, &nl);
133d7a2dcd7Sclaudio 			aspath_put(state->aspath.aspath);
134d7a2dcd7Sclaudio 			state->aspath.aspath = aspath_get(np, nl);
135d7a2dcd7Sclaudio 			free(np);
136d7a2dcd7Sclaudio 			break;
13798d902b5Sclaudio 		case ACTION_SET_NEXTHOP:
13823676e2aSclaudio 			fatalx("unexpected filter action in RDE");
13923676e2aSclaudio 		case ACTION_SET_NEXTHOP_REF:
14098d902b5Sclaudio 		case ACTION_SET_NEXTHOP_REJECT:
14198d902b5Sclaudio 		case ACTION_SET_NEXTHOP_BLACKHOLE:
142ce9d64eaSclaudio 		case ACTION_SET_NEXTHOP_NOMODIFY:
1437c989460Shenning 		case ACTION_SET_NEXTHOP_SELF:
14423676e2aSclaudio 			nexthop_modify(set->action.nh_ref, set->type, aid,
145b5a1e014Sclaudio 			    &state->nexthop, &state->nhflags);
14698d902b5Sclaudio 			break;
14798d902b5Sclaudio 		case ACTION_SET_COMMUNITY:
148e7adcfeaSclaudio 			community_set(&state->communities,
149dd87f852Sclaudio 			    &set->action.community, peer);
150688b3329Sclaudio 			break;
151aaa4f5dfSclaudio 		case ACTION_DEL_COMMUNITY:
152e7adcfeaSclaudio 			community_delete(&state->communities,
153dd87f852Sclaudio 			    &set->action.community, peer);
154aaa4f5dfSclaudio 			break;
15598d902b5Sclaudio 		case ACTION_PFTABLE:
156e2691ddeSclaudio 			/* convert pftable name to an id */
157e2691ddeSclaudio 			set->action.id = pftable_name2id(set->action.pftable);
158e2691ddeSclaudio 			set->type = ACTION_PFTABLE_ID;
159e2691ddeSclaudio 			/* FALLTHROUGH */
160e2691ddeSclaudio 		case ACTION_PFTABLE_ID:
161effde4cfSclaudio 			pftable_unref(state->aspath.pftableid);
162effde4cfSclaudio 			state->aspath.pftableid = pftable_ref(set->action.id);
16398d902b5Sclaudio 			break;
16415aea9d4Sclaudio 		case ACTION_RTLABEL:
16515aea9d4Sclaudio 			/* convert the route label to an id for faster access */
16615aea9d4Sclaudio 			set->action.id = rtlabel_name2id(set->action.rtlabel);
16715aea9d4Sclaudio 			set->type = ACTION_RTLABEL_ID;
16815aea9d4Sclaudio 			/* FALLTHROUGH */
16915aea9d4Sclaudio 		case ACTION_RTLABEL_ID:
170effde4cfSclaudio 			rtlabel_unref(state->aspath.rtlabelid);
171effde4cfSclaudio 			state->aspath.rtlabelid = rtlabel_ref(set->action.id);
17215aea9d4Sclaudio 			break;
173cd3afea8Shenning 		case ACTION_SET_ORIGIN:
174effde4cfSclaudio 			state->aspath.origin = set->action.origin;
175cd3afea8Shenning 			break;
17698d902b5Sclaudio 		}
177597db7f7Sdjm 	}
17884ff2965Sclaudio }
17984ff2965Sclaudio 
180928a56d5Sclaudio /* return 1 when prefix matches filter_prefix, 0 if not */
181928a56d5Sclaudio static int
rde_prefix_match(struct filter_prefix * fp,struct bgpd_addr * prefix,uint8_t plen)182928a56d5Sclaudio rde_prefix_match(struct filter_prefix *fp, struct bgpd_addr *prefix,
18339386878Sclaudio     uint8_t plen)
184928a56d5Sclaudio {
185928a56d5Sclaudio 	if (fp->addr.aid != prefix->aid)
186928a56d5Sclaudio 		/* don't use IPv4 rules for IPv6 and vice versa */
187928a56d5Sclaudio 		return (0);
188928a56d5Sclaudio 
189928a56d5Sclaudio 	if (prefix_compare(prefix, &fp->addr, fp->len))
190928a56d5Sclaudio 		return (0);
191928a56d5Sclaudio 
192928a56d5Sclaudio 	/* test prefixlen stuff too */
193928a56d5Sclaudio 	switch (fp->op) {
194928a56d5Sclaudio 	case OP_NONE: /* perfect match */
195928a56d5Sclaudio 		return (plen == fp->len);
196928a56d5Sclaudio 	case OP_EQ:
197928a56d5Sclaudio 		return (plen == fp->len_min);
198928a56d5Sclaudio 	case OP_NE:
199928a56d5Sclaudio 		return (plen != fp->len_min);
200928a56d5Sclaudio 	case OP_RANGE:
201928a56d5Sclaudio 		return ((plen >= fp->len_min) &&
202928a56d5Sclaudio 		    (plen <= fp->len_max));
203928a56d5Sclaudio 	case OP_XRANGE:
204928a56d5Sclaudio 		return ((plen < fp->len_min) ||
205928a56d5Sclaudio 		    (plen > fp->len_max));
206928a56d5Sclaudio 	default:
207928a56d5Sclaudio 		log_warnx("%s: unsupported prefix operation", __func__);
208928a56d5Sclaudio 		return (0);
209928a56d5Sclaudio 	}
210928a56d5Sclaudio }
211928a56d5Sclaudio 
212928a56d5Sclaudio static int
rde_filter_match(struct filter_rule * f,struct rde_peer * peer,struct rde_peer * from,struct filterstate * state,struct bgpd_addr * prefix,uint8_t plen)213ec583527Sclaudio rde_filter_match(struct filter_rule *f, struct rde_peer *peer,
214928a56d5Sclaudio     struct rde_peer *from, struct filterstate *state,
215245e5d07Sclaudio     struct bgpd_addr *prefix, uint8_t plen)
21684ff2965Sclaudio {
217d1ac9b38Sclaudio 	struct rde_aspath *asp = &state->aspath;
218dd87f852Sclaudio 	int i;
219b5a1e014Sclaudio 
220b5a1e014Sclaudio 	if (f->peer.ebgp && !peer->conf.ebgp)
221b28cd7d4Sphessler 		return (0);
222b5a1e014Sclaudio 	if (f->peer.ibgp && peer->conf.ebgp)
223b28cd7d4Sphessler 		return (0);
224b28cd7d4Sphessler 
2256f1dba6eSclaudio 	if (f->match.ovs.is_set) {
226f8fade75Sclaudio 		if ((state->vstate & ROA_MASK) != f->match.ovs.validity)
2276f1dba6eSclaudio 			return (0);
2286f1dba6eSclaudio 	}
2296f1dba6eSclaudio 
230060f4cb2Sclaudio 	if (f->match.avs.is_set) {
231060f4cb2Sclaudio 		if (((state->vstate >> 4) & ASPA_MASK) != f->match.avs.validity)
232060f4cb2Sclaudio 			return (0);
233060f4cb2Sclaudio 	}
234060f4cb2Sclaudio 
235b391831cSclaudio 	if (asp != NULL && f->match.as.type != AS_UNDEF) {
236a34ea928Sclaudio 		if (aspath_match(asp->aspath, &f->match.as,
237a34ea928Sclaudio 		    peer->conf.remote_as) == 0)
238052562feSclaudio 			return (0);
239052562feSclaudio 	}
240052562feSclaudio 
2414a044d31Sclaudio 	if (asp != NULL && f->match.aslen.type != ASLEN_NONE)
2424a044d31Sclaudio 		if (aspath_lenmatch(asp->aspath, f->match.aslen.type,
2434a044d31Sclaudio 		    f->match.aslen.aslen) == 0)
2444a044d31Sclaudio 			return (0);
2454a044d31Sclaudio 
246e7adcfeaSclaudio 	for (i = 0; i < MAX_COMM_MATCH; i++) {
247e7adcfeaSclaudio 		if (f->match.community[i].flags == 0)
248688b3329Sclaudio 			break;
249e7adcfeaSclaudio 		if (community_match(&state->communities,
250e7adcfeaSclaudio 		    &f->match.community[i], peer) == 0)
2510df2230cSclaudio 			return (0);
25236e003c6Sclaudio 	}
2530df2230cSclaudio 
254bd0e176eSclaudio 	if (f->match.maxcomm != 0) {
255bd0e176eSclaudio 		if (f->match.maxcomm >
256bd0e176eSclaudio 		    community_count(&state->communities, COMMUNITY_TYPE_BASIC))
257bd0e176eSclaudio 			return (0);
258bd0e176eSclaudio 	}
259bd0e176eSclaudio 	if (f->match.maxextcomm != 0) {
260bd0e176eSclaudio 		if (f->match.maxextcomm >
261bd0e176eSclaudio 		    community_count(&state->communities, COMMUNITY_TYPE_EXT))
262bd0e176eSclaudio 			return (0);
263bd0e176eSclaudio 	}
264bd0e176eSclaudio 	if (f->match.maxlargecomm != 0) {
265bd0e176eSclaudio 		if (f->match.maxlargecomm >
266bd0e176eSclaudio 		    community_count(&state->communities, COMMUNITY_TYPE_LARGE))
267bd0e176eSclaudio 			return (0);
268bd0e176eSclaudio 	}
269bd0e176eSclaudio 
270d1ac9b38Sclaudio 	if (f->match.nexthop.flags != 0) {
2719c206d22Sclaudio 		struct bgpd_addr *nexthop, *cmpaddr;
272b5a1e014Sclaudio 		if (state->nexthop == NULL)
2739c206d22Sclaudio 			/* no nexthop, skip */
2749c206d22Sclaudio 			return (0);
275b5a1e014Sclaudio 		nexthop = &state->nexthop->exit_nexthop;
2769c206d22Sclaudio 		if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR)
2779c206d22Sclaudio 			cmpaddr = &f->match.nexthop.addr;
2789c206d22Sclaudio 		else
279928a56d5Sclaudio 			cmpaddr = &from->remote_addr;
2809c206d22Sclaudio 		if (cmpaddr->aid != nexthop->aid)
2819c206d22Sclaudio 			/* don't use IPv4 rules for IPv6 and vice versa */
2829c206d22Sclaudio 			return (0);
2839c206d22Sclaudio 
2849c206d22Sclaudio 		switch (cmpaddr->aid) {
2859c206d22Sclaudio 		case AID_INET:
2869c206d22Sclaudio 			if (cmpaddr->v4.s_addr != nexthop->v4.s_addr)
2879c206d22Sclaudio 				return (0);
2889c206d22Sclaudio 			break;
2899c206d22Sclaudio 		case AID_INET6:
2909c206d22Sclaudio 			if (memcmp(&cmpaddr->v6, &nexthop->v6,
2919c206d22Sclaudio 			    sizeof(struct in6_addr)))
2929c206d22Sclaudio 				return (0);
2939c206d22Sclaudio 			break;
2949c206d22Sclaudio 		default:
2959c206d22Sclaudio 			fatalx("King Bula lost in address space");
2969c206d22Sclaudio 		}
2979c206d22Sclaudio 	}
2989c206d22Sclaudio 
2996f1dba6eSclaudio 	/* origin-set lookups match only on ROA_VALID */
3006f1dba6eSclaudio 	if (asp != NULL && f->match.originset.ps != NULL) {
3016f1dba6eSclaudio 		if (trie_roa_check(&f->match.originset.ps->th, prefix, plen,
302a34ea928Sclaudio 		    aspath_origin(asp->aspath)) != ROA_VALID)
3036f1dba6eSclaudio 			return (0);
3046f1dba6eSclaudio 	}
3056f1dba6eSclaudio 
306441aaadcSbenno 	/*
307441aaadcSbenno 	 * prefixset and prefix filter rules are mutual exclusive
308441aaadcSbenno 	 */
309441aaadcSbenno 	if (f->match.prefixset.flags != 0) {
310a02daaddSclaudio 		if (f->match.prefixset.ps == NULL ||
3119ed42aa2Sbenno 		    !trie_match(&f->match.prefixset.ps->th, prefix, plen,
3129ed42aa2Sbenno 		    (f->match.prefixset.flags & PREFIXSET_FLAG_LONGER)))
313441aaadcSbenno 			return (0);
314b02ef208Sbenno 	} else if (f->match.prefix.addr.aid != 0)
315928a56d5Sclaudio 		return (rde_prefix_match(&f->match.prefix, prefix, plen));
316441aaadcSbenno 
31784ff2965Sclaudio 	/* matched somewhen or is anymatch rule  */
31884ff2965Sclaudio 	return (1);
31984ff2965Sclaudio }
3200df2230cSclaudio 
321595dd55bSclaudio /* return true when the rule f can never match for this peer */
322b900620cSclaudio int
rde_filter_skip_rule(struct rde_peer * peer,struct filter_rule * f)323595dd55bSclaudio rde_filter_skip_rule(struct rde_peer *peer, struct filter_rule *f)
324595dd55bSclaudio {
325595dd55bSclaudio 	/* if any of the two is unset then rule can't be skipped */
326595dd55bSclaudio 	if (peer == NULL || f == NULL)
327595dd55bSclaudio 		return (0);
328595dd55bSclaudio 
329595dd55bSclaudio 	if (f->peer.groupid != 0 &&
330595dd55bSclaudio 	    f->peer.groupid != peer->conf.groupid)
331595dd55bSclaudio 		return (1);
332595dd55bSclaudio 
333595dd55bSclaudio 	if (f->peer.peerid != 0 &&
334595dd55bSclaudio 	    f->peer.peerid != peer->conf.id)
335595dd55bSclaudio 		return (1);
336595dd55bSclaudio 
337595dd55bSclaudio 	if (f->peer.remote_as != 0 &&
338595dd55bSclaudio 	    f->peer.remote_as != peer->conf.remote_as)
339595dd55bSclaudio 		return (1);
340595dd55bSclaudio 
341595dd55bSclaudio 	if (f->peer.ebgp != 0 &&
342595dd55bSclaudio 	    f->peer.ebgp != peer->conf.ebgp)
343595dd55bSclaudio 		return (1);
344595dd55bSclaudio 
345595dd55bSclaudio 	if (f->peer.ibgp != 0 &&
346595dd55bSclaudio 	    f->peer.ibgp != !peer->conf.ebgp)
347595dd55bSclaudio 		return (1);
348595dd55bSclaudio 
349595dd55bSclaudio 	return (0);
350595dd55bSclaudio }
351595dd55bSclaudio 
3520df2230cSclaudio int
rde_filter_equal(struct filter_head * a,struct filter_head * b)353b900620cSclaudio rde_filter_equal(struct filter_head *a, struct filter_head *b)
354ff2f0a45Sclaudio {
355ff2f0a45Sclaudio 	struct filter_rule	*fa, *fb;
3566f1dba6eSclaudio 	struct rde_prefixset	*psa, *psb, *osa, *osb;
357a8e18e82Sclaudio 	struct as_set		*asa, *asb;
358de6b13a4Sbenno 	int			 r;
359ff2f0a45Sclaudio 
36028b060e1Sclaudio 	fa = a ? TAILQ_FIRST(a) : NULL;
36128b060e1Sclaudio 	fb = b ? TAILQ_FIRST(b) : NULL;
362ff2f0a45Sclaudio 
363ff2f0a45Sclaudio 	while (fa != NULL || fb != NULL) {
364ff2f0a45Sclaudio 		/* compare the two rules */
365ff2f0a45Sclaudio 		if ((fa == NULL && fb != NULL) || (fa != NULL && fb == NULL))
366ff2f0a45Sclaudio 			/* new rule added or removed */
367ff2f0a45Sclaudio 			return (0);
368ff2f0a45Sclaudio 
369ff2f0a45Sclaudio 		if (fa->action != fb->action || fa->quick != fb->quick)
370ff2f0a45Sclaudio 			return (0);
371ff2f0a45Sclaudio 		if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer)))
372ff2f0a45Sclaudio 			return (0);
373441aaadcSbenno 
374441aaadcSbenno 		/* compare filter_rule.match without the prefixset pointer */
375441aaadcSbenno 		psa = fa->match.prefixset.ps;
376441aaadcSbenno 		psb = fb->match.prefixset.ps;
3776f1dba6eSclaudio 		osa = fa->match.originset.ps;
3786f1dba6eSclaudio 		osb = fb->match.originset.ps;
379a8e18e82Sclaudio 		asa = fa->match.as.aset;
380a8e18e82Sclaudio 		asb = fb->match.as.aset;
381441aaadcSbenno 		fa->match.prefixset.ps = fb->match.prefixset.ps = NULL;
3826f1dba6eSclaudio 		fa->match.originset.ps = fb->match.originset.ps = NULL;
383a8e18e82Sclaudio 		fa->match.as.aset = fb->match.as.aset = NULL;
384de6b13a4Sbenno 		r = memcmp(&fa->match, &fb->match, sizeof(fa->match));
385de6b13a4Sbenno 		/* fixup the struct again */
386441aaadcSbenno 		fa->match.prefixset.ps = psa;
387441aaadcSbenno 		fb->match.prefixset.ps = psb;
3886f1dba6eSclaudio 		fa->match.originset.ps = osa;
3896f1dba6eSclaudio 		fb->match.originset.ps = osb;
390a8e18e82Sclaudio 		fa->match.as.aset = asa;
391a8e18e82Sclaudio 		fb->match.as.aset = asb;
392de6b13a4Sbenno 		if (r != 0)
393de6b13a4Sbenno 			return (0);
3946f1dba6eSclaudio 		if (fa->match.prefixset.ps != NULL &&
395a02daaddSclaudio 		    fa->match.prefixset.ps->dirty) {
396441aaadcSbenno 			log_debug("%s: prefixset %s has changed",
397441aaadcSbenno 			    __func__, fa->match.prefixset.name);
398441aaadcSbenno 			return (0);
399441aaadcSbenno 		}
4006f1dba6eSclaudio 		if (fa->match.originset.ps != NULL &&
4016f1dba6eSclaudio 		    fa->match.originset.ps->dirty) {
4026f1dba6eSclaudio 			log_debug("%s: originset %s has changed",
4036f1dba6eSclaudio 			    __func__, fa->match.originset.name);
4046f1dba6eSclaudio 			return (0);
4056f1dba6eSclaudio 		}
406a8e18e82Sclaudio 		if ((fa->match.as.flags & AS_FLAG_AS_SET) &&
40759e404fbSclaudio 		    fa->match.as.aset->dirty) {
408a8e18e82Sclaudio 			log_debug("%s: as-set %s has changed",
409a8e18e82Sclaudio 			    __func__, fa->match.as.name);
410a8e18e82Sclaudio 			return (0);
411a8e18e82Sclaudio 		}
412a8e18e82Sclaudio 
413ff2f0a45Sclaudio 		if (!filterset_equal(&fa->set, &fb->set))
414ff2f0a45Sclaudio 			return (0);
415ff2f0a45Sclaudio 
416ff2f0a45Sclaudio 		fa = TAILQ_NEXT(fa, entry);
417ff2f0a45Sclaudio 		fb = TAILQ_NEXT(fb, entry);
418ff2f0a45Sclaudio 	}
419ff2f0a45Sclaudio 	return (1);
420ff2f0a45Sclaudio }
421ff2f0a45Sclaudio 
42228b060e1Sclaudio void
rde_filterstate_init(struct filterstate * state)423977f29edSclaudio rde_filterstate_init(struct filterstate *state)
424977f29edSclaudio {
425977f29edSclaudio 	memset(state, 0, sizeof(*state));
426977f29edSclaudio 	path_prep(&state->aspath);
427977f29edSclaudio }
428977f29edSclaudio 
429977f29edSclaudio static void
rde_filterstate_set(struct filterstate * state,struct rde_aspath * asp,struct rde_community * communities,struct nexthop * nh,uint8_t nhflags,uint8_t vstate)430977f29edSclaudio rde_filterstate_set(struct filterstate *state, struct rde_aspath *asp,
431245e5d07Sclaudio     struct rde_community *communities, struct nexthop *nh, uint8_t nhflags,
432245e5d07Sclaudio     uint8_t vstate)
433effde4cfSclaudio {
434977f29edSclaudio 	rde_filterstate_init(state);
435effde4cfSclaudio 
43681c29ec3Sclaudio 	if (asp)
43781c29ec3Sclaudio 		path_copy(&state->aspath, asp);
438e7adcfeaSclaudio 	if (communities)
439e7adcfeaSclaudio 		communities_copy(&state->communities, communities);
440b5a1e014Sclaudio 	state->nexthop = nexthop_ref(nh);
44140222badSclaudio 	state->nhflags = nhflags;
442245e5d07Sclaudio 	state->vstate = vstate;
443effde4cfSclaudio }
444effde4cfSclaudio 
445f8fade75Sclaudio /*
446f8fade75Sclaudio  * Build a filterstate based on the prefix p.
447f8fade75Sclaudio  */
448effde4cfSclaudio void
rde_filterstate_prep(struct filterstate * state,struct prefix * p)449977f29edSclaudio rde_filterstate_prep(struct filterstate *state, struct prefix *p)
450977f29edSclaudio {
451977f29edSclaudio 	rde_filterstate_set(state, prefix_aspath(p), prefix_communities(p),
452f8fade75Sclaudio 	    prefix_nexthop(p), prefix_nhflags(p), p->validation_state);
453977f29edSclaudio }
454977f29edSclaudio 
455f8fade75Sclaudio /*
456f8fade75Sclaudio  * Copy a filterstate to a new filterstate.
457f8fade75Sclaudio  */
458977f29edSclaudio void
rde_filterstate_copy(struct filterstate * state,struct filterstate * src)459977f29edSclaudio rde_filterstate_copy(struct filterstate *state, struct filterstate *src)
460977f29edSclaudio {
461977f29edSclaudio 	rde_filterstate_set(state, &src->aspath, &src->communities,
462977f29edSclaudio 	    src->nexthop, src->nhflags, src->vstate);
463977f29edSclaudio }
464977f29edSclaudio 
465f8fade75Sclaudio /*
466f8fade75Sclaudio  * Set the vstate based on the aspa_state and the supplied roa vstate.
467f8fade75Sclaudio  * This function must be called after rde_filterstate_init().
468f8fade75Sclaudio  * rde_filterstate_prep() and rde_filterstate_copy() set the right vstate.
469f8fade75Sclaudio  */
470f8fade75Sclaudio void
rde_filterstate_set_vstate(struct filterstate * state,uint8_t roa_vstate,uint8_t aspa_state)471f8fade75Sclaudio rde_filterstate_set_vstate(struct filterstate *state, uint8_t roa_vstate,
472f8fade75Sclaudio     uint8_t aspa_state)
473f8fade75Sclaudio {
474f8fade75Sclaudio 	state->vstate = aspa_state << 4;
475f8fade75Sclaudio 	state->vstate |= roa_vstate & ROA_MASK;
476f8fade75Sclaudio }
477f8fade75Sclaudio 
478977f29edSclaudio void
rde_filterstate_clean(struct filterstate * state)479effde4cfSclaudio rde_filterstate_clean(struct filterstate *state)
480effde4cfSclaudio {
481effde4cfSclaudio 	path_clean(&state->aspath);
482e7adcfeaSclaudio 	communities_clean(&state->communities);
483e2c0fe86Sclaudio 	nexthop_unref(state->nexthop);
484b5a1e014Sclaudio 	state->nexthop = NULL;
485effde4cfSclaudio }
486effde4cfSclaudio 
487effde4cfSclaudio void
filterlist_free(struct filter_head * fh)48804c6d98aSclaudio filterlist_free(struct filter_head *fh)
48928b060e1Sclaudio {
49028b060e1Sclaudio 	struct filter_rule	*r;
49128b060e1Sclaudio 
49228b060e1Sclaudio 	if (fh == NULL)
49328b060e1Sclaudio 		return;
49428b060e1Sclaudio 
49528b060e1Sclaudio 	while ((r = TAILQ_FIRST(fh)) != NULL) {
49628b060e1Sclaudio 		TAILQ_REMOVE(fh, r, entry);
49728b060e1Sclaudio 		filterset_free(&r->set);
49828b060e1Sclaudio 		free(r);
49928b060e1Sclaudio 	}
50028b060e1Sclaudio 	free(fh);
50128b060e1Sclaudio }
50228b060e1Sclaudio 
503ebcafe57Sclaudio /* free a filterset and take care of possible name2id references */
50415aea9d4Sclaudio void
filterset_free(struct filter_set_head * sh)50515aea9d4Sclaudio filterset_free(struct filter_set_head *sh)
50615aea9d4Sclaudio {
50715aea9d4Sclaudio 	struct filter_set	*s;
50815aea9d4Sclaudio 
509d288d268Sclaudio 	if (sh == NULL)
510d288d268Sclaudio 		return;
511d288d268Sclaudio 
51276630fdaSclaudio 	while ((s = TAILQ_FIRST(sh)) != NULL) {
51376630fdaSclaudio 		TAILQ_REMOVE(sh, s, entry);
51415aea9d4Sclaudio 		if (s->type == ACTION_RTLABEL_ID)
51515aea9d4Sclaudio 			rtlabel_unref(s->action.id);
516e2691ddeSclaudio 		else if (s->type == ACTION_PFTABLE_ID)
517e2691ddeSclaudio 			pftable_unref(s->action.id);
51823676e2aSclaudio 		else if (s->type == ACTION_SET_NEXTHOP_REF)
51923676e2aSclaudio 			nexthop_unref(s->action.nh_ref);
52015aea9d4Sclaudio 		free(s);
52115aea9d4Sclaudio 	}
52215aea9d4Sclaudio }
52315aea9d4Sclaudio 
524ebcafe57Sclaudio /*
525ebcafe57Sclaudio  * this function is a bit more complicated than a memcmp() because there are
526ebcafe57Sclaudio  * types that need to be considered equal e.g. ACTION_SET_MED and
527ebcafe57Sclaudio  * ACTION_SET_RELATIVE_MED. Also ACTION_SET_COMMUNITY and ACTION_SET_NEXTHOP
528ff2f0a45Sclaudio  * need some special care. It only checks the types and not the values so
529ff2f0a45Sclaudio  * it does not do a real compare.
530ebcafe57Sclaudio  */
531ebcafe57Sclaudio int
filterset_cmp(struct filter_set * a,struct filter_set * b)532ebcafe57Sclaudio filterset_cmp(struct filter_set *a, struct filter_set *b)
533ebcafe57Sclaudio {
534d63de11bSclaudio 	if (strcmp(filterset_name(a->type), filterset_name(b->type)))
535ebcafe57Sclaudio 		return (a->type - b->type);
536ebcafe57Sclaudio 
537a265ad1cSclaudio 	if (a->type == ACTION_SET_COMMUNITY ||
538a265ad1cSclaudio 	    a->type == ACTION_DEL_COMMUNITY) {	/* a->type == b->type */
539dd87f852Sclaudio 		return (memcmp(&a->action.community, &b->action.community,
540dd87f852Sclaudio 		    sizeof(a->action.community)));
541ebcafe57Sclaudio 	}
542ebcafe57Sclaudio 
543ebcafe57Sclaudio 	if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) {
544ebcafe57Sclaudio 		/*
545c5508ee4Sclaudio 		 * This is the only interesting case, all others are considered
546ebcafe57Sclaudio 		 * equal. It does not make sense to e.g. set a nexthop and
547ebcafe57Sclaudio 		 * reject it at the same time. Allow one IPv4 and one IPv6
548ebcafe57Sclaudio 		 * per filter set or only one of the other nexthop modifiers.
549ebcafe57Sclaudio 		 */
550d6c2e4e8Sclaudio 		return (a->action.nexthop.aid - b->action.nexthop.aid);
551ebcafe57Sclaudio 	}
552ebcafe57Sclaudio 
553ebcafe57Sclaudio 	/* equal */
554ebcafe57Sclaudio 	return (0);
555ebcafe57Sclaudio }
556ebcafe57Sclaudio 
557dcd4a44dSclaudio /*
558dcd4a44dSclaudio  * move filterset from source to dest. dest will be initialized first.
559dcd4a44dSclaudio  * After the move source is an empty list.
560dcd4a44dSclaudio  */
5619c8b0cd3Sclaudio void
filterset_move(struct filter_set_head * source,struct filter_set_head * dest)5629c8b0cd3Sclaudio filterset_move(struct filter_set_head *source, struct filter_set_head *dest)
5639c8b0cd3Sclaudio {
5649c8b0cd3Sclaudio 	TAILQ_INIT(dest);
5659c8b0cd3Sclaudio 	if (source == NULL)
5669c8b0cd3Sclaudio 		return;
567a4249091Sbenno 	TAILQ_CONCAT(dest, source, entry);
5689c8b0cd3Sclaudio }
5699c8b0cd3Sclaudio 
570dcd4a44dSclaudio /*
571dcd4a44dSclaudio  * copy filterset from source to dest. dest will be initialized first.
572dcd4a44dSclaudio  */
573dcd4a44dSclaudio void
filterset_copy(struct filter_set_head * source,struct filter_set_head * dest)574dcd4a44dSclaudio filterset_copy(struct filter_set_head *source, struct filter_set_head *dest)
575dcd4a44dSclaudio {
576dcd4a44dSclaudio 	struct filter_set	*s, *t;
577dcd4a44dSclaudio 
578dcd4a44dSclaudio 	TAILQ_INIT(dest);
579dcd4a44dSclaudio 	if (source == NULL)
580dcd4a44dSclaudio 		return;
581dcd4a44dSclaudio 
582dcd4a44dSclaudio 	TAILQ_FOREACH(s, source, entry) {
583dcd4a44dSclaudio 		if ((t = malloc(sizeof(struct filter_set))) == NULL)
584dcd4a44dSclaudio 			fatal(NULL);
585dcd4a44dSclaudio 		memcpy(t, s, sizeof(struct filter_set));
586*bc2d12c4Sclaudio 		if (t->type == ACTION_RTLABEL_ID)
587*bc2d12c4Sclaudio 			rtlabel_ref(t->action.id);
588*bc2d12c4Sclaudio 		else if (t->type == ACTION_PFTABLE_ID)
589*bc2d12c4Sclaudio 			pftable_ref(t->action.id);
590*bc2d12c4Sclaudio 		else if (t->type == ACTION_SET_NEXTHOP_REF)
591*bc2d12c4Sclaudio 			nexthop_ref(t->action.nh_ref);
592dcd4a44dSclaudio 		TAILQ_INSERT_TAIL(dest, t, entry);
593dcd4a44dSclaudio 	}
594dcd4a44dSclaudio }
595dcd4a44dSclaudio 
596ff2f0a45Sclaudio int
filterset_equal(struct filter_set_head * ah,struct filter_set_head * bh)597ff2f0a45Sclaudio filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh)
598ff2f0a45Sclaudio {
599ff2f0a45Sclaudio 	struct filter_set	*a, *b;
600ff2f0a45Sclaudio 	const char		*as, *bs;
601ff2f0a45Sclaudio 
602ff2f0a45Sclaudio 	for (a = TAILQ_FIRST(ah), b = TAILQ_FIRST(bh);
603ff2f0a45Sclaudio 	    a != NULL && b != NULL;
604ff2f0a45Sclaudio 	    a = TAILQ_NEXT(a, entry), b = TAILQ_NEXT(b, entry)) {
605ff2f0a45Sclaudio 		switch (a->type) {
606ff2f0a45Sclaudio 		case ACTION_SET_PREPEND_SELF:
607ff2f0a45Sclaudio 		case ACTION_SET_PREPEND_PEER:
608ff2f0a45Sclaudio 			if (a->type == b->type &&
609ff2f0a45Sclaudio 			    a->action.prepend == b->action.prepend)
610ff2f0a45Sclaudio 				continue;
611ff2f0a45Sclaudio 			break;
612d7a2dcd7Sclaudio 		case ACTION_SET_AS_OVERRIDE:
613d7a2dcd7Sclaudio 			if (a->type == b->type)
614d7a2dcd7Sclaudio 				continue;
615d7a2dcd7Sclaudio 			break;
616ff2f0a45Sclaudio 		case ACTION_SET_LOCALPREF:
617ff2f0a45Sclaudio 		case ACTION_SET_MED:
618ff2f0a45Sclaudio 		case ACTION_SET_WEIGHT:
619ff2f0a45Sclaudio 			if (a->type == b->type &&
620ff2f0a45Sclaudio 			    a->action.metric == b->action.metric)
621ff2f0a45Sclaudio 				continue;
622ff2f0a45Sclaudio 			break;
623ff2f0a45Sclaudio 		case ACTION_SET_RELATIVE_LOCALPREF:
624ff2f0a45Sclaudio 		case ACTION_SET_RELATIVE_MED:
625ff2f0a45Sclaudio 		case ACTION_SET_RELATIVE_WEIGHT:
626ff2f0a45Sclaudio 			if (a->type == b->type &&
627ff2f0a45Sclaudio 			    a->action.relative == b->action.relative)
628ff2f0a45Sclaudio 				continue;
629ff2f0a45Sclaudio 			break;
630ff2f0a45Sclaudio 		case ACTION_SET_NEXTHOP:
631ff2f0a45Sclaudio 			if (a->type == b->type &&
632ff2f0a45Sclaudio 			    memcmp(&a->action.nexthop, &b->action.nexthop,
633ff2f0a45Sclaudio 			    sizeof(a->action.nexthop)) == 0)
634ff2f0a45Sclaudio 				continue;
635ff2f0a45Sclaudio 			break;
63623676e2aSclaudio 		case ACTION_SET_NEXTHOP_REF:
63723676e2aSclaudio 			if (a->type == b->type &&
63823676e2aSclaudio 			    a->action.nh_ref == b->action.nh_ref)
63923676e2aSclaudio 				continue;
64023676e2aSclaudio 			break;
641ff2f0a45Sclaudio 		case ACTION_SET_NEXTHOP_BLACKHOLE:
642ff2f0a45Sclaudio 		case ACTION_SET_NEXTHOP_REJECT:
643ff2f0a45Sclaudio 		case ACTION_SET_NEXTHOP_NOMODIFY:
6447c989460Shenning 		case ACTION_SET_NEXTHOP_SELF:
645ff2f0a45Sclaudio 			if (a->type == b->type)
646ff2f0a45Sclaudio 				continue;
647ff2f0a45Sclaudio 			break;
648aaa4f5dfSclaudio 		case ACTION_DEL_COMMUNITY:
649ff2f0a45Sclaudio 		case ACTION_SET_COMMUNITY:
650ff2f0a45Sclaudio 			if (a->type == b->type &&
651ff2f0a45Sclaudio 			    memcmp(&a->action.community, &b->action.community,
652ff2f0a45Sclaudio 			    sizeof(a->action.community)) == 0)
653ff2f0a45Sclaudio 				continue;
654ff2f0a45Sclaudio 			break;
655ff2f0a45Sclaudio 		case ACTION_PFTABLE:
656ff2f0a45Sclaudio 		case ACTION_PFTABLE_ID:
657ff2f0a45Sclaudio 			if (b->type == ACTION_PFTABLE)
658ff2f0a45Sclaudio 				bs = b->action.pftable;
659ff2f0a45Sclaudio 			else if (b->type == ACTION_PFTABLE_ID)
660ff2f0a45Sclaudio 				bs = pftable_id2name(b->action.id);
661ff2f0a45Sclaudio 			else
662ff2f0a45Sclaudio 				break;
663ff2f0a45Sclaudio 
664ff2f0a45Sclaudio 			if (a->type == ACTION_PFTABLE)
665ff2f0a45Sclaudio 				as = a->action.pftable;
666ff2f0a45Sclaudio 			else
667ff2f0a45Sclaudio 				as = pftable_id2name(a->action.id);
668ff2f0a45Sclaudio 
669ff2f0a45Sclaudio 			if (strcmp(as, bs) == 0)
670ff2f0a45Sclaudio 				continue;
671ff2f0a45Sclaudio 			break;
672ff2f0a45Sclaudio 		case ACTION_RTLABEL:
673ff2f0a45Sclaudio 		case ACTION_RTLABEL_ID:
674ff2f0a45Sclaudio 			if (b->type == ACTION_RTLABEL)
675ff2f0a45Sclaudio 				bs = b->action.rtlabel;
676ff2f0a45Sclaudio 			else if (b->type == ACTION_RTLABEL_ID)
677ff2f0a45Sclaudio 				bs = rtlabel_id2name(b->action.id);
678ff2f0a45Sclaudio 			else
679ff2f0a45Sclaudio 				break;
680ff2f0a45Sclaudio 
681ff2f0a45Sclaudio 			if (a->type == ACTION_RTLABEL)
682ff2f0a45Sclaudio 				as = a->action.rtlabel;
683ff2f0a45Sclaudio 			else
684ff2f0a45Sclaudio 				as = rtlabel_id2name(a->action.id);
685ff2f0a45Sclaudio 
686ff2f0a45Sclaudio 			if (strcmp(as, bs) == 0)
687ff2f0a45Sclaudio 				continue;
688ff2f0a45Sclaudio 			break;
689cd3afea8Shenning 		case ACTION_SET_ORIGIN:
690cd3afea8Shenning 			if (a->type == b->type &&
691cd3afea8Shenning 			    a->action.origin == b->action.origin)
692cd3afea8Shenning 				continue;
693cd3afea8Shenning 			break;
694ff2f0a45Sclaudio 		}
695ff2f0a45Sclaudio 		/* compare failed */
696ff2f0a45Sclaudio 		return (0);
697ff2f0a45Sclaudio 	}
698ff2f0a45Sclaudio 	if (a != NULL || b != NULL)
699ff2f0a45Sclaudio 		return (0);
700ff2f0a45Sclaudio 	return (1);
701ff2f0a45Sclaudio }
702ebcafe57Sclaudio 
703d63de11bSclaudio const char *
filterset_name(enum action_types type)704d63de11bSclaudio filterset_name(enum action_types type)
705d63de11bSclaudio {
706d63de11bSclaudio 	switch (type) {
707d63de11bSclaudio 	case ACTION_SET_LOCALPREF:
708d63de11bSclaudio 	case ACTION_SET_RELATIVE_LOCALPREF:
709d63de11bSclaudio 		return ("localpref");
710d63de11bSclaudio 	case ACTION_SET_MED:
711d63de11bSclaudio 	case ACTION_SET_RELATIVE_MED:
712d63de11bSclaudio 		return ("metric");
713d63de11bSclaudio 	case ACTION_SET_WEIGHT:
714d63de11bSclaudio 	case ACTION_SET_RELATIVE_WEIGHT:
715d63de11bSclaudio 		return ("weight");
716d63de11bSclaudio 	case ACTION_SET_PREPEND_SELF:
717d63de11bSclaudio 		return ("prepend-self");
718d63de11bSclaudio 	case ACTION_SET_PREPEND_PEER:
719d63de11bSclaudio 		return ("prepend-peer");
720d7a2dcd7Sclaudio 	case ACTION_SET_AS_OVERRIDE:
721d7a2dcd7Sclaudio 		return ("as-override");
722d63de11bSclaudio 	case ACTION_SET_NEXTHOP:
72323676e2aSclaudio 	case ACTION_SET_NEXTHOP_REF:
724d63de11bSclaudio 	case ACTION_SET_NEXTHOP_REJECT:
725d63de11bSclaudio 	case ACTION_SET_NEXTHOP_BLACKHOLE:
726d63de11bSclaudio 	case ACTION_SET_NEXTHOP_NOMODIFY:
727d63de11bSclaudio 	case ACTION_SET_NEXTHOP_SELF:
728d63de11bSclaudio 		return ("nexthop");
729d63de11bSclaudio 	case ACTION_SET_COMMUNITY:
730d63de11bSclaudio 		return ("community");
731d63de11bSclaudio 	case ACTION_DEL_COMMUNITY:
732d63de11bSclaudio 		return ("community delete");
733d63de11bSclaudio 	case ACTION_PFTABLE:
734d63de11bSclaudio 	case ACTION_PFTABLE_ID:
735d63de11bSclaudio 		return ("pftable");
736d63de11bSclaudio 	case ACTION_RTLABEL:
737d63de11bSclaudio 	case ACTION_RTLABEL_ID:
738d63de11bSclaudio 		return ("rtlabel");
739cd3afea8Shenning 	case ACTION_SET_ORIGIN:
740cd3afea8Shenning 		return ("origin");
741d63de11bSclaudio 	}
742d63de11bSclaudio 
743d63de11bSclaudio 	fatalx("filterset_name: got lost");
744d63de11bSclaudio }
745a3593556Sphessler 
746a3593556Sphessler /*
747a3593556Sphessler  * Copyright (c) 2001 Daniel Hartmeier
748a3593556Sphessler  * All rights reserved.
749a3593556Sphessler  *
750a3593556Sphessler  * Redistribution and use in source and binary forms, with or without
751a3593556Sphessler  * modification, are permitted provided that the following conditions
752a3593556Sphessler  * are met:
753a3593556Sphessler  *
754a3593556Sphessler  *    - Redistributions of source code must retain the above copyright
755a3593556Sphessler  *      notice, this list of conditions and the following disclaimer.
756a3593556Sphessler  *    - Redistributions in binary form must reproduce the above
757a3593556Sphessler  *      copyright notice, this list of conditions and the following
758a3593556Sphessler  *      disclaimer in the documentation and/or other materials provided
759a3593556Sphessler  *      with the distribution.
760a3593556Sphessler  *
761a3593556Sphessler  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
762a3593556Sphessler  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
763a3593556Sphessler  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
764a3593556Sphessler  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
765a3593556Sphessler  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
766a3593556Sphessler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
767a3593556Sphessler  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
768a3593556Sphessler  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
769a3593556Sphessler  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
770a3593556Sphessler  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
771a3593556Sphessler  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
772a3593556Sphessler  * POSSIBILITY OF SUCH DAMAGE.
773a3593556Sphessler  *
774a3593556Sphessler  * Effort sponsored in part by the Defense Advanced Research Projects
775a3593556Sphessler  * Agency (DARPA) and Air Force Research Laboratory, Air Force
776a3593556Sphessler  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
777a3593556Sphessler  *
778a3593556Sphessler  */
779a3593556Sphessler 
780a3593556Sphessler #define RDE_FILTER_SET_SKIP_STEPS(i)				\
781a3593556Sphessler 	do {							\
782a3593556Sphessler 		while (head[i] != cur) {			\
78330deac26Sclaudio 			head[i]->skip[i] = cur;			\
784a3593556Sphessler 			head[i] = TAILQ_NEXT(head[i], entry);	\
785a3593556Sphessler 		}						\
786a3593556Sphessler 	} while (0)
787a3593556Sphessler 
788a3593556Sphessler void
rde_filter_calc_skip_steps(struct filter_head * rules)789a3593556Sphessler rde_filter_calc_skip_steps(struct filter_head *rules)
790a3593556Sphessler {
791a3593556Sphessler 	struct filter_rule *cur, *prev, *head[RDE_FILTER_SKIP_COUNT];
792a3593556Sphessler 	int i;
793a3593556Sphessler 
794a3593556Sphessler 	if (rules == NULL)
795a3593556Sphessler 		return;
796a3593556Sphessler 
797a3593556Sphessler 	cur = TAILQ_FIRST(rules);
798a3593556Sphessler 
799a3593556Sphessler 	prev = cur;
800a3593556Sphessler 	for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i)
801a3593556Sphessler 		head[i] = cur;
802a3593556Sphessler 	while (cur != NULL) {
803b900620cSclaudio 		if (cur->peer.peerid != prev->peer.peerid)
804b900620cSclaudio 			RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_PEERID);
805a3593556Sphessler 		if (cur->peer.groupid != prev->peer.groupid)
806a3593556Sphessler 			RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_GROUPID);
807a3593556Sphessler 		if (cur->peer.remote_as != prev->peer.remote_as)
808a3593556Sphessler 			RDE_FILTER_SET_SKIP_STEPS(RDE_FILTER_SKIP_REMOTE_AS);
809a3593556Sphessler 		prev = cur;
810a3593556Sphessler 		cur = TAILQ_NEXT(cur, entry);
811a3593556Sphessler 	}
812a3593556Sphessler 	for (i = 0; i < RDE_FILTER_SKIP_COUNT; ++i)
813a3593556Sphessler 		RDE_FILTER_SET_SKIP_STEPS(i);
814a3593556Sphessler 
815a3593556Sphessler }
816a3593556Sphessler 
817a3593556Sphessler #define RDE_FILTER_TEST_ATTRIB(t, a)				\
818a3593556Sphessler 	do {							\
819a3593556Sphessler 		if (t) {					\
820a3593556Sphessler 			f = a;					\
821a3593556Sphessler 			goto nextrule;				\
822a3593556Sphessler 		}						\
823a3593556Sphessler 	} while (0)
824a3593556Sphessler 
825a3593556Sphessler enum filter_actions
rde_filter(struct filter_head * rules,struct rde_peer * peer,struct rde_peer * from,struct bgpd_addr * prefix,uint8_t plen,struct filterstate * state)826ec583527Sclaudio rde_filter(struct filter_head *rules, struct rde_peer *peer,
82739386878Sclaudio     struct rde_peer *from, struct bgpd_addr *prefix, uint8_t plen,
828245e5d07Sclaudio     struct filterstate *state)
829a3593556Sphessler {
830a3593556Sphessler 	struct filter_rule	*f;
831f390b1a7Sclaudio 	enum filter_actions	 action = ACTION_DENY; /* default deny */
832a3593556Sphessler 
833d1ac9b38Sclaudio 	if (state->aspath.flags & F_ATTR_PARSE_ERR)
834a3593556Sphessler 		/*
835a3593556Sphessler 		 * don't try to filter bad updates just deny them
836a3593556Sphessler 		 * so they act as implicit withdraws
837a3593556Sphessler 		 */
838a3593556Sphessler 		return (ACTION_DENY);
839a3593556Sphessler 
840a3593556Sphessler 	if (rules == NULL)
841a3593556Sphessler 		return (action);
842a3593556Sphessler 
843dd2a9ed2Sclaudio 	if (prefix->aid == AID_FLOWSPECv4 || prefix->aid == AID_FLOWSPECv6)
844dd2a9ed2Sclaudio 		return (ACTION_ALLOW);
845dd2a9ed2Sclaudio 
846a3593556Sphessler 	f = TAILQ_FIRST(rules);
847a3593556Sphessler 	while (f != NULL) {
848a3593556Sphessler 		RDE_FILTER_TEST_ATTRIB(
849b900620cSclaudio 		    (f->peer.peerid &&
850b900620cSclaudio 		     f->peer.peerid != peer->conf.id),
851b900620cSclaudio 		     f->skip[RDE_FILTER_SKIP_PEERID]);
852b900620cSclaudio 		RDE_FILTER_TEST_ATTRIB(
853a3593556Sphessler 		    (f->peer.groupid &&
854a3593556Sphessler 		     f->peer.groupid != peer->conf.groupid),
85530deac26Sclaudio 		     f->skip[RDE_FILTER_SKIP_GROUPID]);
856a3593556Sphessler 		RDE_FILTER_TEST_ATTRIB(
857a3593556Sphessler 		    (f->peer.remote_as &&
858a3593556Sphessler 		     f->peer.remote_as != peer->conf.remote_as),
85930deac26Sclaudio 		     f->skip[RDE_FILTER_SKIP_REMOTE_AS]);
860ec583527Sclaudio 
861245e5d07Sclaudio 		if (rde_filter_match(f, peer, from, state, prefix, plen)) {
862928a56d5Sclaudio 			rde_apply_set(&f->set, peer, from, state, prefix->aid);
863a3593556Sphessler 			if (f->action != ACTION_NONE)
864a3593556Sphessler 				action = f->action;
865a3593556Sphessler 			if (f->quick)
866a3593556Sphessler 				return (action);
867a3593556Sphessler 		}
868a3593556Sphessler 		f = TAILQ_NEXT(f, entry);
869a3593556Sphessler  nextrule: ;
870a3593556Sphessler 	}
871a3593556Sphessler 	return (action);
872a3593556Sphessler }
873