From de065a84831e66c829603d9a098e237e8f5faaa1 Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Tue, 19 Mar 2024 13:30:46 -0700 Subject: [PATCH] oximeter integration (#178) --- Cargo.lock | 1540 ++++++++++++++++++++++------------- Cargo.toml | 6 + bfd/src/lib.rs | 33 +- bfd/src/sm.rs | 128 ++- bgp/src/session.rs | 272 ++++++- ddm-admin-client/Cargo.toml | 2 +- ddm-admin-client/src/lib.rs | 93 ++- ddm/Cargo.toml | 5 + ddm/src/admin.rs | 135 ++- ddm/src/db.rs | 16 + ddm/src/discovery.rs | 67 +- ddm/src/exchange.rs | 44 +- ddm/src/lib.rs | 1 + ddm/src/oxstats.rs | 337 ++++++++ ddm/src/sm.rs | 32 +- ddmadm/src/main.rs | 72 +- ddmd/Cargo.toml | 1 + ddmd/src/main.rs | 58 +- mg-admin-client/Cargo.toml | 2 - mg-admin-client/src/lib.rs | 26 +- mg-common/Cargo.toml | 7 + mg-common/src/lib.rs | 28 + mg-common/src/nexus.rs | 94 +++ mg-common/src/stats.rs | 10 + mg-lower/Cargo.toml | 1 + mg-lower/src/ddm.rs | 7 +- mg-lower/src/dendrite.rs | 40 +- mg-lower/src/lib.rs | 60 +- mgadm/src/bgp.rs | 34 +- mgadm/src/static_routing.rs | 5 +- mgd/Cargo.toml | 6 + mgd/src/admin.rs | 3 + mgd/src/bfd_admin.rs | 2 +- mgd/src/bgp_admin.rs | 5 +- mgd/src/main.rs | 55 +- mgd/src/oxstats.rs | 823 +++++++++++++++++++ openapi/ddm-admin.json | 77 ++ rdb/src/db.rs | 14 + smf/ddm/manifest.xml | 3 + smf/ddm_method_script.sh | 21 +- smf/mgd/manifest.xml | 5 +- smf/mgd_method_script.sh | 12 +- tests/Cargo.toml | 1 + tests/src/ddm.rs | 35 +- 44 files changed, 3486 insertions(+), 732 deletions(-) create mode 100644 ddm/src/oxstats.rs create mode 100644 mg-common/src/nexus.rs create mode 100644 mg-common/src/stats.rs create mode 100644 mgd/src/oxstats.rs diff --git a/Cargo.lock b/Cargo.lock index 6d694e31..61c7412f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,14 +19,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.32", ] [[package]] @@ -38,6 +38,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -55,9 +61,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -69,9 +75,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -103,26 +109,38 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "api_identity" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/omicron?branch=main#0531d6161ee2b670a0ab2a72f26727d4ec3cacaf" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" dependencies = [ "omicron-workspace-hack", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] [[package]] name = "arrayref" @@ -161,18 +179,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -239,6 +257,18 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bfd" version = "0.1.0" @@ -280,7 +310,7 @@ dependencies = [ [[package]] name = "bhyve_api" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "bhyve_api_sys", "libc", @@ -290,7 +320,7 @@ dependencies = [ [[package]] name = "bhyve_api_sys" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "libc", "strum", @@ -304,9 +334,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitstruct" @@ -328,11 +358,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", @@ -354,9 +393,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" @@ -394,12 +433,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -409,9 +445,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", @@ -419,7 +455,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -451,9 +487,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -461,9 +497,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -473,14 +509,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -514,7 +550,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/dendrite?branch=main#90d850d43ccc25f45483227567b37bd7aada0bb0" +source = "git+https://github.com/oxidecomputer/dendrite?branch=main#41ddeab9d43d90a51e6fc1c236dc9982fc76f922" dependencies = [ "anyhow", "chrono", @@ -564,7 +600,7 @@ dependencies = [ [[package]] name = "cpuid_profile_config" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "propolis", "serde", @@ -575,9 +611,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -590,9 +626,9 @@ checksum = "b31d2174830f395fd7e413c2f8a119252de36356982f805f495269331e97559e" [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -650,9 +686,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core", "darling_macro", @@ -660,27 +696,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -694,6 +730,7 @@ name = "ddm" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "common", "dpd-client", "dropshot", @@ -702,8 +739,11 @@ dependencies = [ "ispf", "libnet 0.1.0 (git+https://github.com/oxidecomputer/netadm-sys?branch=main)", "mg-common", + "omicron-common", "opte-ioctl", "oxide-vpc", + "oximeter", + "oximeter-producer", "pretty_assertions", "schemars", "serde", @@ -711,22 +751,23 @@ dependencies = [ "serde_repr", "sled", "slog", - "socket2 0.5.5", + "socket2 0.5.6", "thiserror", "tokio", + "uuid 1.8.0", ] [[package]] name = "ddm-admin-client" version = "0.1.0" dependencies = [ - "mg-common", "percent-encoding", - "progenitor 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", + "progenitor", "reqwest", "serde", "serde_json", "slog", + "uuid 1.8.0", ] [[package]] @@ -762,6 +803,7 @@ dependencies = [ "slog-async", "slog-bunyan", "tokio", + "uuid 1.8.0", ] [[package]] @@ -772,9 +814,9 @@ checksum = "ffe7ed1d93f4553003e20b629abe9085e1e81b1429520f897f8f8860bc6dfc21" [[package]] name = "defmt" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" +checksum = "3939552907426de152b3c2c6f51ed53f98f448babd26f28694c95f5906194595" dependencies = [ "bitflags 1.3.2", "defmt-macros", @@ -782,22 +824,22 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" +checksum = "18bdc7a7b92ac413e19e95240e75d3a73a8d8e78aa24a594c22cbb4d44b4bbda" dependencies = [ "defmt-parser", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "defmt-parser" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" +checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f" dependencies = [ "thiserror", ] @@ -812,6 +854,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derror-macro" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "diff" version = "0.1.13" @@ -853,7 +906,7 @@ dependencies = [ [[package]] name = "dladm" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "libc", "strum", @@ -872,6 +925,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "dns-service-client" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "anyhow", + "chrono", + "http 0.2.12", + "omicron-workspace-hack", + "progenitor", + "reqwest", + "schemars", + "serde", + "slog", +] + [[package]] name = "dof" version = "0.3.0" @@ -883,21 +952,21 @@ dependencies = [ "serde", "serde_json", "thiserror", - "zerocopy", + "zerocopy 0.7.32", ] [[package]] name = "dpd-client" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/dendrite?branch=main#90d850d43ccc25f45483227567b37bd7aada0bb0" +source = "git+https://github.com/oxidecomputer/dendrite?branch=main#41ddeab9d43d90a51e6fc1c236dc9982fc76f922" dependencies = [ "async-trait", "chrono", "common", "crc8", "futures", - "http 0.2.11", - "progenitor 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", + "http 0.2.12", + "progenitor", "regress 0.6.0", "reqwest", "schemars", @@ -905,13 +974,13 @@ dependencies = [ "serde_json", "slog", "tokio", - "uuid 1.7.0", + "uuid 1.8.0", ] [[package]] name = "dropshot" -version = "0.9.1-dev" -source = "git+https://github.com/oxidecomputer/dropshot?branch=main#605a6d1421b610b37cf9435c5094e15b59de88b9" +version = "0.10.1-dev" +source = "git+https://github.com/oxidecomputer/dropshot?branch=main#2d9b9065a864120efa638acdd3b70d53cb11771c" dependencies = [ "async-stream", "async-trait", @@ -924,16 +993,16 @@ dependencies = [ "form_urlencoded", "futures", "hostname", - "http 0.2.11", + "http 0.2.12", "hyper", - "indexmap 2.2.2", + "indexmap 2.2.5", "multer", "openapiv3", "paste", "percent-encoding", "proc-macro2", "rustls 0.22.2", - "rustls-pemfile 2.0.0", + "rustls-pemfile 2.1.1", "schemars", "serde", "serde_json", @@ -947,23 +1016,23 @@ dependencies = [ "slog-term", "tokio", "tokio-rustls 0.25.0", - "toml 0.8.9", + "toml 0.8.12", "usdt", - "uuid 1.7.0", + "uuid 1.8.0", "version_check", "waitgroup", ] [[package]] name = "dropshot_endpoint" -version = "0.9.1-dev" -source = "git+https://github.com/oxidecomputer/dropshot?branch=main#605a6d1421b610b37cf9435c5094e15b59de88b9" +version = "0.10.1-dev" +source = "git+https://github.com/oxidecomputer/dropshot?branch=main#2d9b9065a864120efa638acdd3b70d53cb11771c" dependencies = [ "proc-macro2", "quote", "serde", "serde_tokenstream", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -979,15 +1048,15 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "embedded-io" @@ -1004,6 +1073,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -1042,12 +1123,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - [[package]] name = "fastrand" version = "2.0.1" @@ -1067,10 +1142,10 @@ dependencies = [ ] [[package]] -name = "finl_unicode" -version = "1.2.0" +name = "fixedbitset" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" @@ -1115,7 +1190,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -1205,7 +1280,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -1247,6 +1322,40 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gateway-client" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "base64 0.22.0", + "chrono", + "gateway-messages", + "omicron-workspace-hack", + "progenitor", + "rand", + "reqwest", + "schemars", + "serde", + "serde_json", + "slog", + "uuid 1.8.0", +] + +[[package]] +name = "gateway-messages" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/management-gateway-service?rev=2739c18e80697aa6bc235c935176d14b4d757ee9#2739c18e80697aa6bc235c935176d14b4d757ee9" +dependencies = [ + "bitflags 1.3.2", + "hubpack", + "serde", + "serde_repr", + "static_assertions", + "strum_macros 0.25.3", + "uuid 1.8.0", + "zerocopy 0.6.6", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1296,17 +1405,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.11", - "indexmap 2.2.2", + "http 0.2.12", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -1315,9 +1424,9 @@ dependencies = [ [[package]] name = "half" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" dependencies = [ "cfg-if", "crunchy", @@ -1352,6 +1461,10 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heapless" @@ -1378,6 +1491,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1389,9 +1508,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1402,15 +1521,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1424,9 +1534,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1435,9 +1545,9 @@ dependencies = [ [[package]] name = "http" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1451,7 +1561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.11", + "http 0.2.12", "pin-project-lite", ] @@ -1467,6 +1577,27 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hubpack" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a0b84aeae519f65e0ba3aa998327080993426024edbd5cc38dbaf5ec524303" +dependencies = [ + "hubpack_derive", + "serde", +] + +[[package]] +name = "hubpack_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f928320aff16ee8818ef7309180f8b5897057fd79d9dcb8de3ed1ba6dcc125a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "humantime" version = "2.1.0" @@ -1484,13 +1615,13 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.11", + "http 0.2.12", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -1504,7 +1635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.11", + "http 0.2.12", "hyper", "rustls 0.21.10", "tokio", @@ -1526,9 +1657,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1553,6 +1684,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -1566,7 +1708,7 @@ dependencies = [ [[package]] name = "illumos-sys-hdrs" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" [[package]] name = "indexmap" @@ -1581,9 +1723,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1599,6 +1741,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "internal-dns" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "anyhow", + "chrono", + "dns-service-client", + "futures", + "hyper", + "omicron-common", + "omicron-workspace-hack", + "reqwest", + "slog", + "thiserror", + "trust-dns-resolver", + "uuid 1.8.0", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.6", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1615,6 +1788,17 @@ dependencies = [ "serde", ] +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "ispf" version = "0.1.0" @@ -1649,9 +1833,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1659,10 +1843,10 @@ dependencies = [ [[package]] name = "kstat-macro" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -1694,7 +1878,7 @@ source = "git+https://github.com/oxidecomputer/dlpi-sys#1d587ea98cf2d36f1b1624b0 [[package]] name = "libfalcon" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/falcon?branch=main#1260f16acf6a021ee90696694badc8c735b16204" +source = "git+https://github.com/oxidecomputer/falcon?branch=main#1b228b556f53516f0a78ab9d63be5adf977deb97" dependencies = [ "anstyle", "anyhow", @@ -1722,7 +1906,7 @@ dependencies = [ "tokio", "tokio-tungstenite 0.21.0", "toml 0.7.8", - "uuid 1.7.0", + "uuid 1.8.0", "zone 0.1.8", ] @@ -1776,11 +1960,17 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1799,9 +1989,18 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lru-cache" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] [[package]] name = "macaddr" @@ -1825,14 +2024,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] -name = "md-5" -version = "0.10.6" +name = "matches" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" @@ -1852,9 +2047,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.7.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -1864,11 +2059,9 @@ name = "mg-admin-client" version = "0.1.0" dependencies = [ "anyhow", - "bgp", "chrono", "percent-encoding", - "progenitor 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", - "rdb", + "progenitor", "reqwest", "schemars", "serde", @@ -1881,10 +2074,17 @@ name = "mg-common" version = "0.1.0" dependencies = [ "anstyle", + "backoff", "clap", + "internal-dns", + "omicron-common", + "oximeter", + "oximeter-producer", "schemars", "serde", + "slog", "thiserror", + "tokio", ] [[package]] @@ -1906,8 +2106,9 @@ dependencies = [ "common", "ddm-admin-client", "dpd-client", - "http 0.2.11", + "http 0.2.12", "libnet 0.1.0 (git+https://github.com/oxidecomputer/netadm-sys?branch=main)", + "mg-common", "rdb", "slog", "thiserror", @@ -1936,6 +2137,7 @@ dependencies = [ "slog-envlogger", "slog-term", "tokio", + "uuid 1.8.0", "zone 0.3.0", "ztest", ] @@ -1968,12 +2170,17 @@ dependencies = [ "anyhow", "bfd", "bgp", + "chrono", "clap", "colored", "dropshot", - "http 0.2.11", + "hostname", + "http 0.2.12", "mg-common", "mg-lower", + "omicron-common", + "oximeter", + "oximeter-producer", "rand", "rdb", "schemars", @@ -1983,6 +2190,7 @@ dependencies = [ "slog-term", "thiserror", "tokio", + "uuid 1.8.0", ] [[package]] @@ -1999,18 +2207,18 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -2026,7 +2234,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.0.0", + "http 1.1.0", "httparse", "log", "memchr", @@ -2053,6 +2261,79 @@ dependencies = [ "tempfile", ] +[[package]] +name = "newtype-uuid" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5ff2b31594942586c1520da8f1e5c705729ec67b3c2ad0fe459f0b576e4d9a" +dependencies = [ + "schemars", + "serde", + "uuid 1.8.0", +] + +[[package]] +name = "newtype_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8cd24d9f185bb7223958d8c1ff7a961b74b1953fd05dba7cc568a63b3861ec" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "nexus-client" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "chrono", + "futures", + "ipnetwork", + "nexus-types", + "omicron-common", + "omicron-passwords", + "omicron-uuid-kinds", + "omicron-workspace-hack", + "progenitor", + "regress 0.9.0", + "reqwest", + "schemars", + "serde", + "serde_json", + "slog", + "uuid 1.8.0", +] + +[[package]] +name = "nexus-types" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "anyhow", + "api_identity", + "base64 0.22.0", + "chrono", + "dns-service-client", + "futures", + "gateway-client", + "humantime", + "omicron-common", + "omicron-passwords", + "omicron-uuid-kinds", + "omicron-workspace-hack", + "openssl", + "parse-display", + "schemars", + "serde", + "serde_json", + "serde_with", + "sled-agent-client", + "steno", + "strum", + "thiserror", + "uuid 1.8.0", +] + [[package]] name = "nom" version = "7.1.3" @@ -2078,9 +2359,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] @@ -2093,19 +2374,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -2125,9 +2405,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -2139,7 +2419,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.9", "libc", ] @@ -2182,14 +2462,14 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -2221,7 +2501,7 @@ dependencies = [ [[package]] name = "omicron-common" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/omicron?branch=main#0531d6161ee2b670a0ab2a72f26727d4ec3cacaf" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" dependencies = [ "anyhow", "api_identity", @@ -2232,28 +2512,53 @@ dependencies = [ "dropshot", "futures", "hex", - "http 0.2.11", + "http 0.2.12", "ipnetwork", "macaddr", + "omicron-uuid-kinds", "omicron-workspace-hack", "once_cell", "parse-display", - "progenitor 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", + "progenitor", + "progenitor-client", "rand", + "regress 0.9.0", "reqwest", "schemars", - "semver", + "semver 1.0.22", "serde", "serde_human_bytes", "serde_json", "serde_with", "slog", + "slog-error-chain", "strum", "thiserror", "tokio", - "tokio-postgres", - "toml 0.8.9", - "uuid 1.7.0", + "uuid 1.8.0", +] + +[[package]] +name = "omicron-passwords" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "argon2", + "omicron-workspace-hack", + "rand", + "schemars", + "serde", + "serde_with", + "thiserror", +] + +[[package]] +name = "omicron-uuid-kinds" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "newtype-uuid", + "schemars", ] [[package]] @@ -2281,7 +2586,7 @@ dependencies = [ "hex", "reqwest", "ring 0.16.20", - "semver", + "semver 1.0.22", "serde", "serde_derive", "serde_json", @@ -2306,18 +2611,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc02deea53ffe807708244e5914f6b099ad7015a207ee24317c22112e17d9c5c" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.5", "serde", "serde_json", ] [[package]] name = "openssl" -version = "0.10.63" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types 0.3.2", "libc", @@ -2334,7 +2639,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -2345,9 +2650,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", @@ -2358,9 +2663,10 @@ dependencies = [ [[package]] name = "opte" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" dependencies = [ "cfg-if", + "derror-macro", "dyn-clone", "illumos-sys-hdrs", "kstat-macro", @@ -2368,13 +2674,14 @@ dependencies = [ "postcard", "serde", "smoltcp", + "tabwriter", "version_check", ] [[package]] name = "opte-api" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" dependencies = [ "illumos-sys-hdrs", "ipnetwork", @@ -2386,7 +2693,7 @@ dependencies = [ [[package]] name = "opte-ioctl" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" dependencies = [ "libc", "libnet 0.1.0 (git+https://github.com/oxidecomputer/netadm-sys)", @@ -2400,7 +2707,7 @@ dependencies = [ [[package]] name = "oxide-vpc" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?branch=master#b74f9d9df240fe2670cafb704d7fd3d9267c4007" +source = "git+https://github.com/oxidecomputer/opte?branch=master#a4c956e44fc9b75b58b83ad2eec22f6bd9005262" dependencies = [ "cfg-if", "illumos-sys-hdrs", @@ -2408,13 +2715,14 @@ dependencies = [ "poptrie", "serde", "smoltcp", - "zerocopy", + "tabwriter", + "zerocopy 0.7.32", ] [[package]] name = "oximeter" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/omicron?branch=main#0531d6161ee2b670a0ab2a72f26727d4ec3cacaf" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" dependencies = [ "bytes", "chrono", @@ -2428,18 +2736,38 @@ dependencies = [ "serde_json", "strum", "thiserror", - "uuid 1.7.0", + "uuid 1.8.0", ] [[package]] name = "oximeter-macro-impl" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/omicron?branch=main#0531d6161ee2b670a0ab2a72f26727d4ec3cacaf" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" dependencies = [ "omicron-workspace-hack", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", +] + +[[package]] +name = "oximeter-producer" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "chrono", + "dropshot", + "nexus-client", + "omicron-common", + "omicron-workspace-hack", + "oximeter", + "schemars", + "serde", + "slog", + "slog-dtrace", + "thiserror", + "tokio", + "uuid 1.8.0", ] [[package]] @@ -2492,28 +2820,38 @@ dependencies = [ [[package]] name = "parse-display" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c" +checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5" dependencies = [ - "once_cell", "parse-display-derive", "regex", + "regex-syntax", ] [[package]] name = "parse-display-derive" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68517892c8daf78da08c0db777fcc17e07f2f63ef70041718f8a7630ad84f341" +checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790" dependencies = [ - "once_cell", "proc-macro2", "quote", "regex", - "regex-syntax 0.7.5", + "regex-syntax", "structmeta", - "syn 2.0.48", + "syn 2.0.53", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", ] [[package]] @@ -2530,9 +2868,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.6" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" dependencies = [ "memchr", "thiserror", @@ -2541,9 +2879,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.6" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" dependencies = [ "pest", "pest_generator", @@ -2551,22 +2889,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.6" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "pest_meta" -version = "2.7.6" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" dependencies = [ "once_cell", "pest", @@ -2574,21 +2912,15 @@ dependencies = [ ] [[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" +name = "petgraph" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ - "siphasher", + "fixedbitset", + "indexmap 2.2.5", + "serde", + "serde_derive", ] [[package]] @@ -2605,9 +2937,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -2640,37 +2972,6 @@ dependencies = [ "serde", ] -[[package]] -name = "postgres-protocol" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" -dependencies = [ - "base64 0.21.7", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" -dependencies = [ - "bytes", - "chrono", - "fallible-iterator", - "postgres-protocol", - "uuid 1.7.0", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -2750,94 +3051,47 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "progenitor" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" -dependencies = [ - "progenitor-client 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", - "progenitor-impl 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", - "progenitor-macro 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", - "serde_json", -] - -[[package]] -name = "progenitor" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" -dependencies = [ - "progenitor-client 0.5.0 (git+https://github.com/oxidecomputer/progenitor)", - "progenitor-impl 0.5.0 (git+https://github.com/oxidecomputer/progenitor)", - "progenitor-macro 0.5.0 (git+https://github.com/oxidecomputer/progenitor)", - "serde_json", -] - -[[package]] -name = "progenitor-client" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" -dependencies = [ - "bytes", - "futures-core", - "percent-encoding", - "reqwest", - "serde", - "serde_json", - "serde_urlencoded", -] - -[[package]] -name = "progenitor-client" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" +version = "0.6.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#d3514fcfc4309e7432fba09b65394a97f3e27980" dependencies = [ - "bytes", - "futures-core", - "percent-encoding", - "reqwest", - "serde", + "progenitor-client", + "progenitor-impl", + "progenitor-macro", "serde_json", - "serde_urlencoded", ] [[package]] -name = "progenitor-impl" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" -dependencies = [ - "getopts", - "heck 0.4.1", - "http 0.2.11", - "indexmap 2.2.2", - "openapiv3", - "proc-macro2", - "quote", - "regex", - "schemars", +name = "progenitor-client" +version = "0.6.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#d3514fcfc4309e7432fba09b65394a97f3e27980" +dependencies = [ + "bytes", + "futures-core", + "percent-encoding", + "reqwest", "serde", "serde_json", - "syn 2.0.48", - "thiserror", - "typify", - "unicode-ident", + "serde_urlencoded", ] [[package]] name = "progenitor-impl" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" +version = "0.6.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#d3514fcfc4309e7432fba09b65394a97f3e27980" dependencies = [ "getopts", "heck 0.4.1", - "http 0.2.11", - "indexmap 2.2.2", + "http 0.2.12", + "indexmap 2.2.5", "openapiv3", "proc-macro2", "quote", @@ -2845,7 +3099,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn 2.0.48", + "syn 2.0.53", "thiserror", "typify", "unicode-ident", @@ -2853,46 +3107,29 @@ dependencies = [ [[package]] name = "progenitor-macro" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" -dependencies = [ - "openapiv3", - "proc-macro2", - "progenitor-impl 0.5.0 (git+https://github.com/oxidecomputer/progenitor?branch=main)", - "quote", - "schemars", - "serde", - "serde_json", - "serde_tokenstream", - "serde_yaml", - "syn 2.0.48", -] - -[[package]] -name = "progenitor-macro" -version = "0.5.0" -source = "git+https://github.com/oxidecomputer/progenitor#86b60220b88a2ca3629fb87acf8f83ff35f63aaa" +version = "0.6.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#d3514fcfc4309e7432fba09b65394a97f3e27980" dependencies = [ "openapiv3", "proc-macro2", - "progenitor-impl 0.5.0 (git+https://github.com/oxidecomputer/progenitor)", + "progenitor-impl", "quote", "schemars", "serde", "serde_json", "serde_tokenstream", "serde_yaml", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "propolis" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "anyhow", "bhyve_api", - "bitflags 2.4.2", + "bitflags 2.5.0", "bitstruct", "byteorder", "dladm", @@ -2911,19 +3148,19 @@ dependencies = [ "thiserror", "tokio", "usdt", - "uuid 1.7.0", + "uuid 1.8.0", "viona_api", ] [[package]] name = "propolis-client" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "async-trait", "base64 0.21.7", "futures", - "progenitor 0.5.0 (git+https://github.com/oxidecomputer/progenitor)", + "progenitor", "rand", "reqwest", "schemars", @@ -2933,13 +3170,13 @@ dependencies = [ "thiserror", "tokio", "tokio-tungstenite 0.20.1", - "uuid 1.7.0", + "uuid 1.8.0", ] [[package]] name = "propolis-server-config" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "cpuid_profile_config", "serde", @@ -2951,12 +3188,18 @@ dependencies = [ [[package]] name = "propolis_types" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "schemars", "serde", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.35" @@ -2998,9 +3241,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -3069,26 +3312,20 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -3107,19 +3344,19 @@ dependencies = [ [[package]] name = "regress" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed9969cad8051328011596bf549629f1b800cf1731e7964b1eef8dfc480d2c2" +checksum = "d06f9a1f7cd8473611ba1a480cf35f9c5cffc2954336ba90a982fdb7e7d7f51e" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.3", "memchr", ] [[package]] name = "reqwest" -version = "0.11.24" +version = "0.11.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" dependencies = [ "base64 0.21.7", "bytes", @@ -3127,7 +3364,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.11", + "http 0.2.12", "http-body", "hyper", "hyper-rustls", @@ -3161,6 +3398,16 @@ dependencies = [ "winreg", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "rfb" version = "0.1.0" @@ -3193,16 +3440,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3222,13 +3470,22 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +dependencies = [ + "semver 0.1.20", +] + [[package]] name = "rustix" version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -3242,7 +3499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki 0.101.7", "sct", ] @@ -3254,9 +3511,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.1", + "rustls-webpki 0.102.2", "subtle", "zeroize", ] @@ -3272,9 +3529,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" dependencies = [ "base64 0.21.7", "rustls-pki-types", @@ -3282,9 +3539,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" +checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" [[package]] name = "rustls-webpki" @@ -3292,17 +3549,17 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "rustls-webpki" -version = "0.102.1" +version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", ] @@ -3333,9 +3590,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -3368,7 +3625,7 @@ dependencies = [ "serde", "serde_json", "uuid 0.8.2", - "uuid 1.7.0", + "uuid 1.8.0", ] [[package]] @@ -3406,7 +3663,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -3415,7 +3672,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3444,18 +3701,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" + +[[package]] +name = "semver" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -3471,13 +3734,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -3502,9 +3765,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -3513,9 +3776,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -3529,7 +3792,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -3550,7 +3813,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -3567,16 +3830,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.2", + "indexmap 2.2.5", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -3584,23 +3848,23 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15" +checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "serde_yaml" -version = "0.9.31" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.5", "itoa", "ryu", "serde", @@ -3638,12 +3902,6 @@ dependencies = [ "libc", ] -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "slab" version = "0.4.9" @@ -3669,6 +3927,26 @@ dependencies = [ "parking_lot 0.11.2", ] +[[package]] +name = "sled-agent-client" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/omicron?branch=main#dd4090f038605fcc5fc69d9350d4ca0ef5f5dc34" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "ipnetwork", + "omicron-common", + "omicron-workspace-hack", + "progenitor", + "regress 0.9.0", + "reqwest", + "schemars", + "serde", + "slog", + "uuid 1.8.0", +] + [[package]] name = "slog" version = "2.7.0" @@ -3699,6 +3977,20 @@ dependencies = [ "time", ] +[[package]] +name = "slog-dtrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c4003e4582bc29415fcbf94f53346c9c379d5dafac45d4bafaa39c7f0453ac" +dependencies = [ + "chrono", + "serde", + "serde_json", + "slog", + "usdt", + "version_check", +] + [[package]] name = "slog-envlogger" version = "2.2.0" @@ -3714,6 +4006,25 @@ dependencies = [ "slog-term", ] +[[package]] +name = "slog-error-chain" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/slog-error-chain?branch=main#15f69041f45774602108e47fb25e705dc23acfb2" +dependencies = [ + "slog", + "slog-error-chain-derive", +] + +[[package]] +name = "slog-error-chain-derive" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/slog-error-chain?branch=main#15f69041f45774602108e47fb25e705dc23acfb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "slog-json" version = "2.6.1" @@ -3750,11 +4061,11 @@ dependencies = [ [[package]] name = "slog-term" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c" +checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" dependencies = [ - "atty", + "is-terminal", "slog", "term", "thread_local", @@ -3802,12 +4113,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3829,14 +4140,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "stringprep" -version = "0.1.4" +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "steno" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "6a1e7ccea133c197729abfd16dccf91a3c4d0da1e94bb0c0aa164c2b8a227481" dependencies = [ - "finl_unicode", - "unicode-bidi", - "unicode-normalization", + "anyhow", + "async-trait", + "chrono", + "futures", + "lazy_static", + "newtype_derive", + "petgraph", + "schemars", + "serde", + "serde_json", + "slog", + "thiserror", + "tokio", + "uuid 1.8.0", ] [[package]] @@ -3853,34 +4181,34 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "structmeta" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "structmeta-derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "strum" -version = "0.25.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ - "strum_macros", + "strum_macros 0.26.2", ] [[package]] @@ -3893,7 +4221,20 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.53", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.53", ] [[package]] @@ -3915,9 +4256,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -3979,13 +4320,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", "rustix", "windows-sys 0.52.0", ] @@ -4012,22 +4352,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -4042,9 +4382,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -4052,9 +4392,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", @@ -4112,7 +4452,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -4125,7 +4465,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -4138,32 +4478,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-postgres" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot 0.12.1", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand", - "socket2 0.5.5", - "tokio", - "tokio-util", - "whoami", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -4237,14 +4551,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.9" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.1", + "toml_edit 0.22.8", ] [[package]] @@ -4262,11 +4576,11 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4275,11 +4589,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.5", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c12219811e0c1ba077867254e5ad62ee2c9c190b0d957110750ac0cda1ae96cd" +dependencies = [ + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.5", ] [[package]] @@ -4313,7 +4638,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -4325,6 +4650,51 @@ dependencies = [ "once_cell", ] +[[package]] +name = "trust-dns-proto" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "lru-cache", + "parking_lot 0.12.1", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -4340,7 +4710,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.11", + "http 0.2.12", "httparse", "log", "rand", @@ -4359,7 +4729,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.0.0", + "http 1.1.0", "httparse", "log", "rand", @@ -4377,8 +4747,8 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typify" -version = "0.0.15" -source = "git+https://github.com/oxidecomputer/typify#1f97f167923f001818d461b1286f8a5242abf8b1" +version = "0.0.16" +source = "git+https://github.com/oxidecomputer/typify#c5aec61f3dd371331929b58f71ce086f9899d283" dependencies = [ "typify-impl", "typify-macro", @@ -4386,25 +4756,25 @@ dependencies = [ [[package]] name = "typify-impl" -version = "0.0.15" -source = "git+https://github.com/oxidecomputer/typify#1f97f167923f001818d461b1286f8a5242abf8b1" +version = "0.0.16" +source = "git+https://github.com/oxidecomputer/typify#c5aec61f3dd371331929b58f71ce086f9899d283" dependencies = [ "heck 0.4.1", "log", "proc-macro2", "quote", - "regress 0.7.1", + "regress 0.9.0", "schemars", "serde_json", - "syn 2.0.48", + "syn 2.0.53", "thiserror", "unicode-ident", ] [[package]] name = "typify-macro" -version = "0.0.15" -source = "git+https://github.com/oxidecomputer/typify#1f97f167923f001818d461b1286f8a5242abf8b1" +version = "0.0.16" +source = "git+https://github.com/oxidecomputer/typify#c5aec61f3dd371331929b58f71ce086f9899d283" dependencies = [ "proc-macro2", "quote", @@ -4412,7 +4782,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn 2.0.48", + "syn 2.0.53", "typify-impl", ] @@ -4436,18 +4806,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -4457,9 +4827,9 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -4480,7 +4850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", ] @@ -4510,7 +4880,7 @@ dependencies = [ "proc-macro2", "quote", "serde_tokenstream", - "syn 2.0.48", + "syn 2.0.53", "usdt-impl", ] @@ -4528,7 +4898,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.48", + "syn 2.0.53", "thiserror", "thread-id", "version_check", @@ -4544,7 +4914,7 @@ dependencies = [ "proc-macro2", "quote", "serde_tokenstream", - "syn 2.0.48", + "syn 2.0.53", "usdt-impl", ] @@ -4570,7 +4940,7 @@ dependencies = [ "slog-async", "slog-envlogger", "slog-term", - "socket2 0.5.5", + "socket2 0.5.6", ] [[package]] @@ -4581,9 +4951,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "serde", @@ -4604,7 +4974,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "viona_api" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "libc", "viona_api_sys", @@ -4613,7 +4983,7 @@ dependencies = [ [[package]] name = "viona_api_sys" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?branch=master#910c81e449b775ec8e7c22bc12196cbad938b38a" +source = "git+https://github.com/oxidecomputer/propolis?rev=6dceb9ef69c217cb78a2018bbedafbc19f6ec1af#6dceb9ef69c217cb78a2018bbedafbc19f6ec1af" dependencies = [ "libc", ] @@ -4629,9 +4999,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4654,9 +5024,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4664,24 +5034,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -4691,9 +5061,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4701,22 +5071,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" @@ -4733,9 +5103,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -4743,19 +5113,15 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] -name = "whoami" -version = "1.4.1" +name = "widestring" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "winapi" @@ -4794,7 +5160,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -4812,7 +5178,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -4832,17 +5198,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -4853,9 +5219,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -4865,9 +5231,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -4877,9 +5243,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -4889,9 +5255,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -4901,9 +5267,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -4913,9 +5279,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -4925,15 +5291,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.5.36" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" dependencies = [ "memchr", ] @@ -4965,6 +5340,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive 0.6.6", +] + [[package]] name = "zerocopy" version = "0.7.32" @@ -4972,7 +5357,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.32", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", ] [[package]] @@ -4983,7 +5379,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -5041,7 +5437,7 @@ dependencies = [ [[package]] name = "ztest" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/falcon?branch=main#1260f16acf6a021ee90696694badc8c735b16204" +source = "git+https://github.com/oxidecomputer/falcon?branch=main#1b228b556f53516f0a78ab9d63be5adf977deb97" dependencies = [ "anyhow", "libnet 0.1.0 (git+https://github.com/oxidecomputer/netadm-sys?branch=main)", diff --git a/Cargo.toml b/Cargo.toml index bc989faa..e74dad46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,8 +77,14 @@ ciborium = "0.2" http = "0.2" humantime = "2.1" rand = "0.8" +backoff = "0.4" mg-common = { path = "mg-common" } chrono = { version = "0.4", features = ["serde"] } +oximeter = { git = "https://github.com/oxidecomputer/omicron", branch = "main"} +oximeter-producer = { git = "https://github.com/oxidecomputer/omicron", branch= "main"} +omicron-common = { git = "https://github.com/oxidecomputer/omicron", branch= "main"} +internal-dns = { git = "https://github.com/oxidecomputer/omicron", branch = "main"} +uuid = { version = "1.7", features = ["serde", "v4"] } [workspace.dependencies.opte-ioctl] git = "https://github.com/oxidecomputer/opte" diff --git a/bfd/src/lib.rs b/bfd/src/lib.rs index c675d8ce..f22c341a 100644 --- a/bfd/src/lib.rs +++ b/bfd/src/lib.rs @@ -10,6 +10,8 @@ use slog::{warn, Logger}; use sm::StateMachine; use std::collections::HashMap; use std::net::IpAddr; +use std::sync::atomic::AtomicU64; +use std::sync::Arc; use std::time::Duration; pub mod bidi; @@ -76,10 +78,29 @@ impl Daemon { } } +#[derive(Default)] +pub struct SessionCounters { + pub control_packets_sent: AtomicU64, + pub control_packet_send_failures: AtomicU64, + pub control_packets_received: AtomicU64, + pub admin_down_status_received: AtomicU64, + pub down_status_received: AtomicU64, + pub init_status_received: AtomicU64, + pub up_status_received: AtomicU64, + pub unknown_status_received: AtomicU64, + pub transition_to_init: AtomicU64, + pub transition_to_down: AtomicU64, + pub transition_to_up: AtomicU64, + pub timeout_expired: AtomicU64, + pub message_receive_error: AtomicU64, + pub unexpected_message: AtomicU64, +} + /// A session holds a BFD state machine for a particular peer. pub struct Session { pub sm: StateMachine, pub mode: SessionMode, + pub counters: Arc, } impl Session { @@ -94,10 +115,16 @@ impl Session { db: rdb::Db, log: Logger, ) -> Self { - let mut sm = - StateMachine::new(addr, required_rx, detection_multiplier, log); + let counters = Arc::new(SessionCounters::default()); + let mut sm = StateMachine::new( + addr, + required_rx, + detection_multiplier, + counters.clone(), + log, + ); sm.run(ep, db); - Session { sm, mode } + Session { sm, mode, counters } } } diff --git a/bfd/src/sm.rs b/bfd/src/sm.rs index 50d8b80c..42844c6f 100644 --- a/bfd/src/sm.rs +++ b/bfd/src/sm.rs @@ -2,11 +2,11 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::err; -use crate::packet::Control; +use crate::packet::{Control, State as PacketState}; use crate::{ bidi, inf, packet, trc, util::update_peer_info, wrn, BfdPeerState, PeerInfo, }; +use crate::{err, SessionCounters}; use anyhow::{anyhow, Result}; use slog::{warn, Logger}; use std::net::IpAddr; @@ -48,6 +48,7 @@ pub struct StateMachine { required_rx: Duration, detection_multiplier: u8, kill_switch: Arc, + counters: Arc, log: Logger, } @@ -64,6 +65,7 @@ impl StateMachine { peer: IpAddr, required_rx: Duration, detection_multiplier: u8, + counters: Arc, log: Logger, ) -> Self { let state = Down::new(peer, log.clone()); @@ -73,6 +75,7 @@ impl StateMachine { required_rx, detection_multiplier, kill_switch: Arc::new(AtomicBool::new(false)), + counters, log, } } @@ -122,6 +125,7 @@ impl StateMachine { let peer = self.peer; let kill_switch = self.kill_switch.clone(); let log = self.log.clone(); + let counters = self.counters.clone(); spawn(move || loop { let prev = state.read().unwrap().state(); let (st, ep) = match state.read().unwrap().run( @@ -130,6 +134,7 @@ impl StateMachine { remote.clone(), kill_switch.clone(), db.clone(), + counters.clone(), ) { Ok(result) => result, Err(_) => break, @@ -143,6 +148,23 @@ impl StateMachine { } if prev != new { + match new { + BfdPeerState::AdminDown | BfdPeerState::Down => { + counters + .transition_to_down + .fetch_add(1, Ordering::Relaxed); + } + BfdPeerState::Init => { + counters + .transition_to_init + .fetch_add(1, Ordering::Relaxed); + } + BfdPeerState::Up => { + counters + .transition_to_up + .fetch_add(1, Ordering::Relaxed); + } + } inf!(log, prev, peer; "transition -> {:?}", new); } }); @@ -162,6 +184,7 @@ impl StateMachine { let peer = self.peer; let stop = self.kill_switch.clone(); let log = self.log.clone(); + let counters = self.counters.clone(); // State does not change for the lifetime of the trait so it's safe to // just copy it out of self for sending into the spawned thread. The // reason this is a dynamic method at all is to get runtime polymorphic @@ -203,6 +226,13 @@ impl StateMachine { if let Err(e) = sender.send((peer, pkt)) { wrn!(log, st, peer; "send: {}", e); + counters + .control_packet_send_failures + .fetch_add(1, Ordering::Relaxed); + } else { + counters + .control_packets_sent + .fetch_add(1, Ordering::Relaxed); } }); } @@ -255,6 +285,7 @@ pub(crate) trait State: Sync + Send { remote: Arc>, kill_switch: Arc, db: rdb::Db, + counters: Arc, ) -> Result<(Box, BfdEndpoint)>; /// Return the `BfdPeerState` associated with the implementor of this trait. @@ -297,6 +328,7 @@ pub(crate) trait State: Sync + Send { local: PeerInfo, remote: &Arc>, log: Logger, + counters: Arc, ) -> Result { match endpoint.rx.recv_timeout( local.required_min_rx * local.detection_multiplier.into(), @@ -304,6 +336,34 @@ pub(crate) trait State: Sync + Send { Ok((addr, msg)) => { trc!(log, self.state(), self.peer(); "recv: {:?}", msg); + match msg.state() { + PacketState::Peer(BfdPeerState::AdminDown) => { + counters + .admin_down_status_received + .fetch_add(1, Ordering::Relaxed); + } + PacketState::Peer(BfdPeerState::Down) => { + counters + .down_status_received + .fetch_add(1, Ordering::Relaxed); + } + PacketState::Peer(BfdPeerState::Init) => { + counters + .init_status_received + .fetch_add(1, Ordering::Relaxed); + } + PacketState::Peer(BfdPeerState::Up) => { + counters + .up_status_received + .fetch_add(1, Ordering::Relaxed); + } + PacketState::Unknown(_) => { + counters + .unknown_status_received + .fetch_add(1, Ordering::Relaxed); + } + } + update_peer_info(remote, &msg); if msg.poll() { @@ -320,6 +380,7 @@ pub(crate) trait State: Sync + Send { } Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { wrn!(log, self.state(), self.peer(); "timeout expired"); + counters.timeout_expired.fetch_add(1, Ordering::Relaxed); let next = Down::new(self.peer(), log.clone()); Ok(RecvResult::TransitionTo(Box::new(next))) } @@ -331,6 +392,9 @@ pub(crate) trait State: Sync + Send { "recv: {}, exiting recieve loop", e ); + counters + .message_receive_error + .fetch_add(1, Ordering::Relaxed); Err(anyhow::anyhow!("recv channel closed")) } } @@ -372,6 +436,7 @@ impl State for Down { remote: Arc>, kill_switch: Arc, db: rdb::Db, + counters: Arc, ) -> Result<(Box, BfdEndpoint)> { match self.peer { IpAddr::V4(addr) => db.disable_nexthop4(addr), @@ -384,13 +449,18 @@ impl State for Down { } loop { // Get an incoming message - let (_addr, msg) = - match self.recv(&endpoint, local, &remote, self.log.clone())? { - RecvResult::MessageFrom((addr, control)) => (addr, control), - RecvResult::TransitionTo(state) => { - return Ok((state, endpoint)) - } - }; + let (_addr, msg) = match self.recv( + &endpoint, + local, + &remote, + self.log.clone(), + counters.clone(), + )? { + RecvResult::MessageFrom((addr, control)) => (addr, control), + RecvResult::TransitionTo(state) => { + return Ok((state, endpoint)) + } + }; if kill_switch.load(Ordering::Relaxed) { return Err(anyhow!("killed")); @@ -455,16 +525,22 @@ impl State for Init { remote: Arc>, kill_switch: Arc, _db: rdb::Db, + counters: Arc, ) -> Result<(Box, BfdEndpoint)> { loop { // Get an incoming message - let (_addr, msg) = - match self.recv(&endpoint, local, &remote, self.log.clone())? { - RecvResult::MessageFrom((addr, control)) => (addr, control), - RecvResult::TransitionTo(state) => { - return Ok((state, endpoint)) - } - }; + let (_addr, msg) = match self.recv( + &endpoint, + local, + &remote, + self.log.clone(), + counters.clone(), + )? { + RecvResult::MessageFrom((addr, control)) => (addr, control), + RecvResult::TransitionTo(state) => { + return Ok((state, endpoint)) + } + }; if kill_switch.load(Ordering::Relaxed) { return Err(anyhow!("killed")); @@ -527,6 +603,7 @@ impl State for Up { remote: Arc>, kill_switch: Arc, db: rdb::Db, + counters: Arc, ) -> Result<(Box, BfdEndpoint)> { match self.peer { IpAddr::V4(addr) => db.enable_nexthop4(addr), @@ -539,13 +616,18 @@ impl State for Up { } loop { // Get an incoming message - let (_addr, msg) = - match self.recv(&endpoint, local, &remote, self.log.clone())? { - RecvResult::MessageFrom((addr, control)) => (addr, control), - RecvResult::TransitionTo(state) => { - return Ok((state, endpoint)) - } - }; + let (_addr, msg) = match self.recv( + &endpoint, + local, + &remote, + self.log.clone(), + counters.clone(), + )? { + RecvResult::MessageFrom((addr, control)) => (addr, control), + RecvResult::TransitionTo(state) => { + return Ok((state, endpoint)) + } + }; if kill_switch.load(Ordering::Relaxed) { return Err(anyhow!("killed")); diff --git a/bgp/src/session.rs b/bgp/src/session.rs index 802cebac..12dbf419 100644 --- a/bgp/src/session.rs +++ b/bgp/src/session.rs @@ -22,7 +22,7 @@ use slog::Logger; use std::collections::{BTreeMap, VecDeque}; use std::fmt::{self, Display, Formatter}; use std::net::{Ipv4Addr, SocketAddr}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::mpsc::{Receiver, Sender}; use std::sync::{Arc, Mutex, RwLock}; use std::time::{Duration, Instant}; @@ -409,6 +409,41 @@ impl MessageHistory { } } +#[derive(Default)] +pub struct SessionCounters { + pub keepalives_sent: AtomicU64, + pub keepalives_received: AtomicU64, + pub opens_sent: AtomicU64, + pub opens_received: AtomicU64, + pub notifications_sent: AtomicU64, + pub notifications_received: AtomicU64, + pub updates_sent: AtomicU64, + pub updates_received: AtomicU64, + pub prefixes_advertised: AtomicU64, + pub prefixes_imported: AtomicU64, + pub idle_hold_timer_expirations: AtomicU64, + pub hold_timer_expirations: AtomicU64, + pub unexpected_update_message: AtomicU64, + pub unexpected_keepalive_message: AtomicU64, + pub unexpected_open_message: AtomicU64, + pub update_nexhop_missing: AtomicU64, + pub active_connections_accepted: AtomicU64, + pub passive_connections_accepted: AtomicU64, + pub connection_retries: AtomicU64, + pub open_handle_failures: AtomicU64, + pub transitions_to_idle: AtomicU64, + pub transitions_to_connect: AtomicU64, + pub transitions_to_active: AtomicU64, + pub transitions_to_open_sent: AtomicU64, + pub transitions_to_open_confirm: AtomicU64, + pub transitions_to_session_setup: AtomicU64, + pub transitions_to_established: AtomicU64, + pub notification_send_failure: AtomicU64, + pub open_send_failure: AtomicU64, + pub keepalive_send_failure: AtomicU64, + pub update_send_failure: AtomicU64, +} + /// This is the top level object that tracks a BGP session with a peer. pub struct SessionRunner { /// A sender that can be used to send FSM events to this session. When a @@ -424,6 +459,9 @@ pub struct SessionRunner { /// included in message history. pub message_history: Arc>, + /// Counters for message types sent and received, state transitions, etc. + pub counters: Arc, + session: Arc>, event_rx: Receiver>, state: Arc>, @@ -492,6 +530,7 @@ impl SessionRunner { fanout, router, message_history: Arc::new(Mutex::new(MessageHistory::default())), + counters: Arc::new(SessionCounters::default()), db, } } @@ -544,6 +583,43 @@ impl SessionRunner { // appropriate state variables. if current.kind() != previous { inf!(self; "{} -> {}", previous, current.kind()); + match current.kind() { + FsmStateKind::Idle => { + self.counters + .transitions_to_idle + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::Connect => { + self.counters + .transitions_to_connect + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::Active => { + self.counters + .transitions_to_active + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::OpenSent => { + self.counters + .transitions_to_open_sent + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::OpenConfirm => { + self.counters + .transitions_to_open_confirm + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::SessionSetup => { + self.counters + .transitions_to_session_setup + .fetch_add(1, Ordering::Relaxed); + } + FsmStateKind::Established => { + self.counters + .transitions_to_established + .fetch_add(1, Ordering::Relaxed); + } + } *(lock!(self.state)) = current.kind(); *(lock!(self.last_state_change)) = Instant::now(); } @@ -577,8 +653,32 @@ impl SessionRunner { } FsmEvent::IdleHoldTimerExpires => { inf!(self; "idle hold time expire, attempting connect"); + self.counters + .idle_hold_timer_expirations + .fetch_add(1, Ordering::Relaxed); FsmState::Connect } + FsmEvent::Message(Message::KeepAlive) => { + self.counters + .unexpected_keepalive_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected keepalive message in idle"); + FsmState::Idle + } + FsmEvent::Message(Message::Open(_)) => { + self.counters + .unexpected_open_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected open message in idle"); + FsmState::Idle + } + FsmEvent::Message(Message::Update(_)) => { + self.counters + .unexpected_update_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected update message in idle"); + FsmState::Idle + } x => { wrn!(self; "event {:?} not allowed in idle", x); FsmState::Idle @@ -614,6 +714,9 @@ impl SessionRunner { match event { // If the connect retry timer fires, try to connect again. FsmEvent::ConnectRetryTimerExpires => { + self.counters + .connection_retries + .fetch_add(1, Ordering::Relaxed); if let Err(e) = conn .connect(self.event_tx.clone(), self.clock.resolution) { @@ -635,6 +738,9 @@ impl SessionRunner { self.clock.timers.hold_timer.enable(); lock!(self.session).connect_retry_counter = 0; self.clock.timers.connect_retry_timer.disable(); + self.counters + .passive_connections_accepted + .fetch_add(1, Ordering::Relaxed); return FsmState::OpenSent(accepted); } @@ -651,9 +757,29 @@ impl SessionRunner { self.clock.timers.hold_timer.enable(); lock!(self.session).connect_retry_counter = 0; self.clock.timers.connect_retry_timer.disable(); + self.counters + .active_connections_accepted + .fetch_add(1, Ordering::Relaxed); return FsmState::OpenSent(conn); } - + FsmEvent::Message(Message::KeepAlive) => { + self.counters + .unexpected_keepalive_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected keep alive message in connect"); + } + FsmEvent::Message(Message::Open(_)) => { + self.counters + .unexpected_open_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected open message in connect"); + } + FsmEvent::Message(Message::Update(_)) => { + self.counters + .unexpected_update_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected update message in connect"); + } // Some other event we don't care about fired, log it and carry // on. x => { @@ -682,10 +808,14 @@ impl SessionRunner { .lock() .unwrap() .receive(om.clone().into()); + self.counters.opens_received.fetch_add(1, Ordering::Relaxed); om } FsmEvent::ConnectRetryTimerExpires => { inf!(self; "active: connect retry timer expired"); + self.counters + .connection_retries + .fetch_add(1, Ordering::Relaxed); return FsmState::Idle; } // The underlying connection has accepted a TCP connection @@ -701,9 +831,31 @@ impl SessionRunner { self.clock.timers.hold_timer.enable(); lock!(self.session).connect_retry_counter = 0; self.clock.timers.connect_retry_timer.disable(); + self.counters + .passive_connections_accepted + .fetch_add(1, Ordering::Relaxed); return FsmState::OpenSent(accepted); } - FsmEvent::IdleHoldTimerExpires => return FsmState::Active(conn), + FsmEvent::IdleHoldTimerExpires => { + self.counters + .idle_hold_timer_expirations + .fetch_add(1, Ordering::Relaxed); + return FsmState::Active(conn); + } + FsmEvent::Message(Message::KeepAlive) => { + self.counters + .unexpected_keepalive_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected keepalive message in active"); + return FsmState::Active(conn); + } + FsmEvent::Message(Message::Update(_)) => { + self.counters + .unexpected_update_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected update message in active"); + return FsmState::Active(conn); + } other => { wrn!(self; "active: expected open message, received {:#?}, ignoring", @@ -746,13 +898,31 @@ impl SessionRunner { .lock() .unwrap() .receive(om.clone().into()); + self.counters.opens_received.fetch_add(1, Ordering::Relaxed); om } FsmEvent::HoldTimerExpires => { wrn!(self; "open sent: hold timer expired"); + self.counters + .hold_timer_expirations + .fetch_add(1, Ordering::Relaxed); self.send_hold_timer_expired_notification(&conn); return FsmState::Idle; } + FsmEvent::Message(Message::KeepAlive) => { + self.counters + .unexpected_keepalive_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected keepalive message in open sent"); + return FsmState::Active(conn); + } + FsmEvent::Message(Message::Update(_)) => { + self.counters + .unexpected_update_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected update message in open sent"); + return FsmState::Active(conn); + } other => { wrn!( self; @@ -767,6 +937,9 @@ impl SessionRunner { //TODO send a notification to the peer letting them know we are // rejecting the open message? self.clock.timers.connect_retry_timer.enable(); + self.counters + .open_handle_failures + .fetch_add(1, Ordering::Relaxed); return FsmState::Active(conn); } @@ -792,6 +965,9 @@ impl SessionRunner { self.clock.timers.hold_timer.enable(); self.clock.timers.keepalive_timer.reset(); self.clock.timers.keepalive_timer.enable(); + self.counters + .keepalives_received + .fetch_add(1, Ordering::Relaxed); FsmState::SessionSetup(pc) } @@ -806,15 +982,34 @@ impl SessionRunner { lock!(self.session).connect_retry_counter += 1; self.clock.timers.hold_timer.disable(); self.clock.timers.keepalive_timer.disable(); + self.counters + .notifications_received + .fetch_add(1, Ordering::Relaxed); FsmState::Idle } FsmEvent::HoldTimerExpires => { wrn!(self; "open sent: hold timer expired"); self.clock.timers.hold_timer.disable(); self.send_hold_timer_expired_notification(&pc.conn); + self.counters + .hold_timer_expirations + .fetch_add(1, Ordering::Relaxed); + FsmState::Idle + } + FsmEvent::Message(Message::Open(_)) => { + self.counters + .unexpected_open_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected open message in open confirm"); + FsmState::Idle + } + FsmEvent::Message(Message::Update(_)) => { + self.counters + .unexpected_update_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected update message in open confirm"); FsmState::Idle } - // An event we are not expecting, log it and re-enter this state. other => { wrn!( @@ -896,6 +1091,9 @@ impl SessionRunner { // state and restart the peer FSM from the connect state. FsmEvent::HoldTimerExpires => { wrn!(self; "hold timer expired"); + self.counters + .hold_timer_expirations + .fetch_add(1, Ordering::Relaxed); self.send_hold_timer_expired_notification(&pc.conn); self.exit_established(pc) } @@ -907,6 +1105,9 @@ impl SessionRunner { inf!(self; "update received: {m:#?}"); self.apply_update(m.clone(), pc.id); self.message_history.lock().unwrap().receive(m.into()); + self.counters + .updates_received + .fetch_add(1, Ordering::Relaxed); FsmState::Established(pc) } @@ -915,6 +1116,9 @@ impl SessionRunner { FsmEvent::Message(Message::Notification(m)) => { wrn!(self; "notification received: {m:#?}"); self.message_history.lock().unwrap().receive(m.into()); + self.counters + .notifications_received + .fetch_add(1, Ordering::Relaxed); self.exit_established(pc) } @@ -922,18 +1126,13 @@ impl SessionRunner { // and re-enter the established state. FsmEvent::Message(Message::KeepAlive) => { trc!(self; "keepalive received"); + self.counters + .keepalives_received + .fetch_add(1, Ordering::Relaxed); self.clock.timers.hold_timer.reset(); FsmState::Established(pc) } - // On an unexpected message, log a warning and re-enter the - // established state. - FsmEvent::Message(m) => { - wrn!(self; "established: unexpected message {m:#?}"); - // TODO should we send a notification here? - FsmState::Established(pc) - } - // An announce request has come from the administrative API or // another peer session (redistribution). Send the update to our // peer. @@ -947,6 +1146,16 @@ impl SessionRunner { FsmEvent::IdleHoldTimerExpires => FsmState::Established(pc), + // On an unexpected message, log a warning and re-enter the + // established state. + FsmEvent::Message(Message::Open(_)) => { + self.counters + .unexpected_open_message + .fetch_add(1, Ordering::Relaxed); + wrn!(self; "unexpected open message in open established"); + FsmState::Established(pc) + } + // Some unexpeted event, log and re-enter established. e => { wrn!(self; "unhandled event: {e:?}"); @@ -997,6 +1206,13 @@ impl SessionRunner { trc!(self; "sending keepalive"); if let Err(e) = conn.send(Message::KeepAlive) { err!(self; "failed to send keepalive {e}"); + self.counters + .keepalive_send_failure + .fetch_add(1, Ordering::Relaxed); + } else { + self.counters + .keepalives_sent + .fetch_add(1, Ordering::Relaxed); } } @@ -1024,7 +1240,13 @@ impl SessionRunner { if let Err(e) = conn.send(msg) { err!(self; "failed to send notification {e}"); + self.counters + .notification_send_failure + .fetch_add(1, Ordering::Relaxed); } + self.counters + .notifications_sent + .fetch_add(1, Ordering::Relaxed); } /// Send an open message to the session peer. @@ -1063,7 +1285,16 @@ impl SessionRunner { .unwrap() .send(msg.clone().into()); - conn.send(msg.into()) + self.counters.opens_sent.fetch_add(1, Ordering::Relaxed); + if let Err(e) = conn.send(msg.into()) { + err!(self; "failed to send open {e}"); + self.counters + .open_send_failure + .fetch_add(1, Ordering::Relaxed); + Err(e) + } else { + Ok(()) + } } /// Send an update message to the session peer. @@ -1089,7 +1320,17 @@ impl SessionRunner { .unwrap() .send(update.clone().into()); - conn.send(update.into()) + self.counters.updates_sent.fetch_add(1, Ordering::Relaxed); + + if let Err(e) = conn.send(update.into()) { + err!(self; "failed to send update {e}"); + self.counters + .update_send_failure + .fetch_add(1, Ordering::Relaxed); + Err(e) + } else { + Ok(()) + } } /// Exit the established state. Remove prefixes received from the session @@ -1185,6 +1426,9 @@ impl SessionRunner { self; "update with nlri entries and no nexthop recieved {update:#?}" ); + self.counters + .update_nexhop_missing + .fetch_add(1, Ordering::Relaxed); return; } }; diff --git a/ddm-admin-client/Cargo.toml b/ddm-admin-client/Cargo.toml index 7e210ac7..264386b3 100644 --- a/ddm-admin-client/Cargo.toml +++ b/ddm-admin-client/Cargo.toml @@ -10,4 +10,4 @@ slog.workspace = true percent-encoding.workspace = true reqwest.workspace = true progenitor.workspace = true -mg-common = { path = "../mg-common" } +uuid.workspace = true diff --git a/ddm-admin-client/src/lib.rs b/ddm-admin-client/src/lib.rs index 373e2ff9..38ee46fe 100644 --- a/ddm-admin-client/src/lib.rs +++ b/ddm-admin-client/src/lib.rs @@ -2,11 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -pub use mg_common::net::IpPrefix; -pub use mg_common::net::Ipv4Prefix; -pub use mg_common::net::Ipv6Prefix; -pub use mg_common::net::TunnelOrigin; - progenitor::generate_api!( spec = "../openapi/ddm-admin.json", inner_type = slog::Logger, @@ -19,11 +14,85 @@ progenitor::generate_api!( }), post_hook = (|log: &slog::Logger, result: &Result<_, _>| { slog::trace!(log, "client response"; "result" => ?result); - }), - replace = { - IpPrefix = mg_common::net::IpPrefix, - Ipv4Prefix = mg_common::net::Ipv4Prefix, - Ipv6Prefix = mg_common::net::Ipv6Prefix, - TunnelOrigin = mg_common::net::TunnelOrigin, - } + }) ); + +impl Copy for types::Ipv4Prefix {} +impl Copy for types::Ipv6Prefix {} +impl Copy for types::IpPrefix {} + +impl std::cmp::PartialEq for types::Ipv4Prefix { + fn eq(&self, other: &Self) -> bool { + self.addr.eq(&other.addr) && self.len.eq(&other.len) + } +} + +impl std::cmp::Eq for types::Ipv4Prefix {} + +impl std::hash::Hash for types::Ipv4Prefix { + fn hash(&self, state: &mut H) { + self.addr.hash(state); + self.len.hash(state); + } +} + +impl std::cmp::PartialEq for types::Ipv6Prefix { + fn eq(&self, other: &Self) -> bool { + self.addr.eq(&other.addr) && self.len.eq(&other.len) + } +} + +impl std::cmp::Eq for types::Ipv6Prefix {} + +impl std::hash::Hash for types::Ipv6Prefix { + fn hash(&self, state: &mut H) { + self.addr.hash(state); + self.len.hash(state); + } +} + +impl std::cmp::PartialEq for types::IpPrefix { + fn eq(&self, other: &Self) -> bool { + match self { + types::IpPrefix::V4(x) => match other { + types::IpPrefix::V4(y) => x.eq(y), + _ => false, + }, + types::IpPrefix::V6(x) => match other { + types::IpPrefix::V6(y) => x.eq(y), + _ => false, + }, + } + } +} + +impl std::hash::Hash for types::IpPrefix { + fn hash(&self, state: &mut H) { + match self { + types::IpPrefix::V4(x) => x.hash(state), + types::IpPrefix::V6(x) => x.hash(state), + } + } +} + +impl std::cmp::Eq for types::IpPrefix {} + +impl std::cmp::PartialEq for types::TunnelOrigin { + fn eq(&self, other: &Self) -> bool { + self.overlay_prefix.eq(&other.overlay_prefix) + && self.boundary_addr.eq(&other.boundary_addr) + && self.vni.eq(&other.vni) + && self.metric.eq(&other.metric) + } +} + +impl std::cmp::Eq for types::TunnelOrigin {} + +impl std::hash::Hash for types::TunnelOrigin { + fn hash(&self, state: &mut H) { + self.overlay_prefix.hash(state); + self.boundary_addr.hash(state); + self.vni.hash(state); + self.metric.hash(state); + } +} diff --git a/ddm/Cargo.toml b/ddm/Cargo.toml index f1e5f369..e65af040 100644 --- a/ddm/Cargo.toml +++ b/ddm/Cargo.toml @@ -27,3 +27,8 @@ opte-ioctl.workspace = true oxide-vpc.workspace = true sled.workspace = true mg-common.workspace = true +chrono.workspace = true +omicron-common.workspace = true +oximeter.workspace = true +oximeter-producer.workspace = true +uuid.workspace = true diff --git a/ddm/src/admin.rs b/ddm/src/admin.rs index 8e47128d..918a300d 100644 --- a/ddm/src/admin.rs +++ b/ddm/src/admin.rs @@ -4,7 +4,7 @@ use crate::db::{Db, PeerInfo, TunnelRoute}; use crate::exchange::PathVector; -use crate::sm::{AdminEvent, Event, PrefixSet}; +use crate::sm::{AdminEvent, Event, PrefixSet, SmContext}; use dropshot::endpoint; use dropshot::ApiDescription; use dropshot::ConfigDropshot; @@ -23,28 +23,47 @@ use serde::{Deserialize, Serialize}; use slog::{error, info, warn, Logger}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::mpsc::Sender; use std::sync::Arc; use std::sync::Mutex; use tokio::spawn; +use tokio::task::JoinHandle; +use uuid::Uuid; + +#[derive(Default)] +pub struct RouterStats { + pub originated_underlay_prefixes: AtomicU64, + pub originated_tunnel_endpoints: AtomicU64, +} #[derive(Clone)] pub struct HandlerContext { event_channels: Vec>, db: Db, + stats: Arc, + peers: Vec, + stats_handler: Arc>>>, log: Logger, } +#[allow(clippy::too_many_arguments)] pub fn handler( addr: IpAddr, port: u16, event_channels: Vec>, db: Db, + stats: Arc, + stats_handler: Option>, + peers: Vec, log: Logger, ) -> Result<(), String> { let context = Arc::new(Mutex::new(HandlerContext { event_channels, db, + stats, + peers, + stats_handler: Arc::new(Mutex::new(stats_handler)), log: log.clone(), })); @@ -198,6 +217,19 @@ async fn advertise_prefixes( })?; } + match ctx.db.originated_count() { + Ok(count) => ctx + .stats + .originated_underlay_prefixes + .store(count as u64, Ordering::Relaxed), + Err(e) => { + error!( + ctx.log, + "failed to update originated underlay prefixes stat: {e}" + ) + } + } + Ok(HttpResponseUpdatedNoContent()) } @@ -222,6 +254,18 @@ async fn advertise_tunnel_endpoints( })?; } + match ctx.db.originated_tunnel_count() { + Ok(count) => ctx + .stats + .originated_tunnel_endpoints + .store(count as u64, Ordering::Relaxed), + Err(e) => { + error!( + ctx.log, + "failed to update originated tunnel endpoints stat: {e}" + ) + } + } Ok(HttpResponseUpdatedNoContent()) } @@ -245,6 +289,19 @@ async fn withdraw_prefixes( })?; } + match ctx.db.originated_count() { + Ok(count) => ctx + .stats + .originated_underlay_prefixes + .store(count as u64, Ordering::Relaxed), + Err(e) => { + error!( + ctx.log, + "failed to update originated underlay prefixes stat: {e}" + ) + } + } + Ok(HttpResponseUpdatedNoContent()) } @@ -269,6 +326,19 @@ async fn withdraw_tunnel_endpoints( })?; } + match ctx.db.originated_tunnel_count() { + Ok(count) => ctx + .stats + .originated_tunnel_endpoints + .store(count as u64, Ordering::Relaxed), + Err(e) => { + error!( + ctx.log, + "failed to update originated tunel endpoints stat: {e}" + ) + } + } + Ok(HttpResponseUpdatedNoContent()) } @@ -287,6 +357,67 @@ async fn sync( Ok(HttpResponseUpdatedNoContent()) } +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] +pub struct EnableStatsRequest { + addr: IpAddr, + dns_servers: Vec, + sled_id: Uuid, + rack_id: Uuid, +} + +const DDM_STATS_PORT: u16 = 8001; + +#[endpoint { method = POST, path = "/enable-stats" }] +async fn enable_stats( + ctx: RequestContext>>, + request: TypedBody, +) -> Result { + let rq = request.into_inner(); + let ctx = ctx.context().lock().unwrap(); + + let mut jh = ctx.stats_handler.lock().unwrap(); + if jh.is_none() { + let hostname = hostname::get() + .expect("failed to get hostname") + .to_string_lossy() + .to_string(); + *jh = Some( + crate::oxstats::start_server( + rq.addr, + DDM_STATS_PORT, + ctx.peers.clone(), + ctx.stats.clone(), + rq.dns_servers.clone(), + hostname, + rq.rack_id, + rq.sled_id, + ctx.log.clone(), + ) + .map_err(|e| { + HttpError::for_internal_error(format!( + "failed to start stats server: {e}" + )) + })?, + ); + } + + Ok(HttpResponseUpdatedNoContent()) +} + +#[endpoint { method = POST, path = "/disable-stats" }] +async fn disable_stats( + ctx: RequestContext>>, +) -> Result { + let ctx = ctx.context().lock().unwrap(); + let mut jh = ctx.stats_handler.lock().unwrap(); + if let Some(ref h) = *jh { + h.abort(); + } + *jh = None; + + Ok(HttpResponseUpdatedNoContent()) +} + pub fn api_description( ) -> Result>>, String> { let mut api = ApiDescription::new(); @@ -301,5 +432,7 @@ pub fn api_description( api.register(get_originated)?; api.register(get_originated_tunnel_endpoints)?; api.register(sync)?; + api.register(enable_stats)?; + api.register(disable_stats)?; Ok(api) } diff --git a/ddm/src/db.rs b/ddm/src/db.rs index 0ae299b2..f3edc674 100644 --- a/ddm/src/db.rs +++ b/ddm/src/db.rs @@ -71,10 +71,18 @@ impl Db { self.data.lock().unwrap().imported.clone() } + pub fn imported_count(&self) -> usize { + self.data.lock().unwrap().imported.len() + } + pub fn imported_tunnel(&self) -> HashSet { self.data.lock().unwrap().imported_tunnel.clone() } + pub fn imported_tunnel_count(&self) -> usize { + self.data.lock().unwrap().imported_tunnel.len() + } + pub fn import(&self, r: &HashSet) { self.data.lock().unwrap().imported.extend(r.clone()); } @@ -152,6 +160,10 @@ impl Db { Ok(result) } + pub fn originated_count(&self) -> Result { + Ok(self.originated()?.len()) + } + pub fn originated_tunnel(&self) -> Result, Error> { let tree = self.persistent_data.open_tree(TUNNEL_ORIGINATE)?; let result = tree @@ -184,6 +196,10 @@ impl Db { Ok(result) } + pub fn originated_tunnel_count(&self) -> Result { + Ok(self.originated_tunnel()?.len()) + } + pub fn withdraw( &self, prefixes: &HashSet, diff --git a/ddm/src/discovery.rs b/ddm/src/discovery.rs index 2a2ff2f3..f4d00c81 100644 --- a/ddm/src/discovery.rs +++ b/ddm/src/discovery.rs @@ -86,7 +86,7 @@ //! directly by a hostname of up to 255 bytes in length. use crate::db::{Db, PeerInfo, PeerStatus, RouterKind}; -use crate::sm::{Config, Event, NeighborEvent}; +use crate::sm::{Config, Event, NeighborEvent, SessionStats}; use crate::util::u8_slice_assume_init_ref; use crate::{dbg, err, inf, trc, wrn}; use serde::{Deserialize, Serialize}; @@ -186,6 +186,7 @@ pub(crate) fn handler( config: Config, event: Sender, db: Db, + stats: Arc, log: Logger, ) -> Result<(), DiscoveryError> { // listening on 2 sockets, solicitations are sent to DDM_MADDR, but @@ -229,21 +230,36 @@ pub(crate) fn handler( let stop = Arc::new(AtomicBool::new(false)); - send_solicitations(ctx.clone(), stop.clone()); - listen(ctx.clone(), ctx.mc_socket.clone(), stop.clone())?; - listen(ctx.clone(), ctx.uc_socket.clone(), stop.clone())?; - expire(ctx, stop)?; + send_solicitations(ctx.clone(), stop.clone(), stats.clone()); + listen( + ctx.clone(), + ctx.mc_socket.clone(), + stop.clone(), + stats.clone(), + )?; + listen( + ctx.clone(), + ctx.uc_socket.clone(), + stop.clone(), + stats.clone(), + )?; + expire(ctx, stop, stats.clone())?; Ok(()) } -fn send_solicitations(ctx: HandlerContext, stop: Arc) { +fn send_solicitations( + ctx: HandlerContext, + stop: Arc, + stats: Arc, +) { spawn(move || loop { if let Err(e) = solicit(&ctx) { err!(ctx.log, ctx.config.if_name, "solicit failed: {}", e); stop.store(true, Ordering::Relaxed); break; } + stats.solicitations_sent.fetch_add(1, Ordering::Relaxed); sleep(Duration::from_millis(ctx.config.solicit_interval)); }); } @@ -251,6 +267,7 @@ fn send_solicitations(ctx: HandlerContext, stop: Arc) { fn expire( ctx: HandlerContext, stop: Arc, + stats: Arc, ) -> Result<(), DiscoveryError> { spawn(move || loop { let mut guard = match ctx.nbr.write() { @@ -271,6 +288,7 @@ fn expire( nbr.addr ); *guard = None; + stats.peer_expirations.fetch_add(1, Ordering::Relaxed); emit_nbr_expire( ctx.event.clone(), ctx.log.clone(), @@ -311,10 +329,11 @@ fn listen( ctx: HandlerContext, s: Arc, stop: Arc, + stats: Arc, ) -> Result<(), DiscoveryError> { spawn(move || loop { if let Some((addr, msg)) = recv(&ctx, &s) { - handle_msg(&ctx, msg, &addr); + handle_msg(&ctx, msg, &addr, &stats); }; if stop.load(Ordering::Relaxed) { break; @@ -366,12 +385,24 @@ fn recv( Some((addr, msg)) } -fn handle_msg(ctx: &HandlerContext, msg: DiscoveryPacket, sender: &Ipv6Addr) { +fn handle_msg( + ctx: &HandlerContext, + msg: DiscoveryPacket, + sender: &Ipv6Addr, + stats: &Arc, +) { if msg.is_solicitation() { - handle_solicitation(ctx, sender, msg.hostname.clone()); + handle_solicitation(ctx, sender, msg.hostname.clone(), stats); } if msg.is_advertisement() { - handle_advertisement(ctx, sender, msg.hostname, msg.kind, msg.version); + handle_advertisement( + ctx, + sender, + msg.hostname, + msg.kind, + msg.version, + stats, + ); } } @@ -379,10 +410,12 @@ fn handle_solicitation( ctx: &HandlerContext, sender: &Ipv6Addr, hostname: String, + stats: &Arc, ) { trc!(&ctx.log, ctx.config.if_name, "solicit from {}", hostname); + stats.solicitations_received.fetch_add(1, Ordering::Relaxed); - if let Err(e) = advertise(ctx, Some(*sender)) { + if let Err(e) = advertise(ctx, Some(*sender), stats) { err!(ctx.log, ctx.config.if_name, "icmp advertise: {}", e); } } @@ -393,8 +426,12 @@ fn handle_advertisement( hostname: String, kind: RouterKind, version: u8, + stats: &Arc, ) { trc!(&ctx.log, ctx.config.if_name, "advert from {}", &hostname); + stats + .advertisements_received + .fetch_add(1, Ordering::Relaxed); // TODO: version negotiation // @@ -444,6 +481,7 @@ fn handle_advertisement( nbr.last_seen = Instant::now(); nbr.kind = kind; nbr.addr = *sender; + stats.peer_address_changes.fetch_add(1, Ordering::Relaxed); } nbr.last_seen = Instant::now(); } @@ -462,6 +500,7 @@ fn handle_advertisement( last_seen: Instant::now(), kind, }); + stats.peer_established.fetch_add(1, Ordering::Relaxed); } }; drop(guard); @@ -475,6 +514,7 @@ fn handle_advertisement( }, ); if updated { + stats.peer_address.lock().unwrap().replace(*sender); emit_nbr_update(ctx, sender, version); } } @@ -515,6 +555,7 @@ fn solicit(ctx: &HandlerContext) -> Result { fn advertise( ctx: &HandlerContext, dst: Option, + stats: &Arc, ) -> Result { let msg = DiscoveryPacket::new_advertisement( ctx.hostname.clone(), @@ -528,5 +569,7 @@ fn advertise( let sa: SockAddr = SocketAddrV6::new(addr, DDM_PORT, 0, ctx.config.if_index).into(); - Ok(ctx.uc_socket.send_to(data.as_slice(), &sa)?) + let n = ctx.uc_socket.send_to(data.as_slice(), &sa)?; + stats.advertisements_sent.fetch_add(1, Ordering::Relaxed); + Ok(n) } diff --git a/ddm/src/exchange.rs b/ddm/src/exchange.rs index f04fcc2b..599d91ba 100644 --- a/ddm/src/exchange.rs +++ b/ddm/src/exchange.rs @@ -37,6 +37,7 @@ use serde::{Deserialize, Serialize}; use slog::Logger; use std::collections::HashSet; use std::net::{Ipv6Addr, SocketAddrV6}; +use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; use thiserror::Error; @@ -217,6 +218,7 @@ pub enum ExchangeError { } pub(crate) fn announce_underlay( + ctx: &SmContext, config: Config, prefixes: HashSet, addr: Ipv6Addr, @@ -225,10 +227,11 @@ pub(crate) fn announce_underlay( log: Logger, ) -> Result<(), ExchangeError> { let update = UnderlayUpdate::announce(prefixes); - send_update(config, update.into(), addr, version, rt, log) + send_update(ctx, config, update.into(), addr, version, rt, log) } pub(crate) fn announce_tunnel( + ctx: &SmContext, config: Config, endpoints: HashSet, addr: Ipv6Addr, @@ -238,10 +241,11 @@ pub(crate) fn announce_tunnel( ) -> Result<(), ExchangeError> { let update = TunnelUpdate::announce(endpoints.into_iter().map(Into::into).collect()); - send_update(config, update.into(), addr, version, rt, log) + send_update(ctx, config, update.into(), addr, version, rt, log) } pub(crate) fn withdraw_underlay( + ctx: &SmContext, config: Config, prefixes: HashSet, addr: Ipv6Addr, @@ -250,10 +254,11 @@ pub(crate) fn withdraw_underlay( log: Logger, ) -> Result<(), ExchangeError> { let update = UnderlayUpdate::withdraw(prefixes); - send_update(config, update.into(), addr, version, rt, log) + send_update(ctx, config, update.into(), addr, version, rt, log) } pub(crate) fn withdraw_tunnel( + ctx: &SmContext, config: Config, endpoints: HashSet, addr: Ipv6Addr, @@ -263,7 +268,7 @@ pub(crate) fn withdraw_tunnel( ) -> Result<(), ExchangeError> { let update = TunnelUpdate::withdraw(endpoints.into_iter().map(Into::into).collect()); - send_update(config, update.into(), addr, version, rt, log) + send_update(ctx, config, update.into(), addr, version, rt, log) } pub(crate) fn do_pull( @@ -347,6 +352,7 @@ pub(crate) fn pull( } fn send_update( + ctx: &SmContext, config: Config, update: Update, addr: Ipv6Addr, @@ -354,13 +360,17 @@ fn send_update( rt: Arc, log: Logger, ) -> Result<(), ExchangeError> { + ctx.stats.updates_sent.fetch_add(1, Ordering::Relaxed); match version { - Version::V1 => send_update_v1(config, update.into(), addr, rt, log), - Version::V2 => send_update_v2(config, update, addr, rt, log), + Version::V1 => { + send_update_v1(ctx, config, update.into(), addr, rt, log) + } + Version::V2 => send_update_v2(ctx, config, update, addr, rt, log), } } fn send_update_v2( + ctx: &SmContext, config: Config, update: Update, addr: Ipv6Addr, @@ -372,10 +382,11 @@ fn send_update_v2( "http://[{}%{}]:{}/v2/push", addr, config.if_index, config.exchange_port, ); - send_update_common(uri, payload, config, rt, log) + send_update_common(ctx, uri, payload, config, rt, log) } fn send_update_v1( + ctx: &SmContext, config: Config, update: UpdateV1, addr: Ipv6Addr, @@ -387,10 +398,11 @@ fn send_update_v1( "http://[{}%{}]:{}/push", addr, config.if_index, config.exchange_port, ); - send_update_common(uri, payload, config, rt, log) + send_update_common(ctx, uri, payload, config, rt, log) } fn send_update_common( + ctx: &SmContext, uri: String, payload: String, config: Config, @@ -418,6 +430,7 @@ fn send_update_common( uri, e, ); + ctx.stats.update_send_fail.fetch_add(1, Ordering::Relaxed); Err(e.into()) } } @@ -637,6 +650,11 @@ async fn pull_handler( } fn handle_update(update: &Update, ctx: &HandlerContext) { + ctx.ctx + .stats + .updates_received + .fetch_add(1, Ordering::Relaxed); + if let Some(underlay_update) = &update.underlay { handle_underlay_update(underlay_update, ctx); } @@ -734,6 +752,11 @@ fn handle_tunnel_update(update: &TunnelUpdate, ctx: &HandlerContext) { import, ) } + + ctx.ctx + .stats + .imported_underlay_prefixes + .store(ctx.ctx.db.imported_tunnel_count() as u64, Ordering::Relaxed); } fn handle_underlay_update(update: &UnderlayUpdate, ctx: &HandlerContext) { @@ -802,4 +825,9 @@ fn handle_underlay_update(update: &UnderlayUpdate, ctx: &HandlerContext) { del, &ctx.ctx.rt, ); + + ctx.ctx + .stats + .imported_underlay_prefixes + .store(ctx.ctx.db.imported_count() as u64, Ordering::Relaxed); } diff --git a/ddm/src/lib.rs b/ddm/src/lib.rs index ac37190f..d5e48f41 100644 --- a/ddm/src/lib.rs +++ b/ddm/src/lib.rs @@ -6,6 +6,7 @@ pub mod admin; pub mod db; pub mod discovery; mod exchange; +pub mod oxstats; pub mod sm; pub mod sys; mod util; diff --git a/ddm/src/oxstats.rs b/ddm/src/oxstats.rs new file mode 100644 index 00000000..164e4724 --- /dev/null +++ b/ddm/src/oxstats.rs @@ -0,0 +1,337 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::{ + net::{IpAddr, SocketAddr}, + sync::Arc, + time::Duration, +}; + +use crate::{admin::RouterStats, sm::SmContext}; +use chrono::{DateTime, Utc}; +use dropshot::{ + ConfigDropshot, ConfigLogging, ConfigLoggingLevel, HandlerTaskMode, +}; +use mg_common::{ + counter, + nexus::{resolve_nexus, run_oximeter}, + quantity, +}; +use omicron_common::api::internal::nexus::{ProducerEndpoint, ProducerKind}; +use oximeter::{ + types::{Cumulative, ProducerRegistry}, + Metric, MetricsError, Producer, Sample, Target, +}; +use oximeter_producer::LogConfig; +use slog::Logger; +use std::sync::atomic::Ordering; +use tokio::task::JoinHandle; +use uuid::Uuid; + +#[derive(Clone)] +pub(crate) struct Stats { + pub(crate) start_time: DateTime, + hostname: String, + rack_id: Uuid, + sled_id: Uuid, + peers: Vec, + router_stats: Arc, +} + +#[derive(Debug, Clone, Target)] +struct DdmSession { + hostname: String, + rack_id: Uuid, + sled_id: Uuid, + interface: String, +} + +#[derive(Debug, Clone, Target)] +struct DdmRouter { + hostname: String, + rack_id: Uuid, + sled_id: Uuid, +} + +counter!(SolicitationsSent); +counter!(SolicitationsReceived); +counter!(AdvertisementsSent); +counter!(AdvertisementsReceived); +counter!(PeerExpirations); +counter!(PeerAddressChanges); +counter!(PeerSessionsEstablished); +counter!(UpdatesSent); +counter!(UpdatesReceived); +counter!(UpdateSendFail); +quantity!(ImportedUnderlayPrefixes, u64); +quantity!(ImportedTunnelEndpoints, u64); +quantity!(OriginatedUnderlayPrefixes, u64); +quantity!(OriginatedTunnelEndpoints, u64); + +macro_rules! ddm_session_counter { + ( + $start_time:expr, + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $interface:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &DdmSession { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + interface: $interface, + }, + &$kind { + count: Cumulative::::with_start_time( + $start_time, + $value.load(Ordering::Relaxed), + ), + }, + )? + }; +} + +macro_rules! ddm_session_quantity { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $interface:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &DdmSession { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + interface: $interface, + }, + &$kind { + quantity: $value.load(Ordering::Relaxed), + }, + )? + }; +} + +macro_rules! ddm_router_quantity { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &DdmRouter { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + }, + &$kind { + quantity: $value.load(Ordering::Relaxed), + }, + )? + }; +} + +impl std::fmt::Debug for Stats { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("stats") + } +} + +impl Producer for Stats { + fn produce( + &mut self, + ) -> Result>, MetricsError> { + // Capacity is for number of router level stats plus number session + // level stats. + let mut samples: Vec = Vec::with_capacity(2 + 13); + + samples.push(ddm_router_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + OriginatedUnderlayPrefixes, + self.router_stats.originated_underlay_prefixes + )); + + samples.push(ddm_router_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + OriginatedTunnelEndpoints, + self.router_stats.originated_tunnel_endpoints + )); + + for peer in &self.peers { + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + SolicitationsSent, + peer.stats.solicitations_sent + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + SolicitationsReceived, + peer.stats.solicitations_received + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + AdvertisementsSent, + peer.stats.advertisements_sent + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + AdvertisementsReceived, + peer.stats.advertisements_received + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + PeerExpirations, + peer.stats.peer_expirations + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + PeerAddressChanges, + peer.stats.peer_address_changes + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + PeerSessionsEstablished, + peer.stats.peer_established + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + UpdatesSent, + peer.stats.updates_sent + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + UpdatesReceived, + peer.stats.updates_received + )); + samples.push(ddm_session_counter!( + self.start_time, + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + UpdateSendFail, + peer.stats.update_send_fail + )); + samples.push(ddm_session_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + ImportedUnderlayPrefixes, + peer.stats.imported_underlay_prefixes + )); + samples.push(ddm_session_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + peer.config.if_name.clone(), + ImportedTunnelEndpoints, + peer.stats.imported_tunnel_endpoints + )); + } + + Ok(Box::new(samples.into_iter())) + } +} + +#[allow(clippy::too_many_arguments)] +pub fn start_server( + addr: IpAddr, + port: u16, + peers: Vec, + router_stats: Arc, + dns_servers: Vec, + hostname: String, + rack_id: Uuid, + sled_id: Uuid, + log: Logger, +) -> Result, String> { + let sa = SocketAddr::new(addr, port); + let dropshot = ConfigDropshot { + bind_address: sa, + request_body_max_bytes: 1024 * 1024 * 1024, + default_handler_task_mode: HandlerTaskMode::Detached, + }; + let log_config = LogConfig::Config(ConfigLogging::StderrTerminal { + level: ConfigLoggingLevel::Debug, + }); + let registry = ProducerRegistry::new(); + + let stats_producer = Stats { + start_time: chrono::offset::Utc::now(), + peers, + hostname, + rack_id, + sled_id, + router_stats, + }; + + registry.register_producer(stats_producer).unwrap(); + let producer_info = ProducerEndpoint { + id: registry.producer_id(), + kind: ProducerKind::Service, + address: sa, + base_route: "/collect".to_string(), + interval: Duration::from_secs(1), + }; + + Ok(tokio::spawn(async move { + let nexus_addr = resolve_nexus(log.clone(), &dns_servers).await; + let config = oximeter_producer::Config { + server_info: producer_info, + registration_address: nexus_addr, + log: log_config, + dropshot, + }; + run_oximeter(registry.clone(), config.clone(), log.clone()).await + })) +} diff --git a/ddm/src/sm.rs b/ddm/src/sm.rs index 3c9f0cfb..524f0c3e 100644 --- a/ddm/src/sm.rs +++ b/ddm/src/sm.rs @@ -11,9 +11,9 @@ use mg_common::net::{Ipv6Prefix, TunnelOrigin}; use slog::Logger; use std::collections::HashSet; use std::net::{IpAddr, Ipv6Addr}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::mpsc::{Receiver, Sender}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::thread::sleep; use std::thread::spawn; use std::time::Duration; @@ -151,6 +151,26 @@ pub struct DpdConfig { pub port: u16, } +#[derive(Default)] +pub struct SessionStats { + // Discovery + pub solicitations_sent: AtomicU64, + pub solicitations_received: AtomicU64, + pub advertisements_sent: AtomicU64, + pub advertisements_received: AtomicU64, + pub peer_expirations: AtomicU64, + pub peer_address_changes: AtomicU64, + pub peer_established: AtomicU64, + pub peer_address: Mutex>, + + // Exchange + pub updates_sent: AtomicU64, + pub updates_received: AtomicU64, + pub imported_underlay_prefixes: AtomicU64, + pub imported_tunnel_endpoints: AtomicU64, + pub update_send_fail: AtomicU64, +} + #[derive(Clone)] pub struct SmContext { pub config: Config, @@ -159,6 +179,7 @@ pub struct SmContext { pub event_channels: Vec>, pub rt: Arc, pub hostname: String, + pub stats: Arc, pub log: Logger, } @@ -254,6 +275,7 @@ impl State for Init { self.ctx.config.clone(), self.ctx.tx.clone(), self.ctx.db.clone(), + self.ctx.stats.clone(), self.ctx.log.clone(), ) .unwrap(); // TODO unwrap @@ -562,6 +584,7 @@ impl State for Exchange { }) .collect(); if let Err(e) = crate::exchange::announce_underlay( + &self.ctx, self.ctx.config.clone(), pv, self.peer, @@ -596,6 +619,7 @@ impl State for Exchange { ))) => { let tv: HashSet = endpoints.clone(); if let Err(e) = crate::exchange::announce_tunnel( + &self.ctx, self.ctx.config.clone(), tv, self.peer, @@ -636,6 +660,7 @@ impl State for Exchange { }) .collect(); if let Err(e) = crate::exchange::withdraw_underlay( + &self.ctx, self.ctx.config.clone(), pv, self.peer, @@ -670,6 +695,7 @@ impl State for Exchange { ))) => { let tv: HashSet = endpoints.clone(); if let Err(e) = crate::exchange::withdraw_tunnel( + &self.ctx, self.ctx.config.clone(), tv, self.peer, @@ -745,6 +771,7 @@ impl State for Exchange { if let Some(push) = update.underlay { if !push.announce.is_empty() { if let Err(e) = crate::exchange::announce_underlay( + &self.ctx, self.ctx.config.clone(), push.announce, self.peer, @@ -776,6 +803,7 @@ impl State for Exchange { } if !push.withdraw.is_empty() { if let Err(e) = crate::exchange::withdraw_underlay( + &self.ctx, self.ctx.config.clone(), push.withdraw, self.peer, diff --git a/ddmadm/src/main.rs b/ddmadm/src/main.rs index a67bd991..46005cb5 100644 --- a/ddmadm/src/main.rs +++ b/ddmadm/src/main.rs @@ -5,9 +5,9 @@ use anyhow::Result; use clap::Parser; use colored::*; -use ddm_admin_client::Client; +use ddm_admin_client::{types, Client}; use mg_common::cli::oxide_cli_style; -use mg_common::net::{IpPrefix, Ipv6Prefix, TunnelOrigin}; +use mg_common::net::{IpPrefix, Ipv4Prefix, Ipv6Prefix}; use slog::{Drain, Logger}; use std::io::{stdout, Write}; use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; @@ -156,7 +156,9 @@ async fn run() -> Result<()> { writeln!( &mut tw, "{}\t{}\t{}", - pv.destination, nexthop, strpath, + to_ipv6_prefix(&pv.destination), + nexthop, + strpath, )?; } } @@ -167,14 +169,14 @@ async fn run() -> Result<()> { let mut tw = TabWriter::new(stdout()); writeln!(&mut tw, "{}", "Prefix".dimmed(),)?; for prefix in msg.into_inner() { - writeln!(&mut tw, "{}", prefix)?; + writeln!(&mut tw, "{}", to_ipv6_prefix(&prefix))?; } tw.flush()?; } SubCommand::AdvertisePrefixes(ac) => { - let mut prefixes: Vec = Vec::new(); + let mut prefixes: Vec = Vec::new(); for p in ac.prefixes { - prefixes.push(Ipv6Prefix { + prefixes.push(types::Ipv6Prefix { addr: p.addr, len: p.len, }); @@ -182,9 +184,9 @@ async fn run() -> Result<()> { client.advertise_prefixes(&prefixes).await?; } SubCommand::WithdrawPrefixes(ac) => { - let mut prefixes: Vec = Vec::new(); + let mut prefixes: Vec = Vec::new(); for p in ac.prefixes { - prefixes.push(Ipv6Prefix { + prefixes.push(types::Ipv6Prefix { addr: p.addr, len: p.len, }); @@ -206,7 +208,7 @@ async fn run() -> Result<()> { writeln!( &mut tw, "{}\t{}\t{}\t{}", - endpoint.origin.overlay_prefix, + to_ip_prefix(&endpoint.origin.overlay_prefix), endpoint.origin.boundary_addr, endpoint.origin.vni, endpoint.origin.metric, @@ -229,7 +231,7 @@ async fn run() -> Result<()> { writeln!( &mut tw, "{}\t{}\t{}\t{}", - endpoint.overlay_prefix, + to_ip_prefix(&endpoint.overlay_prefix), endpoint.boundary_addr, endpoint.vni, endpoint.metric, @@ -239,8 +241,8 @@ async fn run() -> Result<()> { } SubCommand::TunnelAdvertise(ep) => { client - .advertise_tunnel_endpoints(&vec![TunnelOrigin { - overlay_prefix: ep.overlay_prefix, + .advertise_tunnel_endpoints(&vec![types::TunnelOrigin { + overlay_prefix: to_types_ip_prefix(&ep.overlay_prefix), boundary_addr: ep.boundary_addr, vni: ep.vni, metric: ep.metric, @@ -249,8 +251,8 @@ async fn run() -> Result<()> { } SubCommand::TunnelWithdraw(ep) => { client - .withdraw_tunnel_endpoints(&vec![TunnelOrigin { - overlay_prefix: ep.overlay_prefix, + .withdraw_tunnel_endpoints(&vec![types::TunnelOrigin { + overlay_prefix: to_types_ip_prefix(&ep.overlay_prefix), boundary_addr: ep.boundary_addr, vni: ep.vni, metric: ep.metric, @@ -272,3 +274,45 @@ fn init_logger() -> Logger { let drain = slog_async::Async::new(drain).build().fuse(); slog::Logger::root(drain, slog::o!()) } + +fn to_ipv6_prefix(x: &types::Ipv6Prefix) -> Ipv6Prefix { + Ipv6Prefix { + addr: x.addr, + len: x.len, + } +} + +fn to_ipv4_prefix(x: &types::Ipv4Prefix) -> Ipv4Prefix { + Ipv4Prefix { + addr: x.addr, + len: x.len, + } +} + +fn to_ip_prefix(x: &types::IpPrefix) -> IpPrefix { + match x { + types::IpPrefix::V4(p) => IpPrefix::V4(to_ipv4_prefix(p)), + types::IpPrefix::V6(p) => IpPrefix::V6(to_ipv6_prefix(p)), + } +} + +fn to_types_ipv6_prefix(x: &Ipv6Prefix) -> types::Ipv6Prefix { + types::Ipv6Prefix { + addr: x.addr, + len: x.len, + } +} + +fn to_types_ipv4_prefix(x: &Ipv4Prefix) -> types::Ipv4Prefix { + types::Ipv4Prefix { + addr: x.addr, + len: x.len, + } +} + +fn to_types_ip_prefix(x: &IpPrefix) -> types::IpPrefix { + match x { + IpPrefix::V4(p) => types::IpPrefix::V4(to_types_ipv4_prefix(p)), + IpPrefix::V6(p) => types::IpPrefix::V6(to_types_ipv6_prefix(p)), + } +} diff --git a/ddmd/Cargo.toml b/ddmd/Cargo.toml index 40e8a5ff..5ee426a3 100644 --- a/ddmd/Cargo.toml +++ b/ddmd/Cargo.toml @@ -14,3 +14,4 @@ tokio.workspace = true hostname.workspace = true dpd-client.workspace = true anstyle.workspace = true +uuid.workspace = true diff --git a/ddmd/src/main.rs b/ddmd/src/main.rs index 3d4a4ed5..a04268fb 100644 --- a/ddmd/src/main.rs +++ b/ddmd/src/main.rs @@ -3,13 +3,15 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use clap::Parser; +use ddm::admin::RouterStats; use ddm::db::{Db, RouterKind}; use ddm::sm::{DpdConfig, SmContext, StateMachine}; use ddm::sys::Route; use slog::{error, Drain, Logger}; -use std::net::{IpAddr, Ipv6Addr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::sync::mpsc::channel; use std::sync::Arc; +use uuid::Uuid; #[derive(Debug, Parser)] #[command(version, about, long_about = None, styles = get_styles())] @@ -73,6 +75,26 @@ struct Arg { /// Where to store the local database #[arg(long, default_value = "/var/run")] data_dir: String, + + /// DNS servers used to find nexus. + #[arg(long)] + dns_servers: Vec, + + /// Register as an oximeter producer. + #[arg(long)] + with_stats: bool, + + /// Port to listen on for the oximeter API. + #[arg(long, default_value_t = 8001)] + oximeter_port: u16, + + /// Id of the rack this router is running on. + #[arg(long)] + rack_uuid: Option, + + /// Id of the sled this router is running on. + #[arg(long)] + sled_uuid: Option, } #[derive(Debug, Parser, Clone)] @@ -129,6 +151,7 @@ async fn main() { log: log.clone(), hostname: hostname.clone(), rt: rt.clone(), + stats: Arc::new(ddm::sm::SessionStats::default()), }; let sm = StateMachine { ctx, rx: Some(rx) }; sms.push(sm); @@ -153,11 +176,44 @@ async fn main() { termination_handler(db.clone(), dpd, rt, log.clone()); + let router_stats = Arc::new(RouterStats::default()); + let peers: Vec = sms.iter().map(|x| x.ctx.clone()).collect(); + let dns_servers: Vec = arg + .dns_servers + .iter() + .filter(|x| x.as_str() != "unknown") + .map(|x| x.parse().unwrap()) + .collect(); + + let stats_handler = if arg.with_stats && !dns_servers.is_empty() { + Some( + ddm::oxstats::start_server( + arg.admin_addr, + arg.oximeter_port, + peers.clone(), + router_stats.clone(), + dns_servers, + hostname.clone(), + arg.rack_uuid + .expect("rack uuid required to start stats server"), + arg.sled_uuid + .expect("sled uuid required to start stats server"), + log.clone(), + ) + .unwrap(), + ) + } else { + None + }; + ddm::admin::handler( arg.admin_addr, arg.admin_port, event_channels, db, + router_stats, + stats_handler, + peers, log, ) .unwrap(); diff --git a/mg-admin-client/Cargo.toml b/mg-admin-client/Cargo.toml index 0f30c1b6..df992f96 100644 --- a/mg-admin-client/Cargo.toml +++ b/mg-admin-client/Cargo.toml @@ -13,5 +13,3 @@ reqwest.workspace = true progenitor.workspace = true schemars.workspace = true chrono.workspace = true -rdb = { path = "../rdb" } -bgp = { path = "../bgp" } diff --git a/mg-admin-client/src/lib.rs b/mg-admin-client/src/lib.rs index 84ab9af0..82594816 100644 --- a/mg-admin-client/src/lib.rs +++ b/mg-admin-client/src/lib.rs @@ -2,9 +2,11 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +/* pub use bgp::messages::Message; pub use bgp::session::{MessageHistory, MessageHistoryEntry}; pub use rdb::{PolicyAction, Prefix4}; +*/ progenitor::generate_api!( spec = "../openapi/mg-admin.json", @@ -20,11 +22,21 @@ progenitor::generate_api!( slog::trace!(log, "client response"; "result" => ?result); }), derives = [schemars::JsonSchema], - replace = { - Prefix4 = rdb::Prefix4, - PolicyAction = rdb::PolicyAction, - Message = bgp::messages::Message, - MessageHistoryEntry = bgp::session::MessageHistoryEntry, - MessageHistory = bgp::session::MessageHistory, - } ); + +impl std::hash::Hash for types::Prefix4 { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.length.hash(state); + } +} + +impl std::cmp::PartialEq for types::Prefix4 { + fn eq(&self, other: &Self) -> bool { + self.value.eq(&other.value) && self.length.eq(&other.length) + } +} + +impl std::cmp::Eq for types::Prefix4 {} + +impl Copy for types::Prefix4 {} diff --git a/mg-common/Cargo.toml b/mg-common/Cargo.toml index 95d8fcc2..d2c4e39b 100644 --- a/mg-common/Cargo.toml +++ b/mg-common/Cargo.toml @@ -9,3 +9,10 @@ anstyle.workspace = true serde.workspace = true schemars.workspace = true thiserror.workspace = true +slog.workspace = true +omicron-common.workspace = true +internal-dns.workspace = true +tokio.workspace = true +oximeter-producer.workspace = true +oximeter.workspace = true +backoff.workspace = true diff --git a/mg-common/src/lib.rs b/mg-common/src/lib.rs index 5f1c8836..7a885b03 100644 --- a/mg-common/src/lib.rs +++ b/mg-common/src/lib.rs @@ -4,6 +4,8 @@ pub mod cli; pub mod net; +pub mod nexus; +pub mod stats; #[macro_export] macro_rules! lock { @@ -25,3 +27,29 @@ macro_rules! write_lock { $rwl.write().expect("rwlock write") }; } + +// +// stats macros +// + +#[macro_export] +macro_rules! counter { + ($name:ident) => { + #[derive(Clone, Copy, Debug, Default, Metric)] + pub struct $name { + #[datum] + count: Cumulative, + } + }; +} + +#[macro_export] +macro_rules! quantity { + ($name:ident, $kind:tt) => { + #[derive(Clone, Copy, Debug, Default, Metric)] + pub struct $name { + #[datum] + quantity: $kind, + } + }; +} diff --git a/mg-common/src/nexus.rs b/mg-common/src/nexus.rs new file mode 100644 index 00000000..c22f14cd --- /dev/null +++ b/mg-common/src/nexus.rs @@ -0,0 +1,94 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use internal_dns::{resolver::Resolver, ServiceName}; +use slog::{info, warn, Logger}; +use std::{net::SocketAddr, time::Duration}; +use tokio::time::sleep; + +pub async fn resolve_nexus( + log: Logger, + dns_servers: &[SocketAddr], +) -> SocketAddr { + info!(log, "resolving nexus"); + loop { + let resolver = match Resolver::new_from_addrs(log.clone(), dns_servers) + { + Ok(resolver) => resolver, + Err(e) => { + warn!(log, "creating nexus resolver failed, waiting 1s: {e}"); + sleep(Duration::from_secs(1)).await; + continue; + } + }; + + let op = || async { + match resolver.lookup_socket_v6(ServiceName::Nexus).await { + Ok(addr) => Ok(addr), + Err(e) => Err(e.into()), + } + }; + + let log_failure = |e, delay| { + warn!(log, "resolving nexus failed, {e} waiting {delay:?}"); + }; + + match omicron_common::backoff::retry_notify( + omicron_common::backoff::retry_policy_internal_service_aggressive(), + op, + log_failure, + ) + .await + { + Ok(addr) => return addr.into(), + Err(e) => { + warn!(log, "error resulving nexus: {e}"); + } + } + } +} + +pub async fn run_oximeter( + registry: oximeter::types::ProducerRegistry, + config: oximeter_producer::Config, + log: Logger, +) { + let op = || async { + match oximeter_producer::Server::with_registry( + registry.clone(), + &config, + ) + .await + { + Ok(s) => Ok(s), + Err(e) => { + if let oximeter_producer::Error::RegistrationError { + retryable, + msg: _, + } = &e + { + if !retryable { + return Err(backoff::Error::Permanent(e)); + } + } + Err(e.into()) + } + } + }; + + let log_failure = |e, delay| { + warn!(log, "stats server not created yet, {e} waiting {delay:?}"); + }; + + let server = omicron_common::backoff::retry_notify( + omicron_common::backoff::retry_policy_internal_service_aggressive(), + op, + log_failure, + ) + .await; + + if let Ok(server) = server { + server.serve_forever().await.expect("metrics server failed"); + } +} diff --git a/mg-common/src/stats.rs b/mg-common/src/stats.rs new file mode 100644 index 00000000..a253e968 --- /dev/null +++ b/mg-common/src/stats.rs @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::sync::atomic::AtomicU64; + +#[derive(Default)] +pub struct MgLowerStats { + pub routes_blocked_by_link_state: AtomicU64, +} diff --git a/mg-lower/Cargo.toml b/mg-lower/Cargo.toml index 1246059f..1df2faae 100644 --- a/mg-lower/Cargo.toml +++ b/mg-lower/Cargo.toml @@ -14,3 +14,4 @@ libnet.workspace = true tokio.workspace = true thiserror.workspace = true http.workspace = true +mg-common.workspace = true diff --git a/mg-lower/src/ddm.rs b/mg-lower/src/ddm.rs index e5d2865c..17e34b67 100644 --- a/mg-lower/src/ddm.rs +++ b/mg-lower/src/ddm.rs @@ -2,7 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use ddm_admin_client::{Client, Ipv6Prefix, TunnelOrigin}; +use ddm_admin_client::types::{Ipv6Prefix, TunnelOrigin}; +use ddm_admin_client::Client; use rdb::Route4ImportKey; use slog::{error, info, Logger}; use std::{collections::HashSet, net::Ipv6Addr, sync::Arc}; @@ -73,8 +74,8 @@ fn ensure_tep_underlay_origin( fn route_to_tunnel(tep: Ipv6Addr, x: &Route4ImportKey) -> TunnelOrigin { TunnelOrigin { - overlay_prefix: ddm_admin_client::IpPrefix::V4( - ddm_admin_client::Ipv4Prefix { + overlay_prefix: ddm_admin_client::types::IpPrefix::V4( + ddm_admin_client::types::Ipv4Prefix { addr: x.prefix.value, len: x.prefix.length, }, diff --git a/mg-lower/src/dendrite.rs b/mg-lower/src/dendrite.rs index 57909192..ed1d5f24 100644 --- a/mg-lower/src/dendrite.rs +++ b/mg-lower/src/dendrite.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::Error; +use crate::Stats; use crate::MG_LOWER_TAG; use dendrite_common::network::Cidr; use dendrite_common::ports::PortId; @@ -18,6 +19,7 @@ use std::collections::HashSet; use std::hash::Hash; use std::net::IpAddr; use std::net::Ipv6Addr; +use std::sync::atomic::Ordering; use std::sync::Arc; const TFPORT_QSFP_DEVICE_PREFIX: &str = "tfportqsfp"; @@ -192,10 +194,14 @@ pub(crate) fn db_route_to_dendrite_route( rs: Vec, log: &Logger, dpd: &DpdClient, + stats: Option<&Stats>, + require_link_up: bool, rt: Arc, ) -> HashSet { let mut result = HashSet::new(); + let mut link_down_count = 0; + for r in &rs { let (port_id, link_id) = match get_port_and_link(r) { Ok((p, l)) => (p, l), @@ -205,25 +211,29 @@ pub(crate) fn db_route_to_dendrite_route( } }; - let link_info = match rt - .block_on(async { dpd.link_get(&port_id, &link_id).await }) - { - Ok(info) => info.into_inner(), - Err(e) => { - error!( + if require_link_up { + let link_info = match rt + .block_on(async { dpd.link_get(&port_id, &link_id).await }) + { + Ok(info) => info.into_inner(), + Err(e) => { + error!( log, "failed to get link info for {port_id:?}/{link_id:?}: {e}" ); - continue; - } - }; + link_down_count += 1; + continue; + } + }; - if link_info.link_state != LinkState::Up { - warn!( + if link_info.link_state != LinkState::Up { + warn!( log, "{port_id:?}/{link_id:?} is not up, not installing into RIB" ); - continue; + link_down_count += 1; + continue; + } } let cidr = dpd_client::Ipv4Cidr { @@ -239,6 +249,12 @@ pub(crate) fn db_route_to_dendrite_route( }; } + if let Some(stats) = stats { + stats + .routes_blocked_by_link_state + .store(link_down_count, Ordering::Relaxed); + } + result } diff --git a/mg-lower/src/lib.rs b/mg-lower/src/lib.rs index 706f9df7..e4ee8704 100644 --- a/mg-lower/src/lib.rs +++ b/mg-lower/src/lib.rs @@ -17,6 +17,7 @@ use ddm::{ use ddm_admin_client::Client as DdmClient; use dendrite::ensure_tep_addr; use dpd_client::Client as DpdClient; +use mg_common::stats::MgLowerStats as Stats; use rdb::{ChangeSet, Db}; use slog::{error, info, Logger}; use std::collections::HashSet; @@ -44,6 +45,7 @@ pub fn run( tep: Ipv6Addr, //tunnel endpoint address db: Db, log: Logger, + stats: Arc, rt: Arc, ) { loop { @@ -57,7 +59,7 @@ pub fn run( let dpd = new_dpd_client(&log); let ddm = new_ddm_client(&log); let mut generation = - match full_sync(tep, &db, &log, &dpd, &ddm, rt.clone()) { + match full_sync(tep, &db, &log, &dpd, &ddm, &stats, rt.clone()) { Ok(gen) => gen, Err(e) => { error!(log, "initializing failed: {e}"); @@ -79,6 +81,7 @@ pub fn run( &dpd, &ddm, generation, + &stats, rt.clone(), ) { Ok(gen) => gen, @@ -92,20 +95,23 @@ pub fn run( // if we've not received updates in the timeout interval, do a // full sync in case something has changed out from under us. Err(RecvTimeoutError::Timeout) => { - generation = - match full_sync(tep, &db, &log, &dpd, &ddm, rt.clone()) - { - Ok(gen) => gen, - Err(e) => { - error!(log, "initializing failed: {e}"); - info!( - log, - "restarting sync loop in one second" - ); - sleep(Duration::from_secs(1)); - continue; - } + generation = match full_sync( + tep, + &db, + &log, + &dpd, + &ddm, + &stats, + rt.clone(), + ) { + Ok(gen) => gen, + Err(e) => { + error!(log, "initializing failed: {e}"); + info!(log, "restarting sync loop in one second"); + sleep(Duration::from_secs(1)); + continue; } + } } Err(RecvTimeoutError::Disconnected) => { error!(log, "mg-lower rdb watcher disconnected"); @@ -124,6 +130,7 @@ fn full_sync( log: &Logger, dpd: &DpdClient, ddm: &DdmClient, + stats: &Arc, rt: Arc, ) -> Result { let generation = db.generation(); @@ -136,8 +143,14 @@ fn full_sync( update_tunnel_endpoints(tep, ddm, &db_imported, rt.clone(), log); // get all imported routes from db - let imported: HashSet = - db_route_to_dendrite_route(db_imported, log, dpd, rt.clone()); + let imported: HashSet = db_route_to_dendrite_route( + db_imported, + log, + dpd, + Some(stats), + true, + rt.clone(), + ); // get all routes created by mg-lower from dendrite let routes = @@ -180,6 +193,7 @@ fn handle_change( dpd: &DpdClient, ddm: &DdmClient, generation: u64, + stats: &Arc, rt: Arc, ) -> Result { info!( @@ -191,18 +205,26 @@ fn handle_change( ); if change.generation > generation + 1 { - return full_sync(tep, db, log, dpd, ddm, rt.clone()); + return full_sync(tep, db, log, dpd, ddm, stats, rt.clone()); } let to_add: Vec = change.import.added.clone().into_iter().collect(); add_tunnel_routes(tep, ddm, &to_add, rt.clone(), log); - let to_add = db_route_to_dendrite_route(to_add, log, dpd, rt.clone()); + let to_add = db_route_to_dendrite_route( + to_add, + log, + dpd, + Some(stats), + true, + rt.clone(), + ); let to_del: Vec = change.import.removed.clone().into_iter().collect(); remove_tunnel_routes(tep, ddm, &to_del, rt.clone(), log); - let to_del = db_route_to_dendrite_route(to_del, log, dpd, rt.clone()); + let to_del = + db_route_to_dendrite_route(to_del, log, dpd, None, false, rt.clone()); update_dendrite(to_add.iter(), to_del.iter(), dpd, rt.clone(), log)?; diff --git a/mgadm/src/bgp.rs b/mgadm/src/bgp.rs index aa2fcbee..7125b020 100644 --- a/mgadm/src/bgp.rs +++ b/mgadm/src/bgp.rs @@ -14,6 +14,13 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::time::Duration; use tabwriter::TabWriter; +fn to_prefix4(p: &types::Prefix4) -> Prefix4 { + Prefix4 { + value: p.value, + length: p.length, + } +} + #[derive(Subcommand, Debug)] pub enum Commands { /// Get the running set of BGP routers. @@ -267,7 +274,10 @@ async fn get_imported(c: Client, asn: u32) { writeln!( &mut tw, "{}\t{}\t{}\t{}", - route.prefix, route.nexthop, id, route.priority, + to_prefix4(&route.prefix), + route.nexthop, + id, + route.priority, ) .unwrap(); } @@ -286,7 +296,7 @@ async fn get_originated(c: Client, asn: u32) { writeln!(&mut tw, "{}", "Prefix".dimmed()).unwrap(); for prefix in &originated { - writeln!(&mut tw, "{}", prefix).unwrap(); + writeln!(&mut tw, "{}", to_prefix4(prefix)).unwrap(); } tw.flush().unwrap(); @@ -305,7 +315,15 @@ async fn delete_neighbor(asn: u32, addr: IpAddr, c: Client) { async fn originate4(originate: Originate4, c: Client) { c.originate4(&types::Originate4Request { asn: originate.asn, - prefixes: originate.prefixes.clone(), + prefixes: originate + .prefixes + .clone() + .into_iter() + .map(|x| types::Prefix4 { + length: x.length, + value: x.value, + }) + .collect(), }) .await .unwrap(); @@ -314,7 +332,15 @@ async fn originate4(originate: Originate4, c: Client) { async fn withdraw4(withdraw: Withdraw4, c: Client) { c.withdraw4(&types::Withdraw4Request { asn: withdraw.asn, - prefixes: withdraw.prefixes.clone(), + prefixes: withdraw + .prefixes + .clone() + .into_iter() + .map(|x| types::Prefix4 { + length: x.length, + value: x.value, + }) + .collect(), }) .await .unwrap(); diff --git a/mgadm/src/static_routing.rs b/mgadm/src/static_routing.rs index 9bc44d58..f5733c62 100644 --- a/mgadm/src/static_routing.rs +++ b/mgadm/src/static_routing.rs @@ -6,7 +6,6 @@ use anyhow::Result; use clap::{Args, Subcommand}; use mg_admin_client::types; use mg_admin_client::Client; -use rdb::Prefix4; use std::net::{AddrParseError, Ipv4Addr}; use std::num::ParseIntError; use thiserror::Error; @@ -68,7 +67,7 @@ pub async fn commands(command: Commands, client: Client) -> Result<()> { let arg = types::AddStaticRoute4Request { routes: types::StaticRoute4List { list: vec![types::StaticRoute4 { - prefix: Prefix4 { + prefix: types::Prefix4 { value: route.destination.addr, length: route.destination.len, }, @@ -82,7 +81,7 @@ pub async fn commands(command: Commands, client: Client) -> Result<()> { let arg = types::DeleteStaticRoute4Request { routes: types::StaticRoute4List { list: vec![types::StaticRoute4 { - prefix: Prefix4 { + prefix: types::Prefix4 { value: route.destination.addr, length: route.destination.len, }, diff --git a/mgd/Cargo.toml b/mgd/Cargo.toml index 0a726ef5..c5e667f3 100644 --- a/mgd/Cargo.toml +++ b/mgd/Cargo.toml @@ -22,6 +22,12 @@ tokio.workspace = true http.workspace = true thiserror.workspace = true rand.workspace = true +oximeter.workspace = true +oximeter-producer.workspace = true +chrono.workspace = true +omicron-common.workspace = true +hostname.workspace = true +uuid.workspace = true [features] default = ["mg-lower"] diff --git a/mgd/src/admin.rs b/mgd/src/admin.rs index 95444360..5491716f 100644 --- a/mgd/src/admin.rs +++ b/mgd/src/admin.rs @@ -6,6 +6,7 @@ use crate::{bfd_admin, bgp_admin, static_admin}; use bfd_admin::BfdContext; use bgp_admin::BgpContext; use dropshot::{ApiDescription, ConfigDropshot, HttpServerStarter}; +use mg_common::stats::MgLowerStats; use rdb::Db; use slog::o; use slog::{error, info, warn, Logger}; @@ -21,6 +22,7 @@ pub struct HandlerContext { pub log: Logger, pub data_dir: String, pub db: Db, + pub mg_lower_stats: Arc, } pub fn start_server( @@ -87,6 +89,7 @@ pub fn api_description() -> ApiDescription> { register!(api, bfd_admin::get_bfd_peers); register!(api, bfd_admin::add_bfd_peer); register!(api, bfd_admin::remove_bfd_peer); + api } diff --git a/mgd/src/bfd_admin.rs b/mgd/src/bfd_admin.rs index ce11f9ed..50a79d3d 100644 --- a/mgd/src/bfd_admin.rs +++ b/mgd/src/bfd_admin.rs @@ -34,7 +34,7 @@ use std::time::Duration; #[derive(Clone)] pub struct BfdContext { /// The underlying deamon being run. - daemon: Arc>, + pub(crate) daemon: Arc>, dispatcher: Arc>, } diff --git a/mgd/src/bgp_admin.rs b/mgd/src/bgp_admin.rs index 04347f53..b8951292 100644 --- a/mgd/src/bgp_admin.rs +++ b/mgd/src/bgp_admin.rs @@ -32,8 +32,9 @@ use std::sync::{Arc, Mutex}; const DEFAULT_BGP_LISTEN: SocketAddr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, BGP_PORT, 0, 0)); +#[derive(Clone)] pub struct BgpContext { - pub(crate) router: Mutex>>>, + pub(crate) router: Arc>>>>, addr_to_session: Arc>>>>, } @@ -45,7 +46,7 @@ impl BgpContext { >, ) -> Self { Self { - router: Mutex::new(BTreeMap::new()), + router: Arc::new(Mutex::new(BTreeMap::new())), addr_to_session, } } diff --git a/mgd/src/main.rs b/mgd/src/main.rs index 23b1ea88..e45a5eee 100644 --- a/mgd/src/main.rs +++ b/mgd/src/main.rs @@ -9,18 +9,21 @@ use bgp::connection_tcp::{BgpConnectionTcp, BgpListenerTcp}; use bgp::log::init_logger; use clap::{Parser, Subcommand}; use mg_common::cli::oxide_cli_style; +use mg_common::stats::MgLowerStats; use rand::Fill; use rdb::{BfdPeerConfig, BgpNeighborInfo, BgpRouterInfo}; use slog::Logger; use std::collections::{BTreeMap, HashMap}; -use std::net::{IpAddr, Ipv6Addr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::sync::{Arc, Mutex}; use std::thread::spawn; +use uuid::Uuid; mod admin; mod bfd_admin; mod bgp_admin; mod error; +mod oxstats; mod static_admin; #[derive(Parser, Debug)] @@ -55,6 +58,26 @@ struct RunArgs { /// Where to store the local database #[arg(long, default_value = "/var/run")] data_dir: String, + + /// Register as an oximemeter producer. + #[arg(long)] + with_stats: bool, + + /// DNS servers used to find nexus. + #[arg(long)] + dns_servers: Vec, + + /// Port to listen on for the oximeter API. + #[arg(long, default_value_t = 4677)] + oximeter_port: u16, + + /// Id of the rack this router is running on. + #[arg(long)] + rack_uuid: Uuid, + + /// Id of the sled this router is running on. + #[arg(long)] + sled_uuid: Uuid, } #[tokio::main] @@ -82,6 +105,7 @@ async fn run(args: RunArgs) { bgp, bfd, data_dir: args.data_dir.clone(), + mg_lower_stats: Arc::new(MgLowerStats::default()), db: db.clone(), }); @@ -91,8 +115,9 @@ async fn run(args: RunArgs) { let ctx = context.clone(); let log = log.clone(); let db = ctx.db.clone(); + let stats = context.mg_lower_stats.clone(); std::thread::spawn(move || { - mg_lower::run(ctx.tep, db, log, rt); + mg_lower::run(ctx.tep, db, log, stats, rt); }); } @@ -112,6 +137,32 @@ async fn run(args: RunArgs) { initialize_static_routes(&db); + let hostname = hostname::get() + .expect("failed to get hostname") + .to_string_lossy() + .to_string(); + + let dns_servers: Vec = args + .dns_servers + .iter() + .filter(|x| x.as_str() != "unknown") + .map(|x| x.parse().unwrap()) + .collect(); + + if args.with_stats && !dns_servers.is_empty() { + oxstats::start_server( + args.admin_addr, + args.oximeter_port, + context.clone(), + dns_servers, + hostname, + args.rack_uuid, + args.sled_uuid, + log.clone(), + ) + .unwrap(); + } + let j = admin::start_server( log.clone(), args.admin_addr, diff --git a/mgd/src/oxstats.rs b/mgd/src/oxstats.rs new file mode 100644 index 00000000..d551e528 --- /dev/null +++ b/mgd/src/oxstats.rs @@ -0,0 +1,823 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use crate::admin::HandlerContext; +use crate::bfd_admin::BfdContext; +use crate::bgp_admin::BgpContext; +use chrono::{DateTime, Utc}; +use dropshot::{ + ConfigDropshot, ConfigLogging, ConfigLoggingLevel, HandlerTaskMode, +}; +use mg_common::nexus::{resolve_nexus, run_oximeter}; +use mg_common::stats::MgLowerStats; +use mg_common::{counter, quantity}; +use omicron_common::api::internal::nexus::{ProducerEndpoint, ProducerKind}; +use oximeter::types::{Cumulative, ProducerRegistry}; +use oximeter::{Metric, MetricsError, Producer, Sample, Target}; +use oximeter_producer::LogConfig; +use rdb::Db; +use slog::{warn, Logger}; +use std::collections::BTreeMap; +use std::net::{IpAddr, SocketAddr}; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::time::Duration; +use tokio::task::JoinHandle; +use uuid::Uuid; + +#[derive(Clone)] +pub(crate) struct Stats { + pub(crate) hostname: String, + pub(crate) rack_id: Uuid, + pub(crate) sled_id: Uuid, + pub(crate) start_time: DateTime, + pub(crate) bfd: BfdContext, + pub(crate) bgp: BgpContext, + pub(crate) db: Db, + pub(crate) mg_lower_stats: Arc, + log: Logger, +} + +#[derive(Debug, Clone, Target)] +struct BgpSession { + rack_id: Uuid, + sled_id: Uuid, + hostname: String, + local_asn: u32, + peer: IpAddr, +} + +#[derive(Debug, Clone, Target)] +struct BfdSession { + rack_id: Uuid, + sled_id: Uuid, + hostname: String, + peer: IpAddr, +} + +#[derive(Debug, Clone, Target)] +struct StaticRoutingConfig { + rack_id: Uuid, + sled_id: Uuid, + hostname: String, +} + +#[derive(Debug, Clone, Target)] +struct SwitchRib { + rack_id: Uuid, + sled_id: Uuid, + hostname: String, +} + +#[derive(Debug, Clone, Target)] +struct MgLower { + rack_id: Uuid, + sled_id: Uuid, + hostname: String, +} + +macro_rules! bgp_session_counter { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $start_time:expr, + $local_asn:expr, + $peer:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &BgpSession { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + local_asn: $local_asn, + peer: $peer, + }, + &$kind { + count: Cumulative::::with_start_time( + $start_time, + $value.load(Ordering::Relaxed), + ), + }, + )? + }; +} + +macro_rules! bfd_session_counter { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $start_time:expr, + $peer:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &BfdSession { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + peer: $peer, + }, + &$kind { + count: Cumulative::::with_start_time( + $start_time, + $value.load(Ordering::Relaxed), + ), + }, + )? + }; +} + +macro_rules! static_counter { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $start_time:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &StaticRoutingConfig { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + }, + &$kind { + count: Cumulative::::with_start_time($start_time, $value), + }, + )? + }; +} + +macro_rules! mg_lower_quantity { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $start_time:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &MgLower { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + }, + &$kind { + quantity: $value.load(Ordering::Relaxed), + }, + )? + }; +} + +macro_rules! rib_quantity { + ( + $hostname:expr, + $rack_id:expr, + $sled_id:expr, + $start_time:expr, + $kind:tt, + $value:expr + ) => { + Sample::new( + &SwitchRib { + hostname: $hostname, + rack_id: $rack_id, + sled_id: $sled_id, + }, + &$kind { quantity: $value }, + )? + }; +} + +// BGP +counter!(KeepalivesSent); +counter!(KeepalivesReceived); +counter!(OpensSent); +counter!(OpensReceived); +counter!(UpdatesSent); +counter!(UpdatesReceived); +counter!(PrefixesAdvertised); +counter!(PrefixesImported); +counter!(IdleHoldTimerExpirations); +counter!(HoldTimerExpirations); +counter!(UnexpectedKeepaliveMessages); +counter!(UnexpectedOpenMessages); +counter!(UnexpectedUpdateMessages); +counter!(UpdateNexthopMissing); +counter!(ActiveConnectionsAccepted); +counter!(PassiveConnectionsAccepted); +counter!(ConnectionRetries); +counter!(OpenHandleFailures); +counter!(TransitionToIdle); +counter!(TransitionToConnect); +counter!(TransitionToActive); +counter!(TransitionToOpenSent); +counter!(TransitionToOpenConfirm); +counter!(TransitionToSessionSetup); +counter!(TransitionToEstablished); +counter!(NotificationSendFailures); +counter!(OpenSendFailures); +counter!(KeepaliveSendFailures); +counter!(UpdateSendFailures); + +// BFD +counter!(ControlPacketsSent); +counter!(ControlPacketSendFailures); +counter!(ControlPacketsReceived); +counter!(TransitionToInit); +counter!(TransitionToDown); +counter!(TransitionToUp); +counter!(TimeoutExpired); +counter!(MessageRecieveError); + +// Static +counter!(StaticRoutes); +counter!(StaticNexthops); + +// RIB +quantity!(ActiveRoutes, u64); + +// Mg-lower +quantity!(RoutesBlockedByLinkState, u64); + +impl std::fmt::Debug for Stats { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("stats")?; + Ok(()) + } +} + +impl Producer for Stats { + fn produce( + &mut self, + ) -> Result>, MetricsError> { + let mut samples = Vec::new(); + + match self.bgp_stats() { + Ok(bgp) => samples.extend(bgp), + Err(e) => { + warn!(self.log, "failed to produce bgp samples: {e}"); + } + } + + match self.bfd_stats() { + Ok(bfd) => samples.extend(bfd), + Err(e) => { + warn!(self.log, "failed to produce bfd samples: {e}"); + } + } + + match self.static_stats() { + Ok(statics) => samples.extend(statics), + Err(e) => { + warn!(self.log, "failed to produce static route samples: {e}"); + } + } + + match self.rib_stats() { + Ok(rib) => samples.extend(rib), + Err(e) => { + warn!(self.log, "failed to produce rib samples: {e}"); + } + } + + match self.mg_lower_stats() { + Ok(mgl) => samples.extend(mgl), + Err(e) => { + warn!(self.log, "failed to produce mg lower samples: {e}"); + } + } + + Ok(Box::new(samples.into_iter())) + } +} + +impl Stats { + fn bgp_stats(&mut self) -> Result, MetricsError> { + let routers = self.bgp.router.lock().unwrap(); + let mut router_counters = BTreeMap::new(); + let mut session_count: usize = 0; + for (asn, r) in &*routers { + let mut session_counters = BTreeMap::new(); + let sessions = r.sessions.lock().unwrap(); + for (addr, session) in &*sessions { + session_counters.insert(*addr, session.counters.clone()); + session_count += 1; + } + router_counters.insert(*asn, session_counters); + } + drop(routers); + + let mut samples = Vec::with_capacity(session_count * 29); + + for (asn, session_counters) in &router_counters { + for (addr, counters) in session_counters { + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + KeepalivesSent, + counters.keepalives_sent + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + KeepalivesReceived, + counters.keepalives_received + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + OpensSent, + counters.opens_sent + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + OpensReceived, + counters.opens_received + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UpdatesSent, + counters.updates_sent + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UpdatesReceived, + counters.updates_received + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + PrefixesAdvertised, + counters.prefixes_advertised + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + PrefixesImported, + counters.prefixes_imported + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + IdleHoldTimerExpirations, + counters.idle_hold_timer_expirations + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + HoldTimerExpirations, + counters.hold_timer_expirations + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UpdateNexthopMissing, + counters.update_nexhop_missing + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + ActiveConnectionsAccepted, + counters.active_connections_accepted + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + PassiveConnectionsAccepted, + counters.passive_connections_accepted + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + ConnectionRetries, + counters.connection_retries + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + OpenHandleFailures, + counters.open_handle_failures + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToIdle, + counters.transitions_to_idle + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToConnect, + counters.transitions_to_connect + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToActive, + counters.transitions_to_active + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToOpenSent, + counters.transitions_to_open_sent + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToOpenConfirm, + counters.transitions_to_open_confirm + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToSessionSetup, + counters.transitions_to_session_setup + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + TransitionToEstablished, + counters.transitions_to_established + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UnexpectedUpdateMessages, + counters.unexpected_update_message + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UnexpectedKeepaliveMessages, + counters.unexpected_keepalive_message + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UnexpectedOpenMessages, + counters.unexpected_open_message + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + NotificationSendFailures, + counters.notification_send_failure + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + KeepaliveSendFailures, + counters.keepalive_send_failure + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + OpenSendFailures, + counters.open_send_failure + )); + samples.push(bgp_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *asn, + *addr, + UpdateSendFailures, + counters.update_send_failure + )); + } + } + + Ok(samples) + } + + fn bfd_stats(&mut self) -> Result, MetricsError> { + let daemon = self.bfd.daemon.lock().unwrap(); + let mut counters = BTreeMap::new(); + for (addr, session) in &daemon.sessions { + counters.insert(*addr, session.counters.clone()); + } + drop(daemon); + + let mut samples = Vec::with_capacity(counters.len() * 8); + + for (addr, counters) in &counters { + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + ControlPacketsSent, + counters.control_packets_sent + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + ControlPacketSendFailures, + counters.control_packet_send_failures + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + ControlPacketsReceived, + counters.control_packets_received + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + TransitionToInit, + counters.transition_to_init + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + TransitionToDown, + counters.transition_to_down + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + TransitionToUp, + counters.transition_to_up + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + TimeoutExpired, + counters.timeout_expired + )); + samples.push(bfd_session_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + *addr, + MessageRecieveError, + counters.message_receive_error + )); + } + + Ok(samples) + } + + fn static_stats(&mut self) -> Result, MetricsError> { + let mut samples = Vec::new(); + + match self.db.get_static4_count() { + Ok(count) => { + samples.push(static_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + StaticRoutes, + count as u64 + )); + } + Err(e) => { + warn!(self.log, "stats: failed to get static4 count: {e}"); + } + } + match self.db.get_static_nexthop4_count() { + Ok(count) => { + samples.push(static_counter!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + StaticNexthops, + count as u64 + )); + } + Err(e) => { + warn!(self.log, "stats: failed to get static4 count: {e}"); + } + } + + Ok(samples) + } + + fn rib_stats(&mut self) -> Result, MetricsError> { + let mut samples = Vec::new(); + + let count = self.db.effective_route_set().len() as u64; + samples.push(rib_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + ActiveRoutes, + count + )); + + Ok(samples) + } + + fn mg_lower_stats(&mut self) -> Result, MetricsError> { + Ok(vec![mg_lower_quantity!( + self.hostname.clone(), + self.rack_id, + self.sled_id, + self.start_time, + RoutesBlockedByLinkState, + self.mg_lower_stats.routes_blocked_by_link_state + )]) + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn start_server( + addr: IpAddr, + port: u16, + context: Arc, + dns_servers: Vec, + hostname: String, + rack_id: Uuid, + sled_id: Uuid, + log: Logger, +) -> Result, String> { + let sa = SocketAddr::new(addr, port); + let dropshot = ConfigDropshot { + bind_address: sa, + request_body_max_bytes: 1024 * 1024 * 1024, + default_handler_task_mode: HandlerTaskMode::Detached, + }; + let log_config = LogConfig::Config(ConfigLogging::StderrTerminal { + level: ConfigLoggingLevel::Debug, + }); + let registry = ProducerRegistry::new(); + let stats_producer = Stats { + hostname, + rack_id, + sled_id, + start_time: chrono::offset::Utc::now(), + bfd: context.bfd.clone(), + bgp: context.bgp.clone(), + db: context.db.clone(), + mg_lower_stats: context.mg_lower_stats.clone(), + log: log.clone(), + }; + registry.register_producer(stats_producer).unwrap(); + let producer_info = ProducerEndpoint { + id: registry.producer_id(), + kind: ProducerKind::Service, + address: sa, + base_route: "/collect".to_string(), + interval: Duration::from_secs(1), + }; + + Ok(tokio::spawn(async move { + let nexus_addr = resolve_nexus(log.clone(), &dns_servers).await; + let config = oximeter_producer::Config { + server_info: producer_info, + registration_address: nexus_addr, + log: log_config, + dropshot, + }; + run_oximeter(registry.clone(), config.clone(), log.clone()).await + })) +} diff --git a/openapi/ddm-admin.json b/openapi/ddm-admin.json index b2d20e9f..0fa17ba7 100644 --- a/openapi/ddm-admin.json +++ b/openapi/ddm-admin.json @@ -5,6 +5,48 @@ "version": "v0.1.0" }, "paths": { + "/disable-stats": { + "post": { + "operationId": "disable_stats", + "responses": { + "204": { + "description": "resource updated" + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, + "/enable-stats": { + "post": { + "operationId": "enable_stats", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableStatsRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "resource updated" + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/originated": { "get": { "operationId": "get_originated", @@ -313,6 +355,35 @@ }, "components": { "schemas": { + "EnableStatsRequest": { + "type": "object", + "properties": { + "addr": { + "type": "string", + "format": "ip" + }, + "dns_servers": { + "type": "array", + "items": { + "type": "string" + } + }, + "rack_id": { + "type": "string", + "format": "uuid" + }, + "sled_id": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "addr", + "dns_servers", + "rack_id", + "sled_id" + ] + }, "Error": { "description": "Error information from a response.", "type": "object", @@ -460,6 +531,12 @@ "type": "string", "format": "ipv6" }, + "metric": { + "default": 0, + "type": "integer", + "format": "uint64", + "minimum": 0 + }, "overlay_prefix": { "$ref": "#/components/schemas/IpPrefix" }, diff --git a/rdb/src/db.rs b/rdb/src/db.rs index c2f7ea16..1e6eb590 100644 --- a/rdb/src/db.rs +++ b/rdb/src/db.rs @@ -412,6 +412,20 @@ impl Db { .collect()) } + pub fn get_static4_count(&self) -> Result { + let tree = self.persistent.open_tree(STATIC4_ROUTES)?; + Ok(tree.len()) + } + + pub fn get_static_nexthop4_count(&self) -> Result { + let entries = self.get_static4()?; + let mut nexthops = HashSet::new(); + for e in entries { + nexthops.insert(e.nexthop); + } + Ok(nexthops.len()) + } + pub fn disable_nexthop4(&self, addr: Ipv4Addr) { let mut imported = lock!(self.imported); let changed: Vec = imported diff --git a/smf/ddm/manifest.xml b/smf/ddm/manifest.xml index f5732539..580e4e13 100644 --- a/smf/ddm/manifest.xml +++ b/smf/ddm/manifest.xml @@ -23,6 +23,9 @@ + + + diff --git a/smf/ddm_method_script.sh b/smf/ddm_method_script.sh index 545f86a1..706da75f 100755 --- a/smf/ddm_method_script.sh +++ b/smf/ddm_method_script.sh @@ -34,19 +34,36 @@ if [[ "$val" != '""' ]]; then export RUST_LOG="$val" fi +val=$(svcprop -c -p config/rack_uuid "${SMF_FMRI}") +if [[ "$val" != 'unknown' ]]; then + args+=( '--rack-uuid' ) + args+=( "$val" ) +fi + +val=$(svcprop -c -p config/sled_uuid "${SMF_FMRI}") +if [[ "$val" != 'unknown' ]]; then + args+=( '--sled-uuid' ) + args+=( "$val" ) +fi + for x in $(svcprop -c -p config/interfaces "${SMF_FMRI}"); do args+=( '-a' ) args+=( "$x" ) done +for x in $(svcprop -c -p config/dns_servers "${SMF_FMRI}"); do + args+=( '--dns-servers' ) + args+=( "$x" ) +done + if [[ -e /opt/oxide/mg-ddm/bin/ddmd ]]; then # mg-ddm.tar.gz gets the binaries at /opt/oxide/mg-ddm/bin/ - exec /opt/oxide/mg-ddm/bin/ddmd "${args[@]}" + exec /opt/oxide/mg-ddm/bin/ddmd --with-stats "${args[@]}" elif [[ -e /opt/oxide/mg-ddm/ddmd ]]; then # maghemite.tar gets the binaries at /opt/oxide/mg-ddm/ - exec /opt/oxide/mg-ddm/ddmd "${args[@]}" + exec /opt/oxide/mg-ddm/ddmd --with-stats "${args[@]}" else exit 1 fi diff --git a/smf/mgd/manifest.xml b/smf/mgd/manifest.xml index 16f5d02b..adebfba7 100644 --- a/smf/mgd/manifest.xml +++ b/smf/mgd/manifest.xml @@ -16,8 +16,11 @@ - + + + + diff --git a/smf/mgd_method_script.sh b/smf/mgd_method_script.sh index 4cb741cb..27b8f291 100755 --- a/smf/mgd_method_script.sh +++ b/smf/mgd_method_script.sh @@ -8,17 +8,23 @@ export RUST_LOG=info args=( --admin-port "$(svcprop -c -p config/admin_port "${SMF_FMRI}")" --admin-addr "$(svcprop -c -p config/admin_host "${SMF_FMRI}")" + --rack-uuid "$(svcprop -c -p config/rack_uuid "${SMF_FMRI}")" + --sled-uuid "$(svcprop -c -p config/sled_uuid "${SMF_FMRI}")" ) +for x in $(svcprop -c -p config/dns_servers "${SMF_FMRI}"); do + args+=( '--dns-servers' ) + args+=( "$x" ) +done + if [[ -e /opt/oxide/mgd/bin/mgd ]]; then # mgd.tar.gz gets the binaries at /opt/oxide/mgd/bin/ - exec /opt/oxide/mgd/bin/mgd run "${args[@]}" + exec /opt/oxide/mgd/bin/mgd run --with-stats "${args[@]}" elif [[ -e /opt/oxide/mgd/mgd ]]; then # maghemite.tar gets the binaries at /opt/oxide/mgd/ - exec /opt/oxide/mgd/mgd run "${args[@]}" + exec /opt/oxide/mgd/mgd run --with-stats "${args[@]}" else exit 1 fi - diff --git a/tests/Cargo.toml b/tests/Cargo.toml index fb6145b9..9189bda0 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -15,3 +15,4 @@ slog-envlogger.workspace = true slog-async.workspace = true tokio.workspace = true ztest.workspace = true +uuid.workspace = true diff --git a/tests/src/ddm.rs b/tests/src/ddm.rs index 4ba4c6f4..a64c0696 100644 --- a/tests/src/ddm.rs +++ b/tests/src/ddm.rs @@ -3,7 +3,8 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use anyhow::{anyhow, Result}; -use ddm_admin_client::{Client, Ipv6Prefix, TunnelOrigin}; +use ddm_admin_client::types::{IpPrefix, Ipv4Prefix, Ipv6Prefix, TunnelOrigin}; +use ddm_admin_client::Client; use slog::{Drain, Logger}; use std::env; use std::net::Ipv6Addr; @@ -165,6 +166,15 @@ impl<'a> RouterZone<'a> { .join(" "); let ddm = if self.v1 { "/opt/ddmd-v1" } else { "/opt/ddmd" }; + let extra_args = if self.v1 { + String::new() + } else { + format!( + "--rack-uuid {} --sled-uuid {}", + uuid::Uuid::new_v4(), + uuid::Uuid::new_v4(), + ) + }; if self.v1 { self.zfs.copy_workspace_to_zone( @@ -202,15 +212,15 @@ impl<'a> RouterZone<'a> { sleep(Duration::from_secs(10)); self.zone.zexec("svcadm enable tfport")?; self.zone.zexec(&format!( - "{} {ddm} --kind transit --dendrite {} &> /opt/ddmd.log &", - "RUST_LOG=trace RUST_BACKTRACE=1", addrs + "{} {ddm} --kind transit --dendrite {} {} &> /opt/ddmd.log &", + "RUST_LOG=trace RUST_BACKTRACE=1", extra_args, addrs ))?; self.zone.zexec("ipadm")?; } else { self.zone.zexec(&format!( - "{} {ddm} --kind server {} &> /opt/ddmd.log &", - "RUST_LOG=trace RUST_BACKTRACE=1", addrs + "{} {ddm} --kind server {} {} &> /opt/ddmd.log &", + "RUST_LOG=trace RUST_BACKTRACE=1", extra_args, addrs ))?; } Ok(()) @@ -572,7 +582,10 @@ async fn run_trio_tests( wait_for_eq!(tunnel_originated_endpoint_count(&t1).await?, 0); t1.advertise_tunnel_endpoints(&vec![TunnelOrigin { - overlay_prefix: "203.0.113.0/24".parse().unwrap(), + overlay_prefix: IpPrefix::V4(Ipv4Prefix { + addr: "203.0.113.0".parse().unwrap(), + len: 24, + }), boundary_addr: "fd00:1701::1".parse().unwrap(), vni: 47, metric: 0, @@ -589,7 +602,10 @@ async fn run_trio_tests( // redudant advertise should not change things t1.advertise_tunnel_endpoints(&vec![TunnelOrigin { - overlay_prefix: "203.0.113.0/24".parse().unwrap(), + overlay_prefix: IpPrefix::V4(Ipv4Prefix { + addr: "203.0.113.0".parse().unwrap(), + len: 24, + }), boundary_addr: "fd00:1701::1".parse().unwrap(), vni: 47, metric: 0, @@ -615,7 +631,10 @@ async fn run_trio_tests( println!("tunnel router restart passed"); t1.withdraw_tunnel_endpoints(&vec![TunnelOrigin { - overlay_prefix: "203.0.113.0/24".parse().unwrap(), + overlay_prefix: IpPrefix::V4(Ipv4Prefix { + addr: "203.0.113.0".parse().unwrap(), + len: 24, + }), boundary_addr: "fd00:1701::1".parse().unwrap(), vni: 47, metric: 0,