From 55a56ce9453581c0c076464419018c1e075a6829 Mon Sep 17 00:00:00 2001 From: purplerain Date: Wed, 5 Feb 2025 06:25:40 +0000 Subject: [PATCH] sync --- distrib/miniroot/install.sub | 4 +- etc/skel/dot.profile | 1 - lib/libcrypto/bn/bn_recp.c | 102 ++++----- lib/libcrypto/evp/evp_pkey.c | 6 +- lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 | 6 +- regress/sys/netinet/tcpthread/tcpthread.c | 14 +- sys/dev/pci/if_iwm.c | 4 +- sys/dev/pci/if_iwn.c | 4 +- sys/dev/pci/if_iwx.c | 4 +- usr.sbin/bgpd/bgpd.h | 26 ++- usr.sbin/bgpd/kroute.c | 11 +- usr.sbin/bgpd/parse.y | 11 +- usr.sbin/bgpd/rde.c | 52 ++++- usr.sbin/bgpd/rde_prefix.c | 195 +++++++++++++++++- usr.sbin/bgpd/rde_update.c | 26 ++- usr.sbin/bgpd/util.c | 216 +++++++++++++++++++- 16 files changed, 572 insertions(+), 110 deletions(-) diff --git a/distrib/miniroot/install.sub b/distrib/miniroot/install.sub index 4fd103824..385cad0f1 100644 --- a/distrib/miniroot/install.sub +++ b/distrib/miniroot/install.sub @@ -2773,8 +2773,8 @@ install_sets() { # Set default location to the first cdrom device if any are found. [[ -n $_cddevs ]] && : ${_d:=cd0} - # In case none of the above applied, set HTTP as default location. - : ${_d:=http} + # In case none of the above applied, set disk as default location. + : ${_d:=disk} # If the default location set so far is not one of the cdrom devices or # is not in the list of valid locations, set a sane default. diff --git a/etc/skel/dot.profile b/etc/skel/dot.profile index e58de9075..52ff7ba68 100644 --- a/etc/skel/dot.profile +++ b/etc/skel/dot.profile @@ -3,5 +3,4 @@ # sh/ksh initialization PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin -export PS1="\[\033[38;5;69m\]┌─(\[\033[38;5;15m\]\u\[\033[38;5;69m\]@\[\033[38;5;15m\]\h\[\033[38;5;69m\])\[\033[38;5;69m\]─[\[\033[38;5;69m\]\w\[\033[38;5;69m\]]\n\[\033[38;5;69m\]└─$\[$(tput sgr0)\] " export PATH HOME TERM diff --git a/lib/libcrypto/bn/bn_recp.c b/lib/libcrypto/bn/bn_recp.c index 8f917e95d..e3f22c52a 100644 --- a/lib/libcrypto/bn/bn_recp.c +++ b/lib/libcrypto/bn/bn_recp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bn_recp.c,v 1.30 2025/01/22 12:53:16 tb Exp $ */ +/* $OpenBSD: bn_recp.c,v 1.33 2025/02/04 20:22:20 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -104,34 +104,6 @@ BN_RECP_CTX_free(BN_RECP_CTX *recp) freezero(recp, sizeof(*recp)); } -/* len is the expected size of the result - * We actually calculate with an extra word of precision, so - * we can do faster division if the remainder is not required. - */ -/* r := 2^len / m */ -static int -BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx) -{ - int ret = -1; - BIGNUM *t; - - BN_CTX_start(ctx); - if ((t = BN_CTX_get(ctx)) == NULL) - goto err; - - if (!BN_set_bit(t, len)) - goto err; - - if (!BN_div_ct(r, NULL, t, m, ctx)) - goto err; - - ret = len; - -err: - BN_CTX_end(ctx); - return ret; -} - int BN_div_reciprocal(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp, BN_CTX *ctx) @@ -139,34 +111,33 @@ BN_div_reciprocal(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp, int i, j, ret = 0; BIGNUM *a, *b, *d, *r; - BN_CTX_start(ctx); - a = BN_CTX_get(ctx); - b = BN_CTX_get(ctx); - if (dv != NULL) - d = dv; - else - d = BN_CTX_get(ctx); - if (rem != NULL) - r = rem; - else - r = BN_CTX_get(ctx); - if (a == NULL || b == NULL || d == NULL || r == NULL) - goto err; - if (BN_ucmp(m, recp->N) < 0) { - BN_zero(d); - if (!bn_copy(r, m)) { - BN_CTX_end(ctx); - return 0; - } - BN_CTX_end(ctx); + if (dv != NULL) + BN_zero(dv); + if (rem != NULL) + return bn_copy(rem, m); return 1; } - /* We want the remainder - * Given input of ABCDEF / ab - * we need multiply ABCDEF by 3 digests of the reciprocal of ab - * + BN_CTX_start(ctx); + if ((a = BN_CTX_get(ctx)) == NULL) + goto err; + if ((b = BN_CTX_get(ctx)) == NULL) + goto err; + + if ((d = dv) == NULL) + d = BN_CTX_get(ctx); + if (d == NULL) + goto err; + + if ((r = rem) == NULL) + r = BN_CTX_get(ctx); + if (r == NULL) + goto err; + + /* + * We want the remainder. Given input of ABCDEF / ab we need to + * multiply ABCDEF by 3 digits of the reciprocal of ab. */ /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */ @@ -175,18 +146,21 @@ BN_div_reciprocal(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp, if (j > i) i = j; - /* Nr := round(2^i / N) */ - if (i != recp->shift) - recp->shift = BN_reciprocal(recp->Nr, recp->N, i, ctx); + /* Compute Nr := (1 << i) / N if necessary. */ + if (i != recp->shift) { + BN_zero(recp->Nr); + if (!BN_set_bit(recp->Nr, i)) + goto err; + if (!BN_div_ct(recp->Nr, NULL, recp->Nr, recp->N, ctx)) + goto err; + recp->shift = i; + } - /* BN_reciprocal returns i, or -1 for an error */ - if (recp->shift == -1) - goto err; - - /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))| - * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))| - * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)| - * = |m/N| + /* + * d := |((m >> BN_num_bits(N)) * recp->Nr) >> (i - BN_num_bits(N))| + * = |((m >> BN_num_bits(N)) * (1 << i) / N) >> (i - BN_num_bits(N))| + * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * 2^BN_num_bits(N) / 2^i | + * = |m / N| */ if (!BN_rshift(a, m, recp->num_bits)) goto err; diff --git a/lib/libcrypto/evp/evp_pkey.c b/lib/libcrypto/evp/evp_pkey.c index 5bec81106..a1e127352 100644 --- a/lib/libcrypto/evp/evp_pkey.c +++ b/lib/libcrypto/evp/evp_pkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: evp_pkey.c,v 1.32 2024/08/31 10:25:38 tb Exp $ */ +/* $OpenBSD: evp_pkey.c,v 1.33 2025/02/04 04:51:34 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 1999. */ @@ -58,6 +58,7 @@ #include #include +#include #include #include @@ -84,7 +85,8 @@ EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8) if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) { EVPerror(EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); - i2t_ASN1_OBJECT(obj_tmp, 80, algoid); + if (i2t_ASN1_OBJECT(obj_tmp, sizeof(obj_tmp), algoid) == 0) + (void)strlcpy(obj_tmp, "unknown", sizeof(obj_tmp)); ERR_asprintf_error_data("TYPE=%s", obj_tmp); goto error; } diff --git a/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 b/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 index 42f68e0a3..2317c57af 100644 --- a/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 +++ b/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: SSL_CTX_set_alpn_select_cb.3,v 1.10 2024/07/11 13:50:44 tb Exp $ +.\" $OpenBSD: SSL_CTX_set_alpn_select_cb.3,v 1.11 2025/02/04 14:00:05 tb Exp $ .\" OpenSSL 87b81496 Apr 19 12:38:27 2017 -0400 .\" OpenSSL b97fdb57 Nov 11 09:33:09 2016 +0100 .\" @@ -49,7 +49,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED .\" OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: July 11 2024 $ +.Dd $Mdocdate: February 4 2025 $ .Dt SSL_CTX_SET_ALPN_SELECT_CB 3 .Os .Sh NAME @@ -215,7 +215,7 @@ variable. .Pp For example: .Bd -literal -const unsigned char *vector = "\e6" "spdy/1" "\e8" "http/1.1"; +const unsigned char *vector = "\ex06" "spdy/1" "\ex08" "http/1.1"; unsigned int length = strlen(vector); .Ed .Pp diff --git a/regress/sys/netinet/tcpthread/tcpthread.c b/regress/sys/netinet/tcpthread/tcpthread.c index 4adbc29e7..11379f174 100644 --- a/regress/sys/netinet/tcpthread/tcpthread.c +++ b/regress/sys/netinet/tcpthread/tcpthread.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcpthread.c,v 1.3 2025/01/13 12:55:13 bluhm Exp $ */ +/* $OpenBSD: tcpthread.c,v 1.4 2025/02/04 22:00:20 bluhm Exp $ */ /* * Copyright (c) 2025 Alexander Bluhm @@ -114,9 +114,15 @@ connect_socket(volatile int *connectp, struct sockaddr *addr) IPPROTO_TCP); if (sock < 0) err(1, "%s: socket", __func__); - if (connect(sock, addr, addr->sa_len) < 0 && - errno != EINPROGRESS) { - err(1, "%s: connect %d", __func__, sock); + if (connect(sock, addr, addr->sa_len) < 0) { + if (errno == EADDRNOTAVAIL) { + /* kernel did run out of ports, ignore error */ + if (close(sock) < 0) + err(1, "%s: close %d", __func__, sock); + return 0; + } + if (errno != EINPROGRESS) + err(1, "%s: connect %d", __func__, sock); } if ((int)atomic_cas_uint(connectp, -1, sock) != -1) { /* another thread has connect slot n */ diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index d4638039e..0a450412d 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwm.c,v 1.417 2024/09/01 03:08:59 jsg Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.418 2025/02/04 09:15:04 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh @@ -8529,7 +8529,7 @@ iwm_scan(struct iwm_softc *sc) * The current mode might have been fixed during association. * Ensure all channels get scanned. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWM_FLAG_SCANNING; diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 85a0d4868..f219e7d74 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.263 2024/05/24 06:02:53 jsg Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.264 2025/02/04 09:15:04 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini @@ -5356,7 +5356,7 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan) * The current mode might have been fixed during association. * Ensure all channels get scanned. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWN_FLAG_SCANNING; diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c index 6ff1a1316..28a7419d8 100644 --- a/sys/dev/pci/if_iwx.c +++ b/sys/dev/pci/if_iwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwx.c,v 1.188 2024/11/08 09:12:46 kettenis Exp $ */ +/* $OpenBSD: if_iwx.c,v 1.189 2025/02/04 09:15:04 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh @@ -7877,7 +7877,7 @@ iwx_scan(struct iwx_softc *sc) * The current mode might have been fixed during association. * Ensure all channels get scanned. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWX_FLAG_SCANNING; diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index d0a3fb4c7..b2ae8a194 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.511 2025/01/31 13:40:23 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.512 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -197,15 +198,33 @@ extern const struct aid aid_vals[]; { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" }, \ { AFI_IPv4, AF_INET, SAFI_FLOWSPEC, "IPv4 flowspec" }, \ { AFI_IPv6, AF_INET6, SAFI_FLOWSPEC, "IPv6 flowspec" }, \ - { AFI_L2VPN, AF_UNSPEC, SAFI_EVPN, "L2VPN evpn" } \ + { AFI_L2VPN, AF_UNSPEC, SAFI_EVPN, "EVPN" }, \ } #define BGP_MPLS_BOS 0x01 +#define ESI_ADDR_LEN 10 + +#define EVPN_ROUTE_TYPE_2 0x02 +#define EVPN_ROUTE_TYPE_3 0x03 +#define EVPN_ROUTE_TYPE_5 0x05 + +struct evpn_addr { + union { + struct in_addr v4; + struct in6_addr v6; + }; + uint32_t ethtag; + uint8_t mac[ETHER_ADDR_LEN]; + uint8_t esi[ESI_ADDR_LEN]; + uint8_t aid; + uint8_t type; +}; struct bgpd_addr { union { struct in_addr v4; struct in6_addr v6; + struct evpn_addr evpn; /* maximum size for a prefix is 256 bits */ }; /* 128-bit address */ uint64_t rd; /* route distinguisher for VPN addrs */ @@ -1578,6 +1597,8 @@ time_t getmonotime(void); /* util.c */ char *ibuf_get_string(struct ibuf *, size_t); const char *log_addr(const struct bgpd_addr *); +const char *log_evpnaddr(const struct bgpd_addr *, struct sockaddr *, + socklen_t); const char *log_in6addr(const struct in6_addr *); const char *log_sockaddr(struct sockaddr *, socklen_t); const char *log_as(uint32_t); @@ -1605,6 +1626,7 @@ int nlri_get_vpn4(struct ibuf *, struct bgpd_addr *, uint8_t *, int); int nlri_get_vpn6(struct ibuf *, struct bgpd_addr *, uint8_t *, int); +int nlri_get_evpn(struct ibuf *, struct bgpd_addr *, uint8_t *); int prefix_compare(const struct bgpd_addr *, const struct bgpd_addr *, int); void inet4applymask(struct in_addr *, const struct in_addr *, int); diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c index 17f412f87..fe0e26001 100644 --- a/usr.sbin/bgpd/kroute.c +++ b/usr.sbin/bgpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.312 2025/01/27 15:22:11 claudio Exp $ */ +/* $OpenBSD: kroute.c,v 1.313 2025/02/04 16:07:46 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -1338,13 +1338,8 @@ ktable_postload(void) if (kt->state == RECONF_DELETE) { ktable_free(i - 1); continue; - } else if (kt->state == RECONF_REINIT) { - if (kt->fib_sync != kt->fib_conf) { - kt->fib_sync = kt->fib_conf; - if (kt->fib_sync) - fetchtable(kt); - } - } + } else if (kt->state == RECONF_REINIT) + kt->fib_sync = kt->fib_conf; /* cleanup old networks */ TAILQ_FOREACH_SAFE(n, &kt->krn, entry, xn) { diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 97a88a8b6..807050165 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.478 2025/01/31 13:40:23 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.479 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -267,7 +267,7 @@ typedef struct { %token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY %token ERROR INCLUDE %token IPSEC ESP AH SPI IKE -%token IPV4 IPV6 +%token IPV4 IPV6 EVPN %token QUALIFY VIA %token NE LE GE XRANGE LONGER MAXLEN MAX %token STRING @@ -1970,6 +1970,12 @@ peeropts : REMOTEAS as4number { curpeer->conf.capabilities.mp[aid] = 1; } } + | ANNOUNCE EVPN enforce { + if ($3) + curpeer->conf.capabilities.mp[AID_EVPN] = 2; + else + curpeer->conf.capabilities.mp[AID_EVPN] = 1; + } | ANNOUNCE REFRESH yesnoenforce { curpeer->conf.capabilities.refresh = $3; } @@ -3546,6 +3552,7 @@ lookup(char *s) /* this has to be sorted always */ static const struct keywords keywords[] = { { "AS", AS }, + { "EVPN", EVPN }, { "IPv4", IPV4 }, { "IPv6", IPV6 }, { "add-path", ADDPATH }, diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 01fab729a..06f0fd42a 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.650 2025/01/27 15:22:11 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.651 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -1596,6 +1596,16 @@ rde_update_dispatch(struct rde_peer *peer, struct ibuf *buf) goto done; } break; + case AID_EVPN: + if (nlri_get_evpn(&unreachbuf, + &prefix, &prefixlen) == -1) { + log_peer_warnx(&peer->conf, + "bad EVPN withdraw prefix"); + rde_update_err(peer, ERR_UPDATE, + ERR_UPD_OPTATTR, &unreachbuf); + goto done; + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: /* ignore flowspec for now */ @@ -1790,6 +1800,16 @@ rde_update_dispatch(struct rde_peer *peer, struct ibuf *buf) goto done; } break; + case AID_EVPN: + if (nlri_get_evpn(&reachbuf, + &prefix, &prefixlen) == -1) { + log_peer_warnx(&peer->conf, + "bad EVPN nlri prefix"); + rde_update_err(peer, ERR_UPDATE, + ERR_UPD_OPTATTR, &reachbuf); + goto done; + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: /* ignore flowspec for now */ @@ -2517,6 +2537,36 @@ rde_get_mp_nexthop(struct ibuf *buf, uint8_t aid, } } break; + case AID_EVPN: + switch (nhlen) { + case 4: + if (ibuf_get_h32(&nhbuf, &nexthop.v4.s_addr) == -1) + return (-1); + nexthop.aid = AID_INET; + break; + case 16: + case 32: + if (ibuf_get(&nhbuf, &nexthop.v6, + sizeof(nexthop.v6)) == -1) + return (-1); + nexthop.aid = AID_INET6; + if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) { + if (peer->local_if_scope != 0) { + nexthop.scope_id = peer->local_if_scope; + } else { + log_peer_warnx(&peer->conf, + "unexpected link-local nexthop: %s", + log_addr(&nexthop)); + return (-1); + } + } + break; + default: + log_peer_warnx(&peer->conf, "bad %s nexthop, " + "bad size %d", aid2str(aid), nhlen); + return (-1); + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: /* nexthop must be 0 and ignored for flowspec */ diff --git a/usr.sbin/bgpd/rde_prefix.c b/usr.sbin/bgpd/rde_prefix.c index 86a45333b..281bc0ff1 100644 --- a/usr.sbin/bgpd/rde_prefix.c +++ b/usr.sbin/bgpd/rde_prefix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_prefix.c,v 1.56 2024/12/30 17:14:02 denis Exp $ */ +/* $OpenBSD: rde_prefix.c,v 1.57 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -95,6 +95,26 @@ struct pt_entry_vpn6 { uint8_t pad2; }; +struct pt_entry_evpn { + RB_ENTRY(pt_entry) pt_e; + uint8_t aid; + uint8_t prefixlen; + uint16_t len; + uint32_t refcnt; + uint64_t rd; + uint32_t ethtag; + uint8_t esi[ESI_ADDR_LEN]; + uint8_t mac[ETHER_ADDR_LEN]; + uint8_t labelstack[6]; + uint8_t labellen; + uint8_t type; + uint8_t vpnaid; + union { + struct in_addr prefix4; + struct in6_addr prefix6; + }; +}; + struct pt_entry_flow { RB_ENTRY(pt_entry) pt_e; uint8_t aid; @@ -130,6 +150,7 @@ void pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) { struct pt_entry_flow *pflow; + struct pt_entry_evpn *evpn; memset(addr, 0, sizeof(struct bgpd_addr)); addr->aid = pte->aid; @@ -157,6 +178,25 @@ pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) ((struct pt_entry_vpn6 *)pte)->labelstack, addr->labellen); break; + case AID_EVPN: + evpn = (struct pt_entry_evpn *)pte; + addr->evpn.type = evpn->type; + addr->rd = evpn->rd; + addr->evpn.ethtag = evpn->ethtag; + addr->labellen = evpn->labellen; + addr->evpn.aid = evpn->vpnaid; + memcpy(addr->labelstack, evpn->labelstack, addr->labellen); + memcpy(addr->evpn.esi, evpn->esi, sizeof(evpn->esi)); + memcpy(addr->evpn.mac, evpn->mac, sizeof(evpn->mac)); + switch (evpn->vpnaid) { + case AID_INET: + addr->evpn.v4 = evpn->prefix4; + break; + case AID_INET6: + addr->evpn.v6 = evpn->prefix6; + break; + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: pflow = (struct pt_entry_flow *)pte; @@ -192,6 +232,7 @@ pt_fill(struct bgpd_addr *prefix, int prefixlen) static struct pt_entry6 pte6; static struct pt_entry_vpn4 pte_vpn4; static struct pt_entry_vpn6 pte_vpn6; + static struct pt_entry_evpn pte_evpn; switch (prefix->aid) { case AID_INET: @@ -242,6 +283,37 @@ pt_fill(struct bgpd_addr *prefix, int prefixlen) memcpy(pte_vpn6.labelstack, prefix->labelstack, prefix->labellen); return ((struct pt_entry *)&pte_vpn6); + case AID_EVPN: + memset(&pte_evpn, 0, sizeof(pte_evpn)); + pte_evpn.len = sizeof(pte_evpn); + pte_evpn.refcnt = UINT32_MAX; + switch (prefix->evpn.aid) { + case AID_UNSPEC: + /* See rfc7432 section 7.2 */ + break; + case AID_INET: + pte_evpn.prefix4 = prefix->evpn.v4; + break; + case AID_INET6: + pte_evpn.prefix6 = prefix->evpn.v6; + break; + default: + fatalx("pt_fill: bad EVPN prefixlen"); + } + pte_evpn.aid = prefix->aid; + pte_evpn.vpnaid = prefix->evpn.aid; + pte_evpn.prefixlen = prefixlen; + pte_evpn.type = prefix->evpn.type; + pte_evpn.rd = prefix->rd; + pte_evpn.ethtag = prefix->evpn.ethtag; + pte_evpn.labellen = prefix->labellen; + memcpy(pte_evpn.labelstack, prefix->labelstack, + pte_evpn.labellen); + memcpy(pte_evpn.esi, prefix->evpn.esi, + sizeof(prefix->evpn.esi)); + memcpy(pte_evpn.mac, prefix->evpn.mac, + sizeof(prefix->evpn.mac)); + return ((struct pt_entry *)&pte_evpn); default: fatalx("pt_fill: unknown af"); } @@ -357,6 +429,7 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) const struct pt_entry_vpn4 *va4, *vb4; const struct pt_entry_vpn6 *va6, *vb6; const struct pt_entry_flow *af, *bf; + const struct pt_entry_evpn *ea, *eb; int i; if (a->aid > b->aid) @@ -425,6 +498,47 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) if (va6->prefixlen < vb6->prefixlen) return (-1); return (0); + case AID_EVPN: + /* XXXX Need different comparator for different types */ + ea = (const struct pt_entry_evpn *)a; + eb = (const struct pt_entry_evpn *)b; + if (ea->ethtag > eb->ethtag) + return (1); + if (ea->ethtag < eb->ethtag) + return (-1); + /* MAC length is always 48 */ + i = memcmp(&ea->mac, &eb->mac, sizeof(ea->mac)); + if (i > 0) + return (1); + if (i < 0) + return (-1); + if (ea->prefixlen > eb->prefixlen) + return (1); + if (ea->prefixlen < eb->prefixlen) + return (-1); + switch (ea->vpnaid) { + case AID_UNSPEC: + break; + case AID_INET: + i = memcmp(&ea->prefix4, &eb->prefix4, + sizeof(struct in_addr)); + if (i > 0) + return (1); + if (i < 0) + return (-1); + break; + case AID_INET6: + i = memcmp(&ea->prefix6, &eb->prefix6, + sizeof(struct in6_addr)); + if (i > 0) + return (1); + if (i < 0) + return (-1); + break; + default: + fatalx("pt_prefix_cmp: unknown evpn af %d", ea->vpnaid); + } + return (0); case AID_FLOWSPECv4: case AID_FLOWSPECv6: af = (const struct pt_entry_flow *)a; @@ -433,7 +547,7 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) bf->flow, bf->len - PT_FLOW_SIZE, a->aid == AID_FLOWSPECv6); default: - fatalx("pt_prefix_cmp: unknown af"); + fatalx("pt_prefix_cmp: unknown af %d", a->aid); } return (-1); } @@ -474,9 +588,10 @@ pt_writebuf(struct ibuf *buf, struct pt_entry *pte, int withdraw, struct pt_entry_vpn4 *pvpn4 = (struct pt_entry_vpn4 *)pte; struct pt_entry_vpn6 *pvpn6 = (struct pt_entry_vpn6 *)pte; struct pt_entry_flow *pflow = (struct pt_entry_flow *)pte; + struct pt_entry_evpn *pevpn = (struct pt_entry_evpn *)pte; struct ibuf *tmp; int flowlen, psize; - uint8_t plen; + uint16_t plen; if ((tmp = ibuf_dynamic(32, UINT16_MAX)) == NULL) goto fail; @@ -549,6 +664,80 @@ pt_writebuf(struct ibuf *buf, struct pt_entry *pte, int withdraw, ibuf_add(tmp, &pvpn6->prefix6, psize) == -1) goto fail; break; + case AID_EVPN: + if (ibuf_add_n8(tmp, pevpn->type) == -1) + goto fail; + switch (pevpn->type) { + case EVPN_ROUTE_TYPE_2: + plen = sizeof(pevpn->rd) * 8; + plen += sizeof(pevpn->esi) * 8; + plen += sizeof(pevpn->ethtag) * 8; + plen += 8; /* MAC length */ + plen += sizeof(pevpn->mac) * 8; + plen += 8; /* IP length */ + plen += pevpn->prefixlen; + plen += pevpn->labellen * 8; + if (ibuf_add_n8(tmp, PREFIX_SIZE(plen) - 1) == -1) + goto fail; + if (ibuf_add_h64(tmp, pevpn->rd) == -1 || + ibuf_add(tmp, pevpn->esi, + sizeof(pevpn->esi)) == -1 || + ibuf_add_h32(tmp, pevpn->ethtag) == -1) + goto fail; + if (ibuf_add_n8(tmp, sizeof(pevpn->mac) * 8) == -1 || + ibuf_add(tmp, pevpn->mac, sizeof(pevpn->mac)) == -1) + goto fail; + if (ibuf_add_n8(tmp, pevpn->prefixlen) == -1) + goto fail; + switch(pevpn->vpnaid) { + case AID_UNSPEC: + /* See rfc7432 section 7.2 */ + break; + case AID_INET: + if (ibuf_add(tmp, &pevpn->prefix4, + sizeof(pevpn->prefix4)) == -1) + goto fail; + break; + case AID_INET6: + if (ibuf_add(tmp, &pevpn->prefix6, + sizeof(pevpn->prefix6)) == -1) + goto fail; + break; + default: + goto fail; + } + if (ibuf_add(tmp, pevpn->labelstack, + pevpn->labellen) == -1) + goto fail; + break; + case EVPN_ROUTE_TYPE_3: + plen = sizeof(pevpn->rd) * 8; + plen += sizeof(pevpn->ethtag) * 8; + plen += 8; /* IP length */ + plen += pevpn->prefixlen; + if (ibuf_add_n8(tmp, PREFIX_SIZE(plen) - 1) == -1) + goto fail; + if (ibuf_add_h64(tmp, pevpn->rd) == -1 || + ibuf_add_h32(tmp, pevpn->ethtag) == -1) + goto fail; + if (ibuf_add_n8(tmp, pevpn->prefixlen) == -1) + goto fail; + switch(pevpn->vpnaid) { + case AID_INET: + if (ibuf_add(tmp, &pevpn->prefix4, + sizeof(pevpn->prefix4)) == -1) + goto fail; + break; + case AID_INET6: + if (ibuf_add(tmp, &pevpn->prefix6, + sizeof(pevpn->prefix6)) == -1) + goto fail; + break; + default: + goto fail; + } + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: flowlen = pflow->len - PT_FLOW_SIZE; diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c index 2639cb7be..ca11b260b 100644 --- a/usr.sbin/bgpd/rde_update.c +++ b/usr.sbin/bgpd/rde_update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_update.c,v 1.174 2025/01/13 13:50:34 claudio Exp $ */ +/* $OpenBSD: rde_update.c,v 1.175 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -478,6 +478,12 @@ up_get_nexthop(struct rde_peer *peer, struct filterstate *state, uint8_t aid) if (peer->local_v6_addr.aid == AID_INET6) peer_local = &peer->local_v6_addr; break; + case AID_EVPN: + if (peer->local_v4_addr.aid == AID_INET) + peer_local = &peer->local_v4_addr; + else if (peer->local_v6_addr.aid == AID_INET6) + peer_local = &peer->local_v6_addr; + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: /* flowspec has no nexthop */ @@ -946,6 +952,24 @@ up_generate_mp_reach(struct ibuf *buf, struct rde_peer *peer, if (ibuf_add(buf, &nexthop->v6, sizeof(nexthop->v6)) == -1) return -1; break; + case AID_EVPN: + if (nh == NULL) + return -1; + nexthop = &nh->exit_nexthop; + if (nexthop->aid == AID_INET) { + if (ibuf_add(buf, &nexthop->v4, + sizeof(nexthop->v4)) == -1) + return -1; + break; + } else if (nexthop->aid == AID_INET6) { + if (ibuf_add(buf, &nexthop->v6, + sizeof(nexthop->v6)) == -1) + return -1; + } else { + /* can't encode nexthop, give up and withdraw prefix */ + return -1; + } + break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: /* no NH */ diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index 29228d5f2..74f808a6d 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.92 2025/01/27 15:22:11 claudio Exp $ */ +/* $OpenBSD: util.c,v 1.93 2025/02/04 18:16:56 denis Exp $ */ /* * Copyright (c) 2006 Claudio Jeker @@ -49,10 +49,78 @@ log_addr(const struct bgpd_addr *addr) snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd), log_sockaddr(sa, len)); return (buf); + case AID_EVPN: + return log_evpnaddr(addr, sa, len); + break; } return ("???"); } +static const char * +log_mac(const uint8_t mac[ETHER_ADDR_LEN]) +{ + static char buf[18]; + + snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], + mac[1], mac[2], mac[3], mac[4], mac[5]); + + return (buf); +} + +static const uint8_t zero_esi[ESI_ADDR_LEN]; + +static const char * +log_esi(const uint8_t esi[ESI_ADDR_LEN]) +{ + static char buf[30]; + + if (memcmp(esi, zero_esi, sizeof(zero_esi)) == 0) + return (""); + + snprintf(buf, sizeof(buf), + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", esi[0], + esi[1], esi[2], esi[3], esi[4], esi[5], esi[6], esi[7], esi[8], + esi[9]); + + return (buf); +} + +const char * +log_evpnaddr(const struct bgpd_addr *addr, struct sockaddr *sa, + socklen_t salen) +{ + static char buf[138]; + uint32_t vni; + uint8_t len; + + switch(addr->evpn.type) { + case EVPN_ROUTE_TYPE_2: + memcpy(&vni, addr->labelstack, addr->labellen); + snprintf(buf, sizeof(buf), "[2]:[%s]:[%s]:[%d]:[48]:[%s]", + log_rd(addr->rd),log_esi(addr->evpn.esi), htonl(vni)>>8, + log_mac(addr->evpn.mac)); + if (sa != NULL) { + len = strlen(buf); + snprintf(buf+len, sizeof(buf)-len, ":[%d]:[%s]", + sa->sa_family == AF_INET ? 32 : 128, + log_sockaddr(sa, salen)); + } + break; + case EVPN_ROUTE_TYPE_3: + if (sa != NULL) { + memcpy(&vni, addr->labelstack, addr->labellen); + snprintf(buf, sizeof(buf), "[3]:[%s]:[%d]:[%s]", + log_rd(addr->rd), + sa->sa_family == AF_INET ? 32 : 128, + log_sockaddr(sa, salen)); + } + break; + default: + break; + } + return (buf); +} + const char * log_in6addr(const struct in6_addr *addr) { @@ -818,6 +886,108 @@ nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix, return (0); } +int +nlri_get_evpn(struct ibuf *buf, struct bgpd_addr *prefix, + uint8_t *prefixlen) +{ + struct ibuf evpnbuf; + uint8_t nlrilen, type, pfxlen = 0, maclen = 0; + + if (ibuf_get_n8(buf, &type) == -1) + return (-1); + if (ibuf_get_n8(buf, &nlrilen) == -1) + return (-1); + + memset(prefix, 0, sizeof(struct bgpd_addr)); + prefix->aid = AID_EVPN; + + switch (type) { + case EVPN_ROUTE_TYPE_2: + if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1) + return (-1); + prefix->evpn.type = EVPN_ROUTE_TYPE_2; + /* RD */ + if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1) + return (-1); + /* ESI */ + if (ibuf_get(&evpnbuf, &prefix->evpn.esi, + sizeof(prefix->evpn.esi)) == -1) + return (-1); + /* Ethernet Tag */ + if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1) + return (-1); + /* MAC length */ + if (ibuf_get_n8(&evpnbuf, &maclen) == -1) + return (-1); + if (maclen != 48) + return (-1); + /* MAC address */ + if (ibuf_get(&evpnbuf, &prefix->evpn.mac, + sizeof(prefix->evpn.mac)) == -1) + return (-1); + /* Prefix length */ + if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1) + return (-1); + /* Destination */ + if (pfxlen == 0) { + /* nothing */ + } else if (pfxlen == 32) { + prefix->evpn.aid = AID_INET; + if (ibuf_get(&evpnbuf, &prefix->evpn.v4, + sizeof(prefix->evpn.v4)) == -1) + return (-1); + } else if (pfxlen == 128) { + prefix->evpn.aid = AID_INET6; + if (ibuf_get(&evpnbuf, &prefix->evpn.v6, + sizeof(prefix->evpn.v6)) == -1) + return (-1); + } else + return (-1); + /* VNI */ + if (ibuf_size(&evpnbuf) != 3 && ibuf_size(&evpnbuf) != 6) + return (-1); + prefix->labellen = ibuf_size(&evpnbuf); + if (ibuf_get(&evpnbuf, prefix->labelstack, + prefix->labellen) == -1) + return (-1); + break; + case EVPN_ROUTE_TYPE_3: + if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1) + return (-1); + prefix->evpn.type = EVPN_ROUTE_TYPE_3; + /* RD */ + if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1) + return (-1); + /* Ethernet Tag */ + if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1) + return (-1); + /* Prefix length */ + if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1) + return (-1); + /* Destination */ + if (pfxlen == 32) { + prefix->evpn.aid = AID_INET; + if (ibuf_get(&evpnbuf, &prefix->evpn.v4, + sizeof(prefix->evpn.v4)) == -1) + return (-1); + } else if (pfxlen == 128) { + prefix->evpn.aid = AID_INET6; + if (ibuf_get(&evpnbuf, &prefix->evpn.v6, + sizeof(prefix->evpn.v6)) == -1) + return (-1); + } else + return (-1); + if (ibuf_size(&evpnbuf) != 0) + return (-1); + break; + default: + return (-1); + } + + *prefixlen = pfxlen; + return (0); +} + static in_addr_t prefixlen2mask(uint8_t prefixlen) { @@ -1003,6 +1173,26 @@ af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) return (-1); } +static socklen_t +addr2sa_in6(struct sockaddr_in6 *sin6, struct in6_addr in6, uint16_t port, + uint32_t scope_id) +{ + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, &in6, sizeof(sin6->sin6_addr)); + sin6->sin6_port = htons(port); + sin6->sin6_scope_id = scope_id; + return (sizeof(struct sockaddr_in6)); +} + +static socklen_t +addr2sa_in(struct sockaddr_in *sin, struct in_addr in, uint16_t port) +{ + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = in.s_addr; + sin->sin_port = htons(port); + return (sizeof(struct sockaddr_in)); +} + /* * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses * the included label stack is ignored and needs to be handled by the caller. @@ -1021,22 +1211,26 @@ addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) switch (addr->aid) { case AID_INET: case AID_VPN_IPv4: - sa_in->sin_family = AF_INET; - sa_in->sin_addr.s_addr = addr->v4.s_addr; - sa_in->sin_port = htons(port); - *len = sizeof(struct sockaddr_in); + *len = addr2sa_in(sa_in, addr->v4, port); break; case AID_INET6: case AID_VPN_IPv6: - sa_in6->sin6_family = AF_INET6; - memcpy(&sa_in6->sin6_addr, &addr->v6, - sizeof(sa_in6->sin6_addr)); - sa_in6->sin6_port = htons(port); - sa_in6->sin6_scope_id = addr->scope_id; - *len = sizeof(struct sockaddr_in6); + *len = addr2sa_in6(sa_in6, addr->v6, port, addr->scope_id); + break; + case AID_EVPN: + if (addr->evpn.aid == AID_INET) + *len = addr2sa_in(sa_in, addr->evpn.v4, port); + else if (addr->evpn.aid == AID_INET6) + *len = addr2sa_in6(sa_in6, addr->evpn.v6, port, + addr->scope_id); + else { + *len = 0; + return (NULL); + } break; case AID_FLOWSPECv4: case AID_FLOWSPECv6: + default: return (NULL); }