From 938fdd31d2fbe2e44d5b28ff8ce18cd7d33a00c1 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Fri, 8 Nov 2024 17:57:53 +0800 Subject: [PATCH 01/11] countersyncd init Signed-off-by: Ze Gan --- countersyncd/Cargo.lock | 1111 +++++++++++++++++++++++++ countersyncd/Cargo.toml | 55 ++ countersyncd/src/actor/ipfix.rs | 456 ++++++++++ countersyncd/src/actor/mod.rs | 2 + countersyncd/src/actor/netlink.rs | 336 ++++++++ countersyncd/src/main.rs | 27 + countersyncd/src/message/buffer.rs | 3 + countersyncd/src/message/ipfix.rs | 3 + countersyncd/src/message/mod.rs | 6 + countersyncd/src/message/netlink.rs | 13 + countersyncd/src/message/saistats.rs | 75 ++ countersyncd/src/message/swss.rs | 23 + countersyncd/tests/data/constants.yml | 4 + 13 files changed, 2114 insertions(+) create mode 100644 countersyncd/Cargo.lock create mode 100644 countersyncd/Cargo.toml create mode 100644 countersyncd/src/actor/ipfix.rs create mode 100644 countersyncd/src/actor/mod.rs create mode 100644 countersyncd/src/actor/netlink.rs create mode 100644 countersyncd/src/main.rs create mode 100644 countersyncd/src/message/buffer.rs create mode 100644 countersyncd/src/message/ipfix.rs create mode 100644 countersyncd/src/message/mod.rs create mode 100644 countersyncd/src/message/netlink.rs create mode 100644 countersyncd/src/message/saistats.rs create mode 100644 countersyncd/src/message/swss.rs create mode 100644 countersyncd/tests/data/constants.yml diff --git a/countersyncd/Cargo.lock b/countersyncd/Cargo.lock new file mode 100644 index 0000000000..419c9055b9 --- /dev/null +++ b/countersyncd/Cargo.lock @@ -0,0 +1,1111 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "binrw" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab81d22cbd2d745852348b2138f3db2103afa8ce043117a374581926a523e267" +dependencies = [ + "array-init", + "binrw_derive 0.11.2", + "bytemuck", +] + +[[package]] +name = "binrw" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b" +dependencies = [ + "array-init", + "binrw_derive 0.14.1", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b019a3efebe7f453612083202887b6f1ace59e20d010672e336eea4ed5be97" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "binrw_derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "cc" +version = "1.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", + "terminal_size", + "unicase", + "unicode-width", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "countersyncd" +version = "0.1.0" +dependencies = [ + "ahash", + "binrw 0.14.1", + "byteorder", + "clap", + "color-eyre", + "ipfix", + "ipfixrw", + "log", + "neli", + "rand", + "tokio", + "yaml-rust", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getset" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[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.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "ipfix" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec14e601f7a267061ae1efed4b7e9ccb178296cb92c6454707e8d312320ecdb" +dependencies = [ + "nom", +] + +[[package]] +name = "ipfixrw" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e18277dde2a264cf269ab1090a9e003b5b323ffb3d02011bdbce697e6aaff18" +dependencies = [ + "ahash", + "binrw 0.11.2", + "csv", + "derive_more", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "neli" +version = "0.7.0-rc2" +source = "git+https://github.com/jbaublitz/neli.git?branch=v0.7.0-rc2#382ae669f699fdbb914cd72c58bfb49b31ed3e07" +dependencies = [ + "bitflags", + "byteorder", + "derive_builder", + "getset", + "libc", + "log", + "neli-proc-macros", + "parking_lot", +] + +[[package]] +name = "neli-proc-macros" +version = "0.2.0-rc2" +source = "git+https://github.com/jbaublitz/neli.git?branch=v0.7.0-rc2#382ae669f699fdbb914cd72c58bfb49b31ed3e07" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "nom" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff" + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +dependencies = [ + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] diff --git a/countersyncd/Cargo.toml b/countersyncd/Cargo.toml new file mode 100644 index 0000000000..b4806ff34b --- /dev/null +++ b/countersyncd/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "countersyncd" +version = "0.1.0" +edition = "2021" + +[dependencies] +# Async runtime +tokio = { version = "1", features = ["full"] } + +# Yaml paser +yaml-rust = "0.4" + +# Ge-netlink +neli = { git = "https://github.com/jbaublitz/neli.git", branch = "v0.7.0-rc2" } + +# IPFIX parser +ipfix = "0.1.1" +ipfixrw = "0.1.0" +ahash = "0.8.11" +binrw = "0.14.1" +byteorder = "1.5.0" + +# Logging +log = "0.4.22" +# simplelog = "0.12" + +rand = "0.8.5" + +# Command line utils +clap = { version = "4", features = ["derive", "cargo", "wrap_help", "unicode", "string", "unstable-styles"] } +color-eyre = "0.6" + +# OTEL + +# tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_info"] } +# tracing-opentelemetry = "0.26" +# tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] } +# +# opentelemetry = { version = "0.25", features = ["trace"] } +# opentelemetry_sdk = { version = "0.25", features = ["rt-tokio"]} +# opentelemetry-semantic-conventions = "0.25" +# opentelemetry-http = "0.25" +# opentelemetry-otlp = { version = "0.25", features = ["tonic"] } +# +# # gRPC and HTTP +# tonic = "0.12" +# tonic-health = "0.12" +# prost = "0.13" +# prost-types = "0.13" +# reqwest = { version = "0.12", default-features = false, features = ["json"] } +# reqwest-middleware = "0.3" +# reqwest-tracing = { version = "0.5", features = ["opentelemetry_0_22"] } +# +# # Other utilities +# once_cell = "1" diff --git a/countersyncd/src/actor/ipfix.rs b/countersyncd/src/actor/ipfix.rs new file mode 100644 index 0000000000..dc0506a8d8 --- /dev/null +++ b/countersyncd/src/actor/ipfix.rs @@ -0,0 +1,456 @@ +use std::{cell::RefCell, collections::LinkedList, rc::Rc, sync::Arc, time::SystemTime}; + +use log::{debug, warn}; +use tokio::{ + select, + sync::mpsc::{Receiver, Sender}, +}; + +use ahash::{HashMap, HashMapExt}; +use byteorder::{ByteOrder, NetworkEndian}; +use ipfix::get_message_length; +use ipfixrw::{ + information_elements::Formatter, + parse_ipfix_message, + parser::{DataRecord, DataRecordKey, DataRecordValue, FieldSpecifier}, + template_store::TemplateStore, +}; + +use super::super::message::{ + buffer::SocketBufferMessage, + ipfix::IPFixTemplates, + saistats::{SAIStat, SAIStats, SAIStatsMessage}, +}; + +struct IpfixCache { + pub templates: TemplateStore, + pub formatter: Rc, + pub last_observer_time: Option, +} + +impl IpfixCache { + pub fn new() -> Self { + let duration_since_epoch = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); + IpfixCache { + templates: Rc::new(RefCell::new(HashMap::new())), + formatter: Rc::new(Formatter::new()), + last_observer_time: Some(duration_since_epoch.as_nanos() as u64), + } + } +} + +type IpfixCacheRef = Rc>; + +pub struct IpfixActor { + saistats_recipients: LinkedList>, + template_recipient: Receiver, + record_recipient: Receiver, + + #[cfg(test)] + prober: Option>, +} + +impl IpfixActor { + pub fn new( + template_recipient: Receiver, + record_recipient: Receiver, + ) -> Self { + IpfixActor { + saistats_recipients: LinkedList::new(), + template_recipient, + record_recipient, + #[cfg(test)] + prober: None, + } + } + + pub fn add_recipient(&mut self, recipient: Sender) { + self.saistats_recipients.push_back(recipient); + } + + fn handle_template(&mut self, templates: IPFixTemplates) { + let cache_ref = Self::get_cache(); + let cache = cache_ref.borrow_mut(); + let mut read_size: usize = 0; + while read_size < templates.len() { + let len = get_message_length(&templates[read_size..]).unwrap(); + let template = &templates[read_size..read_size + len as usize]; + // We suppose that the template is always valid, otherwise we need to raise the panic + parse_ipfix_message(&template, cache.templates.clone(), cache.formatter.clone()) + .unwrap(); + read_size += len as usize; + } + #[cfg(test)] + self.probe(format!("Template {:?} consumed", templates)); + } + + fn handle_record(&mut self, records: SocketBufferMessage) -> Vec { + let cache_ref = Self::get_cache(); + let mut cache = cache_ref.borrow_mut(); + let mut read_size: usize = 0; + let mut messages: Vec = Vec::new(); + while read_size < records.len() { + let len = get_message_length(&records[read_size..]); + if len.is_err() || len.unwrap() as usize + read_size > records.len() { + warn!("Wrong length in the records {:?}", records); + #[cfg(test)] + self.probe("Discard record due to error length".to_string()); + break; + } + let len = len.unwrap(); + let data = &records[read_size..read_size + len as usize]; + let data_message = + parse_ipfix_message(&data, cache.templates.clone(), cache.formatter.clone()); + if data_message.is_err() { + warn!("Not support data message {:?}", data); + read_size += len as usize; + #[cfg(test)] + self.probe(format!("Unknown template, Discard record {:?}", data_message.err().unwrap())); + continue; + } + let data_message = data_message.unwrap(); + let datarecords: Vec<&DataRecord> = data_message.iter_data_records().collect(); + let mut observation_time: Option; + for record in datarecords { + observation_time = get_observation_time(record); + if observation_time.is_none() { + debug!( + "No observation time in record, use the last observer time {:?}", + cache.last_observer_time + ); + observation_time = cache.last_observer_time; + } else if observation_time.unwrap() > cache.last_observer_time.unwrap() { + cache.last_observer_time = observation_time; + } + let mut saistats = SAIStatsMessage::new(SAIStats { + observation_time: observation_time.unwrap(), + stats: Vec::new(), + }); + for (key, val) in record.values.iter() { + if key == &*OBSERVATION_TIME_KEY { + // skip the observation time data + continue; + } + match key { + DataRecordKey::Unrecognized(key) => { + Arc::get_mut(&mut saistats) + .unwrap() + .stats + .push(SAIStat::from((key, val))); + } + _ => continue, + } + } + messages.push(saistats.clone()); + #[cfg(test)] + self.probe("Record parsed".to_string()); + } + read_size += len as usize; + } + messages + } + + thread_local! { + static IPFIX_CACHE: RefCell = RefCell::new(Rc::new(RefCell::new(IpfixCache::new()))); + } + + fn get_cache() -> IpfixCacheRef { + Self::IPFIX_CACHE.with(|cache| cache.borrow().clone()) + } + + pub async fn run(mut actor: IpfixActor) { + loop { + select! { + templates = actor.template_recipient.recv() => { + match templates { + Some(templates) => { + actor.handle_template(templates); + }, + None => { + break; + } + } + }, + record = actor.record_recipient.recv() => { + match record { + Some(record) => { + let messages = actor.handle_record(record); + for recipient in &actor.saistats_recipients { + for message in &messages { + let _ = recipient.send(message.clone()).await; + } + } + }, + None => { + break; + } + } + } + } + } + } + + #[cfg(test)] + pub fn set_prober(&mut self, prober: Sender) { + self.prober = Some(prober); + } + + #[cfg(test)] + fn probe(&self, message: String) { + self.prober.as_ref().unwrap().try_send(message).unwrap(); + } +} + +impl Drop for IpfixActor { + fn drop(&mut self) { + self.template_recipient.close(); + } +} + +use std::sync::LazyLock; + +static OBSERVATION_TIME_KEY: LazyLock = + LazyLock::new(|| DataRecordKey::Unrecognized(FieldSpecifier::new(None, 325, 8))); + +fn get_observation_time(data_record: &DataRecord) -> Option { + let val = data_record.values.get(&*OBSERVATION_TIME_KEY); + match val { + Some(DataRecordValue::Bytes(val)) => Some(NetworkEndian::read_u64(val)), + _ => None, + } +} + +#[cfg(test)] +mod test { + use super::*; + + use tokio::{spawn, sync::mpsc::channel}; + + #[tokio::test] + async fn test_ipfix() { + let (buffer_sender, buffer_reciver) = channel(1); + let (template_sender, template_reciver) = channel(1); + let (saistats_sender, mut saistats_reciver) = channel(100); + let (prober, mut prober_reciver) = channel(100); + + let mut actor = IpfixActor::new(template_reciver, buffer_reciver); + actor.add_recipient(saistats_sender); + actor.set_prober(prober); + let actor_handle = spawn(IpfixActor::run(actor)); + + let template_bytes: [u8; 88] = [ + 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x01, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x00, 0x02, 0x00, 0x1C, // line 4 + 0x01, 0x00, 0x00, 0x03, // line 5 Template ID 256, 3 fields + 0x01, 0x45, 0x00, 0x08, // line 6 Field ID 325, 4 bytes + 0x80, 0x01, 0x00, 0x08, // line 7 Field ID 128, 8 bytes + 0x00, 0x01, 0x00, 0x02, // line 8 Enterprise Number 1, Field ID 1 + 0x80, 0x02, 0x00, 0x08, // line 9 Field ID 129, 8 bytes + 0x80, 0x03, 0x80, 0x04, // line 10 Enterprise Number 128, Field ID 2 + 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 2 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x01, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x00, 0x02, 0x00, 0x1C, // line 4 + 0x01, 0x00, 0x00, 0x03, // line 5 Template ID 256, 3 fields + 0x01, 0x45, 0x00, 0x08, // line 6 Field ID 325, 4 bytes + 0x80, 0x01, 0x00, 0x08, // line 7 Field ID 128, 8 bytes + 0x00, 0x01, 0x00, 0x02, // line 8 Enterprise Number 1, Field ID 1 + 0x80, 0x02, 0x00, 0x08, // line 9 Field ID 129, 8 bytes + 0x80, 0x03, 0x80, 0x04, // line 10 Enterprise Number 128, Field ID 2 + ]; + + // contains data sets for templates 999, 500, 999 + let valid_records_bytes: [u8; 144] = [ + 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x02, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x01, 0x00, 0x00, 0x1C, // line 4 Record 1 + 0x00, 0x00, 0x00, 0x00, // line 5 + 0x00, 0x00, 0x00, 0x01, // line 6 + 0x00, 0x00, 0x00, 0x00, // line 7 + 0x00, 0x00, 0x00, 0x01, // line 8 + 0x00, 0x00, 0x00, 0x00, // line 9 + 0x00, 0x00, 0x00, 0x01, // line 10 + 0x01, 0x00, 0x00, 0x1C, // line 11 Record 2 + 0x00, 0x00, 0x00, 0x00, // line 12 + 0x00, 0x00, 0x00, 0x02, // line 13 + 0x00, 0x00, 0x00, 0x00, // line 14 + 0x00, 0x00, 0x00, 0x02, // line 15 + 0x00, 0x00, 0x00, 0x00, // line 16 + 0x00, 0x00, 0x00, 0x03, // line 17 + 0x00, 0x0A, 0x00, 0x48, // line 18 Packet 2 + 0x00, 0x00, 0x00, 0x00, // line 19 + 0x00, 0x00, 0x00, 0x02, // line 20 + 0x00, 0x00, 0x00, 0x00, // line 21 + 0x01, 0x00, 0x00, 0x1C, // line 22 Record 1 + 0x00, 0x00, 0x00, 0x00, // line 23 + 0x00, 0x00, 0x00, 0x01, // line 24 + 0x00, 0x00, 0x00, 0x00, // line 25 + 0x00, 0x00, 0x00, 0x01, // line 26 + 0x00, 0x00, 0x00, 0x00, // line 27 + 0x00, 0x00, 0x00, 0x04, // line 28 + 0x01, 0x00, 0x00, 0x1C, // line 29 Record 2 + 0x00, 0x00, 0x00, 0x00, // line 30 + 0x00, 0x00, 0x00, 0x02, // line 31 + 0x00, 0x00, 0x00, 0x00, // line 32 + 0x00, 0x00, 0x00, 0x02, // line 33 + 0x00, 0x00, 0x00, 0x00, // line 34 + 0x00, 0x00, 0x00, 0x07, // line 35 + ]; + + template_sender + .send(Arc::new(Vec::from(template_bytes))) + .await + .unwrap(); + let pm = prober_reciver + .recv() + .await + .expect("The template not consumed"); + assert!(pm.contains("Template")); + assert!(pm.contains("consumed")); + + buffer_sender + .send(Arc::new(Vec::from(valid_records_bytes))) + .await + .unwrap(); + for _ in 0..4 { + let pm = prober_reciver + .recv() + .await + .expect("The record not consumed"); + assert!(pm.contains("Record")); + assert!(pm.contains("parsed")); + } + + let invalid_len_record: [u8; 20] = [ + 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x02, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x01, 0x00, 0x00, 0x1C, // line 4 Record 1 + ]; + buffer_sender + .send(Arc::new(Vec::from(invalid_len_record))) + .await + .unwrap(); + assert!(prober_reciver + .recv() + .await + .expect("The record not consumed") + .contains("Discard record due to error length")); + + let unknown_record: [u8; 44] = [ + 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x02, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x03, 0x00, 0x00, 0x1C, // line 4 Record 1 + 0x00, 0x00, 0x00, 0x00, // line 5 + 0x00, 0x00, 0x00, 0x01, // line 6 + 0x00, 0x00, 0x00, 0x00, // line 7 + 0x00, 0x00, 0x00, 0x01, // line 8 + 0x00, 0x00, 0x00, 0x00, // line 9 + 0x00, 0x00, 0x00, 0x01, // line 10 + ]; + buffer_sender + .send(Arc::new(Vec::from(unknown_record))) + .await + .unwrap(); + assert!(prober_reciver + .recv() + .await + .expect("The record not consumed") + .contains("Unknown template, Discard record")); + + drop(buffer_sender); + drop(template_sender); + + let mut received_stats = Vec::new(); + while let Some(stats) = saistats_reciver.recv().await { + received_stats.push(Arc::try_unwrap(stats).unwrap()); + } + + let expected_stats = vec![ + SAIStats { + observation_time: 1, + stats: vec![ + SAIStat { + label: 2, + type_id: 536870915, + stat_id: 536870916, + counter: 1, + }, + SAIStat { + label: 1, + type_id: 1, + stat_id: 2, + counter: 1, + }, + ], + }, + SAIStats { + observation_time: 2, + stats: vec![ + SAIStat { + label: 2, + type_id: 536870915, + stat_id: 536870916, + counter: 3, + }, + SAIStat { + label: 1, + type_id: 1, + stat_id: 2, + counter: 2, + }, + ], + }, + SAIStats { + observation_time: 1, + stats: vec![ + SAIStat { + label: 2, + type_id: 536870915, + stat_id: 536870916, + counter: 4, + }, + SAIStat { + label: 1, + type_id: 1, + stat_id: 2, + counter: 1, + }, + ], + }, + SAIStats { + observation_time: 2, + stats: vec![ + SAIStat { + label: 2, + type_id: 536870915, + stat_id: 536870916, + counter: 7, + }, + SAIStat { + label: 1, + type_id: 1, + stat_id: 2, + counter: 2, + }, + ], + }, + ]; + assert_eq!(received_stats, expected_stats); + + drop(saistats_reciver); + + actor_handle.await.unwrap(); + } +} diff --git a/countersyncd/src/actor/mod.rs b/countersyncd/src/actor/mod.rs new file mode 100644 index 0000000000..3a6ddce6f5 --- /dev/null +++ b/countersyncd/src/actor/mod.rs @@ -0,0 +1,2 @@ +pub mod netlink; +pub mod ipfix; diff --git a/countersyncd/src/actor/netlink.rs b/countersyncd/src/actor/netlink.rs new file mode 100644 index 0000000000..461ebfe7bb --- /dev/null +++ b/countersyncd/src/actor/netlink.rs @@ -0,0 +1,336 @@ +use std::{ + collections::LinkedList, + io, + sync::Arc, + thread::sleep, + time::Duration, + vec, + fs::File, io::prelude::* +}; + +use log::{error, warn}; + +#[allow(unused_imports)] +use neli::{ + consts::socket::{Msg, NlFamily}, + router::synchronous::NlRouter, + socket::NlSocket, + utils::Groups, +}; +use tokio::{ + select, + sync::mpsc::{Receiver, Sender}, +}; + +use yaml_rust::YamlLoader; + +use super::super::message::{buffer::SocketBufferMessage, netlink::{NetlinkCommand, SocketConnect}}; + +#[cfg(not(test))] +type SocketType = NlSocket; +#[cfg(test)] +type SocketType = test::MockSocket; + +#[cfg(not(test))] +// The unit of reconnect interval is milliseconds +const RECONNECT_INTERVAL_MS: u64 = 10_000_u64; +#[cfg(test)] +// The unit of reconnect interval is milliseconds +const RECONNECT_INTERVAL_MS: u64 = 1; +const RECONNECT_MAX_ATTEMPTS: u64 = 5; +const BUFFER_SIZE: usize = 0xFFFF; + +pub struct NetlinkActor { + family: String, + group: String, + socket: Option, + buffer_recipients: LinkedList>, + command_recipient: Receiver, +} + +impl NetlinkActor { + pub fn new(family: &str, group: &str, command_recipient: Receiver) -> Self { + let socket = NetlinkActor::connect(family, group); + NetlinkActor { + family: family.to_string(), + group: group.to_string(), + socket, + buffer_recipients: LinkedList::new(), + command_recipient, + } + } + + pub fn add_recipient(&mut self, recipient: Sender) { + self.buffer_recipients.push_back(recipient); + } + + #[cfg(not(test))] + fn connect(family: &str, group: &str) -> Option { + let (sock, _) = NlRouter::connect( + NlFamily::Generic, + // 0 is pid of kernel -> socket is connected to kernel + Some(0), + Groups::empty(), + ) + .unwrap(); + + let group_id = sock.resolve_nl_mcast_group(family, group); + if group_id.is_err() { + warn!("Failed to resolve group id"); + return None; + } + + let socket = SocketType::connect( + NlFamily::Generic, + // 0 is pid of kernel -> socket is connected to kernel + Some(0), + Groups::empty(), + ) + .unwrap(); + + match socket.add_mcast_membership(Groups::new_groups(&[group_id.unwrap()])) { + Ok(_) => Some(socket), + Err(e) => { + warn!("Failed to add mcast membership: {:?}", e); + None + } + } + } + + #[cfg(test)] + fn connect(_: &str, _: &str) -> Option { + let sock = SocketType::new(); + match sock.valid { + false => None, + true => Some(sock), + } + } + + fn reconnect(&mut self) { + for i in 0..RECONNECT_MAX_ATTEMPTS { + sleep(Duration::from_millis(RECONNECT_INTERVAL_MS)); + match NetlinkActor::connect(&self.family, &self.group) { + Some(socket) => { + self.socket = Some(socket); + return; + } + None => { + warn!( + "Failed to reconnect to netlink socket family: '{}' group: '{}' ... {}/{}", + self.family, self.group, i, RECONNECT_MAX_ATTEMPTS + ); + continue; + } + } + } + error!( + "Failed to reconnect to netlink socket family: '{}' group: '{}'", + self.family, self.group + ); + if !self.command_recipient.is_closed() { + self.command_recipient.close(); + } + } + + fn reset(&mut self, family: &str, group: &str) { + self.family = family.to_string(); + self.group = group.to_string(); + self.reconnect(); + } + + async fn try_recv(socket: Option<&mut SocketType>) -> Result { + match socket { + None => { + sleep(Duration::from_millis(RECONNECT_INTERVAL_MS)); + Err(io::Error::new(io::ErrorKind::Other, "No socket")) + } + Some(socket) => { + let mut buffer = Arc::new(vec![0; BUFFER_SIZE]); + match socket.recv(Arc::get_mut(&mut buffer).unwrap(), Msg::empty()) { + Err(e) => { + Err(e) + } + Ok(size) => { + if size.0 == 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "No more data to receive", + )); + } + Arc::get_mut(&mut buffer).unwrap().resize(size.0, 0); + Ok(buffer) + } + } + } + } + } + + pub async fn run(mut actor: NetlinkActor) { + loop { + select! { + ret = NetlinkActor::try_recv(actor.socket.as_mut()) => { + match ret { + Ok(buffer) => { + for recipient in &actor.buffer_recipients { + recipient.send(buffer.clone()).await.unwrap(); + } + }, + Err(e) => { + warn!("Failed to receive message: {:?}", e); + actor.socket = None; + actor.reconnect(); + }, + } + }, + cmd = actor.command_recipient.recv() => { + match cmd { + None => { + break; + }, + Some(cmd) => { + match cmd { + NetlinkCommand::SocketConnect(SocketConnect{family, group}) => { + actor.reset(&family, &group); + } + NetlinkCommand::Reconnect => { + actor.reconnect(); + } + NetlinkCommand::Close => { + break; + } + } + } + } + } + } + } + } +} + +impl Drop for NetlinkActor { + fn drop(&mut self) { + if !self.command_recipient.is_closed() { + self.command_recipient.close(); + } + } +} + +#[cfg(test)] +const SONIC_CONSTANTS: &str = "tests/data/constants.yml"; +#[cfg(not(test))] +const SONIC_CONSTANTS: &str = "/etc/sonic/constants.yml"; + +pub fn get_genl_family_group() -> (String, String) { + let mut fd = File::open(SONIC_CONSTANTS).unwrap(); + let mut yaml_str = String::new(); + fd.read_to_string(&mut yaml_str).unwrap(); + let constants = &YamlLoader::load_from_str(&yaml_str).unwrap()[0]; + + let stream_telemetry = &constants["constants"]["stream_telemetry"]; + ( + stream_telemetry["genl_family"].as_str().unwrap().to_string(), + stream_telemetry["genl_multicast_group"].as_str().unwrap().to_string() + ) +} + +#[cfg(test)] +mod test { + use super::*; + + use tokio::{spawn, sync::mpsc::channel}; + + const PARTIALLY_VALID_MESSAGES: [&str; 4] = [ + "PARTIALLY_VALID1", + "PARTIALLY_VALID2", + "", // Empty String needs to simulate the reconnect + "PARTIALLY_VALID3", + ]; + + const VALID_MESSAGES: [&str; 2] = ["VALID1", "VALID2"]; + + static mut SOCKET_COUNT: usize = 0; + + pub struct MockSocket { + pub valid: bool, + budget: usize, + messages: Vec, + } + + impl MockSocket { + pub fn new() -> Self { + unsafe { + SOCKET_COUNT += 1; + if SOCKET_COUNT == 1 { + return MockSocket { + valid: true, + budget: PARTIALLY_VALID_MESSAGES.len(), + messages: PARTIALLY_VALID_MESSAGES + .iter() + .map(|s| s.to_string()) + .collect(), + }; + } else { + return MockSocket { + valid: SOCKET_COUNT <= 2, // 2 is the maximum number of sockets + budget: VALID_MESSAGES.len(), + messages: VALID_MESSAGES.iter().map(|s| s.to_string()).collect(), + }; + } + } + } + + pub fn recv(&mut self, buf: &mut [u8], _flags: Msg) -> Result<(usize, Groups), io::Error> { + sleep(Duration::from_millis(1)); + if self.budget == 0 { + return Ok((0, Groups::empty())); + } + let msg = self.messages[self.messages.len() - self.budget].clone(); + self.budget -= 1; + if !msg.is_empty() { + buf[..msg.len()].clone_from_slice(msg.as_bytes()); + Ok((msg.len(), Groups::empty())) + } else { + Err(io::Error::new(io::ErrorKind::Other, "Error Message")) + } + } + } + + #[tokio::test] + async fn test_netlink() { + let (_command_sender, command_reciver) = channel(1); + let (buffer_sender, mut buffer_reciver) = channel(1); + let mut actor = NetlinkActor::new("family", "group", command_reciver); + + actor.add_recipient(buffer_sender); + let task = spawn(NetlinkActor::run(actor)); + + let mut recv_messages = Vec::new(); + for _ in 0..4 { + let buffer = buffer_reciver.recv().await.unwrap(); + recv_messages.push(String::from_utf8(buffer.to_vec()).unwrap()); + } + + let mut expect_messages = Vec::new(); + for msg in PARTIALLY_VALID_MESSAGES.iter() { + if msg.is_empty() { + break; + } + expect_messages.push(msg.to_string()); + } + for msg in VALID_MESSAGES.iter() { + expect_messages.push(msg.to_string()); + } + + assert_eq!(recv_messages, expect_messages); + assert!(unsafe { SOCKET_COUNT } > 1); + + task.await.unwrap(); + } + + #[test] + fn test_family_group_pase() { + let (family, group) = get_genl_family_group(); + assert_eq!(family, "sonic_stel"); + assert_eq!(group, "ipfix"); + } +} diff --git a/countersyncd/src/main.rs b/countersyncd/src/main.rs new file mode 100644 index 0000000000..820591c9a9 --- /dev/null +++ b/countersyncd/src/main.rs @@ -0,0 +1,27 @@ +mod message; +mod actor; + +use tokio::{spawn, sync::mpsc::channel}; + +use actor::{netlink::{NetlinkActor, get_genl_family_group}, ipfix::IpfixActor}; + +#[tokio::main] +async fn main() { + let (_command_sender, command_receiver) = channel(1); + let (socket_sender, socket_receiver) = channel(1); + let (_ipfix_template_sender, ipfix_template_receiver) = channel(1); + let (saistats_sender, _saistats_receiver) = channel(1); + + let (family, group) = get_genl_family_group(); + + let mut netlink = NetlinkActor::new(family.as_str(), group.as_str(), command_receiver); + netlink.add_recipient(socket_sender); + let mut ipfix = IpfixActor::new(ipfix_template_receiver, socket_receiver); + ipfix.add_recipient(saistats_sender); + + let netlink_handle = spawn(NetlinkActor::run(netlink)); + let ipfix_handle = spawn(IpfixActor::run(ipfix)); + + netlink_handle.await.unwrap(); + ipfix_handle.await.unwrap(); +} diff --git a/countersyncd/src/message/buffer.rs b/countersyncd/src/message/buffer.rs new file mode 100644 index 0000000000..58631e4a8e --- /dev/null +++ b/countersyncd/src/message/buffer.rs @@ -0,0 +1,3 @@ +use std::sync::Arc; + +pub type SocketBufferMessage = Arc>; diff --git a/countersyncd/src/message/ipfix.rs b/countersyncd/src/message/ipfix.rs new file mode 100644 index 0000000000..e7e99dac2e --- /dev/null +++ b/countersyncd/src/message/ipfix.rs @@ -0,0 +1,3 @@ +use std::sync::Arc; + +pub type IPFixTemplates = Arc>; diff --git a/countersyncd/src/message/mod.rs b/countersyncd/src/message/mod.rs new file mode 100644 index 0000000000..0e6a11ad8e --- /dev/null +++ b/countersyncd/src/message/mod.rs @@ -0,0 +1,6 @@ +pub mod netlink; +pub mod buffer; +pub mod ipfix; +pub mod saistats; + +pub mod swss; diff --git a/countersyncd/src/message/netlink.rs b/countersyncd/src/message/netlink.rs new file mode 100644 index 0000000000..691cfee21c --- /dev/null +++ b/countersyncd/src/message/netlink.rs @@ -0,0 +1,13 @@ +#[derive(Debug)] +pub struct SocketConnect { + pub family: String, + pub group: String, +} + +#[allow(dead_code)] +#[derive(Debug)] +pub enum NetlinkCommand { + Close, + Reconnect, + SocketConnect(SocketConnect), +} \ No newline at end of file diff --git a/countersyncd/src/message/saistats.rs b/countersyncd/src/message/saistats.rs new file mode 100644 index 0000000000..668a3a6c7a --- /dev/null +++ b/countersyncd/src/message/saistats.rs @@ -0,0 +1,75 @@ +use ipfixrw::parser::{FieldSpecifier, DataRecordValue}; +use byteorder::{ByteOrder, NetworkEndian}; +use std::sync::Arc; + +#[derive(Debug, PartialEq)] +pub struct SAIStat { + pub label: u16, + pub type_id: u32, + pub stat_id: u32, + pub counter: u64, +} + +const EXTENSIONS_RANGE_BASE: u32 = 0x2000_0000; + +impl From<(&FieldSpecifier, &DataRecordValue)> for SAIStat { + + fn from(item: (&FieldSpecifier, &DataRecordValue)) -> Self { + let (key, value) = item; + let enterprise_number = key.enterprise_number.unwrap_or(0); + + let type_id_extension: bool = enterprise_number & 0x8000_0000 != 0; + let stats_id_extension: bool = enterprise_number & 0x0000_8000 != 0; + + let mut type_id = (enterprise_number & 0x7FFF_0000) >> 16; + let mut stat_id = enterprise_number & 0x0000_7FFF; + + if type_id_extension { + type_id += EXTENSIONS_RANGE_BASE; + } + + if stats_id_extension { + stat_id += EXTENSIONS_RANGE_BASE; + } + + let counter = match value { + DataRecordValue::Bytes(counter) => NetworkEndian::read_u64(counter), + _ => 0, + }; + + let label = key.information_element_identifier; + + SAIStat{ + label, + type_id, + stat_id, + counter, + } + } + +} + +#[derive(Debug)] +pub struct SAIStats { + pub observation_time: u64, + pub stats: Vec, +} + +impl PartialEq for SAIStats { + fn eq(&self, other: &Self) -> bool { + if self.observation_time != other.observation_time { + return false + } + if self.stats.len() != other.stats.len() { + return false + } + for s in self.stats.iter() { + if !other.stats.contains(s) { + return false + } + } + true + } +} + +pub type SAIStatsMessage = Arc; diff --git a/countersyncd/src/message/swss.rs b/countersyncd/src/message/swss.rs new file mode 100644 index 0000000000..d7ab349c05 --- /dev/null +++ b/countersyncd/src/message/swss.rs @@ -0,0 +1,23 @@ +#[allow(dead_code)] +pub struct SwssCfgStreamTelemetry {} + +#[allow(dead_code)] +pub struct SwssCfgTelemetryGroup {} + +#[allow(dead_code)] +pub enum SessionStatus { + Enabled, + Disabled, +} + +#[allow(dead_code)] +pub enum SessionType { + Ipfix, +} + +#[allow(dead_code)] +pub struct SwssStateTelemetrySession { + session_status: SessionStatus, + session_type: SessionType, + session_template: [u8], +} diff --git a/countersyncd/tests/data/constants.yml b/countersyncd/tests/data/constants.yml new file mode 100644 index 0000000000..e3b35b506f --- /dev/null +++ b/countersyncd/tests/data/constants.yml @@ -0,0 +1,4 @@ +constants: + stream_telemetry: + genl_family: "sonic_stel" + genl_multicast_group: "ipfix" From 4cc3652fa330112af301e4f60b397b676f89d029 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Tue, 19 Nov 2024 19:49:53 +0800 Subject: [PATCH 02/11] stelorch init Signed-off-by: Ze Gan --- orchagent/Makefile.am | 5 +- orchagent/orchdaemon.cpp | 9 + orchagent/orchdaemon.h | 1 + .../stream_telemetry/counternameupdater.cpp | 70 ++ .../stream_telemetry/counternameupdater.h | 54 ++ orchagent/stream_telemetry/stelmgr.cpp | 643 ++++++++++++++++++ orchagent/stream_telemetry/stelmgr.h | 109 +++ orchagent/stream_telemetry/stelorch.cpp | 527 ++++++++++++++ orchagent/stream_telemetry/stelorch.h | 66 ++ 9 files changed, 1483 insertions(+), 1 deletion(-) create mode 100644 orchagent/stream_telemetry/counternameupdater.cpp create mode 100644 orchagent/stream_telemetry/counternameupdater.h create mode 100644 orchagent/stream_telemetry/stelmgr.cpp create mode 100644 orchagent/stream_telemetry/stelmgr.h create mode 100644 orchagent/stream_telemetry/stelorch.cpp create mode 100644 orchagent/stream_telemetry/stelorch.h diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 8456509da6..a5847157c1 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -117,7 +117,10 @@ orchagent_SOURCES = \ dash/dashtagmgr.cpp \ dash/pbutils.cpp \ twamporch.cpp \ - stporch.cpp + stporch.cpp \ + stream_telemetry/stelorch.cpp \ + stream_telemetry/stelmgr.cpp \ + stream_telemetry/counternameupdater.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp flex_counter/flow_counter_handler.cpp flex_counter/flowcounterrouteorch.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 5b7f1c68f6..9901c3ce1f 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -65,6 +65,7 @@ MonitorOrch *gMonitorOrch; TunnelDecapOrch *gTunneldecapOrch; StpOrch *gStpOrch; MuxOrch *gMuxOrch; +STelOrch *gSTelOrch = nullptr; bool gIsNatSupported = false; event_handle_t g_events_handle; @@ -848,6 +849,14 @@ bool OrchDaemon::init() TwampOrch *twamp_orch = new TwampOrch(confDbTwampTable, stateDbTwampTable, gSwitchOrch, gPortsOrch, vrf_orch); m_orchList.push_back(twamp_orch); + + const vector stel_tables = { + CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME, + CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME + }; + gSTelOrch = new STelOrch(m_configDb, m_stateDb, stel_tables); + m_orchList.push_back(gSTelOrch); + if (WarmStart::isWarmStart()) { bool suc = warmRestoreAndSyncUp(); diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 8cc75325db..293e3b75ca 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -53,6 +53,7 @@ #include "dash/dashorch.h" #include "dash/dashrouteorch.h" #include "dash/dashvnetorch.h" +#include "stream_telemetry/stelorch.h" #include using namespace swss; diff --git a/orchagent/stream_telemetry/counternameupdater.cpp b/orchagent/stream_telemetry/counternameupdater.cpp new file mode 100644 index 0000000000..12aaa5e5f2 --- /dev/null +++ b/orchagent/stream_telemetry/counternameupdater.cpp @@ -0,0 +1,70 @@ +#include "counternameupdater.h" +#include "stelorch.h" + +#include +#include + +extern STelOrch *gSTelOrch; + +CounterNameMapUpdater::CounterNameMapUpdater(const std::string &db_name, const std::string &table_name) + : m_db_name(db_name), + m_table_name(table_name), + m_connector(m_db_name, 0), + m_counters_table(&m_connector, m_table_name) +{ + SWSS_LOG_ENTER(); +} + +void CounterNameMapUpdater::setCounterNameMap(const std::string &counter_name, sai_object_id_t oid) +{ + SWSS_LOG_ENTER(); + + // auto itr = m_local_cache.find(counter_name); + // if (itr != m_local_cache.end()) + // { + // SWSS_LOG_WARN("Counter name %s already exists in the local cache", counter_name.c_str()); + // if (itr->second == oid) + // { + // return; + // } + // } + + assert(gSTelOrch != nullptr); + Message msg{ + .m_table_name = m_table_name.c_str(), + .m_operation = OPERATION::SET, + .m_set{ + .m_counter_name = counter_name.c_str(), + .m_oid = oid, + }, + }; + gSTelOrch->locallyNotify(msg); + + // m_local_cache[counter_name] = oid; + m_counters_table.hset("", counter_name, sai_serialize_object_id(oid)); +} + +void CounterNameMapUpdater::delCounterNameMap(const std::string &counter_name) +{ + SWSS_LOG_ENTER(); + + // auto itr = m_local_cache.find(counter_name); + // if (itr == m_local_cache.end()) + // { + // SWSS_LOG_WARN("Counter name %s does not exist in the local cache", counter_name.c_str()); + // return; + // } + + assert(gSTelOrch != nullptr); + Message msg{ + .m_table_name = m_table_name.c_str(), + .m_operation = OPERATION::DEL, + .m_del{ + .m_counter_name = counter_name.c_str(), + }, + }; + gSTelOrch->locallyNotify(msg); + + // m_local_cache.erase(itr); + m_counters_table.hdel("", counter_name); +} diff --git a/orchagent/stream_telemetry/counternameupdater.h b/orchagent/stream_telemetry/counternameupdater.h new file mode 100644 index 0000000000..4801955352 --- /dev/null +++ b/orchagent/stream_telemetry/counternameupdater.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +#include +#include +#include + +class CounterNameMapUpdater +{ +public: + + enum OPERATION + { + SET, + DEL, + }; + + struct SetPayload + { + const char* m_counter_name; + sai_object_id_t m_oid; + }; + + struct DelPayload + { + const char* m_counter_name; + }; + + struct Message + { + const char* m_table_name; + OPERATION m_operation; + union + { + SetPayload m_set; + DelPayload m_del; + }; + }; + + CounterNameMapUpdater(const std::string &db_name, const std::string &table_name); + ~CounterNameMapUpdater() = default; + + +private: + std::string m_db_name; + std::string m_table_name; + swss::DBConnector m_connector; + swss::Table m_counters_table; + + void setCounterNameMap(const std::string &counter_name, sai_object_id_t oid); + void delCounterNameMap(const std::string &counter_name); +}; diff --git a/orchagent/stream_telemetry/stelmgr.cpp b/orchagent/stream_telemetry/stelmgr.cpp new file mode 100644 index 0000000000..372fabb0e5 --- /dev/null +++ b/orchagent/stream_telemetry/stelmgr.cpp @@ -0,0 +1,643 @@ +#include "stelmgr.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace swss; + +extern sai_object_id_t gSwitchId; +extern sai_tam_api_t *sai_tam_api; + +static set object_counters_to_stats_ids( + const string &group_name, + const set &object_counters) +{ + SWSS_LOG_ENTER(); + sai_object_type_t sai_object_type = STelProfile::group_name_to_sai_type(group_name); + set stats_ids_set; + + auto info = sai_metadata_get_object_type_info(sai_object_type); + if (info == nullptr) + { + SWSS_LOG_THROW("Failed to get the object type info for %s", group_name.c_str()); + } + + auto state_enum = info->statenum; + if (state_enum == nullptr) + { + SWSS_LOG_THROW("The object type %s does not support stats", group_name.c_str()); + } + + string type_prefix = "SAI_" + group_name + "_STAT_"; + + for (size_t i = 0; i < state_enum->valuescount; i++) + { + string state_name = type_prefix + state_enum->valuesnames[i]; + if (object_counters.find(state_name) != object_counters.end()) + { + SWSS_LOG_DEBUG("Found the object counter %s", state_name.c_str()); + stats_ids_set.insert(state_enum->values[i]); + } + } + + if (stats_ids_set.size() != object_counters.size()) + { + SWSS_LOG_THROW("Failed to convert the object counters to stats ids for %s", group_name.c_str()); + } + + return stats_ids_set; +} + +// static uint16_t get_sai_label(const string &object_name) +// { +// SWSS_LOG_ENTER(); +// uint16_t label = 0; + +// if (object_name.rfind("Ethernet", 0) == 0) +// { +// const static regex re("Ethernet(\\d+)(?:\\|(\\d+))?"); +// smatch match; +// if (regex_match(object_name, match, re)) +// { +// label = static_cast(stoi(match[1])); +// if (match.size() == 3) +// { +// label = static_cast(label * 100 + stoi(match[2])); +// } +// } +// } +// else +// { +// SWSS_LOG_THROW("The object %s is not supported", object_name.c_str()); +// } + +// return label; +// } + +// static int32_t get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id) +// { +// SWSS_LOG_ENTER(); + +// switch(object_type) +// { +// case SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP: +// switch(stat_id) +// { +// case SAI_INGRESS_PRIORITY_GROUP_STAT_WATERMARK_BYTES: +// case SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES: +// case SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES: +// return SAI_STATS_MODE_READ_AND_CLEAR; +// default: +// break; +// } +// case SAI_OBJECT_TYPE_BUFFER_POOL: +// switch(stat_id) +// { +// case SAI_BUFFER_POOL_STAT_WATERMARK_BYTES: +// case SAI_BUFFER_POOL_STAT_XOFF_ROOM_WATERMARK_BYTES: +// return SAI_STATS_MODE_READ_AND_CLEAR; +// default: +// break; +// } +// default: +// break; +// } + +// return SAI_STATS_MODE_READ; +// } + +STelProfile::STelProfile( + const std::string &profile_name, + sai_object_id_t sai_tam_obj, + sai_object_id_t sai_tam_collector_obj, + const CounterNameCache &cache) + : m_profile_name(profile_name), + m_setting_state(STREAM_STATE_DISABLED), + m_poll_interval(0), + m_bulk_size(0), + m_counter_name_cache(cache), + m_state(STREAM_STATE_DISABLED), + m_object_count(0), + m_needed_to_be_deployed(false), + m_sai_tam_obj(sai_tam_obj), + m_sai_tam_collector_obj(sai_tam_collector_obj), + m_sai_tam_report_obj(SAI_NULL_OBJECT_ID), + m_sai_tam_tel_type_obj(SAI_NULL_OBJECT_ID), + m_sai_tam_telemetry_obj(SAI_NULL_OBJECT_ID) +{ + SWSS_LOG_ENTER(); + + if (m_sai_tam_obj == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_THROW("The SAI TAM object is not valid"); + } + if (m_sai_tam_collector_obj == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_THROW("The SAI TAM collector object is not valid"); + } + + deployTAM(); +} + +STelProfile::~STelProfile() +{ + SWSS_LOG_ENTER(); + + undeployTAM(); +} + +void STelProfile::setStreamState(STREAM_STATE state) +{ + SWSS_LOG_ENTER(); + + if (state == m_setting_state) + { + return; + } + m_setting_state = state; + m_needed_to_be_deployed = true; +} + +void STelProfile::setPollInterval(uint32_t poll_interval) +{ + SWSS_LOG_ENTER(); + + if (poll_interval == m_poll_interval) + { + return; + } + m_poll_interval = poll_interval; + m_needed_to_be_deployed = true; +} + +void STelProfile::setBulkSize(uint32_t bulk_size) +{ + SWSS_LOG_ENTER(); + + if (bulk_size == m_bulk_size) + { + return; + } + m_bulk_size = bulk_size; + m_needed_to_be_deployed = true; +} + +void STelProfile::setObjectNames(const string &group_name, set &&object_names) +{ + SWSS_LOG_ENTER(); + + sai_object_type_t sai_object_type = group_name_to_sai_type(group_name); + auto itr = m_groups.lower_bound(sai_object_type); + + if (itr == m_groups.end() || itr->first != sai_object_type) + { + m_groups.insert(itr, {sai_object_type, StelGroup{move(object_names), {}}}); + m_object_count += object_names.size(); + } + else + { + if (itr->second.m_object_names == object_names) + { + return; + } + for (const auto &name : itr->second.m_object_names) + { + delObjectSAIID(sai_object_type, name.c_str()); + } + m_object_count -= itr->second.m_object_names.size(); + itr->second.m_object_names = move(object_names); + m_object_count += itr->second.m_object_names.size(); + } + loadCounterNameCache(sai_object_type); + m_needed_to_be_deployed = true; +} + +void STelProfile::setStatsIDs(const string &group_name, const set &object_counters) +{ + SWSS_LOG_ENTER(); + + sai_object_type_t sai_object_type = group_name_to_sai_type(group_name); + auto itr = m_groups.lower_bound(sai_object_type); + set stats_ids_set = object_counters_to_stats_ids(group_name, object_counters); + + if (itr == m_groups.end() || itr->first != sai_object_type) + { + m_groups.insert(itr, {sai_object_type, StelGroup{{}, stats_ids_set}}); + } + else + { + if (itr->second.m_stats_ids == stats_ids_set) + { + return; + } + itr->second.m_stats_ids = move(stats_ids_set); + } + m_needed_to_be_deployed = true; +} + +void STelProfile::setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id) +{ + SWSS_LOG_ENTER(); + + if (!isObjectInProfile(object_type, object_name)) + { + return; + } + + auto &objs = m_name_sai_map[object_type]; + auto itr = objs.find(object_name); + if (itr != objs.end()) + { + if (itr->second == object_id) + { + return; + } + } + objs[object_name] = object_id; + + m_needed_to_be_deployed = true; +} + +void STelProfile::delObjectSAIID(sai_object_type_t object_type, const char *object_name) +{ + SWSS_LOG_ENTER(); + + if (!isObjectInProfile(object_type, object_name)) + { + return; + } + + auto &objs = m_name_sai_map[object_type]; + auto itr = objs.find(object_name); + if (itr == objs.end()) + { + return; + } + objs.erase(itr); + if (objs.empty()) + { + m_name_sai_map.erase(object_type); + } + if (m_state == STREAM_STATE_ENABLED) + { + // TODO: Disable the stream, delete the subscription counter + } +} + +std::vector STelProfile::getObjectTypes() const +{ + std::vector types; + + for (const auto &group : m_groups) + { + types.push_back(group.first); + } + + return types; +} + +void STelProfile::loadGroupFromCfgDB(Table &group_tbl) +{ + SWSS_LOG_ENTER(); + + vector keys; + group_tbl.getKeys(keys); + + boost::char_separator key_sep(group_tbl.getTableNameSeparator().c_str()); + for (const auto &key : keys) + { + boost::tokenizer> tokens(key, key_sep); + + auto profile_name = (tokens.begin()); + if (profile_name == tokens.end()) + { + SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); + } + if (*profile_name != m_profile_name) + { + // Not the profile we are interested in + continue; + } + + auto group_name = ++tokens.begin(); + if (group_name == tokens.end()) + { + SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); + } + + vector items; + if (!group_tbl.get(key, items)) + { + SWSS_LOG_WARN("Failed to get the stream telemetry group: %s.", key.c_str()); + continue; + } + + auto names = fvsGetValue(items, "object_names", true); + if (!names || names->empty()) + { + // TODO: If the object names are empty, implicitly select all objects of the group + SWSS_LOG_WARN("No object names in the stream telemetry group: %s", key.c_str()); + continue; + } + + auto counters = fvsGetValue(items, "object_counters", true); + if (!counters || counters->empty()) + { + SWSS_LOG_ERROR("No object counters in the stream telemetry group: %s", key.c_str()); + continue; + } + + vector buffer; + boost::split(buffer, *names, boost::is_any_of(",")); + set object_names(buffer.begin(), buffer.end()); + setObjectNames(*group_name, move(object_names)); + + buffer.clear(); + boost::split(buffer, *counters, boost::is_any_of(",")); + set object_counters(buffer.begin(), buffer.end()); + setStatsIDs(*group_name, object_counters); + } +} + +void STelProfile::loadCounterNameCache(sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); + + auto itr = m_counter_name_cache.find(object_type); + if (itr == m_counter_name_cache.end()) + { + return; + } + auto group = m_groups.find(object_type); + if (group == m_groups.end()) + { + return; + } + const auto &sai_objs = itr->second; + for (const auto &name : group->second.m_object_names) + { + auto obj = sai_objs.find(name); + if (obj != sai_objs.end()) + { + setObjectSAIID(object_type, name.c_str(), obj->second); + } + } +} + +void STelProfile::tryCommitConfig() +{ + SWSS_LOG_ENTER(); + + m_needed_to_be_deployed &= (m_setting_state == STREAM_STATE_ENABLED); + m_needed_to_be_deployed &= (m_object_count != 0); + m_needed_to_be_deployed &= (m_object_count == m_name_sai_map.size()); + + if (m_needed_to_be_deployed) + { + if (m_state == STREAM_STATE_ENABLED) + { + undeployFromSAI(); + } + deployToSAI(); + } + + m_needed_to_be_deployed = false; +} + +sai_object_type_t STelProfile::group_name_to_sai_type(const string &group_name) +{ + SWSS_LOG_ENTER(); + + sai_object_type_t sai_object_type; + + sai_deserialize_object_type(string("SAI_OBJECT_TYPE_") + group_name, sai_object_type); + return sai_object_type; +} + +bool STelProfile::isObjectInProfile(sai_object_type_t object_type, const std::string &object_name) const +{ + SWSS_LOG_ENTER(); + + auto group = m_groups.find(object_type); + if (group == m_groups.end()) + { + return false; + } + if (group->second.m_object_names.find(object_name) == group->second.m_object_names.end()) + { + return false; + } + + return false; +} + +void STelProfile::deployToSAI() +{ + SWSS_LOG_ENTER(); + + m_state = STREAM_STATE_ENABLED; +} + +void STelProfile::undeployFromSAI() +{ + SWSS_LOG_ENTER(); + + m_state = STREAM_STATE_DISABLED; +} + +void STelProfile::deployTAM() +{ + SWSS_LOG_ENTER(); + + // Delete the existing TAM objects + undeployTAM(); + + vector attrs; + sai_attribute_t attr; + + // Create TAM report object + attr.id = SAI_TAM_REPORT_ATTR_TYPE; + attr.value.s32 = SAI_TAM_REPORT_TYPE_IPFIX; + attrs.push_back(attr); + + attr.id = SAI_TAM_REPORT_ATTR_REPORT_MODE; + attr.value.s32 = SAI_TAM_REPORT_MODE_BULK; + attrs.push_back(attr); + + attr.id = SAI_TAM_REPORT_ATTR_TEMPLATE_REPORT_INTERVAL; + attr.value.u32 = 0; // Don't push the template, Because we hope the template can be proactively queried by orchagent + attrs.push_back(attr); + + attr.id = SAI_TAM_REPORT_ATTR_REPORT_INTERVAL_UNIT; + attr.value.s32 = SAI_TAM_REPORT_INTERVAL_UNIT_USEC; + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_report( + &m_sai_tam_report_obj, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + // Create TAM telemetry type object + attrs.clear(); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_TAM_TELEMETRY_TYPE; + attr.value.s32 = SAI_TAM_TELEMETRY_TYPE_COUNTER_SUBSCRIPTION; + attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_PORT_STATS; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_PORT_STATS_INGRESS; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_PORT_STATS_EGRESS; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_MMU_STATS; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_REPORT_ID; + attr.value.oid = m_sai_tam_report_obj; + attrs.push_back(attr); + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_tel_type( + &m_sai_tam_tel_type_obj, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + // Create TAM telemetry object + attrs.clear(); + + sai_object_id_t sai_object = m_sai_tam_tel_type_obj; + attr.id = SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST; + attr.value.objlist.count = 1; + attr.value.objlist.list = &sai_object; + attrs.push_back(attr); + + sai_object = m_sai_tam_collector_obj; + attr.id = SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST; + attr.value.objlist.count = 1; + attr.value.objlist.list = &sai_object; + attrs.push_back(attr); + + // TODO: Update SAI tam telemetry + // attr.id = SAI_TAM_TELEMETRY_ATTR_REPORTING_TYPE; + // attr.value.s32 = SAI_TAM_REPORTING_TYPE_COUNT_BASED; + // attrs.push_back(attr); + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_telemetry( + &m_sai_tam_telemetry_obj, + gSwitchId, static_cast(attrs.size()), + attrs.data())); +} + +void STelProfile::undeployTAM() +{ + SWSS_LOG_ENTER(); + + if (m_sai_tam_telemetry_obj != SAI_NULL_OBJECT_ID) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_telemetry(m_sai_tam_telemetry_obj)); + m_sai_tam_telemetry_obj = SAI_NULL_OBJECT_ID; + } + + if (m_sai_tam_tel_type_obj != SAI_NULL_OBJECT_ID) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_tel_type(m_sai_tam_tel_type_obj)); + m_sai_tam_tel_type_obj = SAI_NULL_OBJECT_ID; + } + + if (m_sai_tam_report_obj != SAI_NULL_OBJECT_ID) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_report(m_sai_tam_report_obj)); + m_sai_tam_report_obj = SAI_NULL_OBJECT_ID; + } +} + +void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, uint16_t label) +{ + SWSS_LOG_ENTER(); + + vector attrs; + sai_attribute_t attr; + + auto itr = m_sai_tam_counter_subscription_objs.find(sai_obj); + if (itr != m_sai_tam_counter_subscription_objs.end()) + { + auto itr2 = itr->second.find(stat_id); + if (itr2 != itr->second.end()) + { + return; + } + } + + assert(m_sai_tam_tel_type_obj != SAI_NULL_OBJECT_ID); + + attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_TEL_TYPE; + attr.value.oid = m_sai_tam_tel_type_obj; + attrs.push_back(attr); + + attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_OBJECT_ID; + attr.value.oid = stat_id; + attrs.push_back(attr); + + attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STAT_ID; + attr.value.oid = stat_id; + attrs.push_back(attr); + + attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_LABEL; + attr.value.u64 = static_cast(label); + attrs.push_back(attr); + + // TODO: Update SAI counter subscription + // attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STATS_MODE; + // attr.value.s32 = get_stats_mode(object_type, stat_id); + // attrs.push_back(attr); + + sai_object_id_t counter_id; + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_counter_subscription( + &counter_id, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + m_sai_tam_counter_subscription_objs[sai_obj][stat_id] = move( + unique_ptr< + sai_object_id_t, + function>( + new sai_object_id_t(counter_id), + [](sai_object_id_t *p) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_counter_subscription(*p)); + delete p; + })); +} diff --git a/orchagent/stream_telemetry/stelmgr.h b/orchagent/stream_telemetry/stelmgr.h new file mode 100644 index 0000000000..2a2e09867e --- /dev/null +++ b/orchagent/stream_telemetry/stelmgr.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using CounterNameCache = std::unordered_map>; + +struct StelGroup +{ + std::set m_object_names; + std::set m_stats_ids; +}; + +struct StelEntry +{ + std::uint16_t m_label; + sai_object_id_t m_object_id; +}; + +class STelProfile +{ +public: + enum STREAM_STATE + { + STREAM_STATE_ENABLED, + STREAM_STATE_DISABLED, + }; + + STelProfile( + const std::string &profile_name, + sai_object_id_t sai_tam_obj, + sai_object_id_t sai_tam_collector_obj, + const CounterNameCache &cache); + ~STelProfile(); + STelProfile(const STelProfile &) = delete; + STelProfile &operator=(const STelProfile &) = delete; + STelProfile(STelProfile &&) = delete; + STelProfile &operator=(STelProfile &&) = delete; + + void setStreamState(STREAM_STATE state); + void setPollInterval(std::uint32_t poll_interval); + void setBulkSize(std::uint32_t bulk_size); + void setObjectNames(const std::string &group_name, std::set &&object_names); + void setStatsIDs(const std::string &group_name, const std::set &object_counters); + void setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id); + void delObjectSAIID(sai_object_type_t object_type, const char *object_name); + + std::vector getTemplates() const; + std::vector getObjectTypes() const; + + void loadGroupFromCfgDB(swss::Table &group_tbl); + void loadCounterNameCache(sai_object_type_t object_type); + void tryCommitConfig(); + + static sai_object_type_t group_name_to_sai_type(const std::string &group_name); + +private: + // Configuration parameters + const std::string m_profile_name; + STREAM_STATE m_setting_state; + std::uint32_t m_poll_interval; + std::uint32_t m_bulk_size; + std::map m_groups; + + // Runtime parameters + const CounterNameCache &m_counter_name_cache; + STREAM_STATE m_state; + size_t m_object_count; + std::unordered_map< + sai_object_type_t, + std::unordered_map< + std::string, + sai_object_id_t>> + m_name_sai_map; + bool m_needed_to_be_deployed; + + // SAI objects + const sai_object_id_t m_sai_tam_obj; + const sai_object_id_t m_sai_tam_collector_obj; + sai_object_id_t m_sai_tam_report_obj; + sai_object_id_t m_sai_tam_tel_type_obj; + sai_object_id_t m_sai_tam_telemetry_obj; + using counter_subscription_t = std::unique_ptr>; + std::unordered_map< + sai_object_id_t, + std::unordered_map< + sai_stat_id_t, + counter_subscription_t>> + m_sai_tam_counter_subscription_objs; + + bool isObjectInProfile(sai_object_type_t object_type, const std::string &object_name) const; + + void deployToSAI(); + void undeployFromSAI(); + + // SAI calls + void deployTAM(); + void undeployTAM(); + void deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, std::uint16_t label); +}; diff --git a/orchagent/stream_telemetry/stelorch.cpp b/orchagent/stream_telemetry/stelorch.cpp new file mode 100644 index 0000000000..4a966de4b9 --- /dev/null +++ b/orchagent/stream_telemetry/stelorch.cpp @@ -0,0 +1,527 @@ +#include "stelorch.h" + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace swss; + +#define CONSTANTS_FILE "/et/sonic/constants.yml" + +const unordered_map STelOrch::SUPPORT_COUNTER_TABLES = { + {COUNTERS_PORT_NAME_MAP, SAI_OBJECT_TYPE_PORT}, + {COUNTERS_BUFFER_POOL_NAME_MAP, SAI_OBJECT_TYPE_BUFFER_POOL}, + {COUNTERS_QUEUE_NAME_MAP, SAI_OBJECT_TYPE_QUEUE}, + {COUNTERS_PG_NAME_MAP, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP}, +}; + +extern sai_object_id_t gSwitchId; +extern sai_switch_api_t *sai_switch_api; +extern sai_hostif_api_t *sai_hostif_api; +extern sai_tam_api_t *sai_tam_api; + +namespace swss +{ + + template <> + inline void lexical_convert(const string &buffer, ::STelProfile::STREAM_STATE &stage) + { + SWSS_LOG_ENTER(); + + if (buffer == "enable") + { + stage = STelProfile::STREAM_STATE::STREAM_STATE_ENABLED; + } + else if (buffer == "disable") + { + stage = STelProfile::STREAM_STATE::STREAM_STATE_DISABLED; + } + else + { + SWSS_LOG_THROW("Invalid stream state %s", buffer.c_str()); + } + } + +} + +STelOrch::STelOrch( + DBConnector *cfg_db, + DBConnector *state_db, + const vector &tables) + : Orch(cfg_db, tables), + m_state_telemetry_session(state_db, STREAM_TELEMETRY_SESSION), + m_cfg_stream_telemetry_group(state_db, CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME), + m_sai_hostif_obj(SAI_NULL_OBJECT_ID), + m_sai_hostif_trap_group_obj(SAI_NULL_OBJECT_ID), + m_sai_hostif_user_defined_trap_obj(SAI_NULL_OBJECT_ID), + m_sai_hostif_table_entry_obj(SAI_NULL_OBJECT_ID), + m_sai_tam_transport_obj(SAI_NULL_OBJECT_ID), + m_sai_tam_collector_obj(SAI_NULL_OBJECT_ID) +{ + SWSS_LOG_ENTER(); + + createNetlinkChannel("stel", "ipfix"); + createTAM(); +} + +STelOrch::~STelOrch() +{ + SWSS_LOG_ENTER(); + + deleteTAM(); + deleteNetlinkChannel(); +} + +void STelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) +{ + SWSS_LOG_ENTER(); + + auto itr = STelOrch::SUPPORT_COUNTER_TABLES.find(msg.m_table_name); + if (itr == STelOrch::SUPPORT_COUNTER_TABLES.end()) + { + SWSS_LOG_WARN("The counter table %s is not supported by stream telemetry", msg.m_table_name); + return; + } + + // Update the local cache + if (msg.m_operation == CounterNameMapUpdater::SET) + { + m_counter_name_cache[itr->second][msg.m_set.m_counter_name] = msg.m_set.m_oid; + } + else if (msg.m_operation == CounterNameMapUpdater::DEL) + { + m_counter_name_cache[itr->second].erase(msg.m_del.m_counter_name); + } + + // Update the profile + auto itr2 = m_type_profile_mapping.find(itr->second); + if (itr2 == m_type_profile_mapping.end()) + { + return; + } + for (auto itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++) + { + auto profile = *itr3; + if (msg.m_operation == CounterNameMapUpdater::SET) + { + profile->setObjectSAIID(itr->second, msg.m_set.m_counter_name, msg.m_set.m_oid); + } + else if (msg.m_operation == CounterNameMapUpdater::DEL) + { + profile->delObjectSAIID(itr->second, msg.m_del.m_counter_name); + } + else + { + SWSS_LOG_THROW("Unknown operation type %d", msg.m_operation); + } + } +} + +void STelOrch::profileTableSet(const string &profile_name, const vector &values) +{ + SWSS_LOG_ENTER(); + auto profile = getProfile(profile_name); + + auto value_opt = fvsGetValue(values, "stream_state", true); + if (value_opt) + { + STelProfile::STREAM_STATE state; + lexical_convert(*value_opt, state); + profile->setStreamState(state); + } + + value_opt = fvsGetValue(values, "poll_interval", true); + if (value_opt) + { + uint32_t poll_interval; + lexical_convert(*value_opt, poll_interval); + profile->setPollInterval(poll_interval); + } + + value_opt = fvsGetValue(values, "bulk_size", true); + if (value_opt) + { + uint32_t bulk_size; + lexical_convert(*value_opt, bulk_size); + profile->setBulkSize(bulk_size); + } + + // Map the profile to types + // This profile may be inserted by group table + for (auto type : profile->getObjectTypes()) + { + m_type_profile_mapping[type].insert(profile); + } +} + +void STelOrch::profileTableDel(const std::string &profile_name) +{ + SWSS_LOG_ENTER(); + + auto itr = m_name_profile_mapping.find(profile_name); + if (itr == m_name_profile_mapping.end()) + { + return; + } + + auto profile = itr->second; + for (auto type : profile->getObjectTypes()) + { + m_type_profile_mapping[type].erase(profile); + } + m_name_profile_mapping.erase(itr); +} + +void STelOrch::groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values) +{ + SWSS_LOG_ENTER(); + + auto profile = getProfile(profile_name); + auto type = STelProfile::group_name_to_sai_type(group_name); + + + auto value_opt = fvsGetValue(values, "object_names", true); + if (value_opt) + { + vector buffer; + boost::split(buffer, *value_opt, boost::is_any_of(",")); + set object_names(buffer.begin(), buffer.end()); + profile->setObjectNames(group_name, move(object_names)); + } + + value_opt = fvsGetValue(values, "object_counters", true); + if (value_opt) + { + vector buffer; + boost::split(buffer, *value_opt, boost::is_any_of(",")); + set object_counters(buffer.begin(), buffer.end()); + profile->setStatsIDs(group_name, object_counters); + } + + m_type_profile_mapping[type].insert(profile); +} + +void STelOrch::groupTableDel(const std::string &profile_name, const std::string &group_name) +{ + SWSS_LOG_ENTER(); + + auto profile = getProfile(profile_name); + auto type = STelProfile::group_name_to_sai_type(group_name); + m_type_profile_mapping[type].erase(profile); +} + +shared_ptr STelOrch::getProfile(const string &profile_name) +{ + SWSS_LOG_ENTER(); + + if (m_name_profile_mapping.find(profile_name) == m_name_profile_mapping.end()) + { + m_name_profile_mapping.emplace( + profile_name, + make_shared( + profile_name, + m_sai_tam_obj, + m_sai_tam_collector_obj, + m_counter_name_cache)); + } + + return m_name_profile_mapping.at(profile_name); +} + +void STelOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + string table_name = consumer.getTableName(); + + auto itr = consumer.m_toSync.begin(); + while (itr != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = itr->second; + + string key = kfvKey(t); + string op = kfvOp(t); + + if (table_name == CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME) + { + if (op == SET_COMMAND) + { + profileTableSet(key, kfvFieldsValues(t)); + } + else if (op == DEL_COMMAND) + { + profileTableDel(key); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + } + } + else if (table_name == CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME) + { + auto tokens = tokenize(key, '|'); + if (tokens.size() != 2) + { + SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), table_name.c_str()); + } + if (op == SET_COMMAND) + { + groupTableSet(tokens[0], tokens[1], kfvFieldsValues(t)); + } + else if (op == DEL_COMMAND) + { + groupTableDel(tokens[0], tokens[1]); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + } + } + else + { + SWSS_LOG_ERROR("Unknown table %s\n", table_name.c_str()); + } + + itr = consumer.m_toSync.erase(itr); + } +} + +void STelOrch::createNetlinkChannel(const string &genl_family, const string &genl_group) +{ + SWSS_LOG_ENTER(); + + // Delete the existing netlink channel + deleteNetlinkChannel(); + + vector attrs; + sai_attribute_t attr; + + // Create hostif object + attr.id = SAI_HOSTIF_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TYPE_GENETLINK; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_OPER_STATUS; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_NAME; + strncpy(attr.value.chardata, genl_family.c_str(), sizeof(attr.value.chardata)); + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_GENETLINK_MCGRP_NAME; + strncpy(attr.value.chardata, genl_group.c_str(), sizeof(attr.value.chardata)); + attrs.push_back(attr); + + sai_hostif_api->create_hostif(&m_sai_hostif_obj, gSwitchId, static_cast(attrs.size()), attrs.data()); + + // Create hostif trap group object + sai_hostif_api->create_hostif_trap_group(&m_sai_hostif_trap_group_obj, gSwitchId, 0, nullptr); + + // Create hostif user defined trap object + attrs.clear(); + + attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_USER_DEFINED_TRAP_TYPE_TAM; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP; + attr.value.oid = m_sai_hostif_trap_group_obj; + attrs.push_back(attr); + + sai_hostif_api->create_hostif_user_defined_trap(&m_sai_hostif_user_defined_trap_obj, gSwitchId, static_cast(attrs.size()), attrs.data()); + + // Create hostif table entry object + attrs.clear(); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_TYPE_TRAP_ID; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TRAP_ID; + attr.value.oid = m_sai_hostif_user_defined_trap_obj; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_CHANNEL_TYPE; + attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_CHANNEL_TYPE_GENETLINK; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_HOST_IF; + attr.value.oid = m_sai_hostif_obj; + attrs.push_back(attr); + + sai_hostif_api->create_hostif_table_entry(&m_sai_hostif_table_entry_obj, gSwitchId, static_cast(attrs.size()), attrs.data()); +} + +void STelOrch::deleteNetlinkChannel() +{ + SWSS_LOG_ENTER(); + + if (m_sai_hostif_table_entry_obj != SAI_NULL_OBJECT_ID) + { + sai_hostif_api->remove_hostif_table_entry(m_sai_hostif_table_entry_obj); + m_sai_hostif_table_entry_obj = SAI_NULL_OBJECT_ID; + } + if (m_sai_hostif_user_defined_trap_obj != SAI_NULL_OBJECT_ID) + { + sai_hostif_api->remove_hostif_user_defined_trap(m_sai_hostif_user_defined_trap_obj); + m_sai_hostif_user_defined_trap_obj = SAI_NULL_OBJECT_ID; + } + if (m_sai_hostif_trap_group_obj != SAI_NULL_OBJECT_ID) + { + sai_hostif_api->remove_hostif_trap_group(m_sai_hostif_trap_group_obj); + m_sai_hostif_trap_group_obj = SAI_NULL_OBJECT_ID; + } + if (m_sai_hostif_obj != SAI_NULL_OBJECT_ID) + { + sai_hostif_api->remove_hostif(m_sai_hostif_obj); + m_sai_hostif_obj = SAI_NULL_OBJECT_ID; + } +} + +void STelOrch::createTAM() +{ + SWSS_LOG_ENTER(); + + // Delete the existing TAM + deleteTAM(); + + vector attrs; + sai_attribute_t attr; + + // Create TAM transport object + attr.id = SAI_TAM_TRANSPORT_ATTR_TRANSPORT_TYPE; + attr.value.s32 = SAI_TAM_TRANSPORT_TYPE_NONE; + attrs.push_back(attr); + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_transport( + &m_sai_tam_transport_obj, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + // Create TAM collector object + attrs.clear(); + + attr.id = SAI_TAM_COLLECTOR_ATTR_TRANSPORT; + attr.value.oid = m_sai_tam_transport_obj; + attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_LOCALHOST; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_HOSTIF_TRAP; + attr.value.oid = m_sai_hostif_user_defined_trap_obj; + attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_DSCP_VALUE; + attr.value.u8 = 0; + attrs.push_back(attr); + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam_collector( + &m_sai_tam_collector_obj, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + // Create TAM object + attrs.clear(); + attr.id = SAI_TAM_ATTR_TAM_BIND_POINT_TYPE_LIST; + vector bind_point_types = { + SAI_TAM_BIND_POINT_TYPE_PORT, + SAI_TAM_BIND_POINT_TYPE_QUEUE, + }; + attr.value.s32list.count = static_cast(bind_point_types.size()); + attr.value.s32list.list = bind_point_types.data(); + attrs.push_back(attr); + + handleSaiCreateStatus( + SAI_API_TAM, + sai_tam_api->create_tam( + &m_sai_tam_obj, + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + + // Bind the TAM object to switch + vector tam_objects(1024, SAI_NULL_OBJECT_ID); + attrs.clear(); + attr.id = SAI_SWITCH_ATTR_TAM_OBJECT_ID; + attr.value.objlist.count = static_cast(tam_objects.size()); + attr.value.objlist.list = tam_objects.data(); + handleSaiGetStatus( + SAI_API_SWITCH, + sai_switch_api->get_switch_attribute( + gSwitchId, + static_cast(attrs.size()), + attrs.data())); + tam_objects[attr.value.objlist.count] = m_sai_tam_obj; + attr.value.objlist.count++; + handleSaiSetStatus( + SAI_API_SWITCH, + sai_switch_api->set_switch_attribute( + gSwitchId, + &attr)); +} + +void STelOrch::deleteTAM() +{ + SWSS_LOG_ENTER(); + + if (m_sai_tam_obj != SAI_NULL_OBJECT_ID) + { + // Unbind the TAM object from switch + vector tam_objects(1024, SAI_NULL_OBJECT_ID); + sai_attribute_t attr; + attr.id = SAI_SWITCH_ATTR_TAM_OBJECT_ID; + attr.value.objlist.count = static_cast(tam_objects.size()); + attr.value.objlist.list = tam_objects.data(); + handleSaiGetStatus( + SAI_API_SWITCH, + sai_switch_api->get_switch_attribute( + gSwitchId, + 1, + &attr)); + tam_objects.erase( + remove( + tam_objects.begin(), + tam_objects.begin() + attr.value.objlist.count, + m_sai_tam_obj), + tam_objects.end()); + handleSaiSetStatus( + SAI_API_SWITCH, + sai_switch_api->set_switch_attribute( + gSwitchId, + &attr)); + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam(m_sai_tam_obj)); + m_sai_tam_obj = SAI_NULL_OBJECT_ID; + } + if (m_sai_tam_collector_obj != SAI_NULL_OBJECT_ID) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_collector(m_sai_tam_collector_obj)); + m_sai_tam_collector_obj = SAI_NULL_OBJECT_ID; + } + if (m_sai_tam_transport_obj != SAI_NULL_OBJECT_ID) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_transport(m_sai_tam_transport_obj)); + m_sai_tam_transport_obj = SAI_NULL_OBJECT_ID; + } +} diff --git a/orchagent/stream_telemetry/stelorch.h b/orchagent/stream_telemetry/stelorch.h new file mode 100644 index 0000000000..21fe32fe65 --- /dev/null +++ b/orchagent/stream_telemetry/stelorch.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +#include "counternameupdater.h" +#include "stelmgr.h" + +#define CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME "STREAM_TELEMETRY_PROFILE" +#define CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME "STREAM_TELEMETRY_GROUP" +#define STREAM_TELEMETRY_SESSION "STREAM_TELEMETRY_SESSION" + +class STelOrch : public Orch +{ +public: + STelOrch( + swss::DBConnector *cfg_db, + swss::DBConnector *state_db, + const std::vector &tables); + ~STelOrch(); + STelOrch(const STelOrch &) = delete; + STelOrch &operator=(const STelOrch &) = delete; + STelOrch(STelOrch &&) = delete; + STelOrch &operator=(STelOrch &&) = delete; + + static const std::unordered_map SUPPORT_COUNTER_TABLES; + + void locallyNotify(const CounterNameMapUpdater::Message &msg); + +private: + swss::Table m_cfg_stream_telemetry_group; + swss::Table m_state_telemetry_session; + + std::unordered_map> m_name_profile_mapping; + std::unordered_map>> m_type_profile_mapping; + CounterNameCache m_counter_name_cache; + + void profileTableSet(const std::string &profile_name, const std::vector &values); + void profileTableDel(const std::string &profile_name); + void groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values); + void groupTableDel(const std::string &profile_name, const std::string &group_name); + std::shared_ptr getProfile(const std::string &profile_name); + + void doTask(Consumer &consumer); + + // SAI objects + sai_object_id_t m_sai_hostif_obj; + sai_object_id_t m_sai_hostif_trap_group_obj; + sai_object_id_t m_sai_hostif_user_defined_trap_obj; + sai_object_id_t m_sai_hostif_table_entry_obj; + sai_object_id_t m_sai_tam_transport_obj; + sai_object_id_t m_sai_tam_collector_obj; + sai_object_id_t m_sai_tam_obj; + + // SAI calls + void createNetlinkChannel(const std::string &genl_family, const std::string &genl_group); + void deleteNetlinkChannel(); + void createTAM(); + void deleteTAM(); +}; From cd72010ca61ec05c51f1e868d0d262eaa535159c Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Wed, 4 Dec 2024 17:00:36 +0800 Subject: [PATCH 03/11] Add state machine Signed-off-by: Ze Gan --- orchagent/Makefile.am | 3 +- orchagent/stream_telemetry/stelmgr.cpp | 699 ++++++++++++++++------- orchagent/stream_telemetry/stelmgr.h | 104 ++-- orchagent/stream_telemetry/stelorch.cpp | 227 +++++--- orchagent/stream_telemetry/stelorch.h | 14 +- orchagent/stream_telemetry/stelutils.cpp | 163 ++++++ orchagent/stream_telemetry/stelutils.h | 72 +++ 7 files changed, 953 insertions(+), 329 deletions(-) create mode 100644 orchagent/stream_telemetry/stelutils.cpp create mode 100644 orchagent/stream_telemetry/stelutils.h diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index a5847157c1..8d525f5886 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -120,7 +120,8 @@ orchagent_SOURCES = \ stporch.cpp \ stream_telemetry/stelorch.cpp \ stream_telemetry/stelmgr.cpp \ - stream_telemetry/counternameupdater.cpp + stream_telemetry/counternameupdater.cpp \ + stream_telemetry/stelutils.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp flex_counter/flow_counter_handler.cpp flex_counter/flowcounterrouteorch.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/stream_telemetry/stelmgr.cpp b/orchagent/stream_telemetry/stelmgr.cpp index 372fabb0e5..1d3abd02ec 100644 --- a/orchagent/stream_telemetry/stelmgr.cpp +++ b/orchagent/stream_telemetry/stelmgr.cpp @@ -1,4 +1,5 @@ #include "stelmgr.h" +#include "stelutils.h" #include #include @@ -7,7 +8,6 @@ #include #include -#include using namespace std; using namespace swss; @@ -15,191 +15,243 @@ using namespace swss; extern sai_object_id_t gSwitchId; extern sai_tam_api_t *sai_tam_api; -static set object_counters_to_stats_ids( - const string &group_name, - const set &object_counters) +STelProfile::STelProfile( + const string &profile_name, + sai_object_id_t sai_tam_obj, + sai_object_id_t sai_tam_collector_obj, + const CounterNameCache &cache) + : m_profile_name(profile_name), + m_setting_state(SAI_TAM_TEL_TYPE_STATE_STOP_STREAM), + m_poll_interval(0), + m_counter_name_cache(cache), + m_sai_tam_obj(sai_tam_obj), + m_sai_tam_collector_obj(sai_tam_collector_obj) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = STelProfile::group_name_to_sai_type(group_name); - set stats_ids_set; - auto info = sai_metadata_get_object_type_info(sai_object_type); - if (info == nullptr) + if (m_sai_tam_obj == SAI_NULL_OBJECT_ID) { - SWSS_LOG_THROW("Failed to get the object type info for %s", group_name.c_str()); + SWSS_LOG_THROW("The SAI TAM object is not valid"); } + if (m_sai_tam_collector_obj == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_THROW("The SAI TAM collector object is not valid"); + } + + initTelemetry(); +} + +STelProfile::~STelProfile() +{ + SWSS_LOG_ENTER(); +} + +const string &STelProfile::getProfileName() const +{ + SWSS_LOG_ENTER(); - auto state_enum = info->statenum; - if (state_enum == nullptr) + return m_profile_name; +} + +void STelProfile::setStreamState(sai_tam_tel_type_state_t state) +{ + SWSS_LOG_ENTER(); + m_setting_state = state; + + for (const auto &item : m_sai_tam_tel_type_objs) { - SWSS_LOG_THROW("The object type %s does not support stats", group_name.c_str()); + setStreamState(item.first, state); } +} - string type_prefix = "SAI_" + group_name + "_STAT_"; +void STelProfile::setStreamState(sai_object_type_t type, sai_tam_tel_type_state_t state) +{ + SWSS_LOG_ENTER(); - for (size_t i = 0; i < state_enum->valuescount; i++) + auto type_itr = m_sai_tam_tel_type_objs.find(type); + if (type_itr == m_sai_tam_tel_type_objs.end()) { - string state_name = type_prefix + state_enum->valuesnames[i]; - if (object_counters.find(state_name) != object_counters.end()) + return; + } + + auto stats = m_sai_tam_tel_type_states.find(type_itr->second); + if (stats == m_sai_tam_tel_type_states.end()) + { + return; + } + + if (stats->second == state) + { + return; + } + + if (stats->second == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + if (state == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) { - SWSS_LOG_DEBUG("Found the object counter %s", state_name.c_str()); - stats_ids_set.insert(state_enum->values[i]); + if (!isMonitoringObjectReady(type)) + { + return; + } + // Clearup the previous templates + m_sai_tam_tel_type_templates.erase(type); + } + else if (state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) + { + if (m_sai_tam_tel_type_templates.find(type) == m_sai_tam_tel_type_templates.end()) + { + // The template isn't ready + return; + } + if (!isMonitoringObjectReady(type)) + { + return; + } + } + else + { + goto failed_state_transfer; } } - - if (stats_ids_set.size() != object_counters.size()) + else if (stats->second == SAI_TAM_TEL_TYPE_STATE_START_STREAM) { - SWSS_LOG_THROW("Failed to convert the object counters to stats ids for %s", group_name.c_str()); + if (state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + // Nothing to do + } + else if (state == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) + { + // TODO: Implement the transition from started to config generating in Phase2 + SWSS_LOG_THROW("Transfer from start to create config hasn't been implemented yet"); + } + else + { + goto failed_state_transfer; + } + } + else if (stats->second == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) + { + if (state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + // Nothing to do + } + else if (state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) + { + // Nothing to do + } + else + { + goto failed_state_transfer; + } + } + else + { + SWSS_LOG_THROW("Unknown state %d", stats->second); } - return stats_ids_set; -} + sai_attribute_t attr; + // TODO: Update SAI + // attr.id = SAI_TAM_TEL_TYPE_ATTR_STATE; + attr.value.s32 = state; + handleSaiSetStatus( + SAI_API_TAM, + sai_tam_api->set_tam_tel_type_attribute(*type_itr->second, &attr)); -// static uint16_t get_sai_label(const string &object_name) -// { -// SWSS_LOG_ENTER(); -// uint16_t label = 0; - -// if (object_name.rfind("Ethernet", 0) == 0) -// { -// const static regex re("Ethernet(\\d+)(?:\\|(\\d+))?"); -// smatch match; -// if (regex_match(object_name, match, re)) -// { -// label = static_cast(stoi(match[1])); -// if (match.size() == 3) -// { -// label = static_cast(label * 100 + stoi(match[2])); -// } -// } -// } -// else -// { -// SWSS_LOG_THROW("The object %s is not supported", object_name.c_str()); -// } - -// return label; -// } - -// static int32_t get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id) -// { -// SWSS_LOG_ENTER(); - -// switch(object_type) -// { -// case SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP: -// switch(stat_id) -// { -// case SAI_INGRESS_PRIORITY_GROUP_STAT_WATERMARK_BYTES: -// case SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES: -// case SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES: -// return SAI_STATS_MODE_READ_AND_CLEAR; -// default: -// break; -// } -// case SAI_OBJECT_TYPE_BUFFER_POOL: -// switch(stat_id) -// { -// case SAI_BUFFER_POOL_STAT_WATERMARK_BYTES: -// case SAI_BUFFER_POOL_STAT_XOFF_ROOM_WATERMARK_BYTES: -// return SAI_STATS_MODE_READ_AND_CLEAR; -// default: -// break; -// } -// default: -// break; -// } - -// return SAI_STATS_MODE_READ; -// } + stats->second = state; -STelProfile::STelProfile( - const std::string &profile_name, - sai_object_id_t sai_tam_obj, - sai_object_id_t sai_tam_collector_obj, - const CounterNameCache &cache) - : m_profile_name(profile_name), - m_setting_state(STREAM_STATE_DISABLED), - m_poll_interval(0), - m_bulk_size(0), - m_counter_name_cache(cache), - m_state(STREAM_STATE_DISABLED), - m_object_count(0), - m_needed_to_be_deployed(false), - m_sai_tam_obj(sai_tam_obj), - m_sai_tam_collector_obj(sai_tam_collector_obj), - m_sai_tam_report_obj(SAI_NULL_OBJECT_ID), - m_sai_tam_tel_type_obj(SAI_NULL_OBJECT_ID), - m_sai_tam_telemetry_obj(SAI_NULL_OBJECT_ID) + return; + +failed_state_transfer: + SWSS_LOG_THROW("Invalid state transfer from %d to %d", stats->second, state); +} + +void STelProfile::notifyConfigReady(sai_object_type_t object_type) { SWSS_LOG_ENTER(); - if (m_sai_tam_obj == SAI_NULL_OBJECT_ID) + auto itr = m_sai_tam_tel_type_objs.find(object_type); + if (itr == m_sai_tam_tel_type_objs.end()) { - SWSS_LOG_THROW("The SAI TAM object is not valid"); - } - if (m_sai_tam_collector_obj == SAI_NULL_OBJECT_ID) - { - SWSS_LOG_THROW("The SAI TAM collector object is not valid"); + return; } - deployTAM(); + updateTemplates(*itr->second); + setStreamState(object_type, m_setting_state); } -STelProfile::~STelProfile() +sai_tam_tel_type_state_t STelProfile::getTelemetryTypeState(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); - undeployTAM(); + auto itr = m_sai_tam_tel_type_objs.find(object_type); + return m_sai_tam_tel_type_states.at(itr->second); } -void STelProfile::setStreamState(STREAM_STATE state) +STelProfile::sai_guard_t STelProfile::getTAMTelTypeGuard(sai_object_id_t tam_tel_type_obj) const { SWSS_LOG_ENTER(); - if (state == m_setting_state) + for (const auto &item : m_sai_tam_tel_type_objs) { - return; + if (*item.second == tam_tel_type_obj) + { + return item.second; + } } - m_setting_state = state; - m_needed_to_be_deployed = true; + + return sai_guard_t(); } -void STelProfile::setPollInterval(uint32_t poll_interval) +sai_object_type_t STelProfile::getObjectType(sai_object_id_t tam_tel_type_obj) const { SWSS_LOG_ENTER(); - if (poll_interval == m_poll_interval) + auto guard = getTAMTelTypeGuard(tam_tel_type_obj); + if (guard) { - return; + for (const auto &item : m_sai_tam_tel_type_objs) + { + if (item.second == guard) + { + return item.first; + } + } } - m_poll_interval = poll_interval; - m_needed_to_be_deployed = true; + + return SAI_OBJECT_TYPE_NULL; } -void STelProfile::setBulkSize(uint32_t bulk_size) +void STelProfile::setPollInterval(uint32_t poll_interval) { SWSS_LOG_ENTER(); - if (bulk_size == m_bulk_size) + if (poll_interval == m_poll_interval) { return; } - m_bulk_size = bulk_size; - m_needed_to_be_deployed = true; + m_poll_interval = poll_interval; + + for (const auto &report : m_sai_tam_report_objs) + { + sai_attribute_t attr; + attr.id = SAI_TAM_REPORT_ATTR_REPORT_INTERVAL; + attr.value.u32 = m_poll_interval; + handleSaiSetStatus( + SAI_API_TAM, + sai_tam_api->set_tam_report_attribute(*report.second, &attr)); + } } void STelProfile::setObjectNames(const string &group_name, set &&object_names) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = group_name_to_sai_type(group_name); + sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); auto itr = m_groups.lower_bound(sai_object_type); if (itr == m_groups.end() || itr->first != sai_object_type) { - m_groups.insert(itr, {sai_object_type, StelGroup{move(object_names), {}}}); - m_object_count += object_names.size(); + m_groups.insert(itr, {sai_object_type, STelGroup{move(object_names), {}}}); } else { @@ -211,25 +263,27 @@ void STelProfile::setObjectNames(const string &group_name, set &&object_ { delObjectSAIID(sai_object_type, name.c_str()); } - m_object_count -= itr->second.m_object_names.size(); itr->second.m_object_names = move(object_names); - m_object_count += itr->second.m_object_names.size(); } loadCounterNameCache(sai_object_type); - m_needed_to_be_deployed = true; + + // TODO: In the phase 2, we don't need to stop the stream before update the object names + setStreamState(sai_object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); + + undeployCounterSubscriptions(sai_object_type); } void STelProfile::setStatsIDs(const string &group_name, const set &object_counters) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = group_name_to_sai_type(group_name); + sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); auto itr = m_groups.lower_bound(sai_object_type); - set stats_ids_set = object_counters_to_stats_ids(group_name, object_counters); + set stats_ids_set = STelUtils::object_counters_to_stats_ids(group_name, object_counters); if (itr == m_groups.end() || itr->first != sai_object_type) { - m_groups.insert(itr, {sai_object_type, StelGroup{{}, stats_ids_set}}); + m_groups.insert(itr, {sai_object_type, STelGroup{{}, stats_ids_set}}); } else { @@ -239,14 +293,18 @@ void STelProfile::setStatsIDs(const string &group_name, const set &objec } itr->second.m_stats_ids = move(stats_ids_set); } - m_needed_to_be_deployed = true; + + // TODO: In the phase 2, we don't need to stop the stream before update the stats + setStreamState(sai_object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); + + undeployCounterSubscriptions(sai_object_type); } void STelProfile::setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id) { SWSS_LOG_ENTER(); - if (!isObjectInProfile(object_type, object_name)) + if (!isObjectTypeInProfile(object_type, object_name)) { return; } @@ -262,14 +320,18 @@ void STelProfile::setObjectSAIID(sai_object_type_t object_type, const char *obje } objs[object_name] = object_id; - m_needed_to_be_deployed = true; + // TODO: In the phase 2, we don't need to stop the stream before update the object + setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); + + // Update the counter subscription + deployCounterSubscriptions(object_type, object_id, STelUtils::get_sai_label(object_name)); } void STelProfile::delObjectSAIID(sai_object_type_t object_type, const char *object_name) { SWSS_LOG_ENTER(); - if (!isObjectInProfile(object_type, object_name)) + if (!isObjectTypeInProfile(object_type, object_name)) { return; } @@ -280,20 +342,66 @@ void STelProfile::delObjectSAIID(sai_object_type_t object_type, const char *obje { return; } + + // TODO: In the phase 2, we don't need to stop the stream before removing the object + setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); + + // Remove all counters bounded to the object + auto counter_itr = m_sai_tam_counter_subscription_objs.find(object_type); + if (counter_itr != m_sai_tam_counter_subscription_objs.end()) + { + counter_itr->second.erase(itr->second); + if (counter_itr->second.empty()) + { + m_sai_tam_counter_subscription_objs.erase(counter_itr); + } + } + objs.erase(itr); if (objs.empty()) { m_name_sai_map.erase(object_type); } - if (m_state == STREAM_STATE_ENABLED) +} + +bool STelProfile::canBeUpdated() const +{ + SWSS_LOG_ENTER(); + + for (const auto &group : m_groups) { - // TODO: Disable the stream, delete the subscription counter + if (!canBeUpdated(group.first)) + { + return false; + } } + + return true; +} + +bool STelProfile::canBeUpdated(sai_object_type_t object_type) const +{ + SWSS_LOG_ENTER(); + + if (getTelemetryTypeState(object_type) == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) + { + return false; + } + + return true; } -std::vector STelProfile::getObjectTypes() const +const vector &STelProfile::getTemplates(sai_object_type_t object_type) const { - std::vector types; + SWSS_LOG_ENTER(); + + return m_sai_tam_tel_type_templates.at(object_type); +} + +vector STelProfile::getObjectTypes() const +{ + vector types; + types.reserve(m_groups.size()); for (const auto &group : m_groups) { @@ -391,37 +499,45 @@ void STelProfile::loadCounterNameCache(sai_object_type_t object_type) } } -void STelProfile::tryCommitConfig() +void STelProfile::tryCommitConfig(sai_object_type_t object_type) { SWSS_LOG_ENTER(); - m_needed_to_be_deployed &= (m_setting_state == STREAM_STATE_ENABLED); - m_needed_to_be_deployed &= (m_object_count != 0); - m_needed_to_be_deployed &= (m_object_count == m_name_sai_map.size()); + if (!canBeUpdated(object_type)) + { + return; + } - if (m_needed_to_be_deployed) + if (m_setting_state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) { - if (m_state == STREAM_STATE_ENABLED) + auto group = m_groups.find(object_type); + if (group == m_groups.end()) { - undeployFromSAI(); + return; + } + if (group->second.m_object_names.empty()) + { + // TODO: If the object names are empty, implicitly select all objects of the group + return; } - deployToSAI(); + if (!isMonitoringObjectReady(object_type)) + { + deployCounterSubscriptions(object_type); + } + setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_START_STREAM); + } + else if (m_setting_state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); + undeployCounterSubscriptions(object_type); + } + else + { + SWSS_LOG_THROW("Cannot commit the configuration in the state %d", m_setting_state); } - - m_needed_to_be_deployed = false; -} - -sai_object_type_t STelProfile::group_name_to_sai_type(const string &group_name) -{ - SWSS_LOG_ENTER(); - - sai_object_type_t sai_object_type; - - sai_deserialize_object_type(string("SAI_OBJECT_TYPE_") + group_name, sai_object_type); - return sai_object_type; } -bool STelProfile::isObjectInProfile(sai_object_type_t object_type, const std::string &object_name) const +bool STelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const string &object_name) const { SWSS_LOG_ENTER(); @@ -438,27 +554,39 @@ bool STelProfile::isObjectInProfile(sai_object_type_t object_type, const std::st return false; } -void STelProfile::deployToSAI() +bool STelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); - m_state = STREAM_STATE_ENABLED; -} + auto group = m_groups.find(object_type); + if (group == m_groups.end()) + { -void STelProfile::undeployFromSAI() -{ - SWSS_LOG_ENTER(); + SWSS_LOG_THROW("The group for object type %s is not found", sai_serialize_object_type(object_type).c_str()); + } + + auto counters = m_sai_tam_counter_subscription_objs.find(object_type); - m_state = STREAM_STATE_DISABLED; + if (counters == m_sai_tam_counter_subscription_objs.end() || group->second.m_object_names.size() != counters->second.size()) + { + // The monitoring counters are not ready + return false; + } + + return true; } -void STelProfile::deployTAM() +sai_object_id_t STelProfile::getTAMReportObjID(sai_object_type_t object_type) { SWSS_LOG_ENTER(); - // Delete the existing TAM objects - undeployTAM(); + auto itr = m_sai_tam_report_objs.find(object_type); + if (itr != m_sai_tam_report_objs.end()) + { + return *itr->second; + } + sai_object_id_t sai_object; vector attrs; sai_attribute_t attr; @@ -475,19 +603,45 @@ void STelProfile::deployTAM() attr.value.u32 = 0; // Don't push the template, Because we hope the template can be proactively queried by orchagent attrs.push_back(attr); + if (m_poll_interval != 0) + { + attr.id = SAI_TAM_REPORT_ATTR_REPORT_INTERVAL; + attr.value.u32 = m_poll_interval; + attrs.push_back(attr); + } + attr.id = SAI_TAM_REPORT_ATTR_REPORT_INTERVAL_UNIT; attr.value.s32 = SAI_TAM_REPORT_INTERVAL_UNIT_USEC; handleSaiCreateStatus( SAI_API_TAM, sai_tam_api->create_tam_report( - &m_sai_tam_report_obj, + &sai_object, gSwitchId, static_cast(attrs.size()), attrs.data())); + m_sai_tam_report_objs[object_type] = make_unique(sai_object); + + return sai_object; +} + +sai_object_id_t STelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); + + auto itr = m_sai_tam_tel_type_objs.find(object_type); + if (itr != m_sai_tam_tel_type_objs.end()) + { + return *itr->second; + } + return sai_object_id_t(); + + sai_object_id_t sai_object; + vector attrs; + sai_attribute_t attr; + // Create TAM telemetry type object - attrs.clear(); attr.id = SAI_TAM_TEL_TYPE_ATTR_TAM_TELEMETRY_TYPE; attr.value.s32 = SAI_TAM_TELEMETRY_TYPE_COUNTER_SUBSCRIPTION; @@ -509,73 +663,85 @@ void STelProfile::deployTAM() attr.value.booldata = true; attrs.push_back(attr); + // attr.id = SAI_TAM_TEL_TYPE_ATTR_MODE ; + // attr.value.boolean = SAI_TAM_TEL_TYPE_MODE_SINGLE_TYPE; + // attrs.push_back(attr); + attr.id = SAI_TAM_TEL_TYPE_ATTR_REPORT_ID; - attr.value.oid = m_sai_tam_report_obj; + attr.value.oid = getTAMReportObjID(object_type); attrs.push_back(attr); handleSaiCreateStatus( SAI_API_TAM, sai_tam_api->create_tam_tel_type( - &m_sai_tam_tel_type_obj, + &sai_object, gSwitchId, static_cast(attrs.size()), attrs.data())); - // Create TAM telemetry object - attrs.clear(); + m_sai_tam_tel_type_objs[object_type] = move( + sai_guard_t( + new sai_object_id_t(sai_object), + [this](sai_object_id_t *p) + { + STELUTILS_DEL_SAI_OBJECT_LIST( + *this->m_sai_tam_telemetry_obj, + SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST, + *p, + SAI_API_TAM, + tam, + tam_telemetry); - sai_object_id_t sai_object = m_sai_tam_tel_type_obj; - attr.id = SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST; - attr.value.objlist.count = 1; - attr.value.objlist.list = &sai_object; - attrs.push_back(attr); + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_tel_type(*p)); + delete p; + })); + m_sai_tam_tel_type_states[m_sai_tam_tel_type_objs[object_type]] = SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; + + STELUTILS_ADD_SAI_OBJECT_LIST( + *m_sai_tam_telemetry_obj, + SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST, + sai_object, + SAI_API_TAM, + tam, + tam_telemetry); + + return sai_object; +} + +void STelProfile::initTelemetry() +{ + SWSS_LOG_ENTER(); + sai_object_id_t sai_object; + vector attrs; + sai_attribute_t attr; + + // Create TAM telemetry object sai_object = m_sai_tam_collector_obj; attr.id = SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST; attr.value.objlist.count = 1; attr.value.objlist.list = &sai_object; attrs.push_back(attr); - // TODO: Update SAI tam telemetry - // attr.id = SAI_TAM_TELEMETRY_ATTR_REPORTING_TYPE; - // attr.value.s32 = SAI_TAM_REPORTING_TYPE_COUNT_BASED; - // attrs.push_back(attr); - handleSaiCreateStatus( SAI_API_TAM, sai_tam_api->create_tam_telemetry( - &m_sai_tam_telemetry_obj, + &sai_object, gSwitchId, static_cast(attrs.size()), attrs.data())); -} -void STelProfile::undeployTAM() -{ - SWSS_LOG_ENTER(); - - if (m_sai_tam_telemetry_obj != SAI_NULL_OBJECT_ID) - { - handleSaiRemoveStatus( - SAI_API_TAM, - sai_tam_api->remove_tam_telemetry(m_sai_tam_telemetry_obj)); - m_sai_tam_telemetry_obj = SAI_NULL_OBJECT_ID; - } - - if (m_sai_tam_tel_type_obj != SAI_NULL_OBJECT_ID) - { - handleSaiRemoveStatus( - SAI_API_TAM, - sai_tam_api->remove_tam_tel_type(m_sai_tam_tel_type_obj)); - m_sai_tam_tel_type_obj = SAI_NULL_OBJECT_ID; - } - - if (m_sai_tam_report_obj != SAI_NULL_OBJECT_ID) - { - handleSaiRemoveStatus( - SAI_API_TAM, - sai_tam_api->remove_tam_report(m_sai_tam_report_obj)); - m_sai_tam_report_obj = SAI_NULL_OBJECT_ID; - } + m_sai_tam_telemetry_obj = move( + sai_guard_t( + new sai_object_id_t(sai_object), + [](sai_object_id_t *p) + { + handleSaiRemoveStatus( + SAI_API_TAM, + sai_tam_api->remove_tam_telemetry(*p)); + delete p; + })); } void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, uint16_t label) @@ -585,8 +751,8 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o vector attrs; sai_attribute_t attr; - auto itr = m_sai_tam_counter_subscription_objs.find(sai_obj); - if (itr != m_sai_tam_counter_subscription_objs.end()) + auto itr = m_sai_tam_counter_subscription_objs[object_type].find(sai_obj); + if (itr != m_sai_tam_counter_subscription_objs[object_type].end()) { auto itr2 = itr->second.find(stat_id); if (itr2 != itr->second.end()) @@ -598,7 +764,7 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o assert(m_sai_tam_tel_type_obj != SAI_NULL_OBJECT_ID); attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_TEL_TYPE; - attr.value.oid = m_sai_tam_tel_type_obj; + attr.value.oid = getTAMTelTypeObjID(object_type); attrs.push_back(attr); attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_OBJECT_ID; @@ -628,10 +794,8 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o static_cast(attrs.size()), attrs.data())); - m_sai_tam_counter_subscription_objs[sai_obj][stat_id] = move( - unique_ptr< - sai_object_id_t, - function>( + m_sai_tam_counter_subscription_objs[object_type][sai_obj][stat_id] = move( + sai_guard_t( new sai_object_id_t(counter_id), [](sai_object_id_t *p) { @@ -641,3 +805,96 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o delete p; })); } + +void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type, sai_object_id_t sai_obj, std::uint16_t label) +{ + SWSS_LOG_ENTER(); + + // TODO: Bulk create the counter subscriptions + auto group = m_groups.find(object_type); + if (group == m_groups.end()) + { + return; + } + + for (const auto &stat_id : group->second.m_stats_ids) + { + deployCounterSubscription(object_type, sai_obj, stat_id, label); + } +} + +void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); + + // TODO: Bulk create the counter subscriptions + + auto group = m_groups.find(object_type); + if (group == m_groups.end()) + { + return; + } + for (const auto &name : group->second.m_object_names) + { + auto itr = m_name_sai_map[object_type].find(name); + if (itr == m_name_sai_map[object_type].end()) + { + continue; + } + for (const auto &stat_id : group->second.m_stats_ids) + { + deployCounterSubscription(object_type, itr->second, stat_id, STelUtils::get_sai_label(name)); + } + } +} + +void STelProfile::undeployCounterSubscriptions(sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); + + // TODO: Bulk remove the counter subscriptions + m_sai_tam_counter_subscription_objs.erase(object_type); +} + +void STelProfile::updateTemplates(sai_object_id_t tam_tel_type_obj) +{ + SWSS_LOG_ENTER(); + + auto object_type = getObjectType(tam_tel_type_obj); + if (object_type == SAI_OBJECT_TYPE_NULL) + { + SWSS_LOG_THROW("The object type is not found"); + } + + // Estimate the template size + auto counters = m_sai_tam_counter_subscription_objs.find(object_type); + if (counters == m_sai_tam_counter_subscription_objs.end()) + { + SWSS_LOG_THROW("The counter subscription object is not found"); + } + size_t counters_count = 0; + for (const auto &item : counters->second) + { + counters_count += item.second.size(); + } +#define COUNTER_SIZE (8LLU) +#define IPFIX_TEMPLATE_MAX_SIZE (0xffffLLU) +#define IPFIX_HEADER_SIZE (16LLU) +#define IPFIX_TEMPLATE_METADATA_SIZE (12LLU) +#define IPFIX_TEMPLATE_MAX_STATS_COUNT (((IPFIX_TEMPLATE_MAX_SIZE - IPFIX_HEADER_SIZE - IPFIX_TEMPLATE_METADATA_SIZE) / COUNTER_SIZE) - 1LLU) + size_t estimated_template_size = (counters_count / IPFIX_TEMPLATE_MAX_STATS_COUNT + 1) * IPFIX_TEMPLATE_MAX_SIZE; + + vector buffer(estimated_template_size, 0); + + sai_attribute_t attr; + // attr.id = SAI_TAM_TEL_TYPE_ATTR_IPFIX_TEMPLATES; + attr.value.u8list.count = static_cast(buffer.size()); + attr.value.u8list.list = buffer.data(); + handleSaiGetStatus( + SAI_API_TAM, + sai_tam_api->get_tam_tel_type_attribute(tam_tel_type_obj, 1, &attr)); + + buffer.resize(attr.value.u8list.count); + + m_sai_tam_tel_type_templates[object_type] = move(buffer); +} diff --git a/orchagent/stream_telemetry/stelmgr.h b/orchagent/stream_telemetry/stelmgr.h index 2a2e09867e..e3b4054b85 100644 --- a/orchagent/stream_telemetry/stelmgr.h +++ b/orchagent/stream_telemetry/stelmgr.h @@ -12,29 +12,48 @@ #include #include +/** + * @brief TAM telemetry type state of state machine + */ +typedef enum _sai_tam_tel_type_state_t +{ + /** + * @brief Telemetry type is stopped + * + * In this stage, the recording stream should be stopped, + * and the configuration should be cleared. + */ + SAI_TAM_TEL_TYPE_STATE_STOP_STREAM, + + /** + * @brief Telemetry type is started + * + * In this stage, the recording stream should be started, + * and the latest configuration should be applied. + */ + SAI_TAM_TEL_TYPE_STATE_START_STREAM, + + /** + * @brief Telemetry type configuration is prepared, + * + * We expect the configuration to be generated in the feature, + * And notify the user by sai_tam_tel_type_config_change_notification_fn + */ + SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG, + +} sai_tam_tel_type_state_t; + using CounterNameCache = std::unordered_map>; -struct StelGroup +struct STelGroup { std::set m_object_names; std::set m_stats_ids; }; -struct StelEntry -{ - std::uint16_t m_label; - sai_object_id_t m_object_id; -}; - class STelProfile { public: - enum STREAM_STATE - { - STREAM_STATE_ENABLED, - STREAM_STATE_DISABLED, - }; - STelProfile( const std::string &profile_name, sai_object_id_t sai_tam_obj, @@ -46,64 +65,75 @@ class STelProfile STelProfile(STelProfile &&) = delete; STelProfile &operator=(STelProfile &&) = delete; - void setStreamState(STREAM_STATE state); + using sai_guard_t = std::shared_ptr; + + const std::string& getProfileName() const; + void setStreamState(sai_tam_tel_type_state_t state); + void setStreamState(sai_object_type_t object_type, sai_tam_tel_type_state_t state); + void notifyConfigReady(sai_object_type_t object_type); + sai_tam_tel_type_state_t getTelemetryTypeState(sai_object_type_t object_type) const; + sai_guard_t getTAMTelTypeGuard(sai_object_id_t tam_tel_type_obj) const; + sai_object_type_t getObjectType(sai_object_id_t tam_tel_type_obj) const; void setPollInterval(std::uint32_t poll_interval); void setBulkSize(std::uint32_t bulk_size); void setObjectNames(const std::string &group_name, std::set &&object_names); void setStatsIDs(const std::string &group_name, const std::set &object_counters); void setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id); void delObjectSAIID(sai_object_type_t object_type, const char *object_name); + bool canBeUpdated() const; + bool canBeUpdated(sai_object_type_t object_type) const; - std::vector getTemplates() const; + const std::vector &getTemplates(sai_object_type_t object_type) const; std::vector getObjectTypes() const; void loadGroupFromCfgDB(swss::Table &group_tbl); void loadCounterNameCache(sai_object_type_t object_type); - void tryCommitConfig(); - - static sai_object_type_t group_name_to_sai_type(const std::string &group_name); + void tryCommitConfig(sai_object_type_t object_type); private: // Configuration parameters const std::string m_profile_name; - STREAM_STATE m_setting_state; + sai_tam_tel_type_state_t m_setting_state; std::uint32_t m_poll_interval; - std::uint32_t m_bulk_size; - std::map m_groups; + std::map m_groups; // Runtime parameters const CounterNameCache &m_counter_name_cache; - STREAM_STATE m_state; - size_t m_object_count; + std::unordered_map< sai_object_type_t, std::unordered_map< std::string, sai_object_id_t>> m_name_sai_map; - bool m_needed_to_be_deployed; // SAI objects const sai_object_id_t m_sai_tam_obj; const sai_object_id_t m_sai_tam_collector_obj; - sai_object_id_t m_sai_tam_report_obj; - sai_object_id_t m_sai_tam_tel_type_obj; - sai_object_id_t m_sai_tam_telemetry_obj; - using counter_subscription_t = std::unique_ptr>; std::unordered_map< - sai_object_id_t, + sai_object_type_t, std::unordered_map< - sai_stat_id_t, - counter_subscription_t>> + sai_object_id_t, + std::unordered_map< + sai_stat_id_t, + sai_guard_t>>> m_sai_tam_counter_subscription_objs; + sai_guard_t m_sai_tam_telemetry_obj; + std::unordered_map m_sai_tam_tel_type_states; + std::unordered_map m_sai_tam_tel_type_objs; + std::unordered_map m_sai_tam_report_objs; + std::unordered_map> m_sai_tam_tel_type_templates; - bool isObjectInProfile(sai_object_type_t object_type, const std::string &object_name) const; - - void deployToSAI(); - void undeployFromSAI(); + bool isObjectTypeInProfile(sai_object_type_t object_type, const std::string &object_name) const; + bool isMonitoringObjectReady(sai_object_type_t object_type) const; // SAI calls - void deployTAM(); - void undeployTAM(); + sai_object_id_t getTAMReportObjID(sai_object_type_t object_type); + sai_object_id_t getTAMTelTypeObjID(sai_object_type_t object_type); + void initTelemetry(); void deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, std::uint16_t label); + void deployCounterSubscriptions(sai_object_type_t object_type, sai_object_id_t sai_obj, std::uint16_t label); + void deployCounterSubscriptions(sai_object_type_t object_type); + void undeployCounterSubscriptions(sai_object_type_t object_type); + void updateTemplates(sai_object_id_t tam_tel_type_obj); }; diff --git a/orchagent/stream_telemetry/stelorch.cpp b/orchagent/stream_telemetry/stelorch.cpp index 4a966de4b9..deece63abd 100644 --- a/orchagent/stream_telemetry/stelorch.cpp +++ b/orchagent/stream_telemetry/stelorch.cpp @@ -1,10 +1,12 @@ #include "stelorch.h" +#include "stelutils.h" #include #include #include #include #include +#include #include @@ -31,17 +33,17 @@ namespace swss { template <> - inline void lexical_convert(const string &buffer, ::STelProfile::STREAM_STATE &stage) + inline void lexical_convert(const string &buffer, sai_tam_tel_type_state_t &stage) { SWSS_LOG_ENTER(); if (buffer == "enable") { - stage = STelProfile::STREAM_STATE::STREAM_STATE_ENABLED; + stage = SAI_TAM_TEL_TYPE_STATE_START_STREAM; } else if (buffer == "disable") { - stage = STelProfile::STREAM_STATE::STREAM_STATE_DISABLED; + stage = SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; } else { @@ -57,7 +59,7 @@ STelOrch::STelOrch( const vector &tables) : Orch(cfg_db, tables), m_state_telemetry_session(state_db, STREAM_TELEMETRY_SESSION), - m_cfg_stream_telemetry_group(state_db, CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME), + m_asic_db("ASIC_DB", 0), m_sai_hostif_obj(SAI_NULL_OBJECT_ID), m_sai_hostif_trap_group_obj(SAI_NULL_OBJECT_ID), m_sai_hostif_user_defined_trap_obj(SAI_NULL_OBJECT_ID), @@ -69,12 +71,19 @@ STelOrch::STelOrch( createNetlinkChannel("stel", "ipfix"); createTAM(); + + m_asic_notification_consumer = make_shared(&m_asic_db, "NOTIFICATIONS"); + auto notifier = new Notifier(m_asic_notification_consumer.get(), this, "TAM_TEL_TYPE_STATE"); + Orch::addExecutor(notifier); } STelOrch::~STelOrch() { SWSS_LOG_ENTER(); + m_name_profile_mapping.clear(); + m_type_profile_mapping.clear(); + deleteTAM(); deleteNetlinkChannel(); } @@ -109,13 +118,22 @@ void STelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) for (auto itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++) { auto profile = *itr3; + const char *counter_name = msg.m_operation == CounterNameMapUpdater::SET ? msg.m_set.m_counter_name : msg.m_del.m_counter_name; + + if (!profile->canBeUpdated(itr->second)) + { + // TODO: Here is a potential issue, we may need to retry the task. + SWSS_LOG_WARN("The profile %s is not ready to be updated, but the object %s want to be updated", profile->getProfileName().c_str(), counter_name); + continue; + } + if (msg.m_operation == CounterNameMapUpdater::SET) { - profile->setObjectSAIID(itr->second, msg.m_set.m_counter_name, msg.m_set.m_oid); + profile->setObjectSAIID(itr->second, counter_name, msg.m_set.m_oid); } else if (msg.m_operation == CounterNameMapUpdater::DEL) { - profile->delObjectSAIID(itr->second, msg.m_del.m_counter_name); + profile->delObjectSAIID(itr->second, counter_name); } else { @@ -124,15 +142,20 @@ void STelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) } } -void STelOrch::profileTableSet(const string &profile_name, const vector &values) +task_process_status STelOrch::profileTableSet(const string &profile_name, const vector &values) { SWSS_LOG_ENTER(); auto profile = getProfile(profile_name); + if (!profile->canBeUpdated()) + { + return task_process_status::task_need_retry; + } + auto value_opt = fvsGetValue(values, "stream_state", true); if (value_opt) { - STelProfile::STREAM_STATE state; + sai_tam_tel_type_state_t state; lexical_convert(*value_opt, state); profile->setStreamState(state); } @@ -145,47 +168,55 @@ void STelOrch::profileTableSet(const string &profile_name, const vectorsetPollInterval(poll_interval); } - value_opt = fvsGetValue(values, "bulk_size", true); - if (value_opt) - { - uint32_t bulk_size; - lexical_convert(*value_opt, bulk_size); - profile->setBulkSize(bulk_size); - } - // Map the profile to types // This profile may be inserted by group table for (auto type : profile->getObjectTypes()) { m_type_profile_mapping[type].insert(profile); + profile->tryCommitConfig(type); } + + return task_process_status::task_success; } -void STelOrch::profileTableDel(const std::string &profile_name) +task_process_status STelOrch::profileTableDel(const std::string &profile_name) { SWSS_LOG_ENTER(); auto itr = m_name_profile_mapping.find(profile_name); if (itr == m_name_profile_mapping.end()) { - return; + return task_process_status::task_success; + } + + if (!itr->second->canBeUpdated()) + { + return task_process_status::task_need_retry; } auto profile = itr->second; for (auto type : profile->getObjectTypes()) { + profile->tryCommitConfig(type); m_type_profile_mapping[type].erase(profile); + m_state_telemetry_session.del(profile_name + "|" + STelUtils::sai_type_to_group_name(type)); } m_name_profile_mapping.erase(itr); + + return task_process_status::task_success; } -void STelOrch::groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values) +task_process_status STelOrch::groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values) { SWSS_LOG_ENTER(); auto profile = getProfile(profile_name); - auto type = STelProfile::group_name_to_sai_type(group_name); + auto type = STelUtils::group_name_to_sai_type(group_name); + if (!profile->canBeUpdated(type)) + { + return task_process_status::task_need_retry; + } auto value_opt = fvsGetValue(values, "object_names", true); if (value_opt) @@ -205,16 +236,32 @@ void STelOrch::groupTableSet(const std::string &profile_name, const std::string profile->setStatsIDs(group_name, object_counters); } + profile->tryCommitConfig(type); + m_type_profile_mapping[type].insert(profile); + + return task_process_status::task_success; } -void STelOrch::groupTableDel(const std::string &profile_name, const std::string &group_name) +task_process_status STelOrch::groupTableDel(const std::string &profile_name, const std::string &group_name) { SWSS_LOG_ENTER(); auto profile = getProfile(profile_name); - auto type = STelProfile::group_name_to_sai_type(group_name); + auto type = STelUtils::group_name_to_sai_type(group_name); + + if (!profile->canBeUpdated(type)) + { + return task_process_status::task_need_retry; + } + + profile->setObjectSAIID(type, group_name.c_str(), SAI_NULL_OBJECT_ID); + profile->tryCommitConfig(type); + m_type_profile_mapping[type].erase(profile); + m_state_telemetry_session.del(profile_name + "|" + group_name); + + return task_process_status::task_success; } shared_ptr STelOrch::getProfile(const string &profile_name) @@ -235,6 +282,73 @@ shared_ptr STelOrch::getProfile(const string &profile_name) return m_name_profile_mapping.at(profile_name); } +void STelOrch::doTask(swss::NotificationConsumer &consumer) +{ + SWSS_LOG_ENTER(); + + std::string op; + std::string data; + std::vector values; + + consumer.pop(op, data, values); + + if (&consumer != m_asic_notification_consumer.get()) + { + SWSS_LOG_ERROR("Unknown consumer"); + return; + } + + if (op != SAI_SWITCH_NOTIFICATION_NAME_TAM_TEL_TYPE_CONFIG_CHANGE) + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + return; + } + + sai_object_id_t tam_tel_type_obj = SAI_NULL_OBJECT_ID; + + // sai_deserialize_tam_tel_type_config_ntf(data, tam_tel_type_obj); + + if (tam_tel_type_obj == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("The TAM tel type object is not valid"); + return; + } + + for (auto &profile : m_name_profile_mapping) + { + auto type = profile.second->getObjectType(tam_tel_type_obj); + if (type != SAI_OBJECT_TYPE_NULL) + { + profile.second->notifyConfigReady(type); + // TODO: TryCommitConfig once the template has been applied by CounterSyncd in the phase2 + profile.second->tryCommitConfig(type); + // Update state db + vector values; + auto state = profile.second->getTelemetryTypeState(type); + if (state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) + { + values.emplace_back("stream_status", "enable"); + } + else if (state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + values.emplace_back("stream_status", "disable"); + } + else + { + SWSS_LOG_THROW("Unexpected state %d", state); + } + + values.emplace_back("session_type", "ipfix"); + + auto templates = profile.second->getTemplates(type); + values.emplace_back("session_config", string(templates.begin(), templates.end())); + + m_state_telemetry_session.set(profile.first + "|" + STelUtils::sai_type_to_group_name(type), values); + break; + } + } +} + void STelOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -244,6 +358,7 @@ void STelOrch::doTask(Consumer &consumer) auto itr = consumer.m_toSync.begin(); while (itr != consumer.m_toSync.end()) { + task_process_status status = task_process_status::task_failed; KeyOpFieldsValuesTuple t = itr->second; string key = kfvKey(t); @@ -253,11 +368,11 @@ void STelOrch::doTask(Consumer &consumer) { if (op == SET_COMMAND) { - profileTableSet(key, kfvFieldsValues(t)); + status = profileTableSet(key, kfvFieldsValues(t)); } else if (op == DEL_COMMAND) { - profileTableDel(key); + status = profileTableDel(key); } else { @@ -273,11 +388,11 @@ void STelOrch::doTask(Consumer &consumer) } if (op == SET_COMMAND) { - groupTableSet(tokens[0], tokens[1], kfvFieldsValues(t)); + status = groupTableSet(tokens[0], tokens[1], kfvFieldsValues(t)); } else if (op == DEL_COMMAND) { - groupTableDel(tokens[0], tokens[1]); + status = groupTableDel(tokens[0], tokens[1]); } else { @@ -289,7 +404,14 @@ void STelOrch::doTask(Consumer &consumer) SWSS_LOG_ERROR("Unknown table %s\n", table_name.c_str()); } - itr = consumer.m_toSync.erase(itr); + if (status == task_process_status::task_need_retry) + { + ++itr; + } + else + { + itr = consumer.m_toSync.erase(itr); + } } } @@ -456,24 +578,14 @@ void STelOrch::createTAM() attrs.data())); // Bind the TAM object to switch - vector tam_objects(1024, SAI_NULL_OBJECT_ID); - attrs.clear(); - attr.id = SAI_SWITCH_ATTR_TAM_OBJECT_ID; - attr.value.objlist.count = static_cast(tam_objects.size()); - attr.value.objlist.list = tam_objects.data(); - handleSaiGetStatus( - SAI_API_SWITCH, - sai_switch_api->get_switch_attribute( - gSwitchId, - static_cast(attrs.size()), - attrs.data())); - tam_objects[attr.value.objlist.count] = m_sai_tam_obj; - attr.value.objlist.count++; - handleSaiSetStatus( + + STELUTILS_ADD_SAI_OBJECT_LIST( + gSwitchId, + SAI_SWITCH_ATTR_TAM_OBJECT_ID, + m_sai_tam_obj, SAI_API_SWITCH, - sai_switch_api->set_switch_attribute( - gSwitchId, - &attr)); + switch, + switch); } void STelOrch::deleteTAM() @@ -483,28 +595,13 @@ void STelOrch::deleteTAM() if (m_sai_tam_obj != SAI_NULL_OBJECT_ID) { // Unbind the TAM object from switch - vector tam_objects(1024, SAI_NULL_OBJECT_ID); - sai_attribute_t attr; - attr.id = SAI_SWITCH_ATTR_TAM_OBJECT_ID; - attr.value.objlist.count = static_cast(tam_objects.size()); - attr.value.objlist.list = tam_objects.data(); - handleSaiGetStatus( - SAI_API_SWITCH, - sai_switch_api->get_switch_attribute( - gSwitchId, - 1, - &attr)); - tam_objects.erase( - remove( - tam_objects.begin(), - tam_objects.begin() + attr.value.objlist.count, - m_sai_tam_obj), - tam_objects.end()); - handleSaiSetStatus( + STELUTILS_DEL_SAI_OBJECT_LIST( + gSwitchId, + SAI_SWITCH_ATTR_TAM_OBJECT_ID, + m_sai_tam_obj, SAI_API_SWITCH, - sai_switch_api->set_switch_attribute( - gSwitchId, - &attr)); + switch, + switch); handleSaiRemoveStatus( SAI_API_TAM, sai_tam_api->remove_tam(m_sai_tam_obj)); diff --git a/orchagent/stream_telemetry/stelorch.h b/orchagent/stream_telemetry/stelorch.h index 21fe32fe65..8a1b8b708f 100644 --- a/orchagent/stream_telemetry/stelorch.h +++ b/orchagent/stream_telemetry/stelorch.h @@ -16,6 +16,8 @@ #define CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME "STREAM_TELEMETRY_GROUP" #define STREAM_TELEMETRY_SESSION "STREAM_TELEMETRY_SESSION" +#define SAI_SWITCH_NOTIFICATION_NAME_TAM_TEL_TYPE_CONFIG_CHANGE "tam_tel_type_config_change" + class STelOrch : public Orch { public: @@ -34,19 +36,21 @@ class STelOrch : public Orch void locallyNotify(const CounterNameMapUpdater::Message &msg); private: - swss::Table m_cfg_stream_telemetry_group; swss::Table m_state_telemetry_session; + swss::DBConnector m_asic_db; + std::shared_ptr m_asic_notification_consumer; std::unordered_map> m_name_profile_mapping; std::unordered_map>> m_type_profile_mapping; CounterNameCache m_counter_name_cache; - void profileTableSet(const std::string &profile_name, const std::vector &values); - void profileTableDel(const std::string &profile_name); - void groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values); - void groupTableDel(const std::string &profile_name, const std::string &group_name); + task_process_status profileTableSet(const std::string &profile_name, const std::vector &values); + task_process_status profileTableDel(const std::string &profile_name); + task_process_status groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values); + task_process_status groupTableDel(const std::string &profile_name, const std::string &group_name); std::shared_ptr getProfile(const std::string &profile_name); + void doTask(swss::NotificationConsumer &consumer); void doTask(Consumer &consumer); // SAI objects diff --git a/orchagent/stream_telemetry/stelutils.cpp b/orchagent/stream_telemetry/stelutils.cpp new file mode 100644 index 0000000000..6a2ec470a4 --- /dev/null +++ b/orchagent/stream_telemetry/stelutils.cpp @@ -0,0 +1,163 @@ +#include "stelutils.h" + +#include +#include + +#include +#include + +using namespace std; + +#define OBJECT_TYPE_PREFIX "SAI_OBJECT_TYPE_" + +vector STelUtils::get_sai_object_list( + sai_object_id_t obj, + sai_attr_id_t attr_id, + sai_api_t api, + function get_attribute_handler) +{ + SWSS_LOG_ENTER(); + + vector obj_list(1024, SAI_NULL_OBJECT_ID); + sai_attribute_t attr; + + attr.id = attr_id; + attr.value.objlist.count = static_cast(obj_list.size()); + attr.value.objlist.list = obj_list.data(); + + handleSaiGetStatus( + api, + get_attribute_handler( + obj, + 1, + &attr)); + assert(attr.value.objlist.count < obj_list.size()); + + obj_list.erase( + obj_list.begin() + attr.value.objlist.count, + obj_list.end()); + + return obj_list; +} + +sai_object_type_t STelUtils::group_name_to_sai_type(const string &group_name) +{ + SWSS_LOG_ENTER(); + + sai_object_type_t sai_object_type; + + sai_deserialize_object_type(string(OBJECT_TYPE_PREFIX) + boost::to_upper_copy(group_name), sai_object_type); + return sai_object_type; +} + +std::string STelUtils::sai_type_to_group_name(sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); + + std::string group_name = sai_serialize_object_type(object_type); + + group_name.erase(0, sizeof(OBJECT_TYPE_PREFIX) - 1); + + return group_name; +} + +set STelUtils::object_counters_to_stats_ids( + const string &group_name, + const set &object_counters) +{ + SWSS_LOG_ENTER(); + sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); + set stats_ids_set; + + auto info = sai_metadata_get_object_type_info(sai_object_type); + if (info == nullptr) + { + SWSS_LOG_THROW("Failed to get the object type info for %s", group_name.c_str()); + } + + auto state_enum = info->statenum; + if (state_enum == nullptr) + { + SWSS_LOG_THROW("The object type %s does not support stats", group_name.c_str()); + } + + string type_prefix = "SAI_" + group_name + "_STAT_"; + + for (size_t i = 0; i < state_enum->valuescount; i++) + { + string state_name = type_prefix + state_enum->valuesnames[i]; + if (object_counters.find(state_name) != object_counters.end()) + { + SWSS_LOG_DEBUG("Found the object counter %s", state_name.c_str()); + stats_ids_set.insert(state_enum->values[i]); + } + } + + if (stats_ids_set.size() != object_counters.size()) + { + SWSS_LOG_THROW("Failed to convert the object counters to stats ids for %s", group_name.c_str()); + } + + return stats_ids_set; +} + +sai_stats_mode_t STelUtils::get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id) +{ + SWSS_LOG_ENTER(); + + switch(object_type) + { + case SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP: + switch(stat_id) + { + case SAI_INGRESS_PRIORITY_GROUP_STAT_WATERMARK_BYTES: + case SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES: + case SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES: + return SAI_STATS_MODE_READ_AND_CLEAR; + default: + break; + } + break; + case SAI_OBJECT_TYPE_BUFFER_POOL: + switch(stat_id) + { + case SAI_BUFFER_POOL_STAT_WATERMARK_BYTES: + case SAI_BUFFER_POOL_STAT_XOFF_ROOM_WATERMARK_BYTES: + return SAI_STATS_MODE_READ_AND_CLEAR; + default: + break; + } + break; + default: + break; + } + + return SAI_STATS_MODE_READ; +} + + +uint16_t STelUtils::get_sai_label(const string &object_name) +{ + SWSS_LOG_ENTER(); + uint16_t label = 0; + + if (object_name.rfind("Ethernet", 0) == 0) + { + const static regex re("Ethernet(\\d+)(?:\\|(\\d+))?"); + smatch match; + if (regex_match(object_name, match, re)) + { + label = static_cast(stoi(match[1])); + if (match.size() == 3) + { + label = static_cast(label * 100 + stoi(match[2])); + } + } + } + else + { + SWSS_LOG_THROW("The object %s is not supported", object_name.c_str()); + } + + return label; +} diff --git a/orchagent/stream_telemetry/stelutils.h b/orchagent/stream_telemetry/stelutils.h new file mode 100644 index 0000000000..bf2c8c7f67 --- /dev/null +++ b/orchagent/stream_telemetry/stelutils.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +class STelUtils +{ +public: + STelUtils() = delete; + + static std::vector get_sai_object_list( + sai_object_id_t obj, + sai_attr_id_t attr_id, + sai_api_t api, + std::function get_attribute_handler); + static sai_object_type_t group_name_to_sai_type(const std::string &group_name); + static std::string sai_type_to_group_name(sai_object_type_t object_type); + static std::set object_counters_to_stats_ids( + const std::string &group_name, + const std::set &object_counters); + static sai_stats_mode_t get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id); + static std::uint16_t get_sai_label(const std::string &object_name); +}; + +#define STELUTILS_ADD_SAI_OBJECT_LIST(obj, attr_id, inserted_obj, api_type_name, api_name, obj_type_name) \ + { \ + sai_attribute_t attr; \ + auto obj_list = STelUtils::get_sai_object_list( \ + obj, \ + attr_id, \ + api_type_name, \ + sai_## api_name ## _api->get_ ## obj_type_name ## _attribute); \ + obj_list.push_back(inserted_obj); \ + attr.id = attr_id; \ + attr.value.objlist.count = static_cast(obj_list.size()); \ + attr.value.objlist.list = obj_list.data(); \ + handleSaiSetStatus( \ + api_type_name, \ + sai_ ## api_name ## _api->set_ ## obj_type_name ## _attribute( \ + obj, \ + &attr)); \ + } + +#define STELUTILS_DEL_SAI_OBJECT_LIST(obj, attr_id, removed_obj, api_type_name, api_name, obj_type_name) \ + { \ + sai_attribute_t attr; \ + auto obj_list = STelUtils::get_sai_object_list( \ + obj, \ + attr_id, \ + api_type_name, \ + sai_ ## api_name ## _api->get_ ## obj_type_name ## _attribute); \ + obj_list.erase( \ + std::remove( \ + obj_list.begin(), \ + obj_list.end(), \ + removed_obj), \ + obj_list.end()); \ + attr.id = attr_id; \ + attr.value.objlist.count = static_cast(obj_list.size()); \ + attr.value.objlist.list = obj_list.data(); \ + handleSaiSetStatus( \ + api_type_name, \ + sai_ ## api_name ## _api->set_ ## obj_type_name ## _attribute( \ + obj, \ + &attr)); \ + } From 3c23099d8032e2e98aff9507a0af907e72732c14 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Fri, 20 Dec 2024 15:41:35 +0800 Subject: [PATCH 04/11] Fix ipfix LazyLock Signed-off-by: Ze Gan --- countersyncd/Cargo.lock | 148 +++++++++++++++++++++++++++++++- countersyncd/Cargo.toml | 3 + countersyncd/src/actor/ipfix.rs | 7 +- 3 files changed, 153 insertions(+), 5 deletions(-) diff --git a/countersyncd/Cargo.lock b/countersyncd/Cargo.lock index 419c9055b9..d34b384fbf 100644 --- a/countersyncd/Cargo.lock +++ b/countersyncd/Cargo.lock @@ -30,6 +30,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.18" @@ -106,6 +115,26 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.79", +] + [[package]] name = "binrw" version = "0.11.2" @@ -187,12 +216,32 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.20" @@ -282,7 +331,9 @@ dependencies = [ "ipfixrw", "log", "neli", + "once_cell", "rand", + "swss-common", "tokio", "yaml-rust", ] @@ -446,6 +497,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "heck" version = "0.5.0" @@ -476,7 +533,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eec14e601f7a267061ae1efed4b7e9ccb178296cb92c6454707e8d312320ecdb" dependencies = [ - "nom", + "nom 2.2.1", ] [[package]] @@ -497,6 +554,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -515,6 +581,16 @@ version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -549,6 +625,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -603,6 +685,16 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "object" version = "0.32.2" @@ -662,6 +754,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn 2.0.79", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -741,12 +843,47 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.37" @@ -844,6 +981,15 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "swss-common" +version = "0.1.0" +source = "git+https://github.com/sonic-net/sonic-dash-ha.git?branch=master#521082b95b9f5b0acf93b272bf49a11222e7b259" +dependencies = [ + "bindgen", + "libc", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/countersyncd/Cargo.toml b/countersyncd/Cargo.toml index b4806ff34b..c1085af78b 100644 --- a/countersyncd/Cargo.toml +++ b/countersyncd/Cargo.toml @@ -25,6 +25,7 @@ log = "0.4.22" # simplelog = "0.12" rand = "0.8.5" +once_cell = "1.18.0" # Command line utils clap = { version = "4", features = ["derive", "cargo", "wrap_help", "unicode", "string", "unstable-styles"] } @@ -53,3 +54,5 @@ color-eyre = "0.6" # # # Other utilities # once_cell = "1" + +swss-common = {git = "https://github.com/sonic-net/sonic-dash-ha.git", branch = "master"} diff --git a/countersyncd/src/actor/ipfix.rs b/countersyncd/src/actor/ipfix.rs index dc0506a8d8..0171cd47e4 100644 --- a/countersyncd/src/actor/ipfix.rs +++ b/countersyncd/src/actor/ipfix.rs @@ -5,6 +5,7 @@ use tokio::{ select, sync::mpsc::{Receiver, Sender}, }; +use once_cell::sync::Lazy; use ahash::{HashMap, HashMapExt}; use byteorder::{ByteOrder, NetworkEndian}; @@ -209,10 +210,8 @@ impl Drop for IpfixActor { } } -use std::sync::LazyLock; - -static OBSERVATION_TIME_KEY: LazyLock = - LazyLock::new(|| DataRecordKey::Unrecognized(FieldSpecifier::new(None, 325, 8))); +static OBSERVATION_TIME_KEY: Lazy = +Lazy::new(|| DataRecordKey::Unrecognized(FieldSpecifier::new(None, 325, 8))); fn get_observation_time(data_record: &DataRecord) -> Option { let val = data_record.values.get(&*OBSERVATION_TIME_KEY); From a562764ee3911faf148e4f691f0ac7c0aed5a435 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Fri, 20 Dec 2024 19:45:03 +0800 Subject: [PATCH 05/11] Template updates Signed-off-by: Ze Gan --- countersyncd/src/actor/ipfix.rs | 49 +++++++++++++++++++++++++------ countersyncd/src/message/ipfix.rs | 1 + 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/countersyncd/src/actor/ipfix.rs b/countersyncd/src/actor/ipfix.rs index 0171cd47e4..aee769c08c 100644 --- a/countersyncd/src/actor/ipfix.rs +++ b/countersyncd/src/actor/ipfix.rs @@ -13,13 +13,13 @@ use ipfix::get_message_length; use ipfixrw::{ information_elements::Formatter, parse_ipfix_message, - parser::{DataRecord, DataRecordKey, DataRecordValue, FieldSpecifier}, + parser::{DataRecord, DataRecordKey, DataRecordValue, FieldSpecifier, Message}, template_store::TemplateStore, }; use super::super::message::{ buffer::SocketBufferMessage, - ipfix::IPFixTemplates, + ipfix::IPFixTemplatesMessage, saistats::{SAIStat, SAIStats, SAIStatsMessage}, }; @@ -46,8 +46,10 @@ type IpfixCacheRef = Rc>; pub struct IpfixActor { saistats_recipients: LinkedList>, - template_recipient: Receiver, + template_recipient: Receiver, record_recipient: Receiver, + temporary_templates_map: HashMap, + applied_templates_map: HashMap>, #[cfg(test)] prober: Option>, @@ -55,13 +57,15 @@ pub struct IpfixActor { impl IpfixActor { pub fn new( - template_recipient: Receiver, + template_recipient: Receiver, record_recipient: Receiver, ) -> Self { IpfixActor { saistats_recipients: LinkedList::new(), template_recipient, record_recipient, + temporary_templates_map: HashMap::new(), + applied_templates_map: HashMap::new(), #[cfg(test)] prober: None, } @@ -71,7 +75,28 @@ impl IpfixActor { self.saistats_recipients.push_back(recipient); } - fn handle_template(&mut self, templates: IPFixTemplates) { + fn insert_temporary_template(&mut self, msg_key: &String, templates: Message) { + templates.iter_template_records().for_each(|record| { + self.temporary_templates_map + .insert(record.template_id, msg_key.clone()); + }); + } + + fn update_applied_template(&mut self, template_id: u16) { + if !self.temporary_templates_map.contains_key(&template_id) { + return; + } + let msg_key = self.temporary_templates_map.get(&template_id).unwrap().clone(); + let mut template_ids = Vec::new(); + self.temporary_templates_map.iter().filter(|(_, v)| **v == msg_key).for_each(|(&k, _)| { + template_ids.push(k); + }); + self.temporary_templates_map.retain(|_, v| *v != msg_key); + self.applied_templates_map.insert(msg_key, template_ids); + } + + fn handle_template(&mut self, templates: IPFixTemplatesMessage) { + let (msg_key, templates) = templates; let cache_ref = Self::get_cache(); let cache = cache_ref.borrow_mut(); let mut read_size: usize = 0; @@ -79,8 +104,9 @@ impl IpfixActor { let len = get_message_length(&templates[read_size..]).unwrap(); let template = &templates[read_size..read_size + len as usize]; // We suppose that the template is always valid, otherwise we need to raise the panic - parse_ipfix_message(&template, cache.templates.clone(), cache.formatter.clone()) + let new_templates: ipfixrw::parser::Message = parse_ipfix_message(&template, cache.templates.clone(), cache.formatter.clone()) .unwrap(); + self.insert_temporary_template(&msg_key, new_templates); read_size += len as usize; } #[cfg(test)] @@ -112,6 +138,11 @@ impl IpfixActor { continue; } let data_message = data_message.unwrap(); + data_message.sets.iter().for_each(|set| { + if let ipfixrw::parser::Records::Data{set_id, data: _} = set.records { + self.update_applied_template(set_id); + } + }); let datarecords: Vec<&DataRecord> = data_message.iter_data_records().collect(); let mut observation_time: Option; for record in datarecords { @@ -256,7 +287,7 @@ mod test { 0x00, 0x00, 0x00, 0x01, // line 2 0x00, 0x00, 0x00, 0x00, // line 3 0x00, 0x02, 0x00, 0x1C, // line 4 - 0x01, 0x00, 0x00, 0x03, // line 5 Template ID 256, 3 fields + 0x01, 0x01, 0x00, 0x03, // line 5 Template ID 257, 3 fields 0x01, 0x45, 0x00, 0x08, // line 6 Field ID 325, 4 bytes 0x80, 0x01, 0x00, 0x08, // line 7 Field ID 128, 8 bytes 0x00, 0x01, 0x00, 0x02, // line 8 Enterprise Number 1, Field ID 1 @@ -295,7 +326,7 @@ mod test { 0x00, 0x00, 0x00, 0x01, // line 26 0x00, 0x00, 0x00, 0x00, // line 27 0x00, 0x00, 0x00, 0x04, // line 28 - 0x01, 0x00, 0x00, 0x1C, // line 29 Record 2 + 0x01, 0x01, 0x00, 0x1C, // line 29 Record 2 0x00, 0x00, 0x00, 0x00, // line 30 0x00, 0x00, 0x00, 0x02, // line 31 0x00, 0x00, 0x00, 0x00, // line 32 @@ -305,7 +336,7 @@ mod test { ]; template_sender - .send(Arc::new(Vec::from(template_bytes))) + .send((String::from(""), Arc::new(Vec::from(template_bytes)))) .await .unwrap(); let pm = prober_reciver diff --git a/countersyncd/src/message/ipfix.rs b/countersyncd/src/message/ipfix.rs index e7e99dac2e..8b10a98ab4 100644 --- a/countersyncd/src/message/ipfix.rs +++ b/countersyncd/src/message/ipfix.rs @@ -1,3 +1,4 @@ use std::sync::Arc; pub type IPFixTemplates = Arc>; +pub type IPFixTemplatesMessage = (String, IPFixTemplates); From 0377fbfa12f0ae732a9d66daad43cfef63dc8798 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Fri, 27 Dec 2024 13:48:22 +0800 Subject: [PATCH 06/11] countersyncd refactor logs Signed-off-by: Ze Gan --- countersyncd/Cargo.lock | 30 +++++++++ countersyncd/Cargo.toml | 3 + countersyncd/src/actor/ipfix.rs | 113 +++++++++++++------------------- countersyncd/src/actor/mod.rs | 1 + countersyncd/src/actor/swss.rs | 45 +++++++++++++ countersyncd/src/lib.rs | 1 + countersyncd/src/test_common.rs | 56 ++++++++++++++++ 7 files changed, 181 insertions(+), 68 deletions(-) create mode 100644 countersyncd/src/actor/swss.rs create mode 100644 countersyncd/src/lib.rs create mode 100644 countersyncd/src/test_common.rs diff --git a/countersyncd/Cargo.lock b/countersyncd/Cargo.lock index d34b384fbf..16707a563e 100644 --- a/countersyncd/Cargo.lock +++ b/countersyncd/Cargo.lock @@ -327,6 +327,7 @@ dependencies = [ "byteorder", "clap", "color-eyre", + "env_logger", "ipfix", "ipfixrw", "log", @@ -442,6 +443,29 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "errno" version = "0.3.9" @@ -515,6 +539,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "ident_case" version = "1.0.1" diff --git a/countersyncd/Cargo.toml b/countersyncd/Cargo.toml index c1085af78b..eb44da4287 100644 --- a/countersyncd/Cargo.toml +++ b/countersyncd/Cargo.toml @@ -22,6 +22,7 @@ byteorder = "1.5.0" # Logging log = "0.4.22" +env_logger = "0.11.6" # simplelog = "0.12" rand = "0.8.5" @@ -55,4 +56,6 @@ color-eyre = "0.6" # # Other utilities # once_cell = "1" + + swss-common = {git = "https://github.com/sonic-net/sonic-dash-ha.git", branch = "master"} diff --git a/countersyncd/src/actor/ipfix.rs b/countersyncd/src/actor/ipfix.rs index aee769c08c..0ddd571ffe 100644 --- a/countersyncd/src/actor/ipfix.rs +++ b/countersyncd/src/actor/ipfix.rs @@ -1,11 +1,11 @@ use std::{cell::RefCell, collections::LinkedList, rc::Rc, sync::Arc, time::SystemTime}; use log::{debug, warn}; +use once_cell::sync::Lazy; use tokio::{ select, sync::mpsc::{Receiver, Sender}, }; -use once_cell::sync::Lazy; use ahash::{HashMap, HashMapExt}; use byteorder::{ByteOrder, NetworkEndian}; @@ -50,9 +50,6 @@ pub struct IpfixActor { record_recipient: Receiver, temporary_templates_map: HashMap, applied_templates_map: HashMap>, - - #[cfg(test)] - prober: Option>, } impl IpfixActor { @@ -66,8 +63,6 @@ impl IpfixActor { record_recipient, temporary_templates_map: HashMap::new(), applied_templates_map: HashMap::new(), - #[cfg(test)] - prober: None, } } @@ -86,11 +81,18 @@ impl IpfixActor { if !self.temporary_templates_map.contains_key(&template_id) { return; } - let msg_key = self.temporary_templates_map.get(&template_id).unwrap().clone(); + let msg_key = self + .temporary_templates_map + .get(&template_id) + .unwrap() + .clone(); let mut template_ids = Vec::new(); - self.temporary_templates_map.iter().filter(|(_, v)| **v == msg_key).for_each(|(&k, _)| { - template_ids.push(k); - }); + self.temporary_templates_map + .iter() + .filter(|(_, v)| **v == msg_key) + .for_each(|(&k, _)| { + template_ids.push(k); + }); self.temporary_templates_map.retain(|_, v| *v != msg_key); self.applied_templates_map.insert(msg_key, template_ids); } @@ -104,13 +106,13 @@ impl IpfixActor { let len = get_message_length(&templates[read_size..]).unwrap(); let template = &templates[read_size..read_size + len as usize]; // We suppose that the template is always valid, otherwise we need to raise the panic - let new_templates: ipfixrw::parser::Message = parse_ipfix_message(&template, cache.templates.clone(), cache.formatter.clone()) - .unwrap(); + let new_templates: ipfixrw::parser::Message = + parse_ipfix_message(&template, cache.templates.clone(), cache.formatter.clone()) + .unwrap(); self.insert_temporary_template(&msg_key, new_templates); read_size += len as usize; } - #[cfg(test)] - self.probe(format!("Template {:?} consumed", templates)); + debug!("Template {:?} consumed", templates); } fn handle_record(&mut self, records: SocketBufferMessage) -> Vec { @@ -122,8 +124,6 @@ impl IpfixActor { let len = get_message_length(&records[read_size..]); if len.is_err() || len.unwrap() as usize + read_size > records.len() { warn!("Wrong length in the records {:?}", records); - #[cfg(test)] - self.probe("Discard record due to error length".to_string()); break; } let len = len.unwrap(); @@ -133,13 +133,11 @@ impl IpfixActor { if data_message.is_err() { warn!("Not support data message {:?}", data); read_size += len as usize; - #[cfg(test)] - self.probe(format!("Unknown template, Discard record {:?}", data_message.err().unwrap())); continue; } let data_message = data_message.unwrap(); data_message.sets.iter().for_each(|set| { - if let ipfixrw::parser::Records::Data{set_id, data: _} = set.records { + if let ipfixrw::parser::Records::Data { set_id, data: _ } = set.records { self.update_applied_template(set_id); } }); @@ -176,8 +174,7 @@ impl IpfixActor { } } messages.push(saistats.clone()); - #[cfg(test)] - self.probe("Record parsed".to_string()); + debug!("Record parsed"); } read_size += len as usize; } @@ -223,16 +220,6 @@ impl IpfixActor { } } } - - #[cfg(test)] - pub fn set_prober(&mut self, prober: Sender) { - self.prober = Some(prober); - } - - #[cfg(test)] - fn probe(&self, message: String) { - self.prober.as_ref().unwrap().try_send(message).unwrap(); - } } impl Drop for IpfixActor { @@ -242,7 +229,7 @@ impl Drop for IpfixActor { } static OBSERVATION_TIME_KEY: Lazy = -Lazy::new(|| DataRecordKey::Unrecognized(FieldSpecifier::new(None, 325, 8))); + Lazy::new(|| DataRecordKey::Unrecognized(FieldSpecifier::new(None, 325, 8))); fn get_observation_time(data_record: &DataRecord) -> Option { let val = data_record.values.get(&*OBSERVATION_TIME_KEY); @@ -255,7 +242,7 @@ fn get_observation_time(data_record: &DataRecord) -> Option { #[cfg(test)] mod test { use super::*; - + use countersyncd::test_common::{assert_logs, capture_logs}; use tokio::{spawn, sync::mpsc::channel}; #[tokio::test] @@ -263,11 +250,9 @@ mod test { let (buffer_sender, buffer_reciver) = channel(1); let (template_sender, template_reciver) = channel(1); let (saistats_sender, mut saistats_reciver) = channel(100); - let (prober, mut prober_reciver) = channel(100); - let mut actor = IpfixActor::new(template_reciver, buffer_reciver); actor.add_recipient(saistats_sender); - actor.set_prober(prober); + let actor_handle = spawn(IpfixActor::run(actor)); let template_bytes: [u8; 88] = [ @@ -339,25 +324,14 @@ mod test { .send((String::from(""), Arc::new(Vec::from(template_bytes)))) .await .unwrap(); - let pm = prober_reciver - .recv() - .await - .expect("The template not consumed"); - assert!(pm.contains("Template")); - assert!(pm.contains("consumed")); + + // Wait for the template to be processed + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; buffer_sender .send(Arc::new(Vec::from(valid_records_bytes))) .await .unwrap(); - for _ in 0..4 { - let pm = prober_reciver - .recv() - .await - .expect("The record not consumed"); - assert!(pm.contains("Record")); - assert!(pm.contains("parsed")); - } let invalid_len_record: [u8; 20] = [ 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 @@ -370,11 +344,6 @@ mod test { .send(Arc::new(Vec::from(invalid_len_record))) .await .unwrap(); - assert!(prober_reciver - .recv() - .await - .expect("The record not consumed") - .contains("Discard record due to error length")); let unknown_record: [u8; 44] = [ 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 1 @@ -393,19 +362,6 @@ mod test { .send(Arc::new(Vec::from(unknown_record))) .await .unwrap(); - assert!(prober_reciver - .recv() - .await - .expect("The record not consumed") - .contains("Unknown template, Discard record")); - - drop(buffer_sender); - drop(template_sender); - - let mut received_stats = Vec::new(); - while let Some(stats) = saistats_reciver.recv().await { - received_stats.push(Arc::try_unwrap(stats).unwrap()); - } let expected_stats = vec![ SAIStats { @@ -477,10 +433,31 @@ mod test { ], }, ]; + + let mut received_stats = Vec::new(); + while let Some(stats) = saistats_reciver.recv().await { + received_stats.push(Arc::try_unwrap(stats).unwrap()); + if received_stats.len() == expected_stats.len() { + break; + } + } + assert_eq!(received_stats, expected_stats); + drop(buffer_sender); + drop(template_sender); drop(saistats_reciver); actor_handle.await.unwrap(); + let logs = capture_logs(); + println!("Logs: {}", logs); + // assert_logs(vec![ + // "[DEBUG] Record parsed", + // "[DEBUG] Record parsed", + // "[DEBUG] Record parsed", + // "[DEBUG] Record parsed", + // "[WARN] Wrong length in the records [0, 10, 0, 72]", + // "[WARN] Not support data message [0, 10, 0, 44]", + // ]); } } diff --git a/countersyncd/src/actor/mod.rs b/countersyncd/src/actor/mod.rs index 3a6ddce6f5..fa26a591bd 100644 --- a/countersyncd/src/actor/mod.rs +++ b/countersyncd/src/actor/mod.rs @@ -1,2 +1,3 @@ pub mod netlink; pub mod ipfix; +// pub mod swss; diff --git a/countersyncd/src/actor/swss.rs b/countersyncd/src/actor/swss.rs new file mode 100644 index 0000000000..8a575af505 --- /dev/null +++ b/countersyncd/src/actor/swss.rs @@ -0,0 +1,45 @@ +use swss_common::{SubscriberStateTable, DbConnector}; +use super::super::message::ipfix::IPFixTemplates; + +use tokio::sync::mpsc::Sender; + +const SOCK_PATH: &str = "/var/run/redis/redis.sock"; +const STATE_DB_ID: i32 = 6; +const STATE_STREAM_TELEMETRY_SESSION_TABLE: &str = "STREAM_TELEMETRY_SESSION"; + +pub struct SwssActor { + pub session_table: SubscriberStateTable, + template_recipient: Sender, +} + +impl SwssActor { + pub fn new(template_recipient: Sender) -> Self { + let connect = DbConnector::new_unix(STATE_DB_ID, SOCK_PATH, 0); + let session_table = SubscriberStateTable::new(connect, STATE_STREAM_TELEMETRY_SESSION_TABLE, None, None); + SwssActor { + session_table, + template_recipient, + } + } + + pub async fn run(mut actor: SwssActor) { + loop { + let items = actor.session_table.pops(); + println!("SwssActor: {:?}", items); + } + } +} + +// #[cfg(test)] +// mod test { +// use super::*; + +// use tokio::{spawn, sync::mpsc::channel}; + +// #[tokio::test] +// async fn test_swss() { +// let (template_sender, template_recipient) = channel(1); +// let swss_actor = SwssActor::new(template_sender); +// SwssActor::run(swss_actor).await; +// } +// } diff --git a/countersyncd/src/lib.rs b/countersyncd/src/lib.rs new file mode 100644 index 0000000000..837825ab0c --- /dev/null +++ b/countersyncd/src/lib.rs @@ -0,0 +1 @@ +pub mod test_common; \ No newline at end of file diff --git a/countersyncd/src/test_common.rs b/countersyncd/src/test_common.rs new file mode 100644 index 0000000000..65fe90cb97 --- /dev/null +++ b/countersyncd/src/test_common.rs @@ -0,0 +1,56 @@ +use log::LevelFilter::Debug; +use std::io::Write; +use std::sync::{Arc, Mutex, Once, OnceLock}; + +static INIT_ENV_LOGGER: Once = Once::new(); + +static LOG_BUFFER: OnceLock>>> = OnceLock::new(); + +fn get_log_buffer() -> &'static Arc>> { + LOG_BUFFER.get_or_init(|| Arc::new(Mutex::new(Vec::new()))) +} + +pub fn capture_logs() -> String { + INIT_ENV_LOGGER.call_once(|| { + env_logger::builder() + .is_test(true) + .filter_level(Debug) + .format({ + let buffer = get_log_buffer().clone(); + move |_, record| { + let mut buffer = buffer.lock().unwrap(); + writeln!(buffer, "[{}] {}", record.level(), record.args()).unwrap(); + Ok(()) + } + }) + .init(); + }); + + let buffer = get_log_buffer().lock().unwrap(); + String::from_utf8(buffer.clone()).expect("Log buffer should be valid UTF-8") +} + +pub fn clear_logs() { + let mut buffer = get_log_buffer().lock().unwrap(); + buffer.clear(); +} + +pub fn assert_logs(expected: Vec<&str>) { + let logs_string = capture_logs(); + println!("logs: {}", logs_string); + let mut logs = logs_string.lines().collect::>(); + let mut reverse_expected = expected.clone(); + reverse_expected.reverse(); + logs.reverse(); + + let mut match_count = 0; + for line in logs { + if reverse_expected.is_empty() { + break; + } + if line.contains(reverse_expected[match_count]) { + match_count += 1; + } + } + assert_eq!(match_count, expected.len(), "\nexpected logs {}\n, got logs {}\n", expected.join("\n"), logs_string); +} From f24f6aa172722e0ff0420a3e2c13ecc74dad310e Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Sun, 13 Apr 2025 07:06:27 +0800 Subject: [PATCH 07/11] Update countersyncd Signed-off-by: Ze Gan --- countersyncd/Cargo.lock | 188 ++++++++++++++++---------------- countersyncd/Cargo.toml | 2 +- countersyncd/src/actor/ipfix.rs | 100 ++++++++--------- countersyncd/src/test_common.rs | 7 +- 4 files changed, 147 insertions(+), 150 deletions(-) diff --git a/countersyncd/Cargo.lock b/countersyncd/Cargo.lock index 16707a563e..e8343ab586 100644 --- a/countersyncd/Cargo.lock +++ b/countersyncd/Cargo.lock @@ -80,11 +80,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -132,7 +133,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] @@ -185,15 +186,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -203,15 +204,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.1.37" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -244,9 +245,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", @@ -254,9 +255,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", @@ -269,21 +270,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "color-eyre" @@ -341,9 +342,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -434,7 +435,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] @@ -468,12 +469,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -505,14 +506,14 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" +checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] @@ -523,9 +524,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "heck" @@ -533,12 +534,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "humantime" version = "2.1.0" @@ -595,9 +590,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "lazy_static" @@ -607,9 +602,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -629,9 +624,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" @@ -645,9 +640,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -672,11 +667,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", @@ -685,7 +679,7 @@ dependencies = [ [[package]] name = "neli" version = "0.7.0-rc2" -source = "git+https://github.com/jbaublitz/neli.git?branch=v0.7.0-rc2#382ae669f699fdbb914cd72c58bfb49b31ed3e07" +source = "git+https://github.com/jbaublitz/neli.git?tag=neli-v0.7.0-rc2#73528ae1fb0b2af177711f1a7c6228349d770dfb" dependencies = [ "bitflags", "byteorder", @@ -700,7 +694,7 @@ dependencies = [ [[package]] name = "neli-proc-macros" version = "0.2.0-rc2" -source = "git+https://github.com/jbaublitz/neli.git?branch=v0.7.0-rc2#382ae669f699fdbb914cd72c58bfb49b31ed3e07" +source = "git+https://github.com/jbaublitz/neli.git?tag=neli-v0.7.0-rc2#73528ae1fb0b2af177711f1a7c6228349d770dfb" dependencies = [ "either", "proc-macro2", @@ -771,9 +765,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "ppv-lite86" @@ -786,12 +780,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] @@ -813,23 +807,23 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -866,9 +860,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] @@ -916,15 +910,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -941,22 +935,22 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] @@ -991,9 +985,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1014,7 +1008,7 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "swss-common" version = "0.1.0" -source = "git+https://github.com/sonic-net/sonic-dash-ha.git?branch=master#521082b95b9f5b0acf93b272bf49a11222e7b259" +source = "git+https://github.com/sonic-net/sonic-dash-ha.git?branch=master#8cbbbbc6552c09ac0d81c2d93914ef2fa1b2d32b" dependencies = [ "bindgen", "libc", @@ -1033,9 +1027,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -1044,9 +1038,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -1064,9 +1058,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.41.1" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -1082,20 +1076,20 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -1103,9 +1097,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -1113,9 +1107,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -1123,9 +1117,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "sharded-slab", "thread_local", @@ -1134,15 +1128,15 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -1158,9 +1152,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version_check" @@ -1283,5 +1277,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.96", ] diff --git a/countersyncd/Cargo.toml b/countersyncd/Cargo.toml index eb44da4287..0ad759f3a4 100644 --- a/countersyncd/Cargo.toml +++ b/countersyncd/Cargo.toml @@ -11,7 +11,7 @@ tokio = { version = "1", features = ["full"] } yaml-rust = "0.4" # Ge-netlink -neli = { git = "https://github.com/jbaublitz/neli.git", branch = "v0.7.0-rc2" } +neli = { git = "https://github.com/jbaublitz/neli.git", tag = "neli-v0.7.0-rc2" } # IPFIX parser ipfix = "0.1.1" diff --git a/countersyncd/src/actor/ipfix.rs b/countersyncd/src/actor/ipfix.rs index 0ddd571ffe..3c262ec1c3 100644 --- a/countersyncd/src/actor/ipfix.rs +++ b/countersyncd/src/actor/ipfix.rs @@ -112,7 +112,7 @@ impl IpfixActor { self.insert_temporary_template(&msg_key, new_templates); read_size += len as usize; } - debug!("Template {:?} consumed", templates); + debug!("Template handle {:?}", templates); } fn handle_record(&mut self, records: SocketBufferMessage) -> Vec { @@ -174,7 +174,7 @@ impl IpfixActor { } } messages.push(saistats.clone()); - debug!("Record parsed"); + debug!("Record parsed {:?}", saistats); } read_size += len as usize; } @@ -247,6 +247,7 @@ mod test { #[tokio::test] async fn test_ipfix() { + capture_logs(); let (buffer_sender, buffer_reciver) = channel(1); let (template_sender, template_reciver) = channel(1); let (saistats_sender, mut saistats_reciver) = channel(100); @@ -280,6 +281,44 @@ mod test { 0x80, 0x03, 0x80, 0x04, // line 10 Enterprise Number 128, Field ID 2 ]; + template_sender + .send((String::from(""), Arc::new(Vec::from(template_bytes)))) + .await + .unwrap(); + + // Wait for the template to be processed + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + let invalid_len_record: [u8; 20] = [ + 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x02, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x01, 0x00, 0x00, 0x1C, // line 4 Record 1 + ]; + buffer_sender + .send(Arc::new(Vec::from(invalid_len_record))) + .await + .unwrap(); + + let unknown_record: [u8; 44] = [ + 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 1 + 0x00, 0x00, 0x00, 0x00, // line 1 + 0x00, 0x00, 0x00, 0x02, // line 2 + 0x00, 0x00, 0x00, 0x00, // line 3 + 0x03, 0x00, 0x00, 0x1C, // line 4 Record 1 + 0x00, 0x00, 0x00, 0x00, // line 5 + 0x00, 0x00, 0x00, 0x01, // line 6 + 0x00, 0x00, 0x00, 0x00, // line 7 + 0x00, 0x00, 0x00, 0x01, // line 8 + 0x00, 0x00, 0x00, 0x00, // line 9 + 0x00, 0x00, 0x00, 0x01, // line 10 + ]; + buffer_sender + .send(Arc::new(Vec::from(unknown_record))) + .await + .unwrap(); + // contains data sets for templates 999, 500, 999 let valid_records_bytes: [u8; 144] = [ 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 @@ -320,49 +359,11 @@ mod test { 0x00, 0x00, 0x00, 0x07, // line 35 ]; - template_sender - .send((String::from(""), Arc::new(Vec::from(template_bytes)))) - .await - .unwrap(); - - // Wait for the template to be processed - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - buffer_sender .send(Arc::new(Vec::from(valid_records_bytes))) .await .unwrap(); - let invalid_len_record: [u8; 20] = [ - 0x00, 0x0A, 0x00, 0x48, // line 0 Packet 1 - 0x00, 0x00, 0x00, 0x00, // line 1 - 0x00, 0x00, 0x00, 0x02, // line 2 - 0x00, 0x00, 0x00, 0x00, // line 3 - 0x01, 0x00, 0x00, 0x1C, // line 4 Record 1 - ]; - buffer_sender - .send(Arc::new(Vec::from(invalid_len_record))) - .await - .unwrap(); - - let unknown_record: [u8; 44] = [ - 0x00, 0x0A, 0x00, 0x2C, // line 0 Packet 1 - 0x00, 0x00, 0x00, 0x00, // line 1 - 0x00, 0x00, 0x00, 0x02, // line 2 - 0x00, 0x00, 0x00, 0x00, // line 3 - 0x03, 0x00, 0x00, 0x1C, // line 4 Record 1 - 0x00, 0x00, 0x00, 0x00, // line 5 - 0x00, 0x00, 0x00, 0x01, // line 6 - 0x00, 0x00, 0x00, 0x00, // line 7 - 0x00, 0x00, 0x00, 0x01, // line 8 - 0x00, 0x00, 0x00, 0x00, // line 9 - 0x00, 0x00, 0x00, 0x01, // line 10 - ]; - buffer_sender - .send(Arc::new(Vec::from(unknown_record))) - .await - .unwrap(); - let expected_stats = vec![ SAIStats { observation_time: 1, @@ -449,15 +450,14 @@ mod test { drop(saistats_reciver); actor_handle.await.unwrap(); - let logs = capture_logs(); - println!("Logs: {}", logs); - // assert_logs(vec![ - // "[DEBUG] Record parsed", - // "[DEBUG] Record parsed", - // "[DEBUG] Record parsed", - // "[DEBUG] Record parsed", - // "[WARN] Wrong length in the records [0, 10, 0, 72]", - // "[WARN] Not support data message [0, 10, 0, 44]", - // ]); + assert_logs(vec![ + "[DEBUG] Template handle", + "[WARN] Wrong length in the records", + "[WARN] Not support data message", + "[DEBUG] Record parsed", + "[DEBUG] Record parsed", + "[DEBUG] Record parsed", + "[DEBUG] Record parsed", + ]); } } diff --git a/countersyncd/src/test_common.rs b/countersyncd/src/test_common.rs index 65fe90cb97..01887af1e5 100644 --- a/countersyncd/src/test_common.rs +++ b/countersyncd/src/test_common.rs @@ -37,7 +37,6 @@ pub fn clear_logs() { pub fn assert_logs(expected: Vec<&str>) { let logs_string = capture_logs(); - println!("logs: {}", logs_string); let mut logs = logs_string.lines().collect::>(); let mut reverse_expected = expected.clone(); reverse_expected.reverse(); @@ -51,6 +50,10 @@ pub fn assert_logs(expected: Vec<&str>) { if line.contains(reverse_expected[match_count]) { match_count += 1; } + + if match_count == reverse_expected.len() { + break; + } } - assert_eq!(match_count, expected.len(), "\nexpected logs {}\n, got logs {}\n", expected.join("\n"), logs_string); + assert_eq!(match_count, expected.len(), "\nexpected logs \n{}\n, got logs \n{}\n", expected.join("\n"), logs_string); } From f601fd803baf615b731f35abe59d2047cb92633e Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Sun, 13 Apr 2025 07:13:08 +0800 Subject: [PATCH 08/11] Update artifact names and fix download artifact script query filter --- dev/Dockerfile.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/Dockerfile.yml b/dev/Dockerfile.yml index acb0d9054b..92b36c8560 100644 --- a/dev/Dockerfile.yml +++ b/dev/Dockerfile.yml @@ -36,7 +36,7 @@ ARG DEBIAN_VERSION # SWSS COMMON ARG SWSS_COMMON_PROJECT_NAME="Azure.sonic-swss-common" -ARG SWSS_COMMON_ARTIFACT_NAME="sonic-swss-common" +ARG SWSS_COMMON_ARTIFACT_NAME="sonic-swss-common-bookworm" ARG SWSS_COMMON_FILE_PATHS="/libswsscommon_1.0.0_${PLATFORM}.deb /libswsscommon-dev_1.0.0_${PLATFORM}.deb" RUN download_artifact.sh "${SWSS_COMMON_PROJECT_NAME}" "${BRANCH_NAME}" "${SWSS_COMMON_ARTIFACT_NAME}" "${SWSS_COMMON_FILE_PATHS}" @@ -44,7 +44,7 @@ RUN download_artifact.sh "${SWSS_COMMON_PROJECT_NAME}" "${BRANCH_NAME}" "${SWSS_ # SAIREDIS ARG SAIREDIS_PROJECT_NAME="Azure.sonic-sairedis" -ARG SAIREDIS_ARTIFACT_NAME="sonic-sairedis" +ARG SAIREDIS_ARTIFACT_NAME="sonic-sairedis-bookworm" ARG SAIREDIS_FILE_PATHS="\ /libsaivs_1.0.0_${PLATFORM}.deb \ /libsaivs-dev_1.0.0_${PLATFORM}.deb \ From 4f9a8b470d4a96e9d2c569fbf59ff119f43dc13c Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Mon, 14 Apr 2025 02:56:43 +0000 Subject: [PATCH 09/11] Rename Stream Telemetry to High Frequency Telemetry Signed-off-by: Ze Gan --- countersyncd/src/actor/netlink.rs | 6 +- countersyncd/src/actor/swss.rs | 4 +- countersyncd/tests/data/constants.yml | 2 +- orchagent/Makefile.am | 9 +- .../counternameupdater.cpp | 4 +- .../counternameupdater.h | 0 .../high_frequency_telemetry/hftelgroup.cpp | 57 +++ .../high_frequency_telemetry/hftelgroup.h | 29 ++ .../hftelorch.cpp} | 222 ++++++----- .../hftelorch.h} | 28 +- .../hftelprofile.cpp} | 345 ++++++++++-------- .../hftelprofile.h} | 67 ++-- .../hftelutils.cpp} | 16 +- .../hftelutils.h} | 12 +- orchagent/orchdaemon.cpp | 8 +- orchagent/orchdaemon.h | 2 +- tests/mock_tests/Makefile.am | 8 +- 17 files changed, 491 insertions(+), 328 deletions(-) rename orchagent/{stream_telemetry => high_frequency_telemetry}/counternameupdater.cpp (97%) rename orchagent/{stream_telemetry => high_frequency_telemetry}/counternameupdater.h (100%) create mode 100644 orchagent/high_frequency_telemetry/hftelgroup.cpp create mode 100644 orchagent/high_frequency_telemetry/hftelgroup.h rename orchagent/{stream_telemetry/stelorch.cpp => high_frequency_telemetry/hftelorch.cpp} (69%) rename orchagent/{stream_telemetry/stelorch.h => high_frequency_telemetry/hftelorch.h} (70%) rename orchagent/{stream_telemetry/stelmgr.cpp => high_frequency_telemetry/hftelprofile.cpp} (67%) rename orchagent/{stream_telemetry/stelmgr.h => high_frequency_telemetry/hftelprofile.h} (73%) rename orchagent/{stream_telemetry/stelutils.cpp => high_frequency_telemetry/hftelutils.cpp} (87%) rename orchagent/{stream_telemetry/stelutils.h => high_frequency_telemetry/hftelutils.h} (87%) diff --git a/countersyncd/src/actor/netlink.rs b/countersyncd/src/actor/netlink.rs index 461ebfe7bb..1f4e8b2fd3 100644 --- a/countersyncd/src/actor/netlink.rs +++ b/countersyncd/src/actor/netlink.rs @@ -226,10 +226,10 @@ pub fn get_genl_family_group() -> (String, String) { fd.read_to_string(&mut yaml_str).unwrap(); let constants = &YamlLoader::load_from_str(&yaml_str).unwrap()[0]; - let stream_telemetry = &constants["constants"]["stream_telemetry"]; + let high_frequency_telemetry = &constants["constants"]["high_frequency_telemetry"]; ( - stream_telemetry["genl_family"].as_str().unwrap().to_string(), - stream_telemetry["genl_multicast_group"].as_str().unwrap().to_string() + high_frequency_telemetry["genl_family"].as_str().unwrap().to_string(), + high_frequency_telemetry["genl_multicast_group"].as_str().unwrap().to_string() ) } diff --git a/countersyncd/src/actor/swss.rs b/countersyncd/src/actor/swss.rs index 8a575af505..a7cf3357ad 100644 --- a/countersyncd/src/actor/swss.rs +++ b/countersyncd/src/actor/swss.rs @@ -5,7 +5,7 @@ use tokio::sync::mpsc::Sender; const SOCK_PATH: &str = "/var/run/redis/redis.sock"; const STATE_DB_ID: i32 = 6; -const STATE_STREAM_TELEMETRY_SESSION_TABLE: &str = "STREAM_TELEMETRY_SESSION"; +const STATE_HIGH_FREQUENCY_TELEMETRY_SESSION_TABLE: &str = "HIGH_FREQUENCY_TELEMETRY_SESSION"; pub struct SwssActor { pub session_table: SubscriberStateTable, @@ -15,7 +15,7 @@ pub struct SwssActor { impl SwssActor { pub fn new(template_recipient: Sender) -> Self { let connect = DbConnector::new_unix(STATE_DB_ID, SOCK_PATH, 0); - let session_table = SubscriberStateTable::new(connect, STATE_STREAM_TELEMETRY_SESSION_TABLE, None, None); + let session_table = SubscriberStateTable::new(connect, STATE_HIGH_FREQUENCY_TELEMETRY_SESSION_TABLE, None, None); SwssActor { session_table, template_recipient, diff --git a/countersyncd/tests/data/constants.yml b/countersyncd/tests/data/constants.yml index e3b35b506f..78fba94ac7 100644 --- a/countersyncd/tests/data/constants.yml +++ b/countersyncd/tests/data/constants.yml @@ -1,4 +1,4 @@ constants: - stream_telemetry: + high_frequency_telemetry: genl_family: "sonic_stel" genl_multicast_group: "ipfix" diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 8d525f5886..0c6516899d 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -118,10 +118,11 @@ orchagent_SOURCES = \ dash/pbutils.cpp \ twamporch.cpp \ stporch.cpp \ - stream_telemetry/stelorch.cpp \ - stream_telemetry/stelmgr.cpp \ - stream_telemetry/counternameupdater.cpp \ - stream_telemetry/stelutils.cpp + high_frequency_telemetry/hftelorch.cpp \ + high_frequency_telemetry/hftelprofile.cpp \ + high_frequency_telemetry/counternameupdater.cpp \ + high_frequency_telemetry/hftelutils.cpp \ + high_frequency_telemetry/hftelgroup.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp flex_counter/flow_counter_handler.cpp flex_counter/flowcounterrouteorch.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/stream_telemetry/counternameupdater.cpp b/orchagent/high_frequency_telemetry/counternameupdater.cpp similarity index 97% rename from orchagent/stream_telemetry/counternameupdater.cpp rename to orchagent/high_frequency_telemetry/counternameupdater.cpp index 12aaa5e5f2..6d752aebc6 100644 --- a/orchagent/stream_telemetry/counternameupdater.cpp +++ b/orchagent/high_frequency_telemetry/counternameupdater.cpp @@ -1,10 +1,10 @@ #include "counternameupdater.h" -#include "stelorch.h" +#include "hftelorch.h" #include #include -extern STelOrch *gSTelOrch; +extern HFTelOrch *gSTelOrch; CounterNameMapUpdater::CounterNameMapUpdater(const std::string &db_name, const std::string &table_name) : m_db_name(db_name), diff --git a/orchagent/stream_telemetry/counternameupdater.h b/orchagent/high_frequency_telemetry/counternameupdater.h similarity index 100% rename from orchagent/stream_telemetry/counternameupdater.h rename to orchagent/high_frequency_telemetry/counternameupdater.h diff --git a/orchagent/high_frequency_telemetry/hftelgroup.cpp b/orchagent/high_frequency_telemetry/hftelgroup.cpp new file mode 100644 index 0000000000..4d8225f868 --- /dev/null +++ b/orchagent/high_frequency_telemetry/hftelgroup.cpp @@ -0,0 +1,57 @@ +#include "hftelgroup.h" +#include "hftelutils.h" + +#include + +using namespace std; + +HFTelGroup::HFTelGroup(const string &group_name) : m_group_name(group_name), + m_objects_ref(m_objects), + m_stats_ids_ref(m_stats_ids) +{ +} + +void HFTelGroup::updateObjects(const set &object_names) +{ + SWSS_LOG_ENTER(); + + m_objects.clear(); + sai_uint16_t lable = 1; + for (auto &name : object_names) + { + m_objects[name] = lable++; + } +} + +void HFTelGroup::updateStatsIDs(const std::set &stats_ids) +{ + SWSS_LOG_ENTER(); + + m_stats_ids = move(stats_ids); +} + +bool HFTelGroup::isSameObjects(const std::set &object_names) const +{ + SWSS_LOG_ENTER(); + + if (m_objects.size() == object_names.size()) + { + for (const auto &name : object_names) + { + if (m_objects.find(name) == m_objects.end()) + { + return false; + } + } + return true; + } + + return false; +} + +bool HFTelGroup::isObjectInGroup(const string &object_name) const +{ + SWSS_LOG_ENTER(); + + return m_objects.find(object_name) != m_objects.end(); +} diff --git a/orchagent/high_frequency_telemetry/hftelgroup.h b/orchagent/high_frequency_telemetry/hftelgroup.h new file mode 100644 index 0000000000..93200c41f8 --- /dev/null +++ b/orchagent/high_frequency_telemetry/hftelgroup.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include + + +class HFTelGroup +{ +public: + HFTelGroup(const std::string& group_name); + ~HFTelGroup() = default; + void updateObjects(const std::set &object_names); + void updateStatsIDs(const std::set &stats_ids); + bool isSameObjects(const std::set &object_names) const; + bool isObjectInGroup(const std::string &object_name) const; + + private: + std::string m_group_name; + // Object names and label IDs + std::unordered_map m_objects; + std::set m_stats_ids; + +public: + const std::unordered_map& m_objects_ref; + const std::set& m_stats_ids_ref; +}; diff --git a/orchagent/stream_telemetry/stelorch.cpp b/orchagent/high_frequency_telemetry/hftelorch.cpp similarity index 69% rename from orchagent/stream_telemetry/stelorch.cpp rename to orchagent/high_frequency_telemetry/hftelorch.cpp index deece63abd..b2a54969a9 100644 --- a/orchagent/stream_telemetry/stelorch.cpp +++ b/orchagent/high_frequency_telemetry/hftelorch.cpp @@ -1,5 +1,5 @@ -#include "stelorch.h" -#include "stelutils.h" +#include "hftelorch.h" +#include "hftelutils.h" #include #include @@ -9,6 +9,9 @@ #include #include +#include +#include +#include #include @@ -17,7 +20,7 @@ using namespace swss; #define CONSTANTS_FILE "/et/sonic/constants.yml" -const unordered_map STelOrch::SUPPORT_COUNTER_TABLES = { +const unordered_map HFTelOrch::SUPPORT_COUNTER_TABLES = { {COUNTERS_PORT_NAME_MAP, SAI_OBJECT_TYPE_PORT}, {COUNTERS_BUFFER_POOL_NAME_MAP, SAI_OBJECT_TYPE_BUFFER_POOL}, {COUNTERS_QUEUE_NAME_MAP, SAI_OBJECT_TYPE_QUEUE}, @@ -53,12 +56,12 @@ namespace swss } -STelOrch::STelOrch( +HFTelOrch::HFTelOrch( DBConnector *cfg_db, DBConnector *state_db, const vector &tables) : Orch(cfg_db, tables), - m_state_telemetry_session(state_db, STREAM_TELEMETRY_SESSION), + m_state_telemetry_session(state_db, STATE_HIGH_FREQUENCY_TELEMETRY_SESSION_TABLE_NAME), m_asic_db("ASIC_DB", 0), m_sai_hostif_obj(SAI_NULL_OBJECT_ID), m_sai_hostif_trap_group_obj(SAI_NULL_OBJECT_ID), @@ -77,7 +80,7 @@ STelOrch::STelOrch( Orch::addExecutor(notifier); } -STelOrch::~STelOrch() +HFTelOrch::~HFTelOrch() { SWSS_LOG_ENTER(); @@ -88,12 +91,12 @@ STelOrch::~STelOrch() deleteNetlinkChannel(); } -void STelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) +void HFTelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) { SWSS_LOG_ENTER(); - auto itr = STelOrch::SUPPORT_COUNTER_TABLES.find(msg.m_table_name); - if (itr == STelOrch::SUPPORT_COUNTER_TABLES.end()) + auto counter_itr = HFTelOrch::SUPPORT_COUNTER_TABLES.find(msg.m_table_name); + if (counter_itr == HFTelOrch::SUPPORT_COUNTER_TABLES.end()) { SWSS_LOG_WARN("The counter table %s is not supported by stream telemetry", msg.m_table_name); return; @@ -102,47 +105,50 @@ void STelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) // Update the local cache if (msg.m_operation == CounterNameMapUpdater::SET) { - m_counter_name_cache[itr->second][msg.m_set.m_counter_name] = msg.m_set.m_oid; + m_counter_name_cache[counter_itr->second][msg.m_set.m_counter_name] = msg.m_set.m_oid; } else if (msg.m_operation == CounterNameMapUpdater::DEL) { - m_counter_name_cache[itr->second].erase(msg.m_del.m_counter_name); + m_counter_name_cache[counter_itr->second].erase(msg.m_del.m_counter_name); } // Update the profile - auto itr2 = m_type_profile_mapping.find(itr->second); - if (itr2 == m_type_profile_mapping.end()) + auto type_itr = m_type_profile_mapping.find(counter_itr->second); + if (type_itr == m_type_profile_mapping.end()) { return; } - for (auto itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++) + for (auto profile_itr = type_itr->second.begin(); profile_itr != type_itr->second.end(); profile_itr++) { - auto profile = *itr3; + auto profile = *profile_itr; const char *counter_name = msg.m_operation == CounterNameMapUpdater::SET ? msg.m_set.m_counter_name : msg.m_del.m_counter_name; - if (!profile->canBeUpdated(itr->second)) + if (!profile->canBeUpdated(counter_itr->second)) { // TODO: Here is a potential issue, we may need to retry the task. + // Because the Syncd is generating the configuration(template), + // we cannot update the monitor objects at this time. SWSS_LOG_WARN("The profile %s is not ready to be updated, but the object %s want to be updated", profile->getProfileName().c_str(), counter_name); continue; } if (msg.m_operation == CounterNameMapUpdater::SET) { - profile->setObjectSAIID(itr->second, counter_name, msg.m_set.m_oid); + profile->setObjectSAIID(counter_itr->second, counter_name, msg.m_set.m_oid); } else if (msg.m_operation == CounterNameMapUpdater::DEL) { - profile->delObjectSAIID(itr->second, counter_name); + profile->delObjectSAIID(counter_itr->second, counter_name); } else { SWSS_LOG_THROW("Unknown operation type %d", msg.m_operation); } + profile->tryCommitConfig(counter_itr->second); } } -task_process_status STelOrch::profileTableSet(const string &profile_name, const vector &values) +task_process_status HFTelOrch::profileTableSet(const string &profile_name, const vector &values) { SWSS_LOG_ENTER(); auto profile = getProfile(profile_name); @@ -168,50 +174,61 @@ task_process_status STelOrch::profileTableSet(const string &profile_name, const profile->setPollInterval(poll_interval); } - // Map the profile to types - // This profile may be inserted by group table - for (auto type : profile->getObjectTypes()) - { - m_type_profile_mapping[type].insert(profile); - profile->tryCommitConfig(type); - } + // // Map the profile to types + // // This profile may be inserted by group table + // for (auto type : profile->getObjectTypes()) + // { + // m_type_profile_mapping[type].insert(profile); + // profile->tryCommitConfig(type); + // } return task_process_status::task_success; } -task_process_status STelOrch::profileTableDel(const std::string &profile_name) +task_process_status HFTelOrch::profileTableDel(const std::string &profile_name) { SWSS_LOG_ENTER(); - auto itr = m_name_profile_mapping.find(profile_name); - if (itr == m_name_profile_mapping.end()) + auto profile_itr = m_name_profile_mapping.find(profile_name); + if (profile_itr == m_name_profile_mapping.end()) { return task_process_status::task_success; } - if (!itr->second->canBeUpdated()) + if (!profile_itr->second->canBeUpdated()) { return task_process_status::task_need_retry; } - auto profile = itr->second; - for (auto type : profile->getObjectTypes()) + if (!profile_itr->second->isEmpty()) { - profile->tryCommitConfig(type); - m_type_profile_mapping[type].erase(profile); - m_state_telemetry_session.del(profile_name + "|" + STelUtils::sai_type_to_group_name(type)); + return task_process_status::task_need_retry; } - m_name_profile_mapping.erase(itr); + + // auto profile = profile_itr->second; + // for (auto type : profile->getObjectTypes()) + // { + // // TODO: Assume the group table has been deleted, Don't need to commit the config again + // // profile->tryCommitConfig(type); + // m_type_profile_mapping[type].erase(profile); + // m_state_telemetry_session.del(profile_name + "|" + HFTelUtils::sai_type_to_group_name(type)); + // } + m_name_profile_mapping.erase(profile_itr); return task_process_status::task_success; } -task_process_status STelOrch::groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values) +task_process_status HFTelOrch::groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values) { SWSS_LOG_ENTER(); - auto profile = getProfile(profile_name); - auto type = STelUtils::group_name_to_sai_type(group_name); + auto profile = tryGetProfile(profile_name); + if (!profile) + { + return task_process_status::task_need_retry; + } + + auto type = HFTelUtils::group_name_to_sai_type(group_name); if (!profile->canBeUpdated(type)) { @@ -243,20 +260,27 @@ task_process_status STelOrch::groupTableSet(const std::string &profile_name, con return task_process_status::task_success; } -task_process_status STelOrch::groupTableDel(const std::string &profile_name, const std::string &group_name) +task_process_status HFTelOrch::groupTableDel(const std::string &profile_name, const std::string &group_name) { SWSS_LOG_ENTER(); - auto profile = getProfile(profile_name); - auto type = STelUtils::group_name_to_sai_type(group_name); + auto profile = tryGetProfile(profile_name); + + if (!profile) + { + SWSS_LOG_WARN("The profile %s is not found", profile_name.c_str()); + return task_process_status::task_success; + } + + auto type = HFTelUtils::group_name_to_sai_type(group_name); if (!profile->canBeUpdated(type)) { return task_process_status::task_need_retry; } - profile->setObjectSAIID(type, group_name.c_str(), SAI_NULL_OBJECT_ID); - profile->tryCommitConfig(type); + // Assumption: We don't need to update the config if the group is being deleted + // profile->tryCommitConfig(type); m_type_profile_mapping[type].erase(profile); m_state_telemetry_session.del(profile_name + "|" + group_name); @@ -264,7 +288,7 @@ task_process_status STelOrch::groupTableDel(const std::string &profile_name, con return task_process_status::task_success; } -shared_ptr STelOrch::getProfile(const string &profile_name) +shared_ptr HFTelOrch::getProfile(const string &profile_name) { SWSS_LOG_ENTER(); @@ -272,7 +296,7 @@ shared_ptr STelOrch::getProfile(const string &profile_name) { m_name_profile_mapping.emplace( profile_name, - make_shared( + make_shared( profile_name, m_sai_tam_obj, m_sai_tam_collector_obj, @@ -282,7 +306,20 @@ shared_ptr STelOrch::getProfile(const string &profile_name) return m_name_profile_mapping.at(profile_name); } -void STelOrch::doTask(swss::NotificationConsumer &consumer) +std::shared_ptr HFTelOrch::tryGetProfile(const std::string &profile_name) +{ + SWSS_LOG_ENTER(); + + auto itr = m_name_profile_mapping.find(profile_name); + if (itr != m_name_profile_mapping.end()) + { + return itr->second; + } + + return std::shared_ptr(); +} + +void HFTelOrch::doTask(swss::NotificationConsumer &consumer) { SWSS_LOG_ENTER(); @@ -306,7 +343,7 @@ void STelOrch::doTask(swss::NotificationConsumer &consumer) sai_object_id_t tam_tel_type_obj = SAI_NULL_OBJECT_ID; - // sai_deserialize_tam_tel_type_config_ntf(data, tam_tel_type_obj); + sai_deserialize_object_id(data, tam_tel_type_obj); if (tam_tel_type_obj == SAI_NULL_OBJECT_ID) { @@ -317,39 +354,50 @@ void STelOrch::doTask(swss::NotificationConsumer &consumer) for (auto &profile : m_name_profile_mapping) { auto type = profile.second->getObjectType(tam_tel_type_obj); - if (type != SAI_OBJECT_TYPE_NULL) + if (type == SAI_OBJECT_TYPE_NULL) { - profile.second->notifyConfigReady(type); - // TODO: TryCommitConfig once the template has been applied by CounterSyncd in the phase2 - profile.second->tryCommitConfig(type); - // Update state db - vector values; - auto state = profile.second->getTelemetryTypeState(type); - if (state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) - { - values.emplace_back("stream_status", "enable"); - } - else if (state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) - { - values.emplace_back("stream_status", "disable"); - } - else - { - SWSS_LOG_THROW("Unexpected state %d", state); - } - - values.emplace_back("session_type", "ipfix"); + continue; + } - auto templates = profile.second->getTemplates(type); - values.emplace_back("session_config", string(templates.begin(), templates.end())); + // TODO: A potential optimization + // We need to notify Config Ready only when the message of State DB is delivered to the CounterSyncd + profile.second->notifyConfigReady(type); - m_state_telemetry_session.set(profile.first + "|" + STelUtils::sai_type_to_group_name(type), values); - break; + // Update state db + vector values; + auto state = profile.second->getTelemetryTypeState(type); + if (state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) + { + values.emplace_back("stream_status", "enable"); + } + else if (state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + { + values.emplace_back("stream_status", "disable"); + } + else + { + SWSS_LOG_THROW("Unexpected state %d", state); } + + values.emplace_back("object_names", boost::algorithm::join(profile.second->getObjectNames(type), ",")); + auto to_string = boost::adaptors::transformed([](sai_uint16_t n) + { return boost::lexical_cast(n); }); + values.emplace_back("object_ids", boost::algorithm::join(profile.second->getObjectLabels(type) | to_string, ",")); + + values.emplace_back("session_type", "ipfix"); + + auto templates = profile.second->getTemplates(type); + values.emplace_back("session_config", string(templates.begin(), templates.end())); + + m_state_telemetry_session.set(profile.first + "|" + HFTelUtils::sai_type_to_group_name(type), values); + + return; } + + SWSS_LOG_ERROR("The TAM tel type object %s is not found in the profile", sai_serialize_object_id(tam_tel_type_obj).c_str()); } -void STelOrch::doTask(Consumer &consumer) +void HFTelOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -364,7 +412,7 @@ void STelOrch::doTask(Consumer &consumer) string key = kfvKey(t); string op = kfvOp(t); - if (table_name == CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME) + if (table_name == CFG_HIGH_FREQUENCY_TELEMETRY_PROFILE_TABLE_NAME) { if (op == SET_COMMAND) { @@ -379,7 +427,7 @@ void STelOrch::doTask(Consumer &consumer) SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); } } - else if (table_name == CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME) + else if (table_name == CFG_HIGH_FREQUENCY_TELEMETRY_GROUP_TABLE_NAME) { auto tokens = tokenize(key, '|'); if (tokens.size() != 2) @@ -415,7 +463,7 @@ void STelOrch::doTask(Consumer &consumer) } } -void STelOrch::createNetlinkChannel(const string &genl_family, const string &genl_group) +void HFTelOrch::createNetlinkChannel(const string &genl_family, const string &genl_group) { SWSS_LOG_ENTER(); @@ -482,7 +530,7 @@ void STelOrch::createNetlinkChannel(const string &genl_family, const string &gen sai_hostif_api->create_hostif_table_entry(&m_sai_hostif_table_entry_obj, gSwitchId, static_cast(attrs.size()), attrs.data()); } -void STelOrch::deleteNetlinkChannel() +void HFTelOrch::deleteNetlinkChannel() { SWSS_LOG_ENTER(); @@ -508,7 +556,7 @@ void STelOrch::deleteNetlinkChannel() } } -void STelOrch::createTAM() +void HFTelOrch::createTAM() { SWSS_LOG_ENTER(); @@ -534,6 +582,16 @@ void STelOrch::createTAM() // Create TAM collector object attrs.clear(); + attr.id = SAI_TAM_COLLECTOR_ATTR_SRC_IP; + attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + attr.value.ipaddr.addr.ip4 = 0; + attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_DST_IP; + attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + attr.value.ipaddr.addr.ip4 = 0; + attrs.push_back(attr); + attr.id = SAI_TAM_COLLECTOR_ATTR_TRANSPORT; attr.value.oid = m_sai_tam_transport_obj; attrs.push_back(attr); @@ -579,7 +637,7 @@ void STelOrch::createTAM() // Bind the TAM object to switch - STELUTILS_ADD_SAI_OBJECT_LIST( + HFTELUTILS_ADD_SAI_OBJECT_LIST( gSwitchId, SAI_SWITCH_ATTR_TAM_OBJECT_ID, m_sai_tam_obj, @@ -588,14 +646,14 @@ void STelOrch::createTAM() switch); } -void STelOrch::deleteTAM() +void HFTelOrch::deleteTAM() { SWSS_LOG_ENTER(); if (m_sai_tam_obj != SAI_NULL_OBJECT_ID) { // Unbind the TAM object from switch - STELUTILS_DEL_SAI_OBJECT_LIST( + HFTELUTILS_DEL_SAI_OBJECT_LIST( gSwitchId, SAI_SWITCH_ATTR_TAM_OBJECT_ID, m_sai_tam_obj, diff --git a/orchagent/stream_telemetry/stelorch.h b/orchagent/high_frequency_telemetry/hftelorch.h similarity index 70% rename from orchagent/stream_telemetry/stelorch.h rename to orchagent/high_frequency_telemetry/hftelorch.h index 8a1b8b708f..a15884ab61 100644 --- a/orchagent/stream_telemetry/stelorch.h +++ b/orchagent/high_frequency_telemetry/hftelorch.h @@ -10,26 +10,21 @@ #include #include "counternameupdater.h" -#include "stelmgr.h" +#include "hftelprofile.h" -#define CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME "STREAM_TELEMETRY_PROFILE" -#define CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME "STREAM_TELEMETRY_GROUP" -#define STREAM_TELEMETRY_SESSION "STREAM_TELEMETRY_SESSION" -#define SAI_SWITCH_NOTIFICATION_NAME_TAM_TEL_TYPE_CONFIG_CHANGE "tam_tel_type_config_change" - -class STelOrch : public Orch +class HFTelOrch : public Orch { public: - STelOrch( + HFTelOrch( swss::DBConnector *cfg_db, swss::DBConnector *state_db, const std::vector &tables); - ~STelOrch(); - STelOrch(const STelOrch &) = delete; - STelOrch &operator=(const STelOrch &) = delete; - STelOrch(STelOrch &&) = delete; - STelOrch &operator=(STelOrch &&) = delete; + ~HFTelOrch(); + HFTelOrch(const HFTelOrch &) = delete; + HFTelOrch &operator=(const HFTelOrch &) = delete; + HFTelOrch(HFTelOrch &&) = delete; + HFTelOrch &operator=(HFTelOrch &&) = delete; static const std::unordered_map SUPPORT_COUNTER_TABLES; @@ -40,15 +35,16 @@ class STelOrch : public Orch swss::DBConnector m_asic_db; std::shared_ptr m_asic_notification_consumer; - std::unordered_map> m_name_profile_mapping; - std::unordered_map>> m_type_profile_mapping; + std::unordered_map> m_name_profile_mapping; + std::unordered_map>> m_type_profile_mapping; CounterNameCache m_counter_name_cache; task_process_status profileTableSet(const std::string &profile_name, const std::vector &values); task_process_status profileTableDel(const std::string &profile_name); task_process_status groupTableSet(const std::string &profile_name, const std::string &group_name, const std::vector &values); task_process_status groupTableDel(const std::string &profile_name, const std::string &group_name); - std::shared_ptr getProfile(const std::string &profile_name); + std::shared_ptr getProfile(const std::string &profile_name); + std::shared_ptr tryGetProfile(const std::string &profile_name); void doTask(swss::NotificationConsumer &consumer); void doTask(Consumer &consumer); diff --git a/orchagent/stream_telemetry/stelmgr.cpp b/orchagent/high_frequency_telemetry/hftelprofile.cpp similarity index 67% rename from orchagent/stream_telemetry/stelmgr.cpp rename to orchagent/high_frequency_telemetry/hftelprofile.cpp index 1d3abd02ec..d4a825d8c1 100644 --- a/orchagent/stream_telemetry/stelmgr.cpp +++ b/orchagent/high_frequency_telemetry/hftelprofile.cpp @@ -1,9 +1,9 @@ -#include "stelmgr.h" -#include "stelutils.h" +#include "hftelprofile.h" +#include "hftelutils.h" +#include "saihelper.h" #include #include -#include #include #include @@ -15,7 +15,7 @@ using namespace swss; extern sai_object_id_t gSwitchId; extern sai_tam_api_t *sai_tam_api; -STelProfile::STelProfile( +HFTelProfile::HFTelProfile( const string &profile_name, sai_object_id_t sai_tam_obj, sai_object_id_t sai_tam_collector_obj, @@ -41,19 +41,19 @@ STelProfile::STelProfile( initTelemetry(); } -STelProfile::~STelProfile() +HFTelProfile::~HFTelProfile() { SWSS_LOG_ENTER(); } -const string &STelProfile::getProfileName() const +const string &HFTelProfile::getProfileName() const { SWSS_LOG_ENTER(); return m_profile_name; } -void STelProfile::setStreamState(sai_tam_tel_type_state_t state) +void HFTelProfile::setStreamState(sai_tam_tel_type_state_t state) { SWSS_LOG_ENTER(); m_setting_state = state; @@ -64,7 +64,7 @@ void STelProfile::setStreamState(sai_tam_tel_type_state_t state) } } -void STelProfile::setStreamState(sai_object_type_t type, sai_tam_tel_type_state_t state) +void HFTelProfile::setStreamState(sai_object_type_t type, sai_tam_tel_type_state_t state) { SWSS_LOG_ENTER(); @@ -150,8 +150,7 @@ void STelProfile::setStreamState(sai_object_type_t type, sai_tam_tel_type_state_ } sai_attribute_t attr; - // TODO: Update SAI - // attr.id = SAI_TAM_TEL_TYPE_ATTR_STATE; + attr.id = SAI_TAM_TEL_TYPE_ATTR_STATE; attr.value.s32 = state; handleSaiSetStatus( SAI_API_TAM, @@ -165,7 +164,7 @@ void STelProfile::setStreamState(sai_object_type_t type, sai_tam_tel_type_state_ SWSS_LOG_THROW("Invalid state transfer from %d to %d", stats->second, state); } -void STelProfile::notifyConfigReady(sai_object_type_t object_type) +void HFTelProfile::notifyConfigReady(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -179,7 +178,7 @@ void STelProfile::notifyConfigReady(sai_object_type_t object_type) setStreamState(object_type, m_setting_state); } -sai_tam_tel_type_state_t STelProfile::getTelemetryTypeState(sai_object_type_t object_type) const +sai_tam_tel_type_state_t HFTelProfile::getTelemetryTypeState(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); @@ -187,7 +186,7 @@ sai_tam_tel_type_state_t STelProfile::getTelemetryTypeState(sai_object_type_t ob return m_sai_tam_tel_type_states.at(itr->second); } -STelProfile::sai_guard_t STelProfile::getTAMTelTypeGuard(sai_object_id_t tam_tel_type_obj) const +HFTelProfile::sai_guard_t HFTelProfile::getTAMTelTypeGuard(sai_object_id_t tam_tel_type_obj) const { SWSS_LOG_ENTER(); @@ -202,7 +201,7 @@ STelProfile::sai_guard_t STelProfile::getTAMTelTypeGuard(sai_object_id_t tam_tel return sai_guard_t(); } -sai_object_type_t STelProfile::getObjectType(sai_object_id_t tam_tel_type_obj) const +sai_object_type_t HFTelProfile::getObjectType(sai_object_id_t tam_tel_type_obj) const { SWSS_LOG_ENTER(); @@ -221,7 +220,7 @@ sai_object_type_t STelProfile::getObjectType(sai_object_id_t tam_tel_type_obj) c return SAI_OBJECT_TYPE_NULL; } -void STelProfile::setPollInterval(uint32_t poll_interval) +void HFTelProfile::setPollInterval(uint32_t poll_interval) { SWSS_LOG_ENTER(); @@ -242,28 +241,30 @@ void STelProfile::setPollInterval(uint32_t poll_interval) } } -void STelProfile::setObjectNames(const string &group_name, set &&object_names) +void HFTelProfile::setObjectNames(const string &group_name, set &&object_names) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); + sai_object_type_t sai_object_type = HFTelUtils::group_name_to_sai_type(group_name); auto itr = m_groups.lower_bound(sai_object_type); if (itr == m_groups.end() || itr->first != sai_object_type) { - m_groups.insert(itr, {sai_object_type, STelGroup{move(object_names), {}}}); + HFTelGroup group(group_name); + group.updateObjects(object_names); + m_groups.insert(itr, {sai_object_type, move(group)}); } else { - if (itr->second.m_object_names == object_names) + if (itr->second.isSameObjects(object_names)) { return; } - for (const auto &name : itr->second.m_object_names) + for (const auto &obj : itr->second.m_objects_ref) { - delObjectSAIID(sai_object_type, name.c_str()); + delObjectSAIID(sai_object_type, obj.first.c_str()); } - itr->second.m_object_names = move(object_names); + itr->second.updateObjects(object_names); } loadCounterNameCache(sai_object_type); @@ -273,25 +274,27 @@ void STelProfile::setObjectNames(const string &group_name, set &&object_ undeployCounterSubscriptions(sai_object_type); } -void STelProfile::setStatsIDs(const string &group_name, const set &object_counters) +void HFTelProfile::setStatsIDs(const string &group_name, const set &object_counters) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); + sai_object_type_t sai_object_type = HFTelUtils::group_name_to_sai_type(group_name); auto itr = m_groups.lower_bound(sai_object_type); - set stats_ids_set = STelUtils::object_counters_to_stats_ids(group_name, object_counters); + set stats_ids_set = HFTelUtils::object_counters_to_stats_ids(group_name, object_counters); if (itr == m_groups.end() || itr->first != sai_object_type) { - m_groups.insert(itr, {sai_object_type, STelGroup{{}, stats_ids_set}}); + HFTelGroup group(group_name); + group.updateStatsIDs(stats_ids_set); + m_groups.insert(itr, {sai_object_type, move(group)}); } else { - if (itr->second.m_stats_ids == stats_ids_set) + if (itr->second.m_stats_ids_ref == stats_ids_set) { return; } - itr->second.m_stats_ids = move(stats_ids_set); + itr->second.updateStatsIDs(stats_ids_set); } // TODO: In the phase 2, we don't need to stop the stream before update the stats @@ -300,7 +303,7 @@ void STelProfile::setStatsIDs(const string &group_name, const set &objec undeployCounterSubscriptions(sai_object_type); } -void STelProfile::setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id) +void HFTelProfile::setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id) { SWSS_LOG_ENTER(); @@ -324,10 +327,10 @@ void STelProfile::setObjectSAIID(sai_object_type_t object_type, const char *obje setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); // Update the counter subscription - deployCounterSubscriptions(object_type, object_id, STelUtils::get_sai_label(object_name)); + deployCounterSubscriptions(object_type, object_id, HFTelUtils::get_sai_label(object_name)); } -void STelProfile::delObjectSAIID(sai_object_type_t object_type, const char *object_name) +void HFTelProfile::delObjectSAIID(sai_object_type_t object_type, const char *object_name) { SWSS_LOG_ENTER(); @@ -364,7 +367,7 @@ void STelProfile::delObjectSAIID(sai_object_type_t object_type, const char *obje } } -bool STelProfile::canBeUpdated() const +bool HFTelProfile::canBeUpdated() const { SWSS_LOG_ENTER(); @@ -379,7 +382,7 @@ bool STelProfile::canBeUpdated() const return true; } -bool STelProfile::canBeUpdated(sai_object_type_t object_type) const +bool HFTelProfile::canBeUpdated(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); @@ -391,90 +394,130 @@ bool STelProfile::canBeUpdated(sai_object_type_t object_type) const return true; } -const vector &STelProfile::getTemplates(sai_object_type_t object_type) const +bool HFTelProfile::isEmpty() const +{ + SWSS_LOG_ENTER(); + + return m_groups.empty(); +} + +const vector &HFTelProfile::getTemplates(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); return m_sai_tam_tel_type_templates.at(object_type); } -vector STelProfile::getObjectTypes() const +const vector HFTelProfile::getObjectNames(sai_object_type_t object_type) const { - vector types; - types.reserve(m_groups.size()); + SWSS_LOG_ENTER(); - for (const auto &group : m_groups) + vector object_names; + auto group = m_groups.find(object_type); + if (group != m_groups.end()) { - types.push_back(group.first); + object_names.reserve(group->second.m_objects_ref.size()); + transform(group->second.m_objects_ref.begin(), group->second.m_objects_ref.end(), object_names.begin(), + [](const auto &pair) + { return pair.first; }); } - return types; + return object_names; } -void STelProfile::loadGroupFromCfgDB(Table &group_tbl) +const vector HFTelProfile::getObjectLabels(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); - vector keys; - group_tbl.getKeys(keys); - - boost::char_separator key_sep(group_tbl.getTableNameSeparator().c_str()); - for (const auto &key : keys) + vector object_labels; + auto group = m_groups.find(object_type); + if (group != m_groups.end()) { - boost::tokenizer> tokens(key, key_sep); - - auto profile_name = (tokens.begin()); - if (profile_name == tokens.end()) - { - SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); - } - if (*profile_name != m_profile_name) - { - // Not the profile we are interested in - continue; - } - - auto group_name = ++tokens.begin(); - if (group_name == tokens.end()) - { - SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); - } - - vector items; - if (!group_tbl.get(key, items)) - { - SWSS_LOG_WARN("Failed to get the stream telemetry group: %s.", key.c_str()); - continue; - } - - auto names = fvsGetValue(items, "object_names", true); - if (!names || names->empty()) - { - // TODO: If the object names are empty, implicitly select all objects of the group - SWSS_LOG_WARN("No object names in the stream telemetry group: %s", key.c_str()); - continue; - } - - auto counters = fvsGetValue(items, "object_counters", true); - if (!counters || counters->empty()) - { - SWSS_LOG_ERROR("No object counters in the stream telemetry group: %s", key.c_str()); - continue; - } + object_labels.reserve(group->second.m_objects_ref.size()); + transform(group->second.m_objects_ref.begin(), group->second.m_objects_ref.end(), object_labels.begin(), + [](const auto &pair) + { return pair.second; }); + } + return object_labels; +} - vector buffer; - boost::split(buffer, *names, boost::is_any_of(",")); - set object_names(buffer.begin(), buffer.end()); - setObjectNames(*group_name, move(object_names)); +vector HFTelProfile::getObjectTypes() const +{ + vector types; + types.reserve(m_groups.size()); - buffer.clear(); - boost::split(buffer, *counters, boost::is_any_of(",")); - set object_counters(buffer.begin(), buffer.end()); - setStatsIDs(*group_name, object_counters); + for (const auto &group : m_groups) + { + types.push_back(group.first); } + + return types; } -void STelProfile::loadCounterNameCache(sai_object_type_t object_type) +// void HFTelProfile::loadGroupFromCfgDB(Table &group_tbl) +// { +// SWSS_LOG_ENTER(); + +// vector keys; +// group_tbl.getKeys(keys); + +// boost::char_separator key_sep(group_tbl.getTableNameSeparator().c_str()); +// for (const auto &key : keys) +// { +// boost::tokenizer> tokens(key, key_sep); + +// auto profile_name = (tokens.begin()); +// if (profile_name == tokens.end()) +// { +// SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); +// } +// if (*profile_name != m_profile_name) +// { +// // Not the profile we are interested in +// continue; +// } + +// auto group_name = ++tokens.begin(); +// if (group_name == tokens.end()) +// { +// SWSS_LOG_THROW("Invalid key %s in the %s", key.c_str(), group_tbl.getTableName().c_str()); +// } + +// vector items; +// if (!group_tbl.get(key, items)) +// { +// SWSS_LOG_WARN("Failed to get the stream telemetry group: %s.", key.c_str()); +// continue; +// } + +// auto names = fvsGetValue(items, "object_names", true); +// if (!names || names->empty()) +// { +// // TODO: If the object names are empty, implicitly select all objects of the group +// SWSS_LOG_WARN("No object names in the stream telemetry group: %s", key.c_str()); +// continue; +// } + +// auto counters = fvsGetValue(items, "object_counters", true); +// if (!counters || counters->empty()) +// { +// SWSS_LOG_ERROR("No object counters in the stream telemetry group: %s", key.c_str()); +// continue; +// } + +// vector buffer; +// boost::split(buffer, *names, boost::is_any_of(",")); +// set object_names(buffer.begin(), buffer.end()); +// setObjectNames(*group_name, move(object_names)); + +// buffer.clear(); +// boost::split(buffer, *counters, boost::is_any_of(",")); +// set object_counters(buffer.begin(), buffer.end()); +// setStatsIDs(*group_name, object_counters); +// } +// } + +void HFTelProfile::loadCounterNameCache(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -489,55 +532,54 @@ void STelProfile::loadCounterNameCache(sai_object_type_t object_type) return; } const auto &sai_objs = itr->second; - for (const auto &name : group->second.m_object_names) + for (const auto &obj : group->second.m_objects_ref) { - auto obj = sai_objs.find(name); - if (obj != sai_objs.end()) + auto sai_obj = sai_objs.find(obj.first); + if (sai_obj != sai_objs.end()) { - setObjectSAIID(object_type, name.c_str(), obj->second); + setObjectSAIID(object_type, obj.first.c_str(), sai_obj->second); } } } -void STelProfile::tryCommitConfig(sai_object_type_t object_type) +bool HFTelProfile::tryCommitConfig(sai_object_type_t object_type) { SWSS_LOG_ENTER(); if (!canBeUpdated(object_type)) { - return; + return false; } - if (m_setting_state == SAI_TAM_TEL_TYPE_STATE_START_STREAM) + if (m_setting_state == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) { - auto group = m_groups.find(object_type); - if (group == m_groups.end()) - { - return; - } - if (group->second.m_object_names.empty()) - { - // TODO: If the object names are empty, implicitly select all objects of the group - return; - } - if (!isMonitoringObjectReady(object_type)) - { - deployCounterSubscriptions(object_type); - } - setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_START_STREAM); + SWSS_LOG_THROW("Cannot commit the configuration in the state %d", m_setting_state); } - else if (m_setting_state == SAI_TAM_TEL_TYPE_STATE_STOP_STREAM) + + auto group = m_groups.find(object_type); + if (group == m_groups.end()) { - setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); - undeployCounterSubscriptions(object_type); + return false; } - else + if (group->second.m_objects_ref.empty()) { - SWSS_LOG_THROW("Cannot commit the configuration in the state %d", m_setting_state); + // TODO: If the object names are empty, implicitly select all objects of the group + return true; + } + if (!isMonitoringObjectReady(object_type)) + { + deployCounterSubscriptions(object_type); + if (!isMonitoringObjectReady(object_type)) + { + // There are some objects still not ready + return false; + } } + setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG); + return true; } -bool STelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const string &object_name) const +bool HFTelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const string &object_name) const { SWSS_LOG_ENTER(); @@ -546,7 +588,7 @@ bool STelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const str { return false; } - if (group->second.m_object_names.find(object_name) == group->second.m_object_names.end()) + if (!group->second.isObjectInGroup(object_name)) { return false; } @@ -554,20 +596,19 @@ bool STelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const str return false; } -bool STelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const +bool HFTelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); auto group = m_groups.find(object_type); if (group == m_groups.end()) { - SWSS_LOG_THROW("The group for object type %s is not found", sai_serialize_object_type(object_type).c_str()); } auto counters = m_sai_tam_counter_subscription_objs.find(object_type); - if (counters == m_sai_tam_counter_subscription_objs.end() || group->second.m_object_names.size() != counters->second.size()) + if (counters == m_sai_tam_counter_subscription_objs.end() || group->second.m_objects_ref.size() != counters->second.size()) { // The monitoring counters are not ready return false; @@ -576,7 +617,7 @@ bool STelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const return true; } -sai_object_id_t STelProfile::getTAMReportObjID(sai_object_type_t object_type) +sai_object_id_t HFTelProfile::getTAMReportObjID(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -626,7 +667,7 @@ sai_object_id_t STelProfile::getTAMReportObjID(sai_object_type_t object_type) return sai_object; } -sai_object_id_t STelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) +sai_object_id_t HFTelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -684,7 +725,7 @@ sai_object_id_t STelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) new sai_object_id_t(sai_object), [this](sai_object_id_t *p) { - STELUTILS_DEL_SAI_OBJECT_LIST( + HFTELUTILS_DEL_SAI_OBJECT_LIST( *this->m_sai_tam_telemetry_obj, SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST, *p, @@ -699,7 +740,7 @@ sai_object_id_t STelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) })); m_sai_tam_tel_type_states[m_sai_tam_tel_type_objs[object_type]] = SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; - STELUTILS_ADD_SAI_OBJECT_LIST( + HFTELUTILS_ADD_SAI_OBJECT_LIST( *m_sai_tam_telemetry_obj, SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST, sai_object, @@ -710,7 +751,7 @@ sai_object_id_t STelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) return sai_object; } -void STelProfile::initTelemetry() +void HFTelProfile::initTelemetry() { SWSS_LOG_ENTER(); @@ -744,7 +785,7 @@ void STelProfile::initTelemetry() })); } -void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, uint16_t label) +void HFTelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_object_id_t sai_obj, sai_stat_id_t stat_id, uint16_t label) { SWSS_LOG_ENTER(); @@ -761,8 +802,6 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o } } - assert(m_sai_tam_tel_type_obj != SAI_NULL_OBJECT_ID); - attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_TEL_TYPE; attr.value.oid = getTAMTelTypeObjID(object_type); attrs.push_back(attr); @@ -779,10 +818,9 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o attr.value.u64 = static_cast(label); attrs.push_back(attr); - // TODO: Update SAI counter subscription - // attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STATS_MODE; - // attr.value.s32 = get_stats_mode(object_type, stat_id); - // attrs.push_back(attr); + attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STATS_MODE; + attr.value.s32 = HFTelUtils::get_stats_mode(object_type, stat_id); + attrs.push_back(attr); sai_object_id_t counter_id; @@ -806,7 +844,7 @@ void STelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_o })); } -void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type, sai_object_id_t sai_obj, std::uint16_t label) +void HFTelProfile::deployCounterSubscriptions(sai_object_type_t object_type, sai_object_id_t sai_obj, std::uint16_t label) { SWSS_LOG_ENTER(); @@ -817,13 +855,13 @@ void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type, sai_ return; } - for (const auto &stat_id : group->second.m_stats_ids) + for (const auto &stat_id : group->second.m_stats_ids_ref) { deployCounterSubscription(object_type, sai_obj, stat_id, label); } } -void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type) +void HFTelProfile::deployCounterSubscriptions(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -834,21 +872,21 @@ void STelProfile::deployCounterSubscriptions(sai_object_type_t object_type) { return; } - for (const auto &name : group->second.m_object_names) + for (const auto &obj : group->second.m_objects_ref) { - auto itr = m_name_sai_map[object_type].find(name); + auto itr = m_name_sai_map[object_type].find(obj.first); if (itr == m_name_sai_map[object_type].end()) { continue; } - for (const auto &stat_id : group->second.m_stats_ids) + for (const auto &stat_id : group->second.m_stats_ids_ref) { - deployCounterSubscription(object_type, itr->second, stat_id, STelUtils::get_sai_label(name)); + deployCounterSubscription(object_type, itr->second, stat_id, HFTelUtils::get_sai_label(obj.first)); } } } -void STelProfile::undeployCounterSubscriptions(sai_object_type_t object_type) +void HFTelProfile::undeployCounterSubscriptions(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -856,7 +894,7 @@ void STelProfile::undeployCounterSubscriptions(sai_object_type_t object_type) m_sai_tam_counter_subscription_objs.erase(object_type); } -void STelProfile::updateTemplates(sai_object_id_t tam_tel_type_obj) +void HFTelProfile::updateTemplates(sai_object_id_t tam_tel_type_obj) { SWSS_LOG_ENTER(); @@ -877,11 +915,12 @@ void STelProfile::updateTemplates(sai_object_id_t tam_tel_type_obj) { counters_count += item.second.size(); } -#define COUNTER_SIZE (8LLU) -#define IPFIX_TEMPLATE_MAX_SIZE (0xffffLLU) -#define IPFIX_HEADER_SIZE (16LLU) -#define IPFIX_TEMPLATE_METADATA_SIZE (12LLU) -#define IPFIX_TEMPLATE_MAX_STATS_COUNT (((IPFIX_TEMPLATE_MAX_SIZE - IPFIX_HEADER_SIZE - IPFIX_TEMPLATE_METADATA_SIZE) / COUNTER_SIZE) - 1LLU) + + const size_t COUNTER_SIZE (8LLU); + const size_t IPFIX_TEMPLATE_MAX_SIZE (0xffffLLU); + const size_t IPFIX_HEADER_SIZE (16LLU); + const size_t IPFIX_TEMPLATE_METADATA_SIZE (12LLU); + const size_t IPFIX_TEMPLATE_MAX_STATS_COUNT (((IPFIX_TEMPLATE_MAX_SIZE - IPFIX_HEADER_SIZE - IPFIX_TEMPLATE_METADATA_SIZE) / COUNTER_SIZE) - 1LLU); size_t estimated_template_size = (counters_count / IPFIX_TEMPLATE_MAX_STATS_COUNT + 1) * IPFIX_TEMPLATE_MAX_SIZE; vector buffer(estimated_template_size, 0); diff --git a/orchagent/stream_telemetry/stelmgr.h b/orchagent/high_frequency_telemetry/hftelprofile.h similarity index 73% rename from orchagent/stream_telemetry/stelmgr.h rename to orchagent/high_frequency_telemetry/hftelprofile.h index e3b4054b85..01c5d527f3 100644 --- a/orchagent/stream_telemetry/stelmgr.h +++ b/orchagent/high_frequency_telemetry/hftelprofile.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -12,58 +13,31 @@ #include #include -/** - * @brief TAM telemetry type state of state machine - */ -typedef enum _sai_tam_tel_type_state_t -{ - /** - * @brief Telemetry type is stopped - * - * In this stage, the recording stream should be stopped, - * and the configuration should be cleared. - */ - SAI_TAM_TEL_TYPE_STATE_STOP_STREAM, - - /** - * @brief Telemetry type is started - * - * In this stage, the recording stream should be started, - * and the latest configuration should be applied. - */ - SAI_TAM_TEL_TYPE_STATE_START_STREAM, - - /** - * @brief Telemetry type configuration is prepared, - * - * We expect the configuration to be generated in the feature, - * And notify the user by sai_tam_tel_type_config_change_notification_fn - */ - SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG, - -} sai_tam_tel_type_state_t; +#include "hftelgroup.h" + using CounterNameCache = std::unordered_map>; -struct STelGroup -{ - std::set m_object_names; - std::set m_stats_ids; -}; +// struct HFTelGroup +// { +// // Object names and label IDs +// std::unordered_map m_objects; +// std::set m_stats_ids; +// }; -class STelProfile +class HFTelProfile { public: - STelProfile( + HFTelProfile( const std::string &profile_name, sai_object_id_t sai_tam_obj, sai_object_id_t sai_tam_collector_obj, const CounterNameCache &cache); - ~STelProfile(); - STelProfile(const STelProfile &) = delete; - STelProfile &operator=(const STelProfile &) = delete; - STelProfile(STelProfile &&) = delete; - STelProfile &operator=(STelProfile &&) = delete; + ~HFTelProfile(); + HFTelProfile(const HFTelProfile &) = delete; + HFTelProfile &operator=(const HFTelProfile &) = delete; + HFTelProfile(HFTelProfile &&) = delete; + HFTelProfile &operator=(HFTelProfile &&) = delete; using sai_guard_t = std::shared_ptr; @@ -82,20 +56,23 @@ class STelProfile void delObjectSAIID(sai_object_type_t object_type, const char *object_name); bool canBeUpdated() const; bool canBeUpdated(sai_object_type_t object_type) const; + bool isEmpty() const; const std::vector &getTemplates(sai_object_type_t object_type) const; + const std::vector getObjectNames(sai_object_type_t object_type) const; + const std::vector getObjectLabels(sai_object_type_t object_type) const; std::vector getObjectTypes() const; - void loadGroupFromCfgDB(swss::Table &group_tbl); + // void loadGroupFromCfgDB(swss::Table &group_tbl); void loadCounterNameCache(sai_object_type_t object_type); - void tryCommitConfig(sai_object_type_t object_type); + bool tryCommitConfig(sai_object_type_t object_type); private: // Configuration parameters const std::string m_profile_name; sai_tam_tel_type_state_t m_setting_state; std::uint32_t m_poll_interval; - std::map m_groups; + std::map m_groups; // Runtime parameters const CounterNameCache &m_counter_name_cache; diff --git a/orchagent/stream_telemetry/stelutils.cpp b/orchagent/high_frequency_telemetry/hftelutils.cpp similarity index 87% rename from orchagent/stream_telemetry/stelutils.cpp rename to orchagent/high_frequency_telemetry/hftelutils.cpp index 6a2ec470a4..55e1459e20 100644 --- a/orchagent/stream_telemetry/stelutils.cpp +++ b/orchagent/high_frequency_telemetry/hftelutils.cpp @@ -1,4 +1,4 @@ -#include "stelutils.h" +#include "hftelutils.h" #include #include @@ -10,7 +10,7 @@ using namespace std; #define OBJECT_TYPE_PREFIX "SAI_OBJECT_TYPE_" -vector STelUtils::get_sai_object_list( +vector HFTelUtils::get_sai_object_list( sai_object_id_t obj, sai_attr_id_t attr_id, sai_api_t api, @@ -40,7 +40,7 @@ vector STelUtils::get_sai_object_list( return obj_list; } -sai_object_type_t STelUtils::group_name_to_sai_type(const string &group_name) +sai_object_type_t HFTelUtils::group_name_to_sai_type(const string &group_name) { SWSS_LOG_ENTER(); @@ -50,7 +50,7 @@ sai_object_type_t STelUtils::group_name_to_sai_type(const string &group_name) return sai_object_type; } -std::string STelUtils::sai_type_to_group_name(sai_object_type_t object_type) +std::string HFTelUtils::sai_type_to_group_name(sai_object_type_t object_type) { SWSS_LOG_ENTER(); @@ -61,12 +61,12 @@ std::string STelUtils::sai_type_to_group_name(sai_object_type_t object_type) return group_name; } -set STelUtils::object_counters_to_stats_ids( +set HFTelUtils::object_counters_to_stats_ids( const string &group_name, const set &object_counters) { SWSS_LOG_ENTER(); - sai_object_type_t sai_object_type = STelUtils::group_name_to_sai_type(group_name); + sai_object_type_t sai_object_type = HFTelUtils::group_name_to_sai_type(group_name); set stats_ids_set; auto info = sai_metadata_get_object_type_info(sai_object_type); @@ -101,7 +101,7 @@ set STelUtils::object_counters_to_stats_ids( return stats_ids_set; } -sai_stats_mode_t STelUtils::get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id) +sai_stats_mode_t HFTelUtils::get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id) { SWSS_LOG_ENTER(); @@ -136,7 +136,7 @@ sai_stats_mode_t STelUtils::get_stats_mode(sai_object_type_t object_type, sai_st } -uint16_t STelUtils::get_sai_label(const string &object_name) +uint16_t HFTelUtils::get_sai_label(const string &object_name) { SWSS_LOG_ENTER(); uint16_t label = 0; diff --git a/orchagent/stream_telemetry/stelutils.h b/orchagent/high_frequency_telemetry/hftelutils.h similarity index 87% rename from orchagent/stream_telemetry/stelutils.h rename to orchagent/high_frequency_telemetry/hftelutils.h index bf2c8c7f67..e5e905d17b 100644 --- a/orchagent/stream_telemetry/stelutils.h +++ b/orchagent/high_frequency_telemetry/hftelutils.h @@ -9,10 +9,10 @@ #include #include -class STelUtils +class HFTelUtils { public: - STelUtils() = delete; + HFTelUtils() = delete; static std::vector get_sai_object_list( sai_object_id_t obj, @@ -28,10 +28,10 @@ class STelUtils static std::uint16_t get_sai_label(const std::string &object_name); }; -#define STELUTILS_ADD_SAI_OBJECT_LIST(obj, attr_id, inserted_obj, api_type_name, api_name, obj_type_name) \ +#define HFTELUTILS_ADD_SAI_OBJECT_LIST(obj, attr_id, inserted_obj, api_type_name, api_name, obj_type_name) \ { \ sai_attribute_t attr; \ - auto obj_list = STelUtils::get_sai_object_list( \ + auto obj_list = HFTelUtils::get_sai_object_list( \ obj, \ attr_id, \ api_type_name, \ @@ -47,10 +47,10 @@ class STelUtils &attr)); \ } -#define STELUTILS_DEL_SAI_OBJECT_LIST(obj, attr_id, removed_obj, api_type_name, api_name, obj_type_name) \ +#define HFTELUTILS_DEL_SAI_OBJECT_LIST(obj, attr_id, removed_obj, api_type_name, api_name, obj_type_name) \ { \ sai_attribute_t attr; \ - auto obj_list = STelUtils::get_sai_object_list( \ + auto obj_list = HFTelUtils::get_sai_object_list( \ obj, \ attr_id, \ api_type_name, \ diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 9901c3ce1f..2b59e426cb 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -65,7 +65,7 @@ MonitorOrch *gMonitorOrch; TunnelDecapOrch *gTunneldecapOrch; StpOrch *gStpOrch; MuxOrch *gMuxOrch; -STelOrch *gSTelOrch = nullptr; +HFTelOrch *gSTelOrch = nullptr; bool gIsNatSupported = false; event_handle_t g_events_handle; @@ -851,10 +851,10 @@ bool OrchDaemon::init() const vector stel_tables = { - CFG_STREAM_TELEMETRY_PROFILE_TABLE_NAME, - CFG_STREAM_TELEMETRY_GROUP_TABLE_NAME + CFG_HIGH_FREQUENCY_TELEMETRY_PROFILE_TABLE_NAME, + CFG_HIGH_FREQUENCY_TELEMETRY_GROUP_TABLE_NAME }; - gSTelOrch = new STelOrch(m_configDb, m_stateDb, stel_tables); + gSTelOrch = new HFTelOrch(m_configDb, m_stateDb, stel_tables); m_orchList.push_back(gSTelOrch); if (WarmStart::isWarmStart()) diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 293e3b75ca..6a373778c6 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -53,7 +53,7 @@ #include "dash/dashorch.h" #include "dash/dashrouteorch.h" #include "dash/dashvnetorch.h" -#include "stream_telemetry/stelorch.h" +#include "high_frequency_telemetry/hftelorch.h" #include using namespace swss; diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index aa859e7c55..12a44266b9 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -146,7 +146,13 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/dash/pbutils.cpp \ $(top_srcdir)/cfgmgr/coppmgr.cpp \ $(top_srcdir)/orchagent/twamporch.cpp \ - $(top_srcdir)/orchagent/stporch.cpp + $(top_srcdir)/orchagent/stporch.cpp \ + $(top_srcdir)/orchagent/high_frequency_telemetry/hftelorch.cpp \ + $(top_srcdir)/orchagent/high_frequency_telemetry/hftelprofile.cpp \ + $(top_srcdir)/orchagent/high_frequency_telemetry/counternameupdater.cpp \ + $(top_srcdir)/orchagent/high_frequency_telemetry/hftelutils.cpp \ + $(top_srcdir)/orchagent/high_frequency_telemetry/hftelgroup.cpp + tests_SOURCES += $(FLEX_CTR_DIR)/flex_counter_manager.cpp $(FLEX_CTR_DIR)/flex_counter_stat_manager.cpp $(FLEX_CTR_DIR)/flow_counter_handler.cpp $(FLEX_CTR_DIR)/flowcounterrouteorch.cpp tests_SOURCES += $(DEBUG_CTR_DIR)/debug_counter.cpp $(DEBUG_CTR_DIR)/drop_counter.cpp From 1f7c0ee6c6af22e4c07c3dd56a159f7b7c5d61b1 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Wed, 16 Apr 2025 14:13:29 +0000 Subject: [PATCH 10/11] Refactor high frequency telemetry classes and improve logging for counter updates --- .../counternameupdater.h | 5 +- .../high_frequency_telemetry/hftelgroup.cpp | 5 +- .../high_frequency_telemetry/hftelgroup.h | 23 +++- .../high_frequency_telemetry/hftelorch.cpp | 58 +++++++-- .../high_frequency_telemetry/hftelprofile.cpp | 110 +++++++++++------- .../high_frequency_telemetry/hftelprofile.h | 5 +- .../high_frequency_telemetry/hftelutils.cpp | 80 +++++++------ .../high_frequency_telemetry/hftelutils.h | 2 +- orchagent/portsorch.cpp | 9 +- orchagent/portsorch.h | 5 +- 10 files changed, 196 insertions(+), 106 deletions(-) diff --git a/orchagent/high_frequency_telemetry/counternameupdater.h b/orchagent/high_frequency_telemetry/counternameupdater.h index 4801955352..c8128a2671 100644 --- a/orchagent/high_frequency_telemetry/counternameupdater.h +++ b/orchagent/high_frequency_telemetry/counternameupdater.h @@ -42,13 +42,12 @@ class CounterNameMapUpdater CounterNameMapUpdater(const std::string &db_name, const std::string &table_name); ~CounterNameMapUpdater() = default; + void setCounterNameMap(const std::string &counter_name, sai_object_id_t oid); + void delCounterNameMap(const std::string &counter_name); private: std::string m_db_name; std::string m_table_name; swss::DBConnector m_connector; swss::Table m_counters_table; - - void setCounterNameMap(const std::string &counter_name, sai_object_id_t oid); - void delCounterNameMap(const std::string &counter_name); }; diff --git a/orchagent/high_frequency_telemetry/hftelgroup.cpp b/orchagent/high_frequency_telemetry/hftelgroup.cpp index 4d8225f868..ff8bbaa827 100644 --- a/orchagent/high_frequency_telemetry/hftelgroup.cpp +++ b/orchagent/high_frequency_telemetry/hftelgroup.cpp @@ -5,10 +5,9 @@ using namespace std; -HFTelGroup::HFTelGroup(const string &group_name) : m_group_name(group_name), - m_objects_ref(m_objects), - m_stats_ids_ref(m_stats_ids) +HFTelGroup::HFTelGroup(const string &group_name) : m_group_name(group_name) { + SWSS_LOG_ENTER(); } void HFTelGroup::updateObjects(const set &object_names) diff --git a/orchagent/high_frequency_telemetry/hftelgroup.h b/orchagent/high_frequency_telemetry/hftelgroup.h index 93200c41f8..7405ea3105 100644 --- a/orchagent/high_frequency_telemetry/hftelgroup.h +++ b/orchagent/high_frequency_telemetry/hftelgroup.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -10,20 +11,32 @@ class HFTelGroup { public: + HFTelGroup() = delete; HFTelGroup(const std::string& group_name); ~HFTelGroup() = default; void updateObjects(const std::set &object_names); void updateStatsIDs(const std::set &stats_ids); bool isSameObjects(const std::set &object_names) const; bool isObjectInGroup(const std::string &object_name) const; + const std::unordered_map& getObjects() const { return m_objects; } + const std::set& getStatsIDs() const { return m_stats_ids; } + std::pair, std::vector> getObjectNamesAndLabels() const + { + std::vector names; + std::vector labels; + names.reserve(m_objects.size()); + labels.reserve(m_objects.size()); + for (const auto& obj : m_objects) + { + names.push_back(obj.first); + labels.push_back(std::to_string(obj.second)); + } + return {names, labels}; + } - private: +private: std::string m_group_name; // Object names and label IDs std::unordered_map m_objects; std::set m_stats_ids; - -public: - const std::unordered_map& m_objects_ref; - const std::set& m_stats_ids_ref; }; diff --git a/orchagent/high_frequency_telemetry/hftelorch.cpp b/orchagent/high_frequency_telemetry/hftelorch.cpp index b2a54969a9..c03266a2d3 100644 --- a/orchagent/high_frequency_telemetry/hftelorch.cpp +++ b/orchagent/high_frequency_telemetry/hftelorch.cpp @@ -102,6 +102,11 @@ void HFTelOrch::locallyNotify(const CounterNameMapUpdater::Message &msg) return; } + SWSS_LOG_NOTICE("The counter table %s is updated, operation %d, object %s", + msg.m_table_name, + msg.m_operation, + msg.m_operation == CounterNameMapUpdater::SET ? msg.m_set.m_counter_name : msg.m_del.m_counter_name); + // Update the local cache if (msg.m_operation == CounterNameMapUpdater::SET) { @@ -159,17 +164,19 @@ task_process_status HFTelOrch::profileTableSet(const string &profile_name, const } auto value_opt = fvsGetValue(values, "stream_state", true); + string stream_state = "disable"; + sai_tam_tel_type_state_t state = SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; if (value_opt) { - sai_tam_tel_type_state_t state; lexical_convert(*value_opt, state); profile->setStreamState(state); + stream_state = *value_opt; } value_opt = fvsGetValue(values, "poll_interval", true); + uint32_t poll_interval = 0; if (value_opt) { - uint32_t poll_interval; lexical_convert(*value_opt, poll_interval); profile->setPollInterval(poll_interval); } @@ -182,6 +189,11 @@ task_process_status HFTelOrch::profileTableSet(const string &profile_name, const // profile->tryCommitConfig(type); // } + SWSS_LOG_NOTICE("The profile %s is set (stream_state: %s, poll_interval: %u)", + profile_name.c_str(), + state == SAI_TAM_TEL_TYPE_STATE_START_STREAM ? "enable" : "disable", + poll_interval); + return task_process_status::task_success; } @@ -215,6 +227,8 @@ task_process_status HFTelOrch::profileTableDel(const std::string &profile_name) // } m_name_profile_mapping.erase(profile_itr); + SWSS_LOG_NOTICE("The profile %s is deleted", profile_name.c_str()); + return task_process_status::task_success; } @@ -235,20 +249,20 @@ task_process_status HFTelOrch::groupTableSet(const std::string &profile_name, co return task_process_status::task_need_retry; } - auto value_opt = fvsGetValue(values, "object_names", true); - if (value_opt) + auto arg_object_names = fvsGetValue(values, "object_names", true); + if (arg_object_names) { vector buffer; - boost::split(buffer, *value_opt, boost::is_any_of(",")); + boost::split(buffer, *arg_object_names, boost::is_any_of(",")); set object_names(buffer.begin(), buffer.end()); profile->setObjectNames(group_name, move(object_names)); } - value_opt = fvsGetValue(values, "object_counters", true); - if (value_opt) + auto arg_object_counters = fvsGetValue(values, "object_counters", true); + if (arg_object_counters) { vector buffer; - boost::split(buffer, *value_opt, boost::is_any_of(",")); + boost::split(buffer, *arg_object_counters, boost::is_any_of(",")); set object_counters(buffer.begin(), buffer.end()); profile->setStatsIDs(group_name, object_counters); } @@ -257,6 +271,12 @@ task_process_status HFTelOrch::groupTableSet(const std::string &profile_name, co m_type_profile_mapping[type].insert(profile); + SWSS_LOG_NOTICE("The group %s with profile %s is set (object_names: %s, object_counters: %s)", + group_name.c_str(), + profile_name.c_str(), + arg_object_names ? arg_object_names->c_str() : "", + arg_object_counters ? arg_object_counters->c_str() : ""); + return task_process_status::task_success; } @@ -285,6 +305,8 @@ task_process_status HFTelOrch::groupTableDel(const std::string &profile_name, co m_type_profile_mapping[type].erase(profile); m_state_telemetry_session.del(profile_name + "|" + group_name); + SWSS_LOG_NOTICE("The group %s with profile %s is deleted", group_name.c_str(), profile_name.c_str()); + return task_process_status::task_success; } @@ -327,6 +349,12 @@ void HFTelOrch::doTask(swss::NotificationConsumer &consumer) std::string data; std::vector values; + if (&consumer != m_asic_notification_consumer.get()) + { + SWSS_LOG_DEBUG("Is not TAM notification"); + return; + } + consumer.pop(op, data, values); if (&consumer != m_asic_notification_consumer.get()) @@ -379,10 +407,12 @@ void HFTelOrch::doTask(swss::NotificationConsumer &consumer) SWSS_LOG_THROW("Unexpected state %d", state); } - values.emplace_back("object_names", boost::algorithm::join(profile.second->getObjectNames(type), ",")); - auto to_string = boost::adaptors::transformed([](sai_uint16_t n) - { return boost::lexical_cast(n); }); - values.emplace_back("object_ids", boost::algorithm::join(profile.second->getObjectLabels(type) | to_string, ",")); + + // values.emplace_back("object_names", boost::algorithm::join(profile.second->getObjectNames(type), ",")); + // auto to_string = boost::adaptors::transformed([](sai_uint16_t n) + // { return boost::lexical_cast(n); }); + // values.emplace_back("object_ids", boost::algorithm::join(profile.second->getObjectLabels(type) | to_string, ",")); + values.emplace_back("session_type", "ipfix"); @@ -391,6 +421,10 @@ void HFTelOrch::doTask(swss::NotificationConsumer &consumer) m_state_telemetry_session.set(profile.first + "|" + HFTelUtils::sai_type_to_group_name(type), values); + SWSS_LOG_NOTICE("The group %s with profile %s is ready", + HFTelUtils::sai_type_to_group_name(type).c_str(), + profile.first.c_str()); + return; } diff --git a/orchagent/high_frequency_telemetry/hftelprofile.cpp b/orchagent/high_frequency_telemetry/hftelprofile.cpp index d4a825d8c1..d305e43f21 100644 --- a/orchagent/high_frequency_telemetry/hftelprofile.cpp +++ b/orchagent/high_frequency_telemetry/hftelprofile.cpp @@ -183,7 +183,16 @@ sai_tam_tel_type_state_t HFTelProfile::getTelemetryTypeState(sai_object_type_t o SWSS_LOG_ENTER(); auto itr = m_sai_tam_tel_type_objs.find(object_type); - return m_sai_tam_tel_type_states.at(itr->second); + if (itr == m_sai_tam_tel_type_objs.end()) + { + return SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; + } + auto state_itr = m_sai_tam_tel_type_states.find(itr->second); + if (state_itr == m_sai_tam_tel_type_states.end()) + { + return SAI_TAM_TEL_TYPE_STATE_STOP_STREAM; + } + return state_itr->second; } HFTelProfile::sai_guard_t HFTelProfile::getTAMTelTypeGuard(sai_object_id_t tam_tel_type_obj) const @@ -260,7 +269,7 @@ void HFTelProfile::setObjectNames(const string &group_name, set &&object { return; } - for (const auto &obj : itr->second.m_objects_ref) + for (const auto &obj : itr->second.getObjects()) { delObjectSAIID(sai_object_type, obj.first.c_str()); } @@ -271,7 +280,7 @@ void HFTelProfile::setObjectNames(const string &group_name, set &&object // TODO: In the phase 2, we don't need to stop the stream before update the object names setStreamState(sai_object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); - undeployCounterSubscriptions(sai_object_type); + // undeployCounterSubscriptions(sai_object_type); } void HFTelProfile::setStatsIDs(const string &group_name, const set &object_counters) @@ -290,7 +299,7 @@ void HFTelProfile::setStatsIDs(const string &group_name, const set &obje } else { - if (itr->second.m_stats_ids_ref == stats_ids_set) + if (itr->second.getStatsIDs() == stats_ids_set) { return; } @@ -300,7 +309,7 @@ void HFTelProfile::setStatsIDs(const string &group_name, const set &obje // TODO: In the phase 2, we don't need to stop the stream before update the stats setStreamState(sai_object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); - undeployCounterSubscriptions(sai_object_type); + deployCounterSubscriptions(sai_object_type); } void HFTelProfile::setObjectSAIID(sai_object_type_t object_type, const char *object_name, sai_object_id_t object_id) @@ -323,11 +332,13 @@ void HFTelProfile::setObjectSAIID(sai_object_type_t object_type, const char *obj } objs[object_name] = object_id; + SWSS_LOG_DEBUG("Set object %s with ID %s in the name sai map", object_name, sai_serialize_object_id(object_id).c_str()); + // TODO: In the phase 2, we don't need to stop the stream before update the object setStreamState(object_type, SAI_TAM_TEL_TYPE_STATE_STOP_STREAM); // Update the counter subscription - deployCounterSubscriptions(object_type, object_id, HFTelUtils::get_sai_label(object_name)); + deployCounterSubscriptions(object_type, object_id, m_groups.at(object_type).getObjects().at(object_name)); } void HFTelProfile::delObjectSAIID(sai_object_type_t object_type, const char *object_name) @@ -364,6 +375,7 @@ void HFTelProfile::delObjectSAIID(sai_object_type_t object_type, const char *obj if (objs.empty()) { m_name_sai_map.erase(object_type); + SWSS_LOG_DEBUG("Delete object %s from the name sai map", object_name); } } @@ -386,6 +398,7 @@ bool HFTelProfile::canBeUpdated(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); + if (getTelemetryTypeState(object_type) == SAI_TAM_TEL_TYPE_STATE_CREATE_CONFIG) { return false; @@ -408,37 +421,50 @@ const vector &HFTelProfile::getTemplates(sai_object_type_t object_type) return m_sai_tam_tel_type_templates.at(object_type); } -const vector HFTelProfile::getObjectNames(sai_object_type_t object_type) const -{ - SWSS_LOG_ENTER(); +// const vector HFTelProfile::getObjectNames(sai_object_type_t object_type) const +// { +// SWSS_LOG_ENTER(); - vector object_names; - auto group = m_groups.find(object_type); - if (group != m_groups.end()) - { - object_names.reserve(group->second.m_objects_ref.size()); - transform(group->second.m_objects_ref.begin(), group->second.m_objects_ref.end(), object_names.begin(), - [](const auto &pair) - { return pair.first; }); - } +// vector object_names; +// auto group = m_groups.find(object_type); +// if (group != m_groups.end()) +// { +// object_names.reserve(group->second.getObjects().size()); +// transform(group->second.getObjects().begin(), group->second.getObjects().end(), object_names.begin(), +// [](const auto &pair) +// { return pair.first; }); +// } - return object_names; -} +// return object_names; +// } + +// const vector HFTelProfile::getObjectLabels(sai_object_type_t object_type) const +// { +// SWSS_LOG_ENTER(); -const vector HFTelProfile::getObjectLabels(sai_object_type_t object_type) const +// vector object_labels; +// auto group = m_groups.find(object_type); +// if (group != m_groups.end()) +// { +// object_labels.reserve(group->second.getObjects().size()); +// transform(group->second.getObjects().begin(), group->second.getObjects().end(), object_labels.begin(), +// [](const auto &pair) +// { return pair.second; }); +// } +// return object_labels; +// } + +pair, vector> HFTelProfile::getObjectNamesAndLabels(sai_object_type_t object_type) const { SWSS_LOG_ENTER(); - vector object_labels; auto group = m_groups.find(object_type); - if (group != m_groups.end()) + if (group == m_groups.end()) { - object_labels.reserve(group->second.m_objects_ref.size()); - transform(group->second.m_objects_ref.begin(), group->second.m_objects_ref.end(), object_labels.begin(), - [](const auto &pair) - { return pair.second; }); + return {vector(), vector()}; } - return object_labels; + + return group->second.getObjectNamesAndLabels(); } vector HFTelProfile::getObjectTypes() const @@ -532,7 +558,7 @@ void HFTelProfile::loadCounterNameCache(sai_object_type_t object_type) return; } const auto &sai_objs = itr->second; - for (const auto &obj : group->second.m_objects_ref) + for (const auto &obj : group->second.getObjects()) { auto sai_obj = sai_objs.find(obj.first); if (sai_obj != sai_objs.end()) @@ -561,7 +587,7 @@ bool HFTelProfile::tryCommitConfig(sai_object_type_t object_type) { return false; } - if (group->second.m_objects_ref.empty()) + if (group->second.getObjects().empty()) { // TODO: If the object names are empty, implicitly select all objects of the group return true; @@ -593,7 +619,7 @@ bool HFTelProfile::isObjectTypeInProfile(sai_object_type_t object_type, const st return false; } - return false; + return true; } bool HFTelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const @@ -608,7 +634,7 @@ bool HFTelProfile::isMonitoringObjectReady(sai_object_type_t object_type) const auto counters = m_sai_tam_counter_subscription_objs.find(object_type); - if (counters == m_sai_tam_counter_subscription_objs.end() || group->second.m_objects_ref.size() != counters->second.size()) + if (counters == m_sai_tam_counter_subscription_objs.end() || group->second.getObjects().size() != counters->second.size()) { // The monitoring counters are not ready return false; @@ -676,7 +702,6 @@ sai_object_id_t HFTelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) { return *itr->second; } - return sai_object_id_t(); sai_object_id_t sai_object; vector attrs; @@ -704,9 +729,9 @@ sai_object_id_t HFTelProfile::getTAMTelTypeObjID(sai_object_type_t object_type) attr.value.booldata = true; attrs.push_back(attr); - // attr.id = SAI_TAM_TEL_TYPE_ATTR_MODE ; - // attr.value.boolean = SAI_TAM_TEL_TYPE_MODE_SINGLE_TYPE; - // attrs.push_back(attr); + attr.id = SAI_TAM_TEL_TYPE_ATTR_MODE ; + attr.value.s32 = SAI_TAM_TEL_TYPE_MODE_SINGLE_TYPE; + attrs.push_back(attr); attr.id = SAI_TAM_TEL_TYPE_ATTR_REPORT_ID; attr.value.oid = getTAMReportObjID(object_type); @@ -758,12 +783,13 @@ void HFTelProfile::initTelemetry() sai_object_id_t sai_object; vector attrs; sai_attribute_t attr; + sai_object_id_t sai_tam_collector_obj = m_sai_tam_collector_obj; // Create TAM telemetry object sai_object = m_sai_tam_collector_obj; attr.id = SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST; attr.value.objlist.count = 1; - attr.value.objlist.list = &sai_object; + attr.value.objlist.list = &sai_tam_collector_obj; attrs.push_back(attr); handleSaiCreateStatus( @@ -807,7 +833,7 @@ void HFTelProfile::deployCounterSubscription(sai_object_type_t object_type, sai_ attrs.push_back(attr); attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_OBJECT_ID; - attr.value.oid = stat_id; + attr.value.oid = sai_obj; attrs.push_back(attr); attr.id = SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STAT_ID; @@ -855,7 +881,7 @@ void HFTelProfile::deployCounterSubscriptions(sai_object_type_t object_type, sai return; } - for (const auto &stat_id : group->second.m_stats_ids_ref) + for (const auto &stat_id : group->second.getStatsIDs()) { deployCounterSubscription(object_type, sai_obj, stat_id, label); } @@ -872,16 +898,16 @@ void HFTelProfile::deployCounterSubscriptions(sai_object_type_t object_type) { return; } - for (const auto &obj : group->second.m_objects_ref) + for (const auto &obj : group->second.getObjects()) { auto itr = m_name_sai_map[object_type].find(obj.first); if (itr == m_name_sai_map[object_type].end()) { continue; } - for (const auto &stat_id : group->second.m_stats_ids_ref) + for (const auto &stat_id : group->second.getStatsIDs()) { - deployCounterSubscription(object_type, itr->second, stat_id, HFTelUtils::get_sai_label(obj.first)); + deployCounterSubscription(object_type, itr->second, stat_id, obj.second); } } } diff --git a/orchagent/high_frequency_telemetry/hftelprofile.h b/orchagent/high_frequency_telemetry/hftelprofile.h index 01c5d527f3..fdd0478496 100644 --- a/orchagent/high_frequency_telemetry/hftelprofile.h +++ b/orchagent/high_frequency_telemetry/hftelprofile.h @@ -59,8 +59,9 @@ class HFTelProfile bool isEmpty() const; const std::vector &getTemplates(sai_object_type_t object_type) const; - const std::vector getObjectNames(sai_object_type_t object_type) const; - const std::vector getObjectLabels(sai_object_type_t object_type) const; + // const std::vector getObjectNames(sai_object_type_t object_type) const; + // const std::vector getObjectLabels(sai_object_type_t object_type) const; + std::pair, std::vector> getObjectNamesAndLabels(sai_object_type_t object_type) const; std::vector getObjectTypes() const; // void loadGroupFromCfgDB(swss::Table &group_tbl); diff --git a/orchagent/high_frequency_telemetry/hftelutils.cpp b/orchagent/high_frequency_telemetry/hftelutils.cpp index 55e1459e20..b198ba402e 100644 --- a/orchagent/high_frequency_telemetry/hftelutils.cpp +++ b/orchagent/high_frequency_telemetry/hftelutils.cpp @@ -25,12 +25,25 @@ vector HFTelUtils::get_sai_object_list( attr.value.objlist.count = static_cast(obj_list.size()); attr.value.objlist.list = obj_list.data(); - handleSaiGetStatus( - api, - get_attribute_handler( - obj, - 1, - &attr)); + auto status = get_attribute_handler( + obj, + 1, + &attr); + if (status != SAI_STATUS_SUCCESS) + { + // TODO: If it's not implemented, we should disable this feature + if (status == SAI_STATUS_NOT_IMPLEMENTED) + { + attr.value.objlist.count = 0; + } + else + { + SWSS_LOG_THROW("Failed to get the object list for %s: %d", sai_serialize_object_id(obj).c_str(), status); + } + } + // handleSaiGetStatus( + // api, + // status)); assert(attr.value.objlist.count < obj_list.size()); obj_list.erase( @@ -85,10 +98,9 @@ set HFTelUtils::object_counters_to_stats_ids( for (size_t i = 0; i < state_enum->valuescount; i++) { - string state_name = type_prefix + state_enum->valuesnames[i]; - if (object_counters.find(state_name) != object_counters.end()) + if (object_counters.find(state_enum->valuesshortnames[i]) != object_counters.end()) { - SWSS_LOG_DEBUG("Found the object counter %s", state_name.c_str()); + SWSS_LOG_DEBUG("Found the object counter %s", state_enum->valuesshortnames[i]); stats_ids_set.insert(state_enum->values[i]); } } @@ -136,28 +148,28 @@ sai_stats_mode_t HFTelUtils::get_stats_mode(sai_object_type_t object_type, sai_s } -uint16_t HFTelUtils::get_sai_label(const string &object_name) -{ - SWSS_LOG_ENTER(); - uint16_t label = 0; - - if (object_name.rfind("Ethernet", 0) == 0) - { - const static regex re("Ethernet(\\d+)(?:\\|(\\d+))?"); - smatch match; - if (regex_match(object_name, match, re)) - { - label = static_cast(stoi(match[1])); - if (match.size() == 3) - { - label = static_cast(label * 100 + stoi(match[2])); - } - } - } - else - { - SWSS_LOG_THROW("The object %s is not supported", object_name.c_str()); - } - - return label; -} +// uint16_t HFTelUtils::get_sai_label(const string &object_name) +// { +// SWSS_LOG_ENTER(); +// uint16_t label = 0; + +// if (object_name.rfind("Ethernet", 0) == 0) +// { +// const static regex re("Ethernet(\\d+)(?:\\|(\\d+))?"); +// smatch match; +// if (regex_match(object_name, match, re)) +// { +// label = static_cast(stoi(match[1])); +// if (match.size() == 3) +// { +// label = static_cast(label * 100 + stoi(match[2])); +// } +// } +// } +// else +// { +// SWSS_LOG_THROW("The object %s is not supported", object_name.c_str()); +// } + +// return label; +// } diff --git a/orchagent/high_frequency_telemetry/hftelutils.h b/orchagent/high_frequency_telemetry/hftelutils.h index e5e905d17b..0d1815cc52 100644 --- a/orchagent/high_frequency_telemetry/hftelutils.h +++ b/orchagent/high_frequency_telemetry/hftelutils.h @@ -25,7 +25,7 @@ class HFTelUtils const std::string &group_name, const std::set &object_counters); static sai_stats_mode_t get_stats_mode(sai_object_type_t object_type, sai_stat_id_t stat_id); - static std::uint16_t get_sai_label(const std::string &object_name); + // static std::uint16_t get_sai_label(const std::string &object_name); }; #define HFTELUTILS_ADD_SAI_OBJECT_LIST(obj, attr_id, inserted_obj, api_type_name, api_name, obj_type_name) \ diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index a4d779d269..6c8e2fcd7d 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -585,7 +585,8 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector(new DBConnector("COUNTERS_DB", 0)); - m_counterTable = unique_ptr(new Table(m_counter_db.get(), COUNTERS_PORT_NAME_MAP)); + // m_counterTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_PORT_NAME_MAP)); + m_counterNameMapUpdater = unique_ptr(new CounterNameMapUpdater("COUNTERS_DB", COUNTERS_PORT_NAME_MAP)); m_counterSysPortTable = unique_ptr
( new Table(m_counter_db.get(), COUNTERS_SYSTEM_PORT_NAME_MAP)); m_counterLagTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_LAG_NAME_MAP)); @@ -3729,7 +3730,8 @@ bool PortsOrch::initPort(const PortConfig &port) FieldValueTuple tuple(p.m_alias, sai_serialize_object_id(p.m_port_id)); vector fields; fields.push_back(tuple); - m_counterTable->set("", fields); + // m_counterTable->set("", fields); + m_counterNameMapUpdater->setCounterNameMap(p.m_alias, p.m_port_id); // Install a flex counter for this port to track stats auto flex_counters_orch = gDirectory.get(); @@ -3828,7 +3830,8 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) } /* remove port name map from counter table */ - m_counterTable->hdel("", alias); + // m_counterTable->hdel("", alias); + m_counterNameMapUpdater->delCounterNameMap(alias); /* Remove the associated port serdes attribute */ removePortSerdesAttribute(p.m_port_id); diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index b1e2ab71eb..e1739aecce 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -21,6 +21,8 @@ #include "port/porthlpr.h" #include "port/portschema.h" +#include "high_frequency_telemetry/counternameupdater.h" + #define FCS_LEN 4 #define VLAN_TAG_LEN 4 #define MAX_MACSEC_SECTAG_SIZE 32 @@ -257,7 +259,8 @@ class PortsOrch : public Orch, public Subject bool setPortPtTimestampTemplate(const Port& port, sai_port_path_tracing_timestamp_type_t ts_type); private: - unique_ptr
m_counterTable; + unique_ptr m_counterNameMapUpdater; + // unique_ptr
m_counterTable; unique_ptr
m_counterSysPortTable; unique_ptr
m_counterLagTable; unique_ptr
m_portTable; From d05805cd2a3252cd518075a320e2c83d09b4e5c7 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Thu, 17 Apr 2025 22:30:19 +0800 Subject: [PATCH 11/11] Add hft test Signed-off-by: Ze Gan --- test_hft_db.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 test_hft_db.py diff --git a/test_hft_db.py b/test_hft_db.py new file mode 100644 index 0000000000..09b7053cdb --- /dev/null +++ b/test_hft_db.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 + +import unittest +import subprocess +import sys +import shlex +import time + + +def run_cmd(cmd): + args = shlex.split(cmd) + result = subprocess.run(args, capture_output=True, text=True) + if result.returncode != 0: + print(result.stderr, file=sys.stderr) + raise subprocess.CalledProcessError( + result.returncode, cmd, + output=result.stdout, + stderr=result.stderr + ) + return result.stdout.strip() + + +def get_redis_hash(key): + out = run_cmd(f"redis-cli -n 1 --raw HGETALL {shlex.quote(key)}") + items = out.splitlines() + return dict(zip(items[0::2], items[1::2])) + + +def get_redis_hashes(pattern): + keys_out = run_cmd(f"redis-cli -n 1 --raw KEYS {shlex.quote(pattern)}") + keys = keys_out.splitlines() + result = {} + for key in keys: + result[key] = get_redis_hash(key) + return result + + +def create_hft_profile(name:str = "test", status:str="enable", polling_interval:int=300): + run_cmd(f'redis-cli -n 4 hset "HIGH_FREQUENCY_TELEMETRY_PROFILE|{name}" "stream_state" "{status}" "poll_interval" "{polling_interval}"') + + +def create_hft_group(profile_name:str="test", group_name:str="PORT", object_names:str="Ethernet0", object_counters:str="IF_IN_OCTETS"): + run_cmd(f'redis-cli -n 4 hset "HIGH_FREQUENCY_TELEMETRY_GROUP|{profile_name}|{group_name}" "object_names" "{object_names}" "object_counters" "{object_counters}"') + + +def get_asic_db(): + tam_transport = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_TRANSPORT:*") + tam_collector = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_COLLECTOR:*") + tam_tel_type = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_TEL_TYPE:*") + tam_report = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_REPORT:*") + tam = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM:*") + tam_counter_subscription = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_COUNTER_SUBSCRIPTION:*") + tam_telemetry = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_TAM_TELEMETRY:*") + hostif_user_defined_trap = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP:*") + host_trap_group = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP:*") + ports = get_redis_hashes("ASIC_STATE:SAI_OBJECT_TYPE_PORT:*") + return { + "tam_transport": tam_transport, + "tam_collector": tam_collector, + "tam_tel_type": tam_tel_type, + "tam_report": tam_report, + "tam": tam, + "tam_counter_subscription": tam_counter_subscription, + "tam_telemetry": tam_telemetry, + "hostif_user_defined_trap": hostif_user_defined_trap, + "host_trap_group": host_trap_group, + "ports": ports + } + + +class TestCalculator(unittest.TestCase): + def test_simply_hft_one_counter(self): + create_hft_profile() + create_hft_group() + time.sleep(10) + asic_db = get_asic_db() + + assert len(asic_db["tam_transport"]) == 1, "Expected one tam transport" + assert list(asic_db["tam_transport"].values())[0]["SAI_TAM_TRANSPORT_ATTR_TRANSPORT_TYPE"] == "SAI_TAM_TRANSPORT_TYPE_NONE", "Expected tam transport type to be SAI_TAM_TRANSPORT_TYPE_NONE" + + assert len(asic_db["tam_collector"]) == 1, "Expected one tam collector" + assert "ASIC_STATE:SAI_OBJECT_TYPE_TAM_TRANSPORT:" + list(asic_db["tam_collector"].values())[0]["SAI_TAM_COLLECTOR_ATTR_TRANSPORT"] in asic_db["tam_transport"], "Expected tam collector to reference tam transport" + assert list(asic_db["tam_collector"].values())[0]["SAI_TAM_COLLECTOR_ATTR_LOCALHOST"] == "true", "Expected tam collector to be localhost" + assert "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP:" + list(asic_db["tam_collector"].values())[0]["SAI_TAM_COLLECTOR_ATTR_HOSTIF_TRAP"] in asic_db["hostif_user_defined_trap"], "Expected tam collector to reference hostif user defined trap" + + assert len(asic_db["tam_tel_type"]) == 1, "Expected one tam telemetry" + assert list(asic_db["tam_tel_type"].values())[0]["SAI_TAM_TEL_TYPE_ATTR_TAM_TELEMETRY_TYPE"] == "SAI_TAM_TELEMETRY_TYPE_COUNTER_SUBSCRIPTION", "Expected tam telemetry type to be SAI_TAM_TELEMETRY_TYPE_COUNTER_SUBSCRIPTION" + assert list(asic_db["tam_tel_type"].values())[0]["SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_PORT_STATS"] == "true", "Expected tam telemetry to be switch enable port stats" + assert list(asic_db["tam_tel_type"].values())[0]["SAI_TAM_TEL_TYPE_ATTR_MODE"] == "SAI_TAM_TEL_TYPE_MODE_SINGLE_TYPE", "Expected tam telemetry to be mode true" + assert "ASIC_STATE:SAI_OBJECT_TYPE_TAM_REPORT:" + list(asic_db["tam_tel_type"].values())[0]["SAI_TAM_TEL_TYPE_ATTR_REPORT_ID"] in asic_db["tam_report"], "Expected tam telemetry to reference tam report" + + + assert len(asic_db["tam_report"]) == 1, "Expected one tam report" + assert list(asic_db["tam_report"].values())[0]["SAI_TAM_REPORT_ATTR_TYPE"] == "SAI_TAM_REPORT_TYPE_IPFIX", "Expected tam report type to be SAI_TAM_REPORT_TYPE_IPFIX" + assert list(asic_db["tam_report"].values())[0]["SAI_TAM_REPORT_ATTR_REPORT_MODE"] == "SAI_TAM_REPORT_MODE_BULK", "Expected tam report mode to be SAI_TAM_REPORT_MODE_BULK" + assert list(asic_db["tam_report"].values())[0]["SAI_TAM_REPORT_ATTR_TEMPLATE_REPORT_INTERVAL"] == "0", "Expected tam report template report interval to be 0" + assert list(asic_db["tam_report"].values())[0]["SAI_TAM_REPORT_ATTR_REPORT_INTERVAL"] == "300", "Expected tam report report interval to be 300" + + + assert len(asic_db["tam"]) == 1, "Expected one tam" + assert "SAI_TAM_BIND_POINT_TYPE_PORT" in list(asic_db["tam"].values())[0]["SAI_TAM_ATTR_TAM_BIND_POINT_TYPE_LIST"], "Expected tam to have bind point type list" + + assert len(asic_db["tam_counter_subscription"]) == 1, "Expected one tam counter subscription" + assert "ASIC_STATE:SAI_OBJECT_TYPE_TAM_TEL_TYPE:" + list(asic_db["tam_counter_subscription"].values())[0]["SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_TEL_TYPE"] in asic_db["tam_tel_type"], "Expected tam counter subscription to reference tam telemetry" + assert "ASIC_STATE:SAI_OBJECT_TYPE_PORT:" + list(asic_db["tam_counter_subscription"].values())[0]["SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_OBJECT_ID"] in asic_db["ports"], "Expected tam counter subscription to reference port" + assert list(asic_db["tam_counter_subscription"].values())[0]["SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STAT_ID"] == "0", "Expected tam counter subscription stat id to be 0" + # assert list(asic_db["tam_counter_subscription"].values())[0]["SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_LABEL"] == "1", "Expected tam counter subscription label to be 1" + assert list(asic_db["tam_counter_subscription"].values())[0]["SAI_TAM_COUNTER_SUBSCRIPTION_ATTR_STATS_MODE"] == "SAI_STATS_MODE_READ", "Expected tam counter subscription stats mode to be SAI_STATS_MODE_READ" + + assert len(asic_db["tam_telemetry"]) == 1, "Expected one tam telemetry" + assert list(asic_db["tam_telemetry"].values())[0]["SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST"].split(":")[0] == "1", "Expected tam telemetry collector list to be 1" + assert "ASIC_STATE:SAI_OBJECT_TYPE_TAM_COLLECTOR:" + ":".join(list(asic_db["tam_telemetry"].values())[0]["SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST"].split(":")[1:3]) in asic_db["tam_collector"], "Expected tam telemetry to reference tam collector" + assert list(asic_db["tam_telemetry"].values())[0]["SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST"].split(":")[0] == "1", "Expected tam telemetry tam type list to be 1" + assert "ASIC_STATE:SAI_OBJECT_TYPE_TAM_TEL_TYPE:" + ":".join(list(asic_db["tam_telemetry"].values())[0]["SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST"].split(":")[1:3]) in asic_db["tam_tel_type"], "Expected tam telemetry to reference tam telemetry type" + + assert len(asic_db["hostif_user_defined_trap"]) == 1, "Expected one hostif user defined trap" + assert list(asic_db["hostif_user_defined_trap"].values())[0]["SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE"] == "SAI_HOSTIF_USER_DEFINED_TRAP_TYPE_TAM", "Expected hostif user defined trap type to be SAI_HOSTIF_USER_DEFINED_TRAP_TYPE_TAM" + assert "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP:" + list(asic_db["hostif_user_defined_trap"].values())[0]["SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP"] in asic_db["host_trap_group"], "Expected hostif user defined trap to reference host trap group" + + +if __name__ == "__main__": + unittest.main()