summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2005-11-02 13:19:31 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2005-11-02 13:19:31 +0000
commit0517d8827de185c45da6197b603e72a2435f73ac (patch)
tree3845990b71c8100856d05f6891bbfeedffcbb94d
parent2c2d822877c7bd4e9ff3ad3c160a7dc3de1c03b7 (diff)
Implement filterset_equal() and rde_filter_equal(). Both return 1 if
the two passed filter(set)s are equal or 0 otherwise. rde_filter_equal() has an additional argument dir to specify which direction should be considered.
-rw-r--r--usr.sbin/bgpd/rde.h4
-rw-r--r--usr.sbin/bgpd/rde_filter.c136
2 files changed, 137 insertions, 3 deletions
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 7e4988bc3ed..bf5d1c92d9f 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.72 2005/11/01 15:21:54 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.73 2005/11/02 13:19:30 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -360,5 +360,7 @@ enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
void rde_apply_set(struct rde_aspath *, struct filter_set_head *,
sa_family_t, struct rde_peer *, enum directions);
int rde_filter_community(struct rde_aspath *, int, int);
+int rde_filter_equal(struct filter_head *, struct filter_head *,
+ enum directions);
#endif /* __RDE_H__ */
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index b238eb40da9..6c48c0dc0cd 100644
--- a/usr.sbin/bgpd/rde_filter.c
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_filter.c,v 1.36 2005/11/01 15:21:54 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.37 2005/11/02 13:19:30 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -26,6 +26,7 @@
int rde_filter_match(struct filter_rule *, struct rde_aspath *,
struct bgpd_addr *, u_int8_t);
+int filterset_equal(struct filter_set_head *, struct filter_set_head *);
enum filter_actions
rde_filter(struct filter_head *rules, struct rde_peer *peer,
@@ -281,6 +282,46 @@ rde_filter_community(struct rde_aspath *asp, int as, int type)
return (community_match(a->data, a->len, as, type));
}
+int
+rde_filter_equal(struct filter_head *a, struct filter_head *b,
+ enum directions dir)
+{
+ struct filter_rule *fa, *fb;
+
+ fa = TAILQ_FIRST(a);
+ fb = TAILQ_FIRST(b);
+
+ while (fa != NULL || fb != NULL) {
+ /* skip all rules with wrong direction */
+ if (fa != NULL && dir != fa->dir) {
+ fa = TAILQ_NEXT(fa, entry);
+ continue;
+ }
+ if (fb != NULL && dir != fb->dir) {
+ fb = TAILQ_NEXT(fb, entry);
+ continue;
+ }
+
+ /* compare the two rules */
+ if ((fa == NULL && fb != NULL) || (fa != NULL && fb == NULL))
+ /* new rule added or removed */
+ return (0);
+
+ if (fa->action != fb->action || fa->quick != fb->quick)
+ return (0);
+ if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer)))
+ return (0);
+ if (memcmp(&fa->match, &fb->match, sizeof(fa->match)))
+ return (0);
+ if (!filterset_equal(&fa->set, &fb->set))
+ return (0);
+
+ fa = TAILQ_NEXT(fa, entry);
+ fb = TAILQ_NEXT(fb, entry);
+ }
+ return (1);
+}
+
/* free a filterset and take care of possible name2id references */
void
filterset_free(struct filter_set_head *sh)
@@ -301,7 +342,8 @@ filterset_free(struct filter_set_head *sh)
* this function is a bit more complicated than a memcmp() because there are
* types that need to be considered equal e.g. ACTION_SET_MED and
* ACTION_SET_RELATIVE_MED. Also ACTION_SET_COMMUNITY and ACTION_SET_NEXTHOP
- * need some special care.
+ * need some special care. It only checks the types and not the values so
+ * it does not do a real compare.
*/
int
filterset_cmp(struct filter_set *a, struct filter_set *b)
@@ -331,4 +373,94 @@ filterset_cmp(struct filter_set *a, struct filter_set *b)
return (0);
}
+int
+filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh)
+{
+ struct filter_set *a, *b;
+ const char *as, *bs;
+
+ for (a = TAILQ_FIRST(ah), b = TAILQ_FIRST(bh);
+ a != NULL && b != NULL;
+ a = TAILQ_NEXT(a, entry), b = TAILQ_NEXT(b, entry)) {
+ switch (a->type) {
+ case ACTION_SET_PREPEND_SELF:
+ case ACTION_SET_PREPEND_PEER:
+ if (a->type == b->type &&
+ a->action.prepend == b->action.prepend)
+ continue;
+ break;
+ case ACTION_SET_LOCALPREF:
+ case ACTION_SET_MED:
+ case ACTION_SET_WEIGHT:
+ if (a->type == b->type &&
+ a->action.metric == b->action.metric)
+ continue;
+ break;
+ case ACTION_SET_RELATIVE_LOCALPREF:
+ case ACTION_SET_RELATIVE_MED:
+ case ACTION_SET_RELATIVE_WEIGHT:
+ if (a->type == b->type &&
+ a->action.relative == b->action.relative)
+ continue;
+ break;
+ case ACTION_SET_NEXTHOP:
+ if (a->type == b->type &&
+ memcmp(&a->action.nexthop, &b->action.nexthop,
+ sizeof(a->action.nexthop)) == 0)
+ continue;
+ break;
+ case ACTION_SET_NEXTHOP_BLACKHOLE:
+ case ACTION_SET_NEXTHOP_REJECT:
+ case ACTION_SET_NEXTHOP_NOMODIFY:
+ if (a->type == b->type)
+ continue;
+ break;
+ case ACTION_SET_COMMUNITY:
+ if (a->type == b->type &&
+ memcmp(&a->action.community, &b->action.community,
+ sizeof(a->action.community)) == 0)
+ continue;
+ break;
+ case ACTION_PFTABLE:
+ case ACTION_PFTABLE_ID:
+ if (b->type == ACTION_PFTABLE)
+ bs = b->action.pftable;
+ else if (b->type == ACTION_PFTABLE_ID)
+ bs = pftable_id2name(b->action.id);
+ else
+ break;
+
+ if (a->type == ACTION_PFTABLE)
+ as = a->action.pftable;
+ else
+ as = pftable_id2name(a->action.id);
+
+ if (strcmp(as, bs) == 0)
+ continue;
+ break;
+ case ACTION_RTLABEL:
+ case ACTION_RTLABEL_ID:
+ if (b->type == ACTION_RTLABEL)
+ bs = b->action.rtlabel;
+ else if (b->type == ACTION_RTLABEL_ID)
+ bs = rtlabel_id2name(b->action.id);
+ else
+ break;
+
+ if (a->type == ACTION_RTLABEL)
+ as = a->action.rtlabel;
+ else
+ as = rtlabel_id2name(a->action.id);
+
+ if (strcmp(as, bs) == 0)
+ continue;
+ break;
+ }
+ /* compare failed */
+ return (0);
+ }
+ if (a != NULL || b != NULL)
+ return (0);
+ return (1);
+}