diff --git a/etc/rpki/apnic.constraints b/etc/rpki/apnic.constraints index 276409ade..449555a46 100644 --- a/etc/rpki/apnic.constraints +++ b/etc/rpki/apnic.constraints @@ -1,4 +1,4 @@ -# $OpenBSD: apnic.constraints,v 1.4 2023/12/26 13:36:18 job Exp $ +# $OpenBSD: apnic.constraints,v 1.5 2024/01/30 03:40:01 job Exp $ # From https://www.iana.org/assignments/ipv6-unicast-address-assignments allow 2001:200::/23 @@ -13,7 +13,15 @@ allow 2400::/12 # IX Assignments allow 2001:7fa::/32 -# AFRINIC Internet Number Resources cannot be transferred +# LACNIC ASNs cannot be transferred to APNIC +# From https://www.iana.org/assignments/as-numbers/as-numbers.xhtml +deny 27648 - 28671 +deny 52224 - 53247 +deny 61440 - 61951 +deny 64099 - 64197 +deny 262144 - 273820 + +# AFRINIC IPv4 resources cannot be transferred to APNIC # From https://www.iana.org/assignments/ipv4-address-space/ deny 41.0.0.0/8 deny 102.0.0.0/8 @@ -58,6 +66,8 @@ deny 196.32.160.0 - 196.39.255.255 deny 196.40.96.0 - 196.41.255.255 deny 196.42.64.0 - 196.216.0.255 deny 196.216.2.0 - 197.255.255.255 + +# AFRINIC ASNs cannot be transferred to APNIC # From https://www.iana.org/assignments/as-numbers/ deny 36864 - 37887 deny 327680 - 328703 @@ -87,6 +97,6 @@ deny 65552 - 131071 # IANA Reserved deny 4200000000 - 4294967294 # RFC 6996 deny 4294967295 # RFC 7300 -# Allow the complement of what is denied +# APNIC supports IPv4 and ASN transfers: allow the complement of what is denied allow 0.0.0.0/0 allow 1 - 4199999999 diff --git a/etc/rpki/arin.constraints b/etc/rpki/arin.constraints index 4eb58fd0c..711512061 100644 --- a/etc/rpki/arin.constraints +++ b/etc/rpki/arin.constraints @@ -1,4 +1,4 @@ -# $OpenBSD: arin.constraints,v 1.3 2023/12/26 13:36:18 job Exp $ +# $OpenBSD: arin.constraints,v 1.4 2024/01/30 03:40:01 job Exp $ # From https://www.iana.org/assignments/ipv6-unicast-address-assignments allow 2001:400::/23 @@ -9,7 +9,15 @@ allow 2610::/23 allow 2620::/23 allow 2630::/12 -# AFRINIC Internet Number Resources cannot be transferred +# LACNIC ASNs cannot be transferred to ARIN +# From https://www.iana.org/assignments/as-numbers/as-numbers.xhtml +deny 27648 - 28671 +deny 52224 - 53247 +deny 61440 - 61951 +deny 64099 - 64197 +deny 262144 - 273820 + +# AFRINIC IPv4 resources cannot be transferred to ARIN # From https://www.iana.org/assignments/ipv4-address-space/ deny 41.0.0.0/8 deny 102.0.0.0/8 @@ -54,6 +62,8 @@ deny 196.32.160.0 - 196.39.255.255 deny 196.40.96.0 - 196.41.255.255 deny 196.42.64.0 - 196.216.0.255 deny 196.216.2.0 - 197.255.255.255 + +# AFRINIC ASNs cannot be transferred to ARIN # From https://www.iana.org/assignments/as-numbers/ deny 36864 - 37887 deny 327680 - 328703 @@ -83,6 +93,6 @@ deny 65552 - 131071 # IANA Reserved deny 4200000000 - 4294967294 # RFC 6996 deny 4294967295 # RFC 7300 -# Allow the complement of what is denied +# ARIN supports IPv4 and ASN transfers: allow the complement of what is denied allow 0.0.0.0/0 allow 1 - 4199999999 diff --git a/etc/rpki/lacnic.constraints b/etc/rpki/lacnic.constraints index 8c2721389..2cd227fd7 100644 --- a/etc/rpki/lacnic.constraints +++ b/etc/rpki/lacnic.constraints @@ -1,9 +1,16 @@ -# $OpenBSD: lacnic.constraints,v 1.3 2023/12/26 13:36:18 job Exp $ +# $OpenBSD: lacnic.constraints,v 1.4 2024/01/30 03:40:01 job Exp $ # From https://www.iana.org/assignments/ipv6-unicast-address-assignments allow 2001:1200::/23 allow 2800::/12 +# From https://www.iana.org/assignments/as-numbers/ +allow 27648 - 28671 +allow 52224 - 53247 +allow 61440 - 61951 +allow 64099 - 64197 +allow 262144 - 273820 + # AFRINIC Internet Number Resources cannot be transferred # From https://www.iana.org/assignments/ipv4-address-space/ deny 41.0.0.0/8 @@ -49,10 +56,6 @@ deny 196.32.160.0 - 196.39.255.255 deny 196.40.96.0 - 196.41.255.255 deny 196.42.64.0 - 196.216.0.255 deny 196.216.2.0 - 197.255.255.255 -# From https://www.iana.org/assignments/as-numbers/ -deny 36864 - 37887 -deny 327680 - 328703 -deny 328704 - 329727 # Private use IPv4 & IPv6 addresses and ASNs deny 0.0.0.0/8 # RFC 1122 Local Identification @@ -69,15 +72,6 @@ deny 198.51.100.0/24 # RFC 5737 TEST-NET-2 deny 203.0.113.0/24 # RFC 5737 TEST-NET-3 deny 224.0.0.0/4 # Multicast deny 240.0.0.0/4 # Reserved -deny 23456 # RFC 4893 AS_TRANS -deny 64496 - 64511 # RFC 5398 -deny 64512 - 65534 # RFC 6996 -deny 65535 # RFC 7300 -deny 65536 - 65551 # RFC 5398 -deny 65552 - 131071 # IANA Reserved -deny 4200000000 - 4294967294 # RFC 6996 -deny 4294967295 # RFC 7300 -# Allow the complement of what is denied +# LACNIC supports only IPv4 transfers: allow the complement of what is denied allow 0.0.0.0/0 -allow 1 - 4199999999 diff --git a/etc/rpki/ripe.constraints b/etc/rpki/ripe.constraints index ae63ba190..6f3879337 100644 --- a/etc/rpki/ripe.constraints +++ b/etc/rpki/ripe.constraints @@ -1,4 +1,4 @@ -# $OpenBSD: ripe.constraints,v 1.3 2023/12/26 13:36:18 job Exp $ +# $OpenBSD: ripe.constraints,v 1.4 2024/01/30 03:40:01 job Exp $ # From https://www.iana.org/assignments/ipv6-unicast-address-assignments allow 2001:600::/23 @@ -16,7 +16,15 @@ allow 2003::/18 allow 2a00::/12 allow 2a10::/12 -# AFRINIC Internet Number Resources cannot be transferred +# LACNIC ASNs cannot be transferred to RIPE NCC +# From https://www.iana.org/assignments/as-numbers/ +deny 27648 - 28671 +deny 52224 - 53247 +deny 61440 - 61951 +deny 64099 - 64197 +deny 262144 - 273820 + +# AFRINIC IPv4 resources cannot be transferred to RIPE NCC # From https://www.iana.org/assignments/ipv4-address-space/ deny 41.0.0.0/8 deny 102.0.0.0/8 @@ -61,6 +69,8 @@ deny 196.32.160.0 - 196.39.255.255 deny 196.40.96.0 - 196.41.255.255 deny 196.42.64.0 - 196.216.0.255 deny 196.216.2.0 - 197.255.255.255 + +# AFRINIC ASNs cannot be transferred to RIPE NCC # From https://www.iana.org/assignments/as-numbers/ deny 36864 - 37887 deny 327680 - 328703 @@ -90,6 +100,6 @@ deny 65552 - 131071 # IANA Reserved deny 4200000000 - 4294967294 # RFC 6996 deny 4294967295 # RFC 7300 -# Allow the complement of what is denied +# RIPE NCC supports IPv4 and ASN transfers: allow the complement of what is denied allow 0.0.0.0/0 allow 1 - 4199999999 diff --git a/lib/libcrypto/cmac/cmac.c b/lib/libcrypto/cmac/cmac.c index 86b1b2d5b..81d6ffc9b 100644 --- a/lib/libcrypto/cmac/cmac.c +++ b/lib/libcrypto/cmac/cmac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmac.c,v 1.21 2024/01/29 06:05:50 tb Exp $ */ +/* $OpenBSD: cmac.c,v 1.22 2024/01/30 17:43:39 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project. */ @@ -131,8 +131,7 @@ LCRYPTO_ALIAS(CMAC_CTX_new); void CMAC_CTX_cleanup(CMAC_CTX *ctx) { - if (ctx->cipher_ctx != NULL) - (void)EVP_CIPHER_CTX_reset(ctx->cipher_ctx); + (void)EVP_CIPHER_CTX_reset(ctx->cipher_ctx); explicit_bzero(ctx->tbl, EVP_MAX_BLOCK_LENGTH); explicit_bzero(ctx->k1, EVP_MAX_BLOCK_LENGTH); explicit_bzero(ctx->k2, EVP_MAX_BLOCK_LENGTH); diff --git a/lib/libcrypto/evp/evp_cipher.c b/lib/libcrypto/evp/evp_cipher.c index 51bbf7065..abdc33eac 100644 --- a/lib/libcrypto/evp/evp_cipher.c +++ b/lib/libcrypto/evp/evp_cipher.c @@ -1,4 +1,4 @@ -/* $OpenBSD: evp_cipher.c,v 1.16 2024/01/07 15:21:04 tb Exp $ */ +/* $OpenBSD: evp_cipher.c,v 1.17 2024/01/30 17:41:01 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -627,6 +627,9 @@ EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx) { + if (ctx == NULL) + return 1; + if (ctx->cipher != NULL) { /* XXX - Avoid leaks, so ignore return value of cleanup()... */ if (ctx->cipher->cleanup != NULL) diff --git a/lib/libcrypto/evp/evp_digest.c b/lib/libcrypto/evp/evp_digest.c index 166b04562..9d8d94afb 100644 --- a/lib/libcrypto/evp/evp_digest.c +++ b/lib/libcrypto/evp/evp_digest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: evp_digest.c,v 1.7 2023/12/29 07:22:47 tb Exp $ */ +/* $OpenBSD: evp_digest.c,v 1.8 2024/01/30 17:41:01 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -258,10 +258,12 @@ EVP_MD_CTX_reset(EVP_MD_CTX *ctx) return EVP_MD_CTX_cleanup(ctx); } -/* This call frees resources associated with the context */ int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { + if (ctx == NULL) + return 1; + /* * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, * because sometimes only copies of the context are ever finalised. diff --git a/lib/libssl/tls13_legacy.c b/lib/libssl/tls13_legacy.c index e5b451cb6..6c33eccc6 100644 --- a/lib/libssl/tls13_legacy.c +++ b/lib/libssl/tls13_legacy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls13_legacy.c,v 1.43 2024/01/27 14:34:28 jsing Exp $ */ +/* $OpenBSD: tls13_legacy.c,v 1.44 2024/01/30 14:50:50 jsing Exp $ */ /* * Copyright (c) 2018, 2019 Joel Sing * @@ -501,6 +501,7 @@ tls13_legacy_shutdown(SSL *ssl) return -1; if (ret != TLS13_IO_SUCCESS) return tls13_legacy_return_code(ssl, ret); + goto done; } ret = tls13_record_layer_send_pending(ctx->rl); @@ -524,6 +525,7 @@ tls13_legacy_shutdown(SSL *ssl) } } + done: if (ssl->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) return 1; diff --git a/regress/lib/libssl/shutdown/shutdowntest.c b/regress/lib/libssl/shutdown/shutdowntest.c index 749ccaa43..5b83add35 100644 --- a/regress/lib/libssl/shutdown/shutdowntest.c +++ b/regress/lib/libssl/shutdown/shutdowntest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: shutdowntest.c,v 1.2 2024/01/27 14:35:13 jsing Exp $ */ +/* $OpenBSD: shutdowntest.c,v 1.3 2024/01/30 14:46:46 jsing Exp $ */ /* * Copyright (c) 2020, 2021, 2024 Joel Sing * @@ -360,7 +360,7 @@ static const struct shutdown_test shutdown_tests[] = { #define N_TLS_TESTS (sizeof(shutdown_tests) / sizeof(*shutdown_tests)) static int -shutdowntest(uint16_t ssl_version, const char *ssl_version_name, +shutdown_test(uint16_t ssl_version, const char *ssl_version_name, const struct shutdown_test *st) { BIO *client_wbio = NULL, *server_wbio = NULL; @@ -479,6 +479,135 @@ shutdowntest(uint16_t ssl_version, const char *ssl_version_name, return failed; } +static int +shutdown_sequence_test(uint16_t ssl_version, const char *ssl_version_name) +{ + BIO *client_wbio = NULL, *server_wbio = NULL; + SSL *client = NULL, *server = NULL; + int shutdown, ret; + int failed = 1; + + fprintf(stderr, "\n== Testing %s, shutdown sequence... ==\n", + ssl_version_name); + + if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) + goto failure; + if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) + goto failure; + + if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) + goto failure; + if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) + goto failure; + + if ((client = tls_client(server_wbio, client_wbio)) == NULL) + goto failure; + if (!SSL_set_min_proto_version(client, ssl_version)) + goto failure; + if (!SSL_set_max_proto_version(client, ssl_version)) + goto failure; + + if ((server = tls_server(client_wbio, server_wbio)) == NULL) + goto failure; + if (!SSL_set_min_proto_version(server, ssl_version)) + goto failure; + if (!SSL_set_max_proto_version(server, ssl_version)) + goto failure; + + if (!do_client_server_loop(client, do_connect, server, do_accept)) { + fprintf(stderr, "FAIL: client and server handshake failed\n"); + goto failure; + } + + if (!do_client_server_loop(client, do_write, server, do_read)) { + fprintf(stderr, "FAIL: client write and server read I/O failed\n"); + goto failure; + } + + if (!do_client_server_loop(client, do_read, server, do_write)) { + fprintf(stderr, "FAIL: client read and server write I/O failed\n"); + goto failure; + } + + /* + * Shutdown in lock step and check return value and shutdown flags. + * + * It is not documented, however some software relies on SSL_shutdown() + * to only send a close-notify on the first call, then indicate that a + * close-notify was received on a second (or later) call. + */ + + if ((shutdown = SSL_get_shutdown(client)) != 0) { + fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", + shutdown, 0); + goto failure; + } + if ((shutdown = SSL_get_shutdown(server)) != 0) { + fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", + shutdown, 0); + goto failure; + } + + if ((ret = SSL_shutdown(client)) != 0) { + fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n", + ret, 0); + goto failure; + } + if ((shutdown = SSL_get_shutdown(client)) != SSL_SENT_SHUTDOWN) { + fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", + shutdown, SSL_SENT_SHUTDOWN); + goto failure; + } + + if ((ret = SSL_shutdown(server)) != 0) { + fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n", + ret, 0); + goto failure; + } + if ((shutdown = SSL_get_shutdown(server)) != SSL_SENT_SHUTDOWN) { + fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", + shutdown, SSL_SENT_SHUTDOWN); + goto failure; + } + + if ((ret = SSL_shutdown(client)) != 1) { + fprintf(stderr, "FAIL: client SSL_shutdown() = %d, want %d\n", + ret, 0); + goto failure; + } + if ((shutdown = SSL_get_shutdown(client)) != + (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) { + fprintf(stderr, "FAIL: client shutdown flags = %x, want %x\n", + shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + goto failure; + } + + if ((ret = SSL_shutdown(server)) != 1) { + fprintf(stderr, "FAIL: server SSL_shutdown() = %d, want %d\n", + ret, 0); + goto failure; + } + if ((shutdown = SSL_get_shutdown(server)) != + (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) { + fprintf(stderr, "FAIL: server shutdown flags = %x, want %x\n", + shutdown, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + goto failure; + } + + fprintf(stderr, "INFO: Done!\n"); + + failed = 0; + + failure: + BIO_free(client_wbio); + BIO_free(server_wbio); + + SSL_free(client); + SSL_free(server); + + return failed; +} + struct ssl_version { uint16_t version; const char *name; @@ -517,9 +646,10 @@ main(int argc, char **argv) for (i = 0; i < N_SSL_VERSIONS; i++) { sv = &ssl_versions[i]; for (j = 0; j < N_TLS_TESTS; j++) { - failed |= shutdowntest(sv->version, sv->name, + failed |= shutdown_test(sv->version, sv->name, &shutdown_tests[j]); } + failed |= shutdown_sequence_test(sv->version, sv->name); } return failed; diff --git a/sys/dev/ic/qwx.c b/sys/dev/ic/qwx.c index c39ecafb4..6e9596973 100644 --- a/sys/dev/ic/qwx.c +++ b/sys/dev/ic/qwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qwx.c,v 1.10 2024/01/29 16:06:45 stsp Exp $ */ +/* $OpenBSD: qwx.c,v 1.13 2024/01/30 15:33:32 stsp Exp $ */ /* * Copyright 2023 Stefan Sperling @@ -651,6 +651,49 @@ void qwx_init_wmi_config_qca6390(struct qwx_softc *sc, config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; } +void +qwx_hw_ipq8074_reo_setup(struct qwx_softc *sc) +{ + uint32_t reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; + uint32_t val; + /* Each hash entry uses three bits to map to a particular ring. */ + uint32_t ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | + HAL_HASH_ROUTING_RING_SW2 << 3 | + HAL_HASH_ROUTING_RING_SW3 << 6 | + HAL_HASH_ROUTING_RING_SW4 << 9 | + HAL_HASH_ROUTING_RING_SW1 << 12 | + HAL_HASH_ROUTING_RING_SW2 << 15 | + HAL_HASH_ROUTING_RING_SW3 << 18 | + HAL_HASH_ROUTING_RING_SW4 << 21; + + val = sc->ops.read32(sc, reo_base + HAL_REO1_GEN_ENABLE); + + val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING; + val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING, + HAL_SRNG_RING_ID_REO2SW1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); + sc->ops.write32(sc, reo_base + HAL_REO1_GEN_ENABLE, val); + + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_0(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_1(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_2(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_3(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, ring_hash_map)); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, ring_hash_map)); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, ring_hash_map)); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, ring_hash_map)); +} + void qwx_init_wmi_config_ipq8074(struct qwx_softc *sc, struct target_resource_config *config) { @@ -710,6 +753,90 @@ void qwx_init_wmi_config_ipq8074(struct qwx_softc *sc, config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt; } +void +qwx_hw_wcn6855_reo_setup(struct qwx_softc *sc) +{ + uint32_t reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; + uint32_t val; + /* Each hash entry uses four bits to map to a particular ring. */ + uint32_t ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | + HAL_HASH_ROUTING_RING_SW2 << 4 | + HAL_HASH_ROUTING_RING_SW3 << 8 | + HAL_HASH_ROUTING_RING_SW4 << 12 | + HAL_HASH_ROUTING_RING_SW1 << 16 | + HAL_HASH_ROUTING_RING_SW2 << 20 | + HAL_HASH_ROUTING_RING_SW3 << 24 | + HAL_HASH_ROUTING_RING_SW4 << 28; + + val = sc->ops.read32(sc, reo_base + HAL_REO1_GEN_ENABLE); + val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); + sc->ops.write32(sc, reo_base + HAL_REO1_GEN_ENABLE, val); + + val = sc->ops.read32(sc, reo_base + HAL_REO1_MISC_CTL(sc)); + val &= ~HAL_REO1_MISC_CTL_FRAGMENT_DST_RING; + val |= FIELD_PREP(HAL_REO1_MISC_CTL_FRAGMENT_DST_RING, + HAL_SRNG_RING_ID_REO2SW1); + sc->ops.write32(sc, reo_base + HAL_REO1_MISC_CTL(sc), val); + + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_0(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_1(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_2(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_3(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, + ring_hash_map); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, + ring_hash_map); +} + +void +qwx_hw_ipq5018_reo_setup(struct qwx_softc *sc) +{ + uint32_t reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; + uint32_t val; + + /* Each hash entry uses three bits to map to a particular ring. */ + uint32_t ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | + HAL_HASH_ROUTING_RING_SW2 << 4 | + HAL_HASH_ROUTING_RING_SW3 << 8 | + HAL_HASH_ROUTING_RING_SW4 << 12 | + HAL_HASH_ROUTING_RING_SW1 << 16 | + HAL_HASH_ROUTING_RING_SW2 << 20 | + HAL_HASH_ROUTING_RING_SW3 << 24 | + HAL_HASH_ROUTING_RING_SW4 << 28; + + val = sc->ops.read32(sc, reo_base + HAL_REO1_GEN_ENABLE); + + val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING; + val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING, + HAL_SRNG_RING_ID_REO2SW1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); + sc->ops.write32(sc, reo_base + HAL_REO1_GEN_ENABLE, val); + + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_0(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_1(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_2(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + sc->ops.write32(sc, reo_base + HAL_REO1_AGING_THRESH_IX_3(sc), + HAL_DEFAULT_REO_TIMEOUT_USEC); + + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, + ring_hash_map); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1, + ring_hash_map); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, + ring_hash_map); + sc->ops.write32(sc, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, + ring_hash_map); +} int qwx_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, int mac_id) { @@ -769,7 +896,9 @@ const struct ath11k_hw_ops ipq8074_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_ipq8074_reo_setup, +#endif + .reo_setup = qwx_hw_ipq8074_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, @@ -813,7 +942,9 @@ const struct ath11k_hw_ops ipq6018_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_ipq8074_reo_setup, +#endif + .reo_setup = qwx_hw_ipq8074_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, @@ -857,7 +988,9 @@ const struct ath11k_hw_ops qca6390_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_ipq8074_reo_setup, +#endif + .reo_setup = qwx_hw_ipq8074_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, @@ -901,7 +1034,9 @@ const struct ath11k_hw_ops qcn9074_ops = { .rx_desc_set_msdu_len = ath11k_hw_qcn9074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_ipq8074_reo_setup, +#endif + .reo_setup = qwx_hw_ipq8074_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, @@ -945,7 +1080,9 @@ const struct ath11k_hw_ops wcn6855_ops = { .rx_desc_set_msdu_len = ath11k_hw_wcn6855_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_wcn6855_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_wcn6855_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_wcn6855_reo_setup, +#endif + .reo_setup = qwx_hw_wcn6855_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_wcn6855_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2, @@ -989,7 +1126,9 @@ const struct ath11k_hw_ops wcn6750_ops = { .rx_desc_set_msdu_len = ath11k_hw_qcn9074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, - .reo_setup = ath11k_hw_wcn6855_reo_setup, +#endif + .reo_setup = qwx_hw_wcn6855_reo_setup, +#ifdef notyet .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, @@ -9145,12 +9284,11 @@ qwx_dp_srng_common_setup(struct qwx_softc *sc) sc->sc_dev.dv_xname, ret); goto err; } -#ifdef notyet + /* When hash based routing of rx packet is enabled, 32 entries to map * the hash values to the ring will be configured. */ sc->hw_params.hw_ops->reo_setup(sc); -#endif return 0; err: @@ -16249,9 +16387,9 @@ qwx_core_pdev_create(struct qwx_softc *sc) ath11k_err(ab, "failed to init spectral %d\n", ret); goto err_thermal_unregister; } - +#endif return 0; - +#if 0 err_thermal_unregister: ath11k_thermal_unregister(ab); err_mac_unregister: @@ -21344,12 +21482,17 @@ qwx_run(struct qwx_softc *sc) return ret; } + /* Enable "ext" IRQs for datapath. */ + sc->ops.irq_enable(sc); + return 0; } int qwx_run_stop(struct qwx_softc *sc) { + sc->ops.irq_disable(sc); + printf("%s: not implemented\n", __func__); return ENOTSUP; } diff --git a/sys/dev/ic/qwxreg.h b/sys/dev/ic/qwxreg.h index 0099c342e..604e67aaf 100644 --- a/sys/dev/ic/qwxreg.h +++ b/sys/dev/ic/qwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxreg.h,v 1.3 2024/01/28 22:30:39 stsp Exp $ */ +/* $OpenBSD: qwxreg.h,v 1.4 2024/01/30 15:32:04 stsp Exp $ */ /* * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. @@ -9593,6 +9593,14 @@ enum hal_reo_exec_status { #define HAL_REO_STATUS_HDR_INFO0_EXEC_TIME GENMASK(25, 16) #define HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS GENMASK(27, 26) +#define HAL_HASH_ROUTING_RING_TCL 0 +#define HAL_HASH_ROUTING_RING_SW1 1 +#define HAL_HASH_ROUTING_RING_SW2 2 +#define HAL_HASH_ROUTING_RING_SW3 3 +#define HAL_HASH_ROUTING_RING_SW4 4 +#define HAL_HASH_ROUTING_RING_REL 5 +#define HAL_HASH_ROUTING_RING_FW 6 + struct hal_reo_status_hdr { uint32_t info0; uint32_t timestamp; diff --git a/sys/dev/ic/qwxvar.h b/sys/dev/ic/qwxvar.h index 91e966760..4cd17295f 100644 --- a/sys/dev/ic/qwxvar.h +++ b/sys/dev/ic/qwxvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxvar.h,v 1.7 2024/01/29 16:06:45 stsp Exp $ */ +/* $OpenBSD: qwxvar.h,v 1.8 2024/01/30 15:32:04 stsp Exp $ */ /* * Copyright (c) 2018-2019 The Linux Foundation. @@ -247,7 +247,9 @@ struct ath11k_hw_ops { void (*rx_desc_set_msdu_len)(struct hal_rx_desc *desc, uint16_t len); struct rx_attention *(*rx_desc_get_attention)(struct hal_rx_desc *desc); uint8_t *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc); - void (*reo_setup)(struct ath11k_base *ab); +#endif + void (*reo_setup)(struct qwx_softc *); +#ifdef notyet uint16_t (*mpdu_info_get_peerid)(uint8_t *tlv_data); bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); uint8_t* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index 014b3000a..22032bf2f 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.c,v 1.302 2024/01/25 09:54:21 claudio Exp $ */ +/* $OpenBSD: bgpctl.c,v 1.303 2024/01/30 13:51:13 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer @@ -471,9 +471,7 @@ show(struct imsg *imsg, struct parse_result *res) struct ctl_show_rib rib; struct rde_memstats stats; struct ibuf ibuf; - u_char *asdata; u_int rescode, ilen; - size_t aslen; switch (imsg->hdr.type) { case IMSG_CTL_SHOW_NEIGHBOR: @@ -528,16 +526,13 @@ show(struct imsg *imsg, struct parse_result *res) output->fib_table(&kt); break; case IMSG_CTL_SHOW_RIB: - if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rib)) - errx(1, "wrong imsg len"); if (output->rib == NULL) break; - /* XXX */ - memcpy(&rib, imsg->data, sizeof(rib)); - aslen = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof(rib); - asdata = imsg->data; - asdata += sizeof(rib); - output->rib(&rib, asdata, aslen, res); + if (imsg_get_ibuf(imsg, &ibuf) == -1) + err(1, "imsg_get_ibuf"); + if (ibuf_get(&ibuf, &rib, sizeof(rib)) == -1) + err(1, "imsg_get_ibuf"); + output->rib(&rib, &ibuf, res); break; case IMSG_CTL_SHOW_RIB_COMMUNITIES: if (output->communities == NULL) @@ -1231,6 +1226,7 @@ show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) struct parse_result res; struct ctl_show_rib_request *req = arg; struct mrt_rib_entry *mre; + struct ibuf ibuf; time_t now; uint16_t i, j; @@ -1296,7 +1292,8 @@ show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) !match_aspath(mre->aspath, mre->aspath_len, &req->as)) continue; - output->rib(&ctl, mre->aspath, mre->aspath_len, &res); + ibuf_from_buffer(&ibuf, mre->aspath, mre->aspath_len); + output->rib(&ctl, &ibuf, &res); if (req->flags & F_CTL_DETAIL) { for (j = 0; j < mre->nattrs; j++) output->attr(mre->attrs[j].attr, diff --git a/usr.sbin/bgpctl/bgpctl.h b/usr.sbin/bgpctl/bgpctl.h index db9e206c1..4ec108688 100644 --- a/usr.sbin/bgpctl/bgpctl.h +++ b/usr.sbin/bgpctl/bgpctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.h,v 1.22 2024/01/25 09:54:21 claudio Exp $ */ +/* $OpenBSD: bgpctl.h,v 1.23 2024/01/30 13:51:13 claudio Exp $ */ /* * Copyright (c) 2019 Claudio Jeker @@ -29,7 +29,7 @@ struct output { void (*interface)(struct ctl_show_interface *); void (*attr)(u_char *, size_t, int, int); void (*communities)(struct ibuf *, struct parse_result *); - void (*rib)(struct ctl_show_rib *, u_char *, size_t, + void (*rib)(struct ctl_show_rib *, struct ibuf *, struct parse_result *); void (*rib_mem)(struct rde_memstats *); void (*set)(struct ctl_show_set *); diff --git a/usr.sbin/bgpctl/output.c b/usr.sbin/bgpctl/output.c index 3a5e59cf4..05f151a0f 100644 --- a/usr.sbin/bgpctl/output.c +++ b/usr.sbin/bgpctl/output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output.c,v 1.48 2024/01/25 09:54:21 claudio Exp $ */ +/* $OpenBSD: output.c,v 1.49 2024/01/30 13:51:13 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer @@ -769,10 +769,9 @@ show_ext_community(u_char *data, uint16_t len) static void show_attr(u_char *data, size_t len, int reqflags, int addpath) { - u_char *path; struct in_addr id; struct bgpd_addr prefix; - struct ibuf ibuf, *buf = &ibuf; + struct ibuf ibuf, *buf = &ibuf, asbuf, *path = NULL; char *aspath; uint32_t as, pathid; uint16_t alen, ioff, short_as, afi; @@ -820,25 +819,27 @@ show_attr(u_char *data, size_t len, int reqflags, int addpath) break; case ATTR_ASPATH: case ATTR_AS4_PATH: + ibuf_from_buffer(buf, data, alen); /* prefer 4-byte AS here */ - e4 = aspath_verify(data, alen, 1, 0); - e2 = aspath_verify(data, alen, 0, 0); + e4 = aspath_verify(buf, 1, 0); + e2 = aspath_verify(buf, 0, 0); if (e4 == 0 || e4 == AS_ERR_SOFT) { - path = data; + ibuf_from_ibuf(&asbuf, buf); } else if (e2 == 0 || e2 == AS_ERR_SOFT) { - path = aspath_inflate(data, alen, &alen); - if (path == NULL) - errx(1, "aspath_inflate failed"); + if ((path = aspath_inflate(buf)) == NULL) { + printf("aspath_inflate failed"); + break; + } + ibuf_from_ibuf(&asbuf, path); } else { printf("bad AS-Path"); break; } - if (aspath_asprint(&aspath, path, alen) == -1) + if (aspath_asprint(&aspath, &asbuf) == -1) err(1, NULL); printf("%s", aspath); free(aspath); - if (path != data) - free(path); + ibuf_free(path); break; case ATTR_NEXTHOP: if (alen == 4) { @@ -1013,7 +1014,7 @@ show_attr(u_char *data, size_t len, int reqflags, int addpath) } static void -show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) +show_rib_brief(struct ctl_show_rib *r, struct ibuf *asbuf) { char *p, *aspath; @@ -1025,7 +1026,7 @@ show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) log_addr(&r->exit_nexthop), r->local_pref, r->med); free(p); - if (aspath_asprint(&aspath, asdata, aslen) == -1) + if (aspath_asprint(&aspath, asbuf) == -1) err(1, NULL); if (strlen(aspath) > 0) printf("%s ", aspath); @@ -1035,8 +1036,7 @@ show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) } static void -show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, - int flag0) +show_rib_detail(struct ctl_show_rib *r, struct ibuf *asbuf, int flag0) { struct in_addr id; char *aspath, *s; @@ -1045,7 +1045,7 @@ show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, log_addr(&r->prefix), r->prefixlen, EOL0(flag0)); - if (aspath_asprint(&aspath, asdata, aslen) == -1) + if (aspath_asprint(&aspath, asbuf) == -1) err(1, NULL); if (strlen(aspath) > 0) printf(" %s%c", aspath, EOL0(flag0)); @@ -1072,13 +1072,12 @@ show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, } static void -show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, - struct parse_result *res) +show_rib(struct ctl_show_rib *r, struct ibuf *aspath, struct parse_result *res) { if (res->flags & F_CTL_DETAIL) - show_rib_detail(r, asdata, aslen, res->flags); + show_rib_detail(r, aspath, res->flags); else - show_rib_brief(r, asdata, aslen); + show_rib_brief(r, aspath); } static void diff --git a/usr.sbin/bgpctl/output_json.c b/usr.sbin/bgpctl/output_json.c index 1ebd27b40..d18672392 100644 --- a/usr.sbin/bgpctl/output_json.c +++ b/usr.sbin/bgpctl/output_json.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output_json.c,v 1.40 2024/01/25 09:54:21 claudio Exp $ */ +/* $OpenBSD: output_json.c,v 1.41 2024/01/30 13:51:13 claudio Exp $ */ /* * Copyright (c) 2020 Claudio Jeker @@ -589,9 +589,8 @@ json_attr(u_char *data, size_t len, int reqflags, int addpath) { struct bgpd_addr prefix; struct in_addr id; - struct ibuf ibuf, *buf = &ibuf; + struct ibuf ibuf, *buf = &ibuf, asbuf, *path = NULL; char *aspath; - u_char *path; uint32_t as, pathid; uint16_t alen, afi, off, short_as; uint8_t flags, type, safi, aid, prefixlen; @@ -645,25 +644,28 @@ json_attr(u_char *data, size_t len, int reqflags, int addpath) break; case ATTR_ASPATH: case ATTR_AS4_PATH: + ibuf_from_buffer(buf, data, alen); /* prefer 4-byte AS here */ - e4 = aspath_verify(data, alen, 1, 0); - e2 = aspath_verify(data, alen, 0, 0); + e4 = aspath_verify(buf, 1, 0); + e2 = aspath_verify(buf, 0, 0); if (e4 == 0 || e4 == AS_ERR_SOFT) { - path = data; + ibuf_from_ibuf(&asbuf, buf); } else if (e2 == 0 || e2 == AS_ERR_SOFT) { - path = aspath_inflate(data, alen, &alen); - if (path == NULL) - errx(1, "aspath_inflate failed"); + if ((path = aspath_inflate(buf)) == NULL) { + json_do_string("error", + "aspath_inflate failed"); + break; + } + ibuf_from_ibuf(&asbuf, path); } else { json_do_string("error", "bad AS-Path"); break; } - if (aspath_asprint(&aspath, path, alen) == -1) + if (aspath_asprint(&aspath, &asbuf) == -1) err(1, NULL); json_do_string("aspath", aspath); free(aspath); - if (path != data) - free(path); + ibuf_free(path); break; case ATTR_NEXTHOP: if (alen == 4) { @@ -841,8 +843,7 @@ bad_len: } static void -json_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, - struct parse_result *res) +json_rib(struct ctl_show_rib *r, struct ibuf *asbuf, struct parse_result *res) { struct in_addr id; char *aspath; @@ -853,7 +854,7 @@ json_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, json_do_printf("prefix", "%s/%u", log_addr(&r->prefix), r->prefixlen); - if (aspath_asprint(&aspath, asdata, aslen) == -1) + if (aspath_asprint(&aspath, asbuf) == -1) err(1, NULL); json_do_string("aspath", aspath); free(aspath); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index fd18f830f..fc31312d8 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.483 2024/01/23 16:13:35 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.484 2024/01/30 13:50:08 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -1542,20 +1542,19 @@ const char *log_as(uint32_t); const char *log_rd(uint64_t); const char *log_ext_subtype(int, uint8_t); const char *log_reason(const char *); +const char *log_aspath_error(int); const char *log_roa(struct roa *); const char *log_aspa(struct aspa_set *); const char *log_rtr_error(enum rtr_error); const char *log_policy(enum role); -int aspath_snprint(char *, size_t, void *, uint16_t); -int aspath_asprint(char **, void *, uint16_t); -size_t aspath_strlen(void *, uint16_t); +int aspath_asprint(char **, struct ibuf *); uint32_t aspath_extract(const void *, int); -int aspath_verify(void *, uint16_t, int, int); +int aspath_verify(struct ibuf *, int, int); #define AS_ERR_LEN -1 #define AS_ERR_TYPE -2 #define AS_ERR_BAD -3 #define AS_ERR_SOFT -4 -u_char *aspath_inflate(void *, uint16_t, uint16_t *); +struct ibuf *aspath_inflate(struct ibuf *); int extract_prefix(const u_char *, int, void *, uint8_t, uint8_t); int nlri_get_prefix(struct ibuf *, struct bgpd_addr *, uint8_t *); int nlri_get_prefix6(struct ibuf *, struct bgpd_addr *, uint8_t *); diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index c357ea67a..17d357c59 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.619 2024/01/25 11:13:35 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.620 2024/01/30 13:50:09 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -1916,13 +1916,6 @@ rde_update_withdraw(struct rde_peer *peer, uint32_t path_id, */ /* attribute parser specific macros */ -#define UPD_READ(t, p, plen, n) \ - do { \ - memcpy(t, p, n); \ - p += n; \ - plen += n; \ - } while (0) - #define CHECK_FLAGS(s, t, m) \ (((s) & ~(ATTR_DEFMASK | (m))) == (t)) @@ -1932,12 +1925,10 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, { struct bgpd_addr nexthop; struct rde_aspath *a = &state->aspath; - struct ibuf attrbuf, tmpbuf; - u_char *p, *npath; + struct ibuf attrbuf, tmpbuf, *npath = NULL; + size_t alen, hlen; uint32_t tmp32, zero = 0; int error; - uint16_t nlen; - size_t attr_len, hlen, plen; uint8_t flags, type; ibuf_from_ibuf(&attrbuf, buf); @@ -1945,30 +1936,26 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, ibuf_get_n8(&attrbuf, &type) == -1) goto bad_list; - if (flags & ATTR_EXTLEN) { - uint16_t alen; - if (ibuf_get_n16(&attrbuf, &alen) == -1) + uint16_t attr_len; + if (ibuf_get_n16(&attrbuf, &attr_len) == -1) goto bad_list; - attr_len = alen; + alen = attr_len; hlen = 4; } else { - uint8_t alen; - if (ibuf_get_n8(&attrbuf, &alen) == -1) + uint8_t attr_len; + if (ibuf_get_n8(&attrbuf, &attr_len) == -1) goto bad_list; - attr_len = alen; + alen = attr_len; hlen = 3; } - if (ibuf_truncate(&attrbuf, attr_len) == -1) + if (ibuf_truncate(&attrbuf, alen) == -1) goto bad_list; /* consume the attribute in buf before moving forward */ - if (ibuf_skip(buf, hlen + attr_len) == -1) + if (ibuf_skip(buf, hlen + alen) == -1) goto bad_list; - p = ibuf_data(&attrbuf); - plen = ibuf_size(&attrbuf); - switch (type) { case ATTR_UNDEF: /* ignore and drop path attributes with a type code of 0 */ @@ -1998,44 +1985,43 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, case ATTR_ASPATH: if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) goto bad_flags; - error = aspath_verify(p, attr_len, peer_has_as4byte(peer), + if (a->flags & F_ATTR_ASPATH) + goto bad_list; + error = aspath_verify(&attrbuf, peer_has_as4byte(peer), peer_accept_no_as_set(peer)); + if (error != 0 && error != AS_ERR_SOFT) { + log_peer_warnx(&peer->conf, "bad ASPATH, %s", + log_aspath_error(error)); + rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH, + NULL); + return (-1); + } + if (peer_has_as4byte(peer)) { + ibuf_from_ibuf(&tmpbuf, &attrbuf); + } else { + if ((npath = aspath_inflate(&attrbuf)) == NULL) + fatal("aspath_inflate"); + ibuf_from_ibuf(&tmpbuf, npath); + } if (error == AS_ERR_SOFT) { + char *str; + /* * soft errors like unexpected segment types are * not considered fatal and the path is just * marked invalid. */ a->flags |= F_ATTR_PARSE_ERR; - } else if (error != 0) { - rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH, - NULL); - return (-1); - } - if (a->flags & F_ATTR_ASPATH) - goto bad_list; - if (peer_has_as4byte(peer)) { - npath = p; - nlen = attr_len; - } else { - npath = aspath_inflate(p, attr_len, &nlen); - if (npath == NULL) - fatal("aspath_inflate"); - } - if (error == AS_ERR_SOFT) { - char *str; - aspath_asprint(&str, npath, nlen); + aspath_asprint(&str, &tmpbuf); log_peer_warnx(&peer->conf, "bad ASPATH %s, " "path invalidated and prefix withdrawn", str ? str : "(bad aspath)"); free(str); } a->flags |= F_ATTR_ASPATH; - a->aspath = aspath_get(npath, nlen); - if (npath != p) - free(npath); - plen += attr_len; + a->aspath = aspath_get(ibuf_data(&tmpbuf), ibuf_size(&tmpbuf)); + ibuf_free(npath); break; case ATTR_NEXTHOP: if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) @@ -2050,7 +2036,6 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, nexthop.aid = AID_INET; if (ibuf_get_h32(&attrbuf, &nexthop.v4.s_addr) == -1) goto bad_len; - /* * Check if the nexthop is a valid IP address. We consider * multicast addresses as invalid. @@ -2245,12 +2230,11 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL)) goto bad_flags; - if ((error = aspath_verify(p, attr_len, 1, + if ((error = aspath_verify(&attrbuf, 1, peer_accept_no_as_set(peer))) != 0) { /* As per RFC6793 use "attribute discard" here. */ log_peer_warnx(&peer->conf, "bad AS4_PATH, " "attribute discarded"); - plen += attr_len; break; } a->flags |= F_ATTR_AS4BYTE_NEW; @@ -2295,7 +2279,6 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, break; } - (void)plen; /* XXX make compiler happy for now */ return (0); bad_len: @@ -2309,7 +2292,6 @@ rde_attr_parse(struct ibuf *buf, struct rde_peer *peer, return (-1); } -#undef UPD_READ #undef CHECK_FLAGS int diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index 6fecee68a..f3b08f945 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.79 2024/01/23 16:13:35 claudio Exp $ */ +/* $OpenBSD: util.c,v 1.80 2024/01/30 13:50:09 claudio Exp $ */ /* * Copyright (c) 2006 Claudio Jeker @@ -32,8 +32,6 @@ #include "rde.h" #include "log.h" -const char *aspath_delim(uint8_t, int); - const char * log_addr(const struct bgpd_addr *addr) { @@ -235,6 +233,26 @@ log_aspa(struct aspa_set *aspa) return errbuf; } +const char * +log_aspath_error(int error) +{ + static char buf[20]; + + switch (error) { + case AS_ERR_LEN: + return "inconsitent lenght"; + case AS_ERR_TYPE: + return "unknown segment type"; + case AS_ERR_BAD: + return "invalid encoding"; + case AS_ERR_SOFT: + return "soft failure"; + default: + snprintf(buf, sizeof(buf), "unknown %d", error); + return buf; + } +} + const char * log_rtr_error(enum rtr_error err) { @@ -286,7 +304,7 @@ log_policy(enum role role) } } -const char * +static const char * aspath_delim(uint8_t seg_type, int closing) { static char db[8]; @@ -318,42 +336,38 @@ aspath_delim(uint8_t seg_type, int closing) } } -int -aspath_snprint(char *buf, size_t size, void *data, uint16_t len) +static int +aspath_snprint(char *buf, size_t size, struct ibuf *in) { -#define UPDATE() \ - do { \ - if (r < 0) \ - return (-1); \ - total_size += r; \ - if ((unsigned int)r < size) { \ - size -= r; \ - buf += r; \ - } else { \ - buf += size; \ - size = 0; \ - } \ +#define UPDATE() \ + do { \ + if (r < 0 || (unsigned int)r >= size) \ + return (-1); \ + size -= r; \ + buf += r; \ } while (0) - uint8_t *seg; - int r, total_size; - uint16_t seg_size; - uint8_t i, seg_type, seg_len; - total_size = 0; - seg = data; - for (; len > 0; len -= seg_size, seg += seg_size) { - seg_type = seg[0]; - seg_len = seg[1]; - seg_size = 2 + sizeof(uint32_t) * seg_len; + struct ibuf data; + uint32_t as; + int r, n = 0; + uint8_t i, seg_type, seg_len; - r = snprintf(buf, size, "%s%s", - total_size != 0 ? " " : "", + ibuf_from_ibuf(&data, in); + while (ibuf_size(&data) > 0) { + if (ibuf_get_n8(&data, &seg_type) == -1 || + ibuf_get_n8(&data, &seg_len) == -1 || + seg_len == 0) + return (-1); + + r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "", aspath_delim(seg_type, 0)); UPDATE(); for (i = 0; i < seg_len; i++) { - r = snprintf(buf, size, "%s", - log_as(aspath_extract(seg, i))); + if (ibuf_get_n32(&data, &as) == -1) + return -1; + + r = snprintf(buf, size, "%s", log_as(as)); UPDATE(); if (i + 1 < seg_len) { r = snprintf(buf, size, " "); @@ -364,73 +378,68 @@ aspath_snprint(char *buf, size_t size, void *data, uint16_t len) UPDATE(); } /* ensure that we have a valid C-string especially for empty as path */ - if (size > 0) - *buf = '\0'; - - return (total_size); + *buf = '\0'; + return (0); #undef UPDATE } -int -aspath_asprint(char **ret, void *data, uint16_t len) +static ssize_t +aspath_strsize(struct ibuf *in) { - size_t slen; - int plen; - - slen = aspath_strlen(data, len) + 1; - *ret = malloc(slen); - if (*ret == NULL) - return (-1); - - plen = aspath_snprint(*ret, slen, data, len); - if (plen == -1) { - free(*ret); - *ret = NULL; - return (-1); - } - - return (0); -} - -size_t -aspath_strlen(void *data, uint16_t len) -{ - uint8_t *seg; - int total_size; + struct ibuf buf; + ssize_t total_size = 0; uint32_t as; - uint16_t seg_size; uint8_t i, seg_type, seg_len; - total_size = 0; - seg = data; - for (; len > 0; len -= seg_size, seg += seg_size) { - seg_type = seg[0]; - seg_len = seg[1]; - seg_size = 2 + sizeof(uint32_t) * seg_len; + ibuf_from_ibuf(&buf, in); + while (ibuf_size(&buf) > 0) { + if (ibuf_get_n8(&buf, &seg_type) == -1 || + ibuf_get_n8(&buf, &seg_len) == -1 || + seg_len == 0) + return (-1); - if (seg_type == AS_SET) - if (total_size != 0) - total_size += 3; - else - total_size += 2; - else if (total_size != 0) + if (total_size != 0) total_size += 1; + total_size += strlen(aspath_delim(seg_type, 0)); for (i = 0; i < seg_len; i++) { - as = aspath_extract(seg, i); + if (ibuf_get_n32(&buf, &as) == -1) + return (-1); do { total_size++; } while ((as = as / 10) != 0); - - if (i + 1 < seg_len) - total_size += 1; } + total_size += seg_len - 1; - if (seg_type == AS_SET) - total_size += 2; + total_size += strlen(aspath_delim(seg_type, 1)); } - return (total_size); + return (total_size + 1); +} + +int +aspath_asprint(char **ret, struct ibuf *data) +{ + ssize_t slen; + + if ((slen = aspath_strsize(data)) == -1) { + *ret = NULL; + errno = EINVAL; + return (-1); + } + + *ret = malloc(slen); + if (*ret == NULL) + return (-1); + + if (aspath_snprint(*ret, slen, data) == -1) { + free(*ret); + *ret = NULL; + errno = EINVAL; + return (-1); + } + + return (0); } /* @@ -456,32 +465,31 @@ aspath_extract(const void *seg, int pos) * Verify that the aspath is correctly encoded. */ int -aspath_verify(void *data, uint16_t len, int as4byte, int noset) +aspath_verify(struct ibuf *in, int as4byte, int noset) { - uint8_t *seg = data; - uint16_t seg_size, as_size = 2; + struct ibuf buf; + int pos, error = 0; uint8_t seg_len, seg_type; - int error = 0; - if (len & 1) + ibuf_from_ibuf(&buf, in); + if (ibuf_size(&buf) & 1) { /* odd length aspath are invalid */ - return (AS_ERR_BAD); + error = AS_ERR_BAD; + goto done; + } - if (as4byte) - as_size = 4; + while (ibuf_size(&buf) > 0) { + if (ibuf_get_n8(&buf, &seg_type) == -1 || + ibuf_get_n8(&buf, &seg_len) == -1) { + error = AS_ERR_LEN; + goto done; + } - for (; len > 0; len -= seg_size, seg += seg_size) { - const uint8_t *ptr; - int pos; - - if (len < 2) /* header length check */ - return (AS_ERR_BAD); - seg_type = seg[0]; - seg_len = seg[1]; - - if (seg_len == 0) + if (seg_len == 0) { /* empty aspath segments are not allowed */ - return (AS_ERR_BAD); + error = AS_ERR_BAD; + goto done; + } /* * BGP confederations should not show up but consider them @@ -497,70 +505,75 @@ aspath_verify(void *data, uint16_t len, int as4byte, int noset) if (noset && seg_type == AS_SET) error = AS_ERR_SOFT; if (seg_type != AS_SET && seg_type != AS_SEQUENCE && - seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET) - return (AS_ERR_TYPE); - - seg_size = 2 + as_size * seg_len; - - if (seg_size > len) - return (AS_ERR_LEN); + seg_type != AS_CONFED_SEQUENCE && + seg_type != AS_CONFED_SET) { + error = AS_ERR_TYPE; + goto done; + } /* RFC 7607 - AS 0 is considered malformed */ - ptr = seg + 2; for (pos = 0; pos < seg_len; pos++) { uint32_t as; - memcpy(&as, ptr, as_size); + if (as4byte) { + if (ibuf_get_n32(&buf, &as) == -1) { + error = AS_ERR_LEN; + goto done; + } + } else { + uint16_t tmp; + if (ibuf_get_n16(&buf, &tmp) == -1) { + error = AS_ERR_LEN; + goto done; + } + as = tmp; + } if (as == 0) error = AS_ERR_SOFT; - ptr += as_size; } } + + done: return (error); /* aspath is valid but probably not loop free */ } /* * convert a 2 byte aspath to a 4 byte one. */ -u_char * -aspath_inflate(void *data, uint16_t len, uint16_t *newlen) +struct ibuf * +aspath_inflate(struct ibuf *in) { - uint8_t *seg, *nseg, *ndata; - uint16_t seg_size, olen, nlen; - uint8_t seg_len; + struct ibuf *out; + uint16_t short_as; + uint8_t seg_type, seg_len; - /* first calculate the length of the aspath */ - seg = data; - nlen = 0; - for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { - seg_len = seg[1]; - seg_size = 2 + sizeof(uint16_t) * seg_len; - nlen += 2 + sizeof(uint32_t) * seg_len; - - if (seg_size > olen) { - errno = ERANGE; - return (NULL); - } - } - - *newlen = nlen; - if ((ndata = malloc(nlen)) == NULL) + /* allocate enough space for the worst case */ + if ((out = ibuf_open(ibuf_size(in) * 2)) == NULL) return (NULL); /* then copy the aspath */ - seg = data; - for (nseg = ndata; nseg < ndata + nlen; ) { - *nseg++ = *seg++; - *nseg++ = seg_len = *seg++; + while (ibuf_size(in) > 0) { + if (ibuf_get_n8(in, &seg_type) == -1 || + ibuf_get_n8(in, &seg_len) == -1 || + seg_len == 0) + goto fail; + if (ibuf_add_n8(out, seg_type) == -1 || + ibuf_add_n8(out, seg_len) == -1) + goto fail; + for (; seg_len > 0; seg_len--) { - *nseg++ = 0; - *nseg++ = 0; - *nseg++ = *seg++; - *nseg++ = *seg++; + if (ibuf_get_n16(in, &short_as) == -1) + goto fail; + if (ibuf_add_n32(out, short_as) == -1) + goto fail; } } - return (ndata); + return (out); + +fail: + ibuf_free(out); + return (NULL); } static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, diff --git a/usr.sbin/rpki-client/http.c b/usr.sbin/rpki-client/http.c index c460c2056..282487aa1 100644 --- a/usr.sbin/rpki-client/http.c +++ b/usr.sbin/rpki-client/http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: http.c,v 1.78 2023/06/28 17:36:09 op Exp $ */ +/* $OpenBSD: http.c,v 1.80 2024/01/30 11:15:05 claudio Exp $ */ /* * Copyright (c) 2020 Nils Fisher * Copyright (c) 2020 Claudio Jeker @@ -1836,6 +1836,8 @@ http_close(struct http_connection *conn) assert(conn->state == STATE_IDLE || conn->state == STATE_CLOSE); conn->state = STATE_CLOSE; + LIST_REMOVE(conn, entry); + LIST_INSERT_HEAD(&active, conn, entry); if (conn->tls != NULL) { switch (tls_close(conn->tls)) { @@ -1985,6 +1987,8 @@ http_handle(struct http_connection *conn) return http_close(conn); case STATE_IDLE: conn->state = STATE_RESPONSE_HEADER; + LIST_REMOVE(conn, entry); + LIST_INSERT_HEAD(&active, conn, entry); return http_read(conn); case STATE_FREE: errx(1, "bad http state"); @@ -2156,8 +2160,10 @@ proc_http(char *bind_addr, int fd) LIST_FOREACH_SAFE(conn, &idle, entry, nc) { if (conn->pfd != NULL && conn->pfd->revents != 0) http_do(conn, http_handle); - else if (conn->idle_time <= now) + else if (conn->idle_time <= now) { + conn->io_time = 0; http_do(conn, http_close); + } if (conn->state == STATE_FREE) http_free(conn); @@ -2168,7 +2174,7 @@ proc_http(char *bind_addr, int fd) /* check if event is ready */ if (conn->pfd != NULL && conn->pfd->revents != 0) http_do(conn, http_handle); - else if (conn->io_time <= now) { + else if (conn->io_time != 0 && conn->io_time <= now) { conn->io_time = 0; if (conn->state == STATE_CONNECT) { warnx("%s: connect timeout", diff --git a/usr.sbin/vmd/vionet.c b/usr.sbin/vmd/vionet.c index 810adde2e..b973577fa 100644 --- a/usr.sbin/vmd/vionet.c +++ b/usr.sbin/vmd/vionet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vionet.c,v 1.7 2024/01/03 03:14:16 dv Exp $ */ +/* $OpenBSD: vionet.c,v 1.8 2024/01/30 23:01:49 dv Exp $ */ /* * Copyright (c) 2023 Dave Voutila @@ -16,9 +16,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include /* PAGE_SIZE */ #include +#include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include @@ -36,7 +34,6 @@ #include #include "atomicio.h" -#include "pci.h" #include "virtio.h" #include "vmd.h" @@ -47,20 +44,36 @@ extern char *__progname; extern struct vmd_vm *current_vm; -/* Device Globals */ -struct event ev_tap; +struct packet { + uint8_t *buf; + size_t len; +}; -static int vionet_rx(struct vionet_dev *); +static int vionet_rx(struct vionet_dev *, int); +static ssize_t vionet_rx_copy(struct vionet_dev *, int, const struct iovec *, + int, size_t); +static ssize_t vionet_rx_zerocopy(struct vionet_dev *, int, + const struct iovec *, int); static void vionet_rx_event(int, short, void *); static uint32_t handle_io_read(struct viodev_msg *, struct virtio_dev *, int8_t *); static int handle_io_write(struct viodev_msg *, struct virtio_dev *); -void vionet_notify_rx(struct virtio_dev *); -int vionet_notifyq(struct virtio_dev *); +static int vionet_notify_tx(struct virtio_dev *); +static int vionet_notifyq(struct virtio_dev *); static void dev_dispatch_vm(int, short, void *); static void handle_sync_io(int, short, void *); +/* Device Globals */ +struct event ev_tap; +struct event ev_inject; +int pipe_inject[2]; +#define READ 0 +#define WRITE 1 +struct iovec iov_rx[VIONET_QUEUE_SIZE]; +struct iovec iov_tx[VIONET_QUEUE_SIZE]; + + __dead void vionet_main(int fd, int fd_vmm) { @@ -79,6 +92,10 @@ vionet_main(int fd, int fd_vmm) if (pledge("stdio vmm proc", NULL) == -1) fatal("pledge"); + /* Initialize iovec arrays. */ + memset(iov_rx, 0, sizeof(iov_rx)); + memset(iov_tx, 0, sizeof(iov_tx)); + /* Receive our vionet_dev, mostly preconfigured. */ sz = atomicio(read, fd, &dev, sizeof(dev)); if (sz != sizeof(dev)) { @@ -153,6 +170,12 @@ vionet_main(int fd, int fd_vmm) } } + /* Initialize our packet injection pipe. */ + if (pipe2(pipe_inject, O_NONBLOCK) == -1) { + log_warn("%s: injection pipe", __func__); + goto fail; + } + /* Initialize libevent so we can start wiring event handlers. */ event_init(); @@ -171,6 +194,12 @@ vionet_main(int fd, int fd_vmm) event_set(&ev_tap, vionet->data_fd, EV_READ | EV_PERSIST, vionet_rx_event, &dev); + /* Add an event for injected packets. */ + log_debug("%s: wiring in packet injection handler (fd=%d)", __func__, + pipe_inject[READ]); + event_set(&ev_inject, pipe_inject[READ], EV_READ | EV_PERSIST, + vionet_rx_event, &dev); + /* Configure our sync channel event handler. */ log_debug("%s: wiring in sync channel handler (fd=%d)", __func__, dev.sync_fd); @@ -209,6 +238,8 @@ vionet_main(int fd, int fd_vmm) close_fd(dev.sync_fd); close_fd(dev.async_fd); close_fd(vionet->data_fd); + close_fd(pipe_inject[READ]); + close_fd(pipe_inject[WRITE]); _exit(ret); /* NOTREACHED */ } @@ -223,6 +254,8 @@ fail: close_fd(dev.sync_fd); close_fd(dev.async_fd); + close_fd(pipe_inject[READ]); + close_fd(pipe_inject[WRITE]); if (vionet != NULL) close_fd(vionet->data_fd); @@ -232,7 +265,7 @@ fail: /* * Update the gpa and hva of the virtqueue. */ -void +static void vionet_update_qa(struct vionet_dev *dev) { struct virtio_vq_info *vq_info; @@ -259,7 +292,7 @@ vionet_update_qa(struct vionet_dev *dev) /* * Update the queue size. */ -void +static void vionet_update_qs(struct vionet_dev *dev) { struct virtio_vq_info *vq_info; @@ -280,33 +313,27 @@ vionet_update_qs(struct vionet_dev *dev) } /* - * vionet_enq_rx + * vionet_rx * - * Take a given packet from the host-side tap and copy it into the guest's - * buffers utilizing the rx virtio ring. If the packet length is invalid - * (too small or too large) or if there are not enough buffers available, - * the packet is dropped. + * Pull packet from the provided fd and fill the receive-side virtqueue. We + * selectively use zero-copy approaches when possible. + * + * Returns 1 if guest notification is needed. Otherwise, returns -1 on failure + * or 0 if no notification is needed. */ -int -vionet_enq_rx(struct vionet_dev *dev, char *pkt, size_t sz, int *spc) +static int +vionet_rx(struct vionet_dev *dev, int fd) { - uint16_t dxx, idx, hdr_desc_idx, chain_hdr_idx; + uint16_t idx, hdr_idx; char *vr = NULL; - size_t bufsz = 0, off = 0, pkt_offset = 0, chunk_size = 0; - size_t chain_len = 0; - struct vring_desc *desc, *pkt_desc, *hdr_desc; + size_t chain_len = 0, iov_cnt; + struct vring_desc *desc, *table; struct vring_avail *avail; struct vring_used *used; struct virtio_vq_info *vq_info; - struct virtio_net_hdr hdr; - size_t hdr_sz; - - if (sz < VIONET_MIN_TXLEN || sz > VIONET_MAX_TXLEN) { - log_warnx("%s: invalid packet size", __func__); - return (0); - } - - hdr_sz = sizeof(hdr); + struct iovec *iov; + int notify = 0; + ssize_t sz; if (!(dev->cfg.device_status & VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK)) { @@ -315,178 +342,287 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, size_t sz, int *spc) } vq_info = &dev->vq[RXQ]; + idx = vq_info->last_avail; vr = vq_info->q_hva; if (vr == NULL) fatalx("%s: vr == NULL", __func__); - /* Compute offsets in ring of descriptors, avail ring, and used ring */ - desc = (struct vring_desc *)(vr); + table = (struct vring_desc *)(vr); avail = (struct vring_avail *)(vr + vq_info->vq_availoffset); used = (struct vring_used *)(vr + vq_info->vq_usedoffset); + used->flags |= VRING_USED_F_NO_NOTIFY; - idx = vq_info->last_avail & VIONET_QUEUE_MASK; - if ((vq_info->notified_avail & VIONET_QUEUE_MASK) == idx) { - log_debug("%s: insufficient available buffer capacity, " - "dropping packet.", __func__); - return (0); - } + while (idx != avail->idx) { + hdr_idx = avail->ring[idx & VIONET_QUEUE_MASK]; + desc = &table[hdr_idx & VIONET_QUEUE_MASK]; + if (!DESC_WRITABLE(desc)) { + log_warnx("%s: invalid descriptor state", __func__); + goto reset; + } - hdr_desc_idx = avail->ring[idx] & VIONET_QUEUE_MASK; - hdr_desc = &desc[hdr_desc_idx]; + iov = &iov_rx[0]; + iov_cnt = 1; - dxx = hdr_desc_idx; - chain_hdr_idx = dxx; - chain_len = 0; + /* + * First descriptor should be at least as large as the + * virtio_net_hdr. It's not technically required, but in + * legacy devices it should be safe to assume. + */ + iov->iov_len = desc->len; + if (iov->iov_len < sizeof(struct virtio_net_hdr)) { + log_warnx("%s: invalid descriptor length", __func__); + goto reset; + } - /* Process the descriptor and walk any potential chain. */ - do { - off = 0; - pkt_desc = &desc[dxx]; - if (!(pkt_desc->flags & VRING_DESC_F_WRITE)) { - log_warnx("%s: invalid descriptor, not writable", + /* + * Insert the virtio_net_hdr and adjust len/base. We do the + * pointer math here before it's a void*. + */ + iov->iov_base = hvaddr_mem(desc->addr, iov->iov_len); + if (iov->iov_base == NULL) + goto reset; + memset(iov->iov_base, 0, sizeof(struct virtio_net_hdr)); + + /* Tweak the iovec to account for the virtio_net_hdr. */ + iov->iov_len -= sizeof(struct virtio_net_hdr); + iov->iov_base = hvaddr_mem(desc->addr + + sizeof(struct virtio_net_hdr), iov->iov_len); + if (iov->iov_base == NULL) + goto reset; + chain_len = iov->iov_len; + + /* + * Walk the remaining chain and collect remaining addresses + * and lengths. + */ + while (desc->flags & VRING_DESC_F_NEXT) { + desc = &table[desc->next & VIONET_QUEUE_MASK]; + if (!DESC_WRITABLE(desc)) { + log_warnx("%s: invalid descriptor state", + __func__); + goto reset; + } + + /* Collect our IO information. Translate gpa's. */ + iov = &iov_rx[iov_cnt]; + iov->iov_len = desc->len; + iov->iov_base = hvaddr_mem(desc->addr, iov->iov_len); + if (iov->iov_base == NULL) + goto reset; + chain_len += iov->iov_len; + + /* Guard against infinitely looping chains. */ + if (++iov_cnt >= nitems(iov_rx)) { + log_warnx("%s: infinite chain detected", + __func__); + goto reset; + } + } + + /* Make sure the driver gave us the bare minimum buffers. */ + if (chain_len < VIONET_MIN_TXLEN) { + log_warnx("%s: insufficient buffers provided", __func__); - return (0); + goto reset; } - /* How much data do we get to write? */ - if (sz - bufsz > pkt_desc->len) - chunk_size = pkt_desc->len; + /* + * If we're enforcing hardware address or handling an injected + * packet, we need to use a copy-based approach. + */ + if (dev->lockedmac || fd != dev->data_fd) + sz = vionet_rx_copy(dev, fd, iov_rx, iov_cnt, + chain_len); else - chunk_size = sz - bufsz; + sz = vionet_rx_zerocopy(dev, fd, iov_rx, iov_cnt); + if (sz == -1) + goto reset; + if (sz == 0) /* No packets, so bail out for now. */ + break; - if (chain_len == 0) { - off = hdr_sz; - if (chunk_size == pkt_desc->len) - chunk_size -= off; - } + /* + * Account for the prefixed header since it wasn't included + * in the copy or zerocopy operations. + */ + sz += sizeof(struct virtio_net_hdr); - /* Write a chunk of data if we need to */ - if (chunk_size && write_mem(pkt_desc->addr + off, - pkt + pkt_offset, chunk_size)) { - log_warnx("%s: failed to write to buffer 0x%llx", - __func__, pkt_desc->addr); - return (0); - } - - chain_len += chunk_size + off; - bufsz += chunk_size; - pkt_offset += chunk_size; - - dxx = pkt_desc->next & VIONET_QUEUE_MASK; - } while (bufsz < sz && pkt_desc->flags & VRING_DESC_F_NEXT); - - /* Move our marker in the ring...*/ - vq_info->last_avail = (vq_info->last_avail + 1) & - VIONET_QUEUE_MASK; - - /* Prepend the virtio net header in the first buffer. */ - memset(&hdr, 0, sizeof(hdr)); - hdr.hdr_len = hdr_sz; - if (write_mem(hdr_desc->addr, &hdr, hdr_sz)) { - log_warnx("vionet: rx enq header write_mem error @ 0x%llx", - hdr_desc->addr); - return (0); + /* Mark our buffers as used. */ + used->ring[used->idx & VIONET_QUEUE_MASK].id = hdr_idx; + used->ring[used->idx & VIONET_QUEUE_MASK].len = sz; + __sync_synchronize(); + used->idx++; + idx++; } - /* Update the index field in the used ring. This must be done last. */ - dev->cfg.isr_status = 1; - *spc = (vq_info->notified_avail - vq_info->last_avail) - & VIONET_QUEUE_MASK; - - /* Update the list of used buffers. */ - used->ring[used->idx & VIONET_QUEUE_MASK].id = chain_hdr_idx; - used->ring[used->idx & VIONET_QUEUE_MASK].len = chain_len; - __sync_synchronize(); - used->idx++; + if (idx != vq_info->last_avail && + !(avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { + notify = 1; + dev->cfg.isr_status |= 1; + } + vq_info->last_avail = idx; + return (notify); +reset: + log_warnx("%s: requesting device reset", __func__); + dev->cfg.device_status |= DEVICE_NEEDS_RESET; + dev->cfg.isr_status |= VIRTIO_CONFIG_ISR_CONFIG_CHANGE; return (1); } /* - * vionet_rx + * vionet_rx_copy * - * Enqueue data that was received on a tap file descriptor - * to the vionet device queue. + * Read a packet off the provided file descriptor, validating packet + * characteristics, and copy into the provided buffers in the iovec array. + * + * It's assumed that the provided iovec array contains validated host virtual + * address translations and not guest physical addreses. + * + * Returns number of bytes copied on success, 0 if packet is dropped, and + * -1 on an error. */ -static int -vionet_rx(struct vionet_dev *dev) +ssize_t +vionet_rx_copy(struct vionet_dev *dev, int fd, const struct iovec *iov, + int iov_cnt, size_t chain_len) { - char buf[PAGE_SIZE]; - int num_enq = 0, spc = 0; - struct ether_header *eh; - ssize_t sz; + static uint8_t buf[VIONET_HARD_MTU]; + struct packet *pkt = NULL; + struct ether_header *eh = NULL; + uint8_t *payload = buf; + size_t i, chunk, nbytes, copied = 0; + ssize_t sz; - do { - sz = read(dev->data_fd, buf, sizeof(buf)); - if (sz == -1) { - /* - * If we get EAGAIN, No data is currently available. - * Do not treat this as an error. - */ - if (errno != EAGAIN) - log_warn("%s: read error", __func__); - } else if (sz > 0) { - eh = (struct ether_header *)buf; - if (!dev->lockedmac || - ETHER_IS_MULTICAST(eh->ether_dhost) || - memcmp(eh->ether_dhost, dev->mac, - sizeof(eh->ether_dhost)) == 0) - num_enq += vionet_enq_rx(dev, buf, sz, &spc); - } else if (sz == 0) { - log_debug("%s: no data", __func__); - break; + /* If reading from the tap(4), try to right-size the read. */ + if (fd == dev->data_fd) + nbytes = MIN(chain_len, VIONET_HARD_MTU); + else if (fd == pipe_inject[READ]) + nbytes = sizeof(struct packet); + else { + log_warnx("%s: invalid fd: %d", __func__, fd); + return (-1); + } + + /* + * Try to pull a packet. The fd should be non-blocking and we don't + * care if we under-read (i.e. sz != nbytes) as we may not have a + * packet large enough to fill the buffer. + */ + sz = read(fd, buf, nbytes); + if (sz == -1) { + if (errno != EAGAIN) { + log_warn("%s: error reading packet", __func__); + return (-1); } - } while (spc > 0 && sz > 0); + return (0); + } else if (fd == dev->data_fd && sz < VIONET_MIN_TXLEN) { + /* If reading the tap(4), we should get valid ethernet. */ + log_warnx("%s: invalid packet size", __func__); + return (0); + } else if (sz != sizeof(struct packet)) { + log_warnx("%s: invalid injected packet object", __func__); + return (0); + } - return (num_enq); + /* Decompose an injected packet, if that's what we're working with. */ + if (fd == pipe_inject[READ]) { + pkt = (struct packet *)buf; + if (pkt->buf == NULL) { + log_warnx("%s: invalid injected packet, no buffer", + __func__); + return (0); + } + if (sz < VIONET_MIN_TXLEN || sz > VIONET_MAX_TXLEN) { + log_warnx("%s: invalid injected packet size", __func__); + goto drop; + } + payload = pkt->buf; + sz = (ssize_t)pkt->len; + } + + /* Validate the ethernet header, if required. */ + if (dev->lockedmac) { + eh = (struct ether_header *)(payload); + if (!ETHER_IS_MULTICAST(eh->ether_dhost) && + memcmp(eh->ether_dhost, dev->mac, + sizeof(eh->ether_dhost)) != 0) + goto drop; + } + + /* Truncate one last time to the chain length, if shorter. */ + sz = MIN(chain_len, (size_t)sz); + + /* + * Copy the packet into the provided buffers. We can use memcpy(3) + * here as the gpa was validated and translated to an hva previously. + */ + for (i = 0; (int)i < iov_cnt && (size_t)sz > copied; i++) { + chunk = MIN(iov[i].iov_len, (size_t)(sz - copied)); + memcpy(iov[i].iov_base, payload + copied, chunk); + copied += chunk; + } + +drop: + /* Free any injected packet buffer. */ + if (pkt != NULL) + free(pkt->buf); + + return (copied); } +/* + * vionet_rx_zerocopy + * + * Perform a vectorized read from the given fd into the guest physical memory + * pointed to by iovecs. + * + * Returns number of bytes read on success, -1 on error, or 0 if EAGAIN was + * returned by readv. + * + */ +static ssize_t +vionet_rx_zerocopy(struct vionet_dev *dev, int fd, const struct iovec *iov, + int iov_cnt) +{ + ssize_t sz; + + if (dev->lockedmac) { + log_warnx("%s: zerocopy not available for locked lladdr", + __func__); + return (-1); + } + + sz = readv(fd, iov, iov_cnt); + if (sz == -1 && errno == EAGAIN) + return (0); + return (sz); +} + + /* * vionet_rx_event * * Called when new data can be received on the tap fd of a vionet device. */ static void -vionet_rx_event(int fd, short kind, void *arg) +vionet_rx_event(int fd, short event, void *arg) { struct virtio_dev *dev = (struct virtio_dev *)arg; - if (vionet_rx(&dev->vionet) > 0) + if (!(event & EV_READ)) + fatalx("%s: invalid event type", __func__); + + if (vionet_rx(&dev->vionet, fd) > 0) virtio_assert_pic_irq(dev, 0); } -void -vionet_notify_rx(struct virtio_dev *dev) -{ - struct vionet_dev *vionet = &dev->vionet; - struct vring_avail *avail; - struct virtio_vq_info *vq_info; - char *vr; - - vq_info = &vionet->vq[RXQ]; - vr = vq_info->q_hva; - if (vr == NULL) - fatalx("%s: vr == NULL", __func__); - - /* Compute offset into avail ring */ - avail = (struct vring_avail *)(vr + vq_info->vq_availoffset); - vq_info->notified_avail = avail->idx - 1; -} - -int +static int vionet_notifyq(struct virtio_dev *dev) { struct vionet_dev *vionet = &dev->vionet; - int ret = 0; switch (vionet->cfg.queue_notify) { - case RXQ: - vionet_notify_rx(dev); - break; - case TXQ: - ret = vionet_notify_tx(dev); - break; + case TXQ: return vionet_notify_tx(dev); default: /* * Catch the unimplemented queue ID 2 (control queue) as @@ -497,23 +633,25 @@ vionet_notifyq(struct virtio_dev *dev) break; } - return (ret); + return (0); } -int +static int vionet_notify_tx(struct virtio_dev *dev) { - uint16_t idx, pkt_desc_idx, hdr_desc_idx, dxx, cnt; - size_t pktsz, chunk_size = 0; - ssize_t dhcpsz = 0; - int ofs, spc = 0; - char *vr = NULL, *pkt = NULL, *dhcppkt = NULL; + uint16_t idx, hdr_idx; + size_t chain_len, iov_cnt; + ssize_t dhcpsz = 0, sz; + int notify = 0; + char *vr = NULL, *dhcppkt = NULL; struct vionet_dev *vionet = &dev->vionet; - struct vring_desc *desc, *pkt_desc, *hdr_desc; + struct vring_desc *desc, *table; struct vring_avail *avail; struct vring_used *used; struct virtio_vq_info *vq_info; struct ether_header *eh; + struct iovec *iov; + struct packet pkt; if (!(vionet->cfg.device_status & VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK)) { @@ -522,155 +660,161 @@ vionet_notify_tx(struct virtio_dev *dev) } vq_info = &vionet->vq[TXQ]; + idx = vq_info->last_avail; vr = vq_info->q_hva; if (vr == NULL) fatalx("%s: vr == NULL", __func__); /* Compute offsets in ring of descriptors, avail ring, and used ring */ - desc = (struct vring_desc *)(vr); + table = (struct vring_desc *)(vr); avail = (struct vring_avail *)(vr + vq_info->vq_availoffset); used = (struct vring_used *)(vr + vq_info->vq_usedoffset); - idx = vq_info->last_avail & VIONET_QUEUE_MASK; + while (idx != avail->idx) { + hdr_idx = avail->ring[idx & VIONET_QUEUE_MASK]; + desc = &table[hdr_idx & VIONET_QUEUE_MASK]; + if (DESC_WRITABLE(desc)) { + log_warnx("%s: invalid descriptor state", __func__); + goto reset; + } - if ((avail->idx & VIONET_QUEUE_MASK) == idx) - return (0); + iov = &iov_tx[0]; + iov_cnt = 0; + chain_len = 0; - while ((avail->idx & VIONET_QUEUE_MASK) != idx) { - hdr_desc_idx = avail->ring[idx] & VIONET_QUEUE_MASK; - hdr_desc = &desc[hdr_desc_idx]; - pktsz = 0; + /* + * As a legacy device, we most likely will receive a lead + * descriptor sized to the virtio_net_hdr. However, the framing + * is not guaranteed, so check for packet data. + */ + iov->iov_len = desc->len; + if (iov->iov_len < sizeof(struct virtio_net_hdr)) { + log_warnx("%s: invalid descriptor length", __func__); + goto reset; + } else if (iov->iov_len > sizeof(struct virtio_net_hdr)) { + /* Chop off the virtio header, leaving packet data. */ + iov->iov_len -= sizeof(struct virtio_net_hdr); + chain_len += iov->iov_len; + iov->iov_base = hvaddr_mem(desc->addr + + sizeof(struct virtio_net_hdr), iov->iov_len); + if (iov->iov_base == NULL) + goto reset; + iov_cnt++; + } - cnt = 0; - dxx = hdr_desc_idx; - do { - pktsz += desc[dxx].len; - dxx = desc[dxx].next & VIONET_QUEUE_MASK; - - /* - * Virtio 1.0, cs04, section 2.4.5: - * "The number of descriptors in the table is defined - * by the queue size for this virtqueue: this is the - * maximum possible descriptor chain length." - */ - if (++cnt >= VIONET_QUEUE_SIZE) { - log_warnx("%s: descriptor table invalid", + /* + * Walk the chain and collect remaining addresses and lengths. + */ + while (desc->flags & VRING_DESC_F_NEXT) { + desc = &table[desc->next & VIONET_QUEUE_MASK]; + if (DESC_WRITABLE(desc)) { + log_warnx("%s: invalid descriptor state", __func__); - goto out; - } - } while (desc[dxx].flags & VRING_DESC_F_NEXT); - - pktsz += desc[dxx].len; - - /* Remove virtio header descriptor len */ - pktsz -= hdr_desc->len; - - /* Drop packets violating device MTU-based limits */ - if (pktsz < VIONET_MIN_TXLEN || pktsz > VIONET_MAX_TXLEN) { - log_warnx("%s: invalid packet size %lu", __func__, - pktsz); - goto drop_packet; - } - pkt = malloc(pktsz); - if (pkt == NULL) { - log_warn("malloc error alloc packet buf"); - goto out; - } - - ofs = 0; - pkt_desc_idx = hdr_desc->next & VIONET_QUEUE_MASK; - pkt_desc = &desc[pkt_desc_idx]; - - while (pkt_desc->flags & VRING_DESC_F_NEXT) { - /* must be not writable */ - if (pkt_desc->flags & VRING_DESC_F_WRITE) { - log_warnx("unexpected writable tx desc " - "%d", pkt_desc_idx); - goto out; + goto reset; } - /* Check we don't read beyond allocated pktsz */ - if (pkt_desc->len > pktsz - ofs) { - log_warnx("%s: descriptor len past pkt len", + /* Collect our IO information, translating gpa's. */ + iov = &iov_tx[iov_cnt]; + iov->iov_len = desc->len; + iov->iov_base = hvaddr_mem(desc->addr, iov->iov_len); + if (iov->iov_base == NULL) + goto reset; + chain_len += iov->iov_len; + + /* Guard against infinitely looping chains. */ + if (++iov_cnt >= nitems(iov_tx)) { + log_warnx("%s: infinite chain detected", __func__); - chunk_size = pktsz - ofs; - } else - chunk_size = pkt_desc->len; - - /* Read packet from descriptor ring */ - if (read_mem(pkt_desc->addr, pkt + ofs, chunk_size)) { - log_warnx("vionet: packet read_mem error " - "@ 0x%llx", pkt_desc->addr); - goto out; + goto reset; } - - ofs += pkt_desc->len; - pkt_desc_idx = pkt_desc->next & VIONET_QUEUE_MASK; - pkt_desc = &desc[pkt_desc_idx]; } - /* Now handle tail descriptor - must be not writable */ - if (pkt_desc->flags & VRING_DESC_F_WRITE) { - log_warnx("unexpected writable tx descriptor %d", - pkt_desc_idx); - goto out; + /* Check if we've got a minimum viable amount of data. */ + if (chain_len < VIONET_MIN_TXLEN) { + sz = chain_len; + goto drop; } - /* Check we don't read beyond allocated pktsz */ - if (pkt_desc->len > pktsz - ofs) { - log_warnx("%s: descriptor len past pkt len", __func__); - chunk_size = pktsz - ofs - pkt_desc->len; - } else - chunk_size = pkt_desc->len; - - /* Read packet from descriptor ring */ - if (read_mem(pkt_desc->addr, pkt + ofs, chunk_size)) { - log_warnx("vionet: packet read_mem error @ " - "0x%llx", pkt_desc->addr); - goto out; + /* + * Packet inspection for ethernet header (if using a "local" + * interface) for possibility of a DHCP packet or (if using + * locked lladdr) for validating ethernet header. + * + * To help preserve zero-copy semantics, we require the first + * descriptor with packet data contains a large enough buffer + * for this inspection. + */ + iov = &iov_tx[0]; + if (vionet->lockedmac) { + if (iov->iov_len < ETHER_HDR_LEN) { + log_warnx("%s: insufficient header data", + __func__); + goto drop; + } + eh = (struct ether_header *)iov->iov_base; + if (memcmp(eh->ether_shost, vionet->mac, + sizeof(eh->ether_shost)) != 0) { + log_warnx("%s: bad source address %s", + __func__, ether_ntoa((struct ether_addr *) + eh->ether_shost)); + sz = chain_len; + goto drop; + } + } + if (vionet->local) { + dhcpsz = dhcp_request(dev, iov->iov_base, iov->iov_len, + &dhcppkt); + log_debug("%s: detected dhcp request of %zu bytes", + __func__, dhcpsz); } - /* reject other source addresses */ - if (vionet->lockedmac && pktsz >= ETHER_HDR_LEN && - (eh = (struct ether_header *)pkt) && - memcmp(eh->ether_shost, vionet->mac, - sizeof(eh->ether_shost)) != 0) - log_debug("vionet: wrong source address %s for vm %d", - ether_ntoa((struct ether_addr *) - eh->ether_shost), dev->vm_id); - else if (vionet->local && - (dhcpsz = dhcp_request(dev, pkt, pktsz, &dhcppkt)) != -1) { - log_debug("vionet: dhcp request," - " local response size %zd", dhcpsz); - - /* XXX signed vs unsigned here, funky cast */ - } else if (write(vionet->data_fd, pkt, pktsz) != (int)pktsz) { - log_warnx("vionet: tx failed writing to tap: " - "%d", errno); - goto out; + /* Write our packet to the tap(4). */ + sz = writev(vionet->data_fd, iov_tx, iov_cnt); + if (sz == -1 && errno != ENOBUFS) { + log_warn("%s", __func__); + goto reset; } - - drop_packet: - vionet->cfg.isr_status = 1; - used->ring[used->idx & VIONET_QUEUE_MASK].id = hdr_desc_idx; - used->ring[used->idx & VIONET_QUEUE_MASK].len = hdr_desc->len; + sz += sizeof(struct virtio_net_hdr); +drop: + used->ring[used->idx & VIONET_QUEUE_MASK].id = hdr_idx; + used->ring[used->idx & VIONET_QUEUE_MASK].len = sz; __sync_synchronize(); used->idx++; + idx++; - vq_info->last_avail = avail->idx & VIONET_QUEUE_MASK; - idx = (idx + 1) & VIONET_QUEUE_MASK; - - free(pkt); - pkt = NULL; + /* Facilitate DHCP reply injection, if needed. */ + if (dhcpsz > 0) { + pkt.buf = dhcppkt; + pkt.len = dhcpsz; + sz = write(pipe_inject[WRITE], &pkt, sizeof(pkt)); + if (sz == -1 && errno != EAGAIN) { + log_warn("%s: packet injection", __func__); + free(pkt.buf); + } else if (sz == -1 && errno == EAGAIN) { + log_debug("%s: dropping dhcp reply", __func__); + free(pkt.buf); + } else if (sz != sizeof(pkt)) { + log_warnx("%s: failed packet injection", + __func__); + free(pkt.buf); + } + log_debug("%s: injected dhcp reply with %ld bytes", + __func__, sz); + } } - if (dhcpsz > 0) - vionet_enq_rx(vionet, dhcppkt, dhcpsz, &spc); - -out: - free(pkt); - free(dhcppkt); + if (idx != vq_info->last_avail && + !(avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { + notify = 1; + vionet->cfg.isr_status |= 1; + } + vq_info->last_avail = idx; + return (notify); +reset: + log_warnx("%s: requesting device reset", __func__); + vionet->cfg.device_status |= DEVICE_NEEDS_RESET; + vionet->cfg.isr_status |= VIRTIO_CONFIG_ISR_CONFIG_CHANGE; return (1); } @@ -728,12 +872,15 @@ dev_dispatch_vm(int fd, short event, void *arg) case IMSG_VMDOP_PAUSE_VM: log_debug("%s: pausing", __func__); event_del(&ev_tap); + event_del(&ev_inject); break; case IMSG_VMDOP_UNPAUSE_VM: log_debug("%s: unpausing", __func__); if (vionet->cfg.device_status - & VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK) + & VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK) { event_add(&ev_tap, NULL); + event_add(&ev_inject, NULL); + } break; case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); @@ -821,6 +968,7 @@ handle_sync_io(int fd, short event, void *arg) case VIODEV_MSG_SHUTDOWN: event_del(&dev->sync_iev.ev); event_del(&ev_tap); + event_del(&ev_inject); event_loopbreak(); return; default: @@ -881,11 +1029,11 @@ handle_io_write(struct viodev_msg *msg, struct virtio_dev *dev) virtio_deassert_pic_irq(dev, msg->vcpu); } event_del(&ev_tap); + event_del(&ev_inject); if (vionet->cfg.device_status & VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK) { - if (event_add(&ev_tap, NULL)) - log_warn("%s: could not initialize virtio tap " - "event handler", __func__); + event_add(&ev_tap, NULL); + event_add(&ev_inject, NULL); } break; default: diff --git a/usr.sbin/vmd/virtio.h b/usr.sbin/vmd/virtio.h index 23608635c..1e51bd731 100644 --- a/usr.sbin/vmd/virtio.h +++ b/usr.sbin/vmd/virtio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.h,v 1.49 2023/09/26 01:53:54 dv Exp $ */ +/* $OpenBSD: virtio.h,v 1.50 2024/01/30 23:01:49 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -366,13 +366,6 @@ int vioblk_restore(int, struct vmd_vm *, int[][VM_MAX_BASE_PER_DISK]); int vionet_dump(int); int vionet_restore(int, struct vmd_vm *, int *); -void vionet_update_qs(struct vionet_dev *); -void vionet_update_qa(struct vionet_dev *); -int vionet_notifyq(struct virtio_dev *); -void vionet_notify_rx(struct virtio_dev *); -int vionet_notify_tx(struct virtio_dev *); -void vionet_process_rx(uint32_t); -int vionet_enq_rx(struct vionet_dev *, char *, size_t, int *); void vionet_set_hostmac(struct vmd_vm *, unsigned int, uint8_t *); int vmmci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);