summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/rde.c197
-rw-r--r--usr.sbin/bgpd/rde.h13
-rw-r--r--usr.sbin/bgpd/rde_attr.c165
-rw-r--r--usr.sbin/bgpd/rde_filter.c16
4 files changed, 344 insertions, 47 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index d953570ea01..1bc3ee8895c 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.120 2004/06/23 07:10:05 henning Exp $ */
+/* $OpenBSD: rde.c,v 1.121 2004/06/24 23:15:58 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -42,6 +42,8 @@ void rde_dispatch_imsg_parent(struct imsgbuf *);
int rde_update_dispatch(struct imsg *);
int rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
+int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
+ u_int8_t *);
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void *, u_int16_t);
void rde_update_log(const char *,
@@ -424,15 +426,16 @@ int
rde_update_dispatch(struct imsg *imsg)
{
struct rde_peer *peer;
- u_char *p, *emsg;
+ u_char *p, *emsg, *mpp;
int pos;
- u_int16_t len;
+ u_int16_t afi, len, mplen;
u_int16_t withdrawn_len;
u_int16_t attrpath_len;
u_int16_t nlri_len, size;
- u_int8_t prefixlen, subtype;
+ u_int8_t prefixlen, safi, subtype;
struct bgpd_addr prefix;
struct attr_flags attrs, fattrs;
+ struct attr *mpattr;
peer = peer_get(imsg->hdr.peerid);
if (peer == NULL) /* unknown peer, cannot happen */
@@ -530,6 +533,57 @@ rde_update_dispatch(struct imsg *imsg)
prefix_remove(peer, &prefix, prefixlen);
}
+ /* withdraw MP_UNREACH_NRLI if available */
+ if (attrpath_len != 0 &&
+ (mpattr = attr_optget(&attrs, ATTR_MP_UNREACH_NLRI)) != NULL) {
+ mpp = mpattr->data;
+ mplen = mpattr->len;
+ memcpy(&afi, mpp, 2);
+ mpp += 2;
+ mplen -= 2;
+ afi = ntohs(afi);
+ safi = *mpp++;
+ mplen--;
+ switch (afi) {
+ case AFI_IPv6:
+ while (mplen > 0) {
+ if ((pos = rde_update_get_prefix6(mpp, mplen,
+ &prefix, &prefixlen)) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad IPv6 withdraw prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+ if (prefixlen > 128) {
+ log_peer_warnx(&peer->conf,
+ "bad IPv6 withdraw prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+
+ mpp += pos;
+ mplen -= pos;
+
+ /* input filter */
+ if (rde_filter(peer, NULL, &prefix, prefixlen,
+ DIR_IN) == ACTION_DENY)
+ continue;
+
+ rde_update_log("withdraw", peer, NULL,
+ &prefix, prefixlen);
+ prefix_remove(peer, &prefix, prefixlen);
+ }
+ default:
+ fatalx("unsupported multipath AF");
+ }
+ }
+
if (attrpath_len == 0) /* 0 = no NLRI information in this message */
return (0);
@@ -599,6 +653,90 @@ rde_update_dispatch(struct imsg *imsg)
path_update(peer, &fattrs, &prefix, prefixlen);
}
+ /* add MP_REACH_NLRI if available */
+ if ((mpattr = attr_optget(&attrs, ATTR_MP_REACH_NLRI)) != NULL) {
+ mpp = mpattr->data;
+ mplen = mpattr->len;
+ memcpy(&afi, mpp, 2);
+ mpp += 2;
+ mplen -= 2;
+ afi = ntohs(afi);
+ safi = *mpp++;
+ mplen--;
+
+ if ((pos = attr_mp_nexthop_check(mpp, mplen, afi)) == -1) {
+ log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+
+ mpp += pos;
+ mplen -= pos;
+
+ if (*p++ != NULL) {
+ /* XXX this is ugly */
+ log_peer_warnx(&peer->conf, "SNPA are not supported");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+ switch (afi) {
+ case AFI_IPv6:
+ while (mplen > 0) {
+ if ((pos = rde_update_get_prefix6(mpp, mplen,
+ &prefix, &prefixlen)) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad IPv6 nlri prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+ if (prefixlen > 128) {
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpattr->data, mpattr->len);
+ attr_free(&attrs);
+ return (-1);
+ }
+
+ mpp += pos;
+ mplen -= pos;
+
+ attr_copy(&fattrs, &attrs);
+ /* input filter */
+ if (rde_filter(peer, &fattrs, &prefix,
+ prefixlen, DIR_IN) == ACTION_DENY) {
+ attr_free(&fattrs);
+ continue;
+ }
+
+ /* XXX IPv4 and IPv6 together */
+ /* max prefix checker */
+ if (peer->conf.max_prefix &&
+ peer->prefix_cnt >= peer->conf.max_prefix) {
+ log_peer_warnx(&peer->conf,
+ "prefix limit reached");
+ rde_update_err(peer, ERR_CEASE,
+ ERR_CEASE_MAX_PREFIX, NULL, 0);
+ attr_free(&attrs);
+ attr_free(&fattrs);
+ return (-1);
+ }
+
+ rde_update_log("update", peer, &fattrs,
+ &prefix, prefixlen);
+ path_update(peer, &fattrs, &prefix, prefixlen);
+ }
+ default:
+ fatalx("unsupported AF");
+ }
+ }
+
/* need to free allocated attribute memory that is no longer used */
attr_free(&attrs);
@@ -624,7 +762,7 @@ rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
p += 1;
plen = 1;
- addr.a32.s_addr = 0;
+ bzero(prefix, sizeof(struct bgpd_addr));
for (i = 0; i <= 3; i++) {
if (pfxlen > i * 8) {
if (len - plen < 1)
@@ -640,6 +778,36 @@ rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
return (plen);
}
+int
+rde_update_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
+ u_int8_t *prefixlen)
+{
+ int i;
+ u_int8_t pfxlen;
+ u_int16_t plen;
+
+ if (len < 1)
+ return (-1);
+
+ memcpy(&pfxlen, p, 1);
+ p += 1;
+ plen = 1;
+
+ bzero(prefix, sizeof(struct bgpd_addr));
+ for (i = 0; i <= 15; i++) {
+ if (pfxlen > i * 8) {
+ if (len - plen < 1)
+ return (-1);
+ memcpy(&prefix->v6.s6_addr[i], p++, 1);
+ plen++;
+ }
+ }
+ prefix->af = AF_INET6;
+ *prefixlen = pfxlen;
+
+ return (plen);
+}
+
void
rde_update_err(struct rde_peer *peer, u_int8_t error, u_int8_t suberr,
void *data, u_int16_t size)
@@ -664,19 +832,30 @@ rde_update_log(const char *message,
const struct bgpd_addr *prefix, u_int8_t prefixlen)
{
char *nexthop = NULL;
+ char *p = NULL;
- if (! (conf->log & BGPD_LOG_UPDATES))
+ if (!(conf->log & BGPD_LOG_UPDATES))
return;
if (attr != NULL)
- asprintf(&nexthop, " via %s", inet_ntoa(attr->nexthop));
+ if (attr_ismp(attr)) {
+ if (asprintf(&nexthop, " via %s",
+ log_addr(attr_mp_nexthop(attr))) == -1)
+ nexthop = NULL;
+ else
+ if (asprintf(&nexthop, " via %s",
+ inet_ntoa(attr->nexthop)) == -1)
+ nexthop = NULL;
+ }
+ if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
+ p = NULL;
log_debug("neighbor %s (AS%u) %s %s/%u %s",
log_addr(&peer->conf.remote_addr), peer->conf.remote_as, message,
- inet_ntoa(prefix->v4), prefixlen,
- nexthop ? nexthop : "");
+ p ? p : "out of memory", nexthop ? nexthop : "");
free(nexthop);
+ free(p);
}
int
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index e82c3b548de..7170224de9f 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.42 2004/06/22 20:28:58 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.43 2004/06/24 23:15:58 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -99,7 +99,9 @@ enum attrtypes {
ATTR_AGGREGATOR,
ATTR_COMMUNITIES,
ATTR_ORIGINATOR_ID,
- ATTR_CLUSTER_LIST
+ ATTR_CLUSTER_LIST,
+ ATTR_MP_REACH_NLRI=14,
+ ATTR_MP_UNREACH_NLRI=15
};
/* attribute flags. 4 low order bits reserved */
@@ -148,7 +150,7 @@ struct nexthop {
#if 0
/*
* currently we use the boolean nexthop state, this could be exchanged
- * with a variable coast with a max for unreachable.
+ * with a variable cost with a max for unreachable.
*/
u_int32_t costs;
#endif
@@ -248,8 +250,11 @@ int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
int attr_optadd(struct attr_flags *, u_int8_t, u_int8_t,
void *, u_int16_t);
-struct attr *attr_optget(struct attr_flags *, u_int8_t);
+struct attr *attr_optget(const struct attr_flags *, u_int8_t);
void attr_optfree(struct attr_flags *);
+int attr_ismp(const struct attr_flags *);
+int attr_mp_nexthop_check(u_char *, u_int16_t, u_int16_t);
+struct bgpd_addr *attr_mp_nexthop(const struct attr_flags *);
int aspath_verify(void *, u_int16_t);
#define AS_ERR_LEN -1
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index 0502f04118b..9bfaa5393ef 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.34 2004/06/24 22:01:54 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.35 2004/06/24 23:15:58 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -44,6 +44,8 @@
#define F_ATTR_NEXTHOP 0x04
#define F_ATTR_LOCALPREF 0x08
#define F_ATTR_MED 0x10
+#define F_ATTR_MP_REACH 0x20
+#define F_ATTR_MP_UNREACH 0x40
#define WFLAG(s, t) \
do { \
@@ -178,14 +180,30 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_ORIGINATOR_ID:
if (attr_len != 4)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, ATTR_PARTIAL))
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
return (-1);
goto optattr;
case ATTR_CLUSTER_LIST:
if ((attr_len & 0x3) != 0)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, ATTR_PARTIAL))
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_MP_REACH_NLRI:
+ if (attr_len < 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ /* the actually validity is checked in rde_update_dispatch() */
+ WFLAG(a->wflags, F_ATTR_MP_REACH);
+ goto optattr;
+ case ATTR_MP_UNREACH_NLRI:
+ if (attr_len < 3)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
return (-1);
+ /* the actually validity is checked in rde_update_dispatch() */
+ WFLAG(a->wflags, F_ATTR_MP_UNREACH);
goto optattr;
default:
optattr:
@@ -203,6 +221,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
u_int8_t *suberr, u_int16_t *size)
{
struct attr *a;
+ u_char *op;
u_int16_t attr_len;
u_int16_t plen = 0;
u_int8_t flags;
@@ -211,15 +230,16 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
*suberr = ERR_UPD_ATTRLEN;
*size = len;
+ op = p;
if (len < 3)
- return (p);
+ return (op);
UPD_READ(&flags, p, plen, 1);
UPD_READ(&type, p, plen, 1);
if (flags & ATTR_EXTLEN) {
if (len - plen < 2)
- return (p);
+ return (op);
UPD_READ(&attr_len, p, plen, 2);
} else {
UPD_READ(&tmp8, p, plen, 1);
@@ -227,7 +247,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
}
if (len - plen < attr_len)
- return (p);
+ return (op);
*size = attr_len;
switch (type) {
@@ -238,7 +258,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
return (NULL);
case ATTR_ORIGIN:
if (attr_len != 1)
- return (p);
+ return (op);
if (attr->wflags & F_ATTR_ORIGIN) {
*suberr = ERR_UPD_ATTRLIST;
*size = 0;
@@ -247,7 +267,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
UPD_READ(&tmp8, p, plen, 1);
if (tmp8 > ORIGIN_INCOMPLETE) {
*suberr = ERR_UPD_ORIGIN;
- return (p);
+ return (op);
}
break;
case ATTR_ASPATH:
@@ -265,7 +285,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
break;
case ATTR_NEXTHOP:
if (attr_len != 4)
- return (p);
+ return (op);
if (attr->wflags & F_ATTR_NEXTHOP) {
*suberr = ERR_UPD_ATTRLIST;
*size = 0;
@@ -274,12 +294,12 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
/* malformed nexthop detected by exclusion method */
*suberr = ERR_UPD_NETWORK;
- return (p);
+ return (op);
}
break;
case ATTR_MED:
if (attr_len != 4)
- return (p);
+ return (op);
if (attr->wflags & F_ATTR_MED) {
*suberr = ERR_UPD_ATTRLIST;
*size = 0;
@@ -288,7 +308,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
break;
case ATTR_LOCALPREF:
if (attr_len != 4)
- return (p);
+ return (op);
if (attr->wflags & F_ATTR_LOCALPREF) {
*suberr = ERR_UPD_ATTRLIST;
*size = 0;
@@ -297,29 +317,37 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
break;
case ATTR_ATOMIC_AGGREGATE:
if (attr_len != 0)
- return (p);
+ return (op);
break;
case ATTR_AGGREGATOR:
if (attr_len != 6)
- return (p);
+ return (op);
break;
case ATTR_COMMUNITIES:
if ((attr_len & 0x3) != 0)
- return (p);
+ return (op);
goto optattr;
case ATTR_ORIGINATOR_ID:
if (attr_len != 4)
- return (p);
+ return (op);
goto optattr;
case ATTR_CLUSTER_LIST:
if ((attr_len & 0x3) != 0)
- return (p);
+ return (op);
+ goto optattr;
+ case ATTR_MP_REACH_NLRI:
+ if (attr_len < 4)
+ return (op);
+ goto optattr;
+ case ATTR_MP_UNREACH_NLRI:
+ if (attr_len < 3)
+ return (op);
goto optattr;
default:
optattr:
if ((flags & ATTR_OPTIONAL) == 0) {
*suberr = ERR_UPD_UNKNWN_WK_ATTR;
- return (p);
+ return (op);
}
TAILQ_FOREACH(a, &attr->others, entry)
if (type == a->type) {
@@ -328,11 +356,11 @@ optattr:
return (NULL);
}
*suberr = ERR_UPD_OPTATTR;
- return (p);
+ return (op);
}
/* can only be a attribute flag error */
*suberr = ERR_UPD_ATTRFLAGS;
- return (p);
+ return (op);
}
#undef UPD_READ
#undef WFLAG
@@ -344,7 +372,8 @@ attr_missing(struct attr_flags *a, int ebgp)
return (ATTR_ORIGIN);
if ((a->wflags & F_ATTR_ASPATH) == 0)
return (ATTR_ASPATH);
- if ((a->wflags & F_ATTR_NEXTHOP) == 0)
+ if ((a->wflags & F_ATTR_MP_REACH) == 0 &&
+ (a->wflags & F_ATTR_NEXTHOP) == 0)
return (ATTR_NEXTHOP);
if (!ebgp)
if ((a->wflags & F_ATTR_LOCALPREF) == 0)
@@ -362,6 +391,10 @@ attr_compare(struct attr_flags *a, struct attr_flags *b)
return (1);
if (a->origin < b->origin)
return (-1);
+ if ((a->wflags & F_ATTR_NEXTHOP) && (b->wflags & F_ATTR_NEXTHOP) == 0)
+ return (1);
+ if ((b->wflags & F_ATTR_NEXTHOP) && (a->wflags & F_ATTR_NEXTHOP) == 0)
+ return (-1);
if (a->nexthop.s_addr > b->nexthop.s_addr)
return (1);
if (a->nexthop.s_addr < b->nexthop.s_addr)
@@ -518,7 +551,7 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
}
struct attr *
-attr_optget(struct attr_flags *attr, u_int8_t type)
+attr_optget(const struct attr_flags *attr, u_int8_t type)
{
struct attr *a;
@@ -544,6 +577,94 @@ attr_optfree(struct attr_flags *attr)
}
}
+int
+attr_ismp(const struct attr_flags *attr)
+{
+ return (attr->wflags & F_ATTR_MP_REACH);
+}
+
+int
+attr_mp_nexthop_check(u_char *data, u_int16_t len, u_int16_t afi)
+{
+ u_int8_t nh_len;
+
+ if (len == 0)
+ return (-1);
+
+ nh_len = *data++;
+ len--;
+
+ if (nh_len > len)
+ return (-1);
+
+ switch (afi) {
+ case AFI_IPv6:
+ if (nh_len != 16 && nh_len != 32) {
+ log_warnx("bad multiprotocol nexthop, bad size");
+ return (-1);
+ }
+ return (nh_len + 1);
+ default:
+ log_warnx("bad multiprotocol nexthop, bad AF");
+ break;
+ }
+
+ return (-1);
+}
+
+/*
+ * this function may only be called after attr_mp_nexthop_check()
+ */
+struct bgpd_addr *
+attr_mp_nexthop(const struct attr_flags *attrs)
+{
+ static struct bgpd_addr address;
+ struct attr *mpattr;
+ u_int8_t *p;
+ u_int16_t afi;
+ u_int8_t nhlen;
+
+ if ((mpattr = attr_optget(attrs, ATTR_MP_REACH_NLRI)) == NULL) {
+ log_warnx("attr_mp_nexthop: no MP_REACH_NLRI available");
+ return (NULL);
+ }
+ p = mpattr->data;
+ if (mpattr->len < 4)
+ fatalx("Who fucked up the code? King Bula?");
+
+ memcpy(&afi, p, 2);
+ afi = ntohs(afi);
+ p += 3;
+
+ nhlen = *p++;
+ if (nhlen > mpattr->len)
+ fatalx("Who fucked up the code? King Bula?");
+
+ bzero(&address, sizeof(address));
+ switch (afi) {
+ case AFI_IPv6:
+ address.af = AF_INET6;
+ if (nhlen == 16) {
+ memcpy(&address.v6.s6_addr, p, 16);
+ return (&address);
+ }
+ if (nhlen == 32) {
+ /*
+ * XXX acctually the link lokal address should be used
+ * for kroute and the global one updates.
+ */
+ memcpy(&address.v6.s6_addr, p, 16);
+ return (&address);
+ }
+ fatalx("Who fucked up the code? King Bula?");
+ default:
+ fatalx("attr_mp_nexthop: unsupported AF");
+ }
+
+ /* NOTREACHED */
+ return (NULL);
+}
+
/* aspath specific functions */
static u_int16_t aspath_extract(void *, int);
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index 38704d1ba0e..cd01ce65082 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.10 2004/06/20 18:35:12 henning Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.11 2004/06/24 23:15:58 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -95,7 +95,6 @@ int
rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
struct bgpd_addr *prefix, u_int8_t plen)
{
- in_addr_t mask;
if (attrs != NULL && f->match.as.type != AS_NONE)
if (aspath_match(attrs->aspath, f->match.as.type,
@@ -109,16 +108,9 @@ rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
if (f->match.prefix.addr.af != 0 &&
f->match.prefix.addr.af == prefix->af) {
- switch (f->match.prefix.addr.af) {
- case AF_INET:
- mask = htonl(0xffffffff << (32 - f->match.prefix.len));
- if ((prefix->v4.s_addr & mask) !=
- (f->match.prefix.addr.v4.s_addr & mask))
- return (0);
- break;
- default:
- fatalx("rde_filter_match: unsupported address family");
- }
+ if (prefix_equal(prefix, &f->match.prefix.addr,
+ f->match.prefix.len) != 0)
+ return (0);
/* test prefixlen stuff too */
switch (f->match.prefixlen.op) {