-/* $OpenBSD: bgpd.h,v 1.461 2023/02/09 13:43:23 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.462 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
int8_t flags[AID_MAX]; /* graceful restart per AID flags */
int8_t restart; /* graceful restart, RFC 4724 */
} grestart;
- enum role role; /* Open Policy, RFC 9234 */
int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */
int8_t add_path[AID_MAX]; /* ADD_PATH, RFC 7911 */
int8_t refresh; /* route refresh, RFC 2918 */
int8_t as4byte; /* 4-byte ASnum, RFC 4893 */
int8_t enhanced_rr; /* enhanced route refresh, RFC 7313 */
- int8_t role_ena; /* 1 for enable, 2 for enforce */
+ int8_t policy; /* Open Policy, RFC 9234, 2 = enforce */
};
/* flags for RFC 4724 - graceful restart */
-/* $OpenBSD: parse.y,v 1.441 2023/01/30 16:51:34 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.442 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
curpeer->conf.eval.maxpaths = $6;
}
| ANNOUNCE POLICY enforce {
- curpeer->conf.capabilities.role_ena = $3;
+ curpeer->conf.capabilities.policy = $3;
}
| ROLE STRING {
if (strcmp($2, "provider") == 0) {
p->conf.capabilities.refresh = 1;
p->conf.capabilities.grestart.restart = 1;
p->conf.capabilities.as4byte = 1;
+ p->conf.capabilities.policy = 1;
p->conf.local_as = conf->as;
p->conf.local_short_as = conf->short_as;
p->conf.remote_port = BGP_PORT;
}
/* BGP role and RFC 9234 role are only valid for EBGP neighbors */
- if (p->conf.ebgp) {
- if (p->conf.role == ROLE_NONE)
- p->conf.capabilities.role_ena = 0;
- p->conf.capabilities.role = p->conf.role;
- } else
+ if (!p->conf.ebgp) {
p->conf.role = ROLE_NONE;
+ p->conf.capabilities.policy = 0;
+ } else if (p->conf.role == ROLE_NONE) {
+ /* no role, no policy capability */
+ p->conf.capabilities.policy = 0;
+ }
/* check for duplicate peer definitions */
RB_FOREACH(xp, peer_head, new_peers)
-/* $OpenBSD: printconf.c,v 1.163 2023/01/24 14:13:12 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.164 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
printf(" max %d", p->eval.maxpaths);
printf("\n");
}
- if (p->capabilities.role_ena) {
+ if (p->capabilities.policy) {
printf("%s\tannounce policy %s\n", c,
- p->capabilities.role_ena == 2 ? "enforce" : "yes");
+ p->capabilities.policy == 2 ? "enforce" : "yes");
}
}
-/* $OpenBSD: rde.c,v 1.593 2023/02/13 18:07:53 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.594 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
uint16_t withdrawn_len;
uint16_t attrpath_len;
uint16_t nlri_len;
- uint8_t aid, prefixlen, safi, subtype, role;
+ uint8_t aid, prefixlen, safi, subtype;
uint32_t fas, pathid;
p = imsg->data;
}
}
- /* inject open policy OTC attribute if needed */
- if (peer_has_open_policy(peer, &role) &&
- (state.aspath.flags & F_ATTR_OTC) == 0) {
- uint32_t tmp;
- switch (role) {
- case CAPA_ROLE_PROVIDER:
- case CAPA_ROLE_RS:
- case CAPA_ROLE_PEER:
- tmp = htonl(peer->conf.remote_as);
- if (attr_optadd(&state.aspath,
- ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_OTC,
- &tmp, sizeof(tmp)) == -1) {
- rde_update_err(peer, ERR_UPDATE,
- ERR_UPD_ATTRLIST, NULL, 0);
- goto done;
- }
- state.aspath.flags |= F_ATTR_OTC;
- }
- }
-
/* aspath needs to be loop free. This is not a hard error. */
if (state.aspath.flags & F_ATTR_ASPATH &&
peer->conf.ebgp &&
NULL, 0);
goto done;
}
+
+ /* inject open policy OTC attribute if needed */
+ if ((state.aspath.flags & F_ATTR_OTC) == 0) {
+ uint32_t tmp;
+ switch (peer->role) {
+ case ROLE_CUSTOMER:
+ case ROLE_RS_CLIENT:
+ case ROLE_PEER:
+ tmp = htonl(peer->conf.remote_as);
+ if (attr_optadd(&state.aspath,
+ ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_OTC,
+ &tmp, sizeof(tmp)) == -1) {
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_ATTRLIST, NULL, 0);
+ goto done;
+ }
+ state.aspath.flags |= F_ATTR_OTC;
+ break;
+ default:
+ break;
+ }
+ }
}
while (nlri_len > 0) {
if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
goto done;
}
+ if (aid == AID_INET6) {
+ /* inject open policy OTC attribute if needed */
+ if ((state.aspath.flags & F_ATTR_OTC) == 0) {
+ uint32_t tmp;
+ switch (peer->role) {
+ case ROLE_CUSTOMER:
+ case ROLE_RS_CLIENT:
+ case ROLE_PEER:
+ tmp = htonl(peer->conf.remote_as);
+ if (attr_optadd(&state.aspath,
+ ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_OTC, &tmp,
+ sizeof(tmp)) == -1) {
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_ATTRLIST, NULL, 0);
+ goto done;
+ }
+ state.aspath.flags |= F_ATTR_OTC;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ /* Only IPv4 and IPv6 unicast do OTC handling */
+ state.aspath.flags &= ~F_ATTR_OTC_LOOP;
+ }
+
/* unlock the previously locked nexthop, it is no longer used */
nexthop_unref(state.nexthop);
state.nexthop = NULL;
int error;
uint16_t attr_len, nlen;
uint16_t plen = 0;
- uint8_t flags, type, role, tmp8;
+ uint8_t flags, type, tmp8;
if (len < 3) {
bad_len:
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
- if (peer_has_open_policy(peer, &role)) {
- switch (role) {
- case CAPA_ROLE_CUSTOMER:
- case CAPA_ROLE_RS_CLIENT:
- a->flags |= F_ATTR_OTC_LOOP | F_ATTR_PARSE_ERR;
- break;
- case CAPA_ROLE_PEER:
- memcpy(&tmp32, p, sizeof(tmp32));
- tmp32 = ntohl(tmp32);
- if (tmp32 != peer->conf.remote_as)
- a->flags |= F_ATTR_OTC_LOOP |
- F_ATTR_PARSE_ERR;
- break;
- }
+ switch (peer->role) {
+ case ROLE_PROVIDER:
+ case ROLE_RS:
+ a->flags |= F_ATTR_OTC_LOOP;
+ break;
+ case ROLE_PEER:
+ memcpy(&tmp32, p, sizeof(tmp32));
+ tmp32 = ntohl(tmp32);
+ if (tmp32 != peer->conf.remote_as)
+ a->flags |= F_ATTR_OTC_LOOP;
+ break;
+ default:
+ break;
}
a->flags |= F_ATTR_OTC;
goto optattr;
-/* $OpenBSD: rde.h,v 1.283 2023/02/13 18:07:53 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.284 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
/* rde_peer.c */
int peer_has_as4byte(struct rde_peer *);
int peer_has_add_path(struct rde_peer *, uint8_t, int);
-int peer_has_open_policy(struct rde_peer *, uint8_t *);
int peer_accept_no_as_set(struct rde_peer *);
void peer_init(void);
void peer_shutdown(void);
-/* $OpenBSD: rde_decide.c,v 1.99 2023/02/13 18:07:53 claudio Exp $ */
+/* $OpenBSD: rde_decide.c,v 1.100 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
struct rde_aspath *asp = prefix_aspath(p);
/* The aspath needs to be loop and error free */
- if (asp == NULL || asp->flags & (F_ATTR_LOOP|F_ATTR_PARSE_ERR))
+ if (asp == NULL ||
+ asp->flags & (F_ATTR_LOOP|F_ATTR_OTC_LOOP|F_ATTR_PARSE_ERR))
return 0;
/* The nexthop must be valid. */
-/* $OpenBSD: rde_peer.c,v 1.29 2023/02/13 18:07:53 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.30 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
return (peer->capa.add_path[aid] & mode);
}
-int
-peer_has_open_policy(struct rde_peer *peer, uint8_t *role)
-{
- *role = peer->capa.role;
- return (peer->capa.role_ena != 0);
-}
-
int
peer_accept_no_as_set(struct rde_peer *peer)
{
-/* $OpenBSD: rde_update.c,v 1.156 2023/02/13 18:07:53 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.157 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
if (asp == NULL || asp->flags & F_ATTR_PARSE_ERR)
fatalx("try to send out a botched path");
- if (asp->flags & F_ATTR_LOOP)
+ if (asp->flags & (F_ATTR_LOOP | F_ATTR_OTC_LOOP))
fatalx("try to send out a looped path");
if (peer == frompeer)
/* RFC9234 open policy handling */
static int
-up_enforce_open_policy(struct rde_peer *peer, struct filterstate *state)
+up_enforce_open_policy(struct rde_peer *peer, struct filterstate *state,
+ uint8_t aid)
{
- uint8_t role;
-
- if (!peer_has_open_policy(peer, &role))
+ /* only for IPv4 and IPv6 unicast */
+ if (aid != AID_INET && aid != AID_INET6)
return 0;
/*
* do not propagate (consider it filtered) if OTC is present and
- * neighbor role is peer, provider or rs.
+ * local role is peer, customer or rs-client.
*/
- if (role == CAPA_ROLE_PEER || role == CAPA_ROLE_PROVIDER ||
- role == CAPA_ROLE_RS)
+ if (peer->role == ROLE_PEER || peer->role == ROLE_CUSTOMER ||
+ peer->role == ROLE_RS_CLIENT)
if (state->aspath.flags & F_ATTR_OTC)
- return (1);
+ return 1;
/*
- * add OTC attribute if not present for peers, customers and rs-clients.
+ * add OTC attribute if not present towards peers, customers and
+ * rs-clients (local roles peer, provider, rs).
*/
- if (role == CAPA_ROLE_PEER || role == CAPA_ROLE_CUSTOMER ||
- role == CAPA_ROLE_RS_CLIENT)
+ if (peer->role == ROLE_PEER || peer->role == ROLE_PROVIDER ||
+ peer->role == ROLE_RS)
if ((state->aspath.flags & F_ATTR_OTC) == 0) {
uint32_t tmp;
}
/* Open Policy Check: acts like an output filter */
- if (up_enforce_open_policy(peer, &state)) {
+ if (up_enforce_open_policy(peer, &state, addr->aid)) {
rde_filterstate_clean(&state);
return UP_FILTERED;
}
-/* $OpenBSD: session.c,v 1.441 2023/02/14 15:37:45 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.442 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
errs += session_capa_add(opb, CAPA_REFRESH, 0);
/* BGP open policy, RFC 9234, only for ebgp sessions */
- if (p->conf.ebgp && p->capa.ann.role_ena &&
- p->capa.ann.role != ROLE_NONE) {
+ if (p->conf.ebgp && p->capa.ann.policy &&
+ p->conf.role != ROLE_NONE &&
+ (p->capa.ann.mp[AID_INET] || p->capa.ann.mp[AID_INET6] ||
+ mpcapa == 0)) {
uint8_t val;
- val = role2capa(p->capa.ann.role);
+ val = role2capa(p->conf.role);
errs += session_capa_add(opb, CAPA_ROLE, 1);
errs += ibuf_add(opb, &val, 1);
}
"disabling route refresh capability");
break;
case CAPA_ROLE:
- peer->capa.ann.role_ena = 0;
- log_peer_warnx(&peer->conf,
- "disabling role capability");
+ if (peer->capa.ann.policy == 1) {
+ peer->capa.ann.policy = 0;
+ log_peer_warnx(&peer->conf,
+ "disabling role capability");
+ } else {
+ log_peer_warnx(&peer->conf,
+ "role capability enforced, "
+ "not disabling");
+ }
break;
case CAPA_RESTART:
peer->capa.ann.grestart.restart = 0;
"Bad role capability length: %u", capa_len);
break;
}
- if (!peer->conf.ebgp)
+ if (!peer->conf.ebgp) {
log_peer_warnx(&peer->conf,
"Received role capability on iBGP session");
- peer->capa.peer.role_ena = 1;
- peer->capa.peer.role = capa2role(*capa_val);
+ break;
+ }
+ peer->capa.peer.policy = 1;
+ peer->remote_role = capa2role(*capa_val);
break;
case CAPA_RESTART:
if (capa_len == 2) {
* See RFC 9234, section 4.2.
* These checks should only happen on ebgp sessions.
*/
- if (p->capa.ann.role_ena != 0 && p->capa.peer.role_ena != 0 &&
+ if (p->capa.ann.policy != 0 && p->capa.peer.policy != 0 &&
p->conf.ebgp) {
- switch (p->capa.ann.role) {
+ switch (p->conf.role) {
case ROLE_PROVIDER:
- if (p->capa.peer.role != ROLE_CUSTOMER)
+ if (p->remote_role != ROLE_CUSTOMER)
goto fail;
break;
case ROLE_RS:
- if (p->capa.peer.role != ROLE_RS_CLIENT)
+ if (p->remote_role != ROLE_RS_CLIENT)
goto fail;
break;
case ROLE_RS_CLIENT:
- if (p->capa.peer.role != ROLE_RS)
+ if (p->remote_role != ROLE_RS)
goto fail;
break;
case ROLE_CUSTOMER:
- if (p->capa.peer.role != ROLE_PROVIDER)
+ if (p->remote_role != ROLE_PROVIDER)
goto fail;
break;
case ROLE_PEER:
- if (p->capa.peer.role != ROLE_PEER)
+ if (p->remote_role != ROLE_PEER)
goto fail;
break;
default:
fail:
log_peer_warnx(&p->conf, "open policy role mismatch: "
- "%s vs %s", log_policy(p->capa.ann.role),
- log_policy(p->capa.peer.role));
+ "our role %s, their role %s",
+ log_policy(p->conf.role),
+ log_policy(p->remote_role));
*suberr = ERR_OPEN_ROLE;
return (-1);
}
- p->capa.neg.role_ena = 1;
- p->capa.neg.role = p->capa.peer.role;
- } else if (p->capa.ann.role_ena == 2 && p->conf.ebgp) {
+ p->capa.neg.policy = 1;
+ } else if (p->capa.ann.policy == 2 && p->conf.ebgp) {
/* enforce presence of open policy role capability */
log_peer_warnx(&p->conf, "open policy role enforced but "
"not present");
-/* $OpenBSD: session.h,v 1.159 2023/02/09 13:43:23 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.160 2023/03/09 13:12:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
enum session_state state;
enum session_state prev_state;
enum reconf_action reconf_action;
+ enum role remote_role;
uint16_t short_as;
uint16_t holdtime;
uint16_t local_port;