-.\" $OpenBSD: bgpd.conf.5,v 1.241 2024/08/12 09:04:23 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.242 2024/08/14 19:09:51 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 12 2024 $
+.Dd $Mdocdate: August 14 2024 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
.Ic Loc-RIB ,
which are created automatically and used by default.
.Pp
+.It Ic rde rib Loc-RIB include filtered
+Include filtered prefixes in the
+.Ic Loc-RIB .
+Filtered prefixes are not eligible by the decision process but can be
+displayed by
+.Xr bgpctl 8 .
+.Pp
.It Xo
.Ic rde
.Ic route-age
-/* $OpenBSD: bgpd.h,v 1.494 2024/08/12 09:04:23 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.495 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
#define F_CTL_AVS_VALID 0x1000000
#define F_CTL_AVS_INVALID 0x2000000
#define F_CTL_AVS_UNKNOWN 0x4000000
+#define F_CTL_FILTERED 0x8000000 /* only set on requests */
#define F_CTL_SSV 0x80000000 /* only used by bgpctl */
#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \
uint16_t min_holdtime;
uint16_t connectretry;
uint8_t fib_priority;
+ uint8_t filtered_in_locrib;
};
extern int cmd_opts;
#define F_PREF_OTC_LEAK 0x080
#define F_PREF_ECMP 0x100
#define F_PREF_AS_WIDE 0x200
+#define F_PREF_FILTERED 0x400
struct ctl_show_rib {
struct bgpd_addr true_nexthop;
-/* $OpenBSD: config.c,v 1.109 2024/05/22 08:41:14 claudio Exp $ */
+/* $OpenBSD: config.c,v 1.110 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
to->min_holdtime = from->min_holdtime;
to->connectretry = from->connectretry;
to->fib_priority = from->fib_priority;
+ to->filtered_in_locrib = from->filtered_in_locrib;
}
void
-/* $OpenBSD: parse.y,v 1.464 2024/08/12 09:04:23 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.465 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
%token SEND RECV PLUS POLICY ROLE
%token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
%token DUMP IN OUT SOCKET RESTRICTED
-%token LOG TRANSPARENT
+%token LOG TRANSPARENT FILTERED
%token TCP MD5SIG PASSWORD KEY TTLSECURITY
%token ALLOW DENY MATCH
%token QUICK
}
free($3);
}
+ | RDE RIB STRING INCLUDE FILTERED {
+ if (strcmp($3, "Loc-RIB") != 0) {
+ yyerror("include filtered only supported in "
+ "Loc-RIB");
+ YYERROR;
+ }
+ conf->filtered_in_locrib = 1;
+ }
| NEXTHOP QUALIFY VIA STRING {
if (!strcmp($4, "bgp"))
conf->flags |= BGPD_FLAG_NEXTHOP_BGP;
{ "ext-community", EXTCOMMUNITY},
{ "fib-priority", FIBPRIORITY},
{ "fib-update", FIBUPDATE},
+ { "filtered", FILTERED},
{ "flags", FLAGS},
{ "flowspec", FLOWSPEC},
{ "fragment", FRAGMENT},
-/* $OpenBSD: printconf.c,v 1.173 2024/05/22 08:41:14 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.174 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
print_l3vpn(vpn);
printf("\n");
+ if (conf->filtered_in_locrib)
+ printf("rde rib Loc-RIB include filtered\n");
SIMPLEQ_FOREACH(rr, rib_l, entry) {
if (rr->flags & F_RIB_NOEVALUATE)
printf("rde rib %s no evaluate\n", rr->name);
-/* $OpenBSD: rde.c,v 1.625 2024/05/22 08:41:14 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.626 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
path_id_tx = pathid_assign(peer, path_id, prefix, prefixlen);
/* add original path to the Adj-RIB-In */
if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, path_id_tx,
- in, prefix, prefixlen) == 1)
+ in, 0, prefix, prefixlen) == 1)
peer->stats.prefix_cnt++;
/* max prefix checker */
&state.nexthop->exit_nexthop, prefix,
prefixlen);
prefix_update(rib, peer, path_id, path_id_tx, &state,
- prefix, prefixlen);
- } else if (prefix_withdraw(rib, peer, path_id, prefix,
- prefixlen)) {
- rde_update_log(wmsg, i, peer,
- NULL, prefix, prefixlen);
+ 0, prefix, prefixlen);
+ } else if (conf->filtered_in_locrib && i == RIB_LOC_START) {
+ rde_update_log(wmsg, i, peer, NULL, prefix, prefixlen);
+ prefix_update(rib, peer, path_id, path_id_tx, &state,
+ 1, prefix, prefixlen);
+ } else {
+ if (prefix_withdraw(rib, peer, path_id, prefix,
+ prefixlen))
+ rde_update_log(wmsg, i, peer,
+ NULL, prefix, prefixlen);
}
rde_filterstate_clean(&state);
rib.aspa_validation_state = prefix_aspa_vstate(p);
rib.dmetric = p->dmetric;
rib.flags = 0;
- if (!adjout) {
+ if (!adjout && prefix_eligible(p)) {
re = prefix_re(p);
TAILQ_FOREACH(xp, &re->prefix_h, entry.list.rib) {
switch (xp->dmetric) {
rib.flags |= F_PREF_ANNOUNCE;
if (prefix_eligible(p))
rib.flags |= F_PREF_ELIGIBLE;
+ if (prefix_filtered(p))
+ rib.flags |= F_PREF_FILTERED;
/* otc loop includes parse err so skip the latter if the first is set */
if (asp->flags & F_ATTR_OTC_LEAK)
rib.flags |= F_PREF_OTC_LEAK;
if ((req->flags & F_CTL_INVALID) &&
(asp->flags & F_ATTR_PARSE_ERR) == 0)
return;
+ if ((req->flags & F_CTL_FILTERED) && !prefix_filtered(p))
+ return;
if ((req->flags & F_CTL_INELIGIBLE) && prefix_eligible(p))
return;
if ((req->flags & F_CTL_LEAKED) &&
struct rde_prefixset_head originsets_old;
struct as_set_head as_sets_old;
uint16_t rid;
- int reload = 0;
+ int reload = 0, force_locrib = 0;
softreconfig = 0;
SIMPLEQ_CONCAT(&originsets_old, &conf->rde_originsets);
SIMPLEQ_CONCAT(&as_sets_old, &conf->as_sets);
+ /* run softreconfig in if filter mode changed */
+ if (conf->filtered_in_locrib != nconf->filtered_in_locrib) {
+ log_debug("filter mode changed, reloading Loc-Rib");
+ force_locrib = 1;
+ }
+
/* merge the main config */
copy_config(conf, nconf);
}
/* bring ribs in sync */
- for (rid = 0; rid < rib_size; rid++) {
+ for (rid = RIB_LOC_START; rid < rib_size; rid++) {
struct rib *rib = rib_byid(rid);
if (rib == NULL)
continue;
rib->state = RECONF_KEEP;
/* FALLTHROUGH */
case RECONF_KEEP:
- if (rde_filter_equal(rib->in_rules, rib->in_rules_tmp))
+ if (!(force_locrib && rid == RIB_LOC_START) &&
+ rde_filter_equal(rib->in_rules, rib->in_rules_tmp))
/* rib is in sync */
break;
- log_debug("in filter change: reloading RIB %s",
+ log_debug("filter change: reloading RIB %s",
rib->name);
rib->state = RECONF_RELOAD;
reload++;
if (action == ACTION_ALLOW) {
/* update Local-RIB */
prefix_update(rib, peer, p->path_id,
- p->path_id_tx, &state,
+ p->path_id_tx, &state, 0,
&prefix, pt->prefixlen);
- } else if (action == ACTION_DENY) {
+ } else if (conf->filtered_in_locrib &&
+ i == RIB_LOC_START) {
+ prefix_update(rib, peer, p->path_id,
+ p->path_id_tx, &state, 1,
+ &prefix, pt->prefixlen);
+ } else {
/* remove from Local-RIB */
prefix_withdraw(rib, peer, p->path_id, &prefix,
pt->prefixlen);
if (action == ACTION_ALLOW) {
/* update Local-RIB */
prefix_update(rib, peer, p->path_id,
- p->path_id_tx, &state,
+ p->path_id_tx, &state, 0,
+ &prefix, pt->prefixlen);
+ } else if (conf->filtered_in_locrib &&
+ i == RIB_LOC_START) {
+ prefix_update(rib, peer, p->path_id,
+ p->path_id_tx, &state, 1,
&prefix, pt->prefixlen);
- } else if (action == ACTION_DENY) {
+ } else {
/* remove from Local-RIB */
prefix_withdraw(rib, peer, p->path_id, &prefix,
pt->prefixlen);
path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, path_id_tx,
- state, &nc->prefix, nc->prefixlen) == 1)
+ state, 0, &nc->prefix, nc->prefixlen) == 1)
peerself->stats.prefix_cnt++;
for (i = RIB_LOC_START; i < rib_size; i++) {
struct rib *rib = rib_byid(i);
rde_update_log("announce", i, peerself,
state->nexthop ? &state->nexthop->exit_nexthop : NULL,
&nc->prefix, nc->prefixlen);
- prefix_update(rib, peerself, 0, path_id_tx, state, &nc->prefix,
- nc->prefixlen);
+ prefix_update(rib, peerself, 0, path_id_tx, state, 0,
+ &nc->prefix, nc->prefixlen);
}
filterset_free(&nc->attrset);
}
-/* $OpenBSD: rde.h,v 1.303 2024/05/29 10:36:32 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.304 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
time_t lastchange;
uint32_t path_id;
uint32_t path_id_tx;
+ uint16_t flags;
uint8_t validation_state;
uint8_t nhflags;
int8_t dmetric; /* decision metric */
- uint8_t flags;
-#define PREFIX_FLAG_WITHDRAW 0x01 /* enqueued on withdraw queue */
-#define PREFIX_FLAG_UPDATE 0x02 /* enqueued on update queue */
-#define PREFIX_FLAG_DEAD 0x04 /* locked but removed */
-#define PREFIX_FLAG_STALE 0x08 /* stale entry (graceful reload) */
-#define PREFIX_FLAG_MASK 0x0f /* mask for the prefix types */
-#define PREFIX_FLAG_ADJOUT 0x10 /* prefix is in the adj-out rib */
-#define PREFIX_FLAG_EOR 0x20 /* prefix is EoR */
-#define PREFIX_NEXTHOP_LINKED 0x40 /* prefix is linked onto nexthop list */
-#define PREFIX_FLAG_LOCKED 0x80 /* locked by rib walker */
+};
+#define PREFIX_FLAG_WITHDRAW 0x0001 /* enqueued on withdraw queue */
+#define PREFIX_FLAG_UPDATE 0x0002 /* enqueued on update queue */
+#define PREFIX_FLAG_DEAD 0x0004 /* locked but removed */
+#define PREFIX_FLAG_STALE 0x0008 /* stale entry (graceful reload) */
+#define PREFIX_FLAG_MASK 0x000f /* mask for the prefix types */
+#define PREFIX_FLAG_ADJOUT 0x0010 /* prefix is in the adj-out rib */
+#define PREFIX_FLAG_EOR 0x0020 /* prefix is EoR */
+#define PREFIX_NEXTHOP_LINKED 0x0040 /* prefix is linked onto nexthop list */
+#define PREFIX_FLAG_LOCKED 0x0080 /* locked by rib walker */
+#define PREFIX_FLAG_FILTERED 0x0100 /* prefix is filtered (ineligible) */
#define PREFIX_DMETRIC_NONE 0
#define PREFIX_DMETRIC_INVALID 1
#define PREFIX_DMETRIC_AS_WIDE 3
#define PREFIX_DMETRIC_ECMP 4
#define PREFIX_DMETRIC_BEST 5
-};
/* possible states for nhflags */
#define NEXTHOP_SELF 0x01
int);
struct prefix *prefix_adjout_match(struct rde_peer *, struct bgpd_addr *);
int prefix_update(struct rib *, struct rde_peer *, uint32_t,
- uint32_t, struct filterstate *, struct bgpd_addr *, int);
+ uint32_t, struct filterstate *, int, struct bgpd_addr *,
+ int);
int prefix_withdraw(struct rib *, struct rde_peer *, uint32_t,
struct bgpd_addr *, int);
int prefix_flowspec_update(struct rde_peer *, struct filterstate *,
return (p->entry.list.re);
}
+static inline int
+prefix_filtered(struct prefix *p)
+{
+ return ((p->flags & PREFIX_FLAG_FILTERED) != 0);
+}
+
void nexthop_shutdown(void);
int nexthop_pending(void);
void nexthop_runner(void);
-/* $OpenBSD: rde_decide.c,v 1.102 2023/10/12 14:22:08 claudio Exp $ */
+/* $OpenBSD: rde_decide.c,v 1.103 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
{
struct rde_aspath *asp = prefix_aspath(p);
+ /* prefix itself is marked ineligible */
+ if (prefix_filtered(p))
+ return 0;
+
/* The aspath needs to be loop and error free */
if (asp == NULL ||
asp->flags & (F_ATTR_LOOP|F_ATTR_OTC_LEAK|F_ATTR_PARSE_ERR))
-/* $OpenBSD: rde_rib.c,v 1.262 2024/05/29 10:34:56 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.263 2024/08/14 19:09:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
static int prefix_add(struct bgpd_addr *, int, struct rib *,
struct rde_peer *, uint32_t, uint32_t, struct rde_aspath *,
struct rde_community *, struct nexthop *,
- uint8_t, uint8_t);
+ uint8_t, uint8_t, int);
static int prefix_move(struct prefix *, struct rde_peer *,
struct rde_aspath *, struct rde_community *,
- struct nexthop *, uint8_t, uint8_t);
+ struct nexthop *, uint8_t, uint8_t, int);
static void prefix_link(struct prefix *, struct rib_entry *,
struct pt_entry *, struct rde_peer *, uint32_t, uint32_t,
*/
int
prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
- uint32_t path_id_tx, struct filterstate *state, struct bgpd_addr *prefix,
- int prefixlen)
+ uint32_t path_id_tx, struct filterstate *state, int filtered,
+ struct bgpd_addr *prefix, int prefixlen)
{
struct rde_aspath *asp, *nasp = &state->aspath;
struct rde_community *comm, *ncomm = &state->communities;
/* no change, update last change */
p->lastchange = getmonotime();
p->validation_state = state->vstate;
+ if (filtered)
+ p->flags |= PREFIX_FLAG_FILTERED;
+ else
+ p->flags &= ~PREFIX_FLAG_FILTERED;
return (0);
}
}
/* If the prefix was found move it else add it to the RIB. */
if (p != NULL)
return (prefix_move(p, peer, asp, comm, state->nexthop,
- state->nhflags, state->vstate));
+ state->nhflags, state->vstate, filtered));
else
return (prefix_add(prefix, prefixlen, rib, peer, path_id,
path_id_tx, asp, comm, state->nexthop, state->nhflags,
- state->vstate));
+ state->vstate, filtered));
}
/*
prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
struct rde_aspath *asp, struct rde_community *comm,
- struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
+ struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate, int filtered)
{
struct pt_entry *pte;
struct prefix *p;
prefix_link(p, re, re->prefix, peer, path_id, path_id_tx, asp, comm,
nexthop, nhflags, vstate);
+ if (filtered)
+ p->flags |= PREFIX_FLAG_FILTERED;
+
/* add possible pftable reference form aspath */
if (asp && asp->pftableid)
rde_pftable_add(asp->pftableid, p);
static int
prefix_move(struct prefix *p, struct rde_peer *peer,
struct rde_aspath *asp, struct rde_community *comm,
- struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
+ struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate, int filtered)
{
struct prefix *np;
prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, p->path_id_tx,
asp, comm, nexthop, nhflags, vstate);
+ if (filtered)
+ np->flags |= PREFIX_FLAG_FILTERED;
+
/* add possible pftable reference from new aspath */
if (asp && asp->pftableid)
rde_pftable_add(asp->pftableid, np);