summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohit Mayank <mohit.ritanil@gmail.com>2023-11-01 11:13:32 -0700
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>2023-11-01 11:13:32 -0700
commit7fc6f7f7e1bdee0716a49bf2ab4a44e1d3623dc7 (patch)
tree70acf57393024262b716998f709a0ea982058412
parent6b64f9f0c0ac00c4e1b493a2499b26c443b744ce (diff)
Add support for recording ethtool stats (#8204)
Summary: The PR is broken into modular commits, so it might be easier to review the PR commit-by-commit. Commit: [Add crate for reading NIC stats using ethtool](https://github.com/facebookincubator/below/commit/965795c0c1b2675cc22cf781a80f5e06cdbea50a) - Adds the library support to read and parse `ethtool` stats using `ioctl` - Parses some common stats into fields while others are stored as raw stats Commit: [Add model to represent ethtool stats](https://github.com/facebookincubator/below/commit/66dbb26ab612d3f87131aabbbf6bd33112234c90) - Adds the model struct and parsing logic to convert `ethtool` stats into a sub-model in existing `network.interface` model Commit: [Add render configs for ethtool fields](https://github.com/facebookincubator/below/commit/9401fed6922f1c843d1ae0ed3e1949cf37b26fad) - Updates and adds the required commands for dumping new fields and model - Adds the parsing for rendering the new fields and model Commit: [Add ability for printing raw_stats in OpenMetrics format](https://github.com/facebookincubator/below/commit/7d6349efa2d1d72795d3e6a18417384e44113fb2) - Modifies the printing logic of `OpenMetrics` format to handle a map type Pull Request resolved: https://github.com/facebookincubator/below/pull/8204 Reviewed By: brianc118 Differential Revision: D50714625 Pulled By: dschatzberg fbshipit-source-id: 156f3054944d86fe489bd9ca5bfb3023d1e02c26
-rw-r--r--Cargo.toml1
-rw-r--r--below/config/src/lib.rs2
-rw-r--r--below/dump/src/command.rs106
-rw-r--r--below/dump/src/ethtool.rs110
-rw-r--r--below/dump/src/lib.rs39
-rw-r--r--below/dump/src/test.rs160
-rw-r--r--below/ethtool/Cargo.toml15
-rw-r--r--below/ethtool/src/errors.rs34
-rw-r--r--below/ethtool/src/ethtool_sys.rs4866
-rw-r--r--below/ethtool/src/lib.rs134
-rw-r--r--below/ethtool/src/reader.rs325
-rw-r--r--below/ethtool/src/test.rs81
-rw-r--r--below/ethtool/src/types.rs27
-rw-r--r--below/model/Cargo.toml1
-rw-r--r--below/model/src/cgroup.rs6
-rw-r--r--below/model/src/collector.rs14
-rw-r--r--below/model/src/common_field_ids.rs13
-rw-r--r--below/model/src/lib.rs41
-rw-r--r--below/model/src/network.rs474
-rw-r--r--below/model/src/sample.rs1
-rw-r--r--below/model/src/sample_model.rs72
-rw-r--r--below/render/src/default_configs.rs73
-rw-r--r--below/render/src/lib.rs20
-rw-r--r--below/src/main.rs2
24 files changed, 6525 insertions, 92 deletions
diff --git a/Cargo.toml b/Cargo.toml
index bccfccdc..d2aac591 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ members = [
"below/common",
"below/config",
"below/dump",
+ "below/ethtool",
"below/gpu_stats",
"below/model",
"below/procfs",
diff --git a/below/config/src/lib.rs b/below/config/src/lib.rs
index 11cde69e..a713cd25 100644
--- a/below/config/src/lib.rs
+++ b/below/config/src/lib.rs
@@ -45,6 +45,7 @@ pub struct BelowConfig {
pub enable_btrfs_stats: bool,
pub btrfs_samples: u64,
pub btrfs_min_pct: f64,
+ pub enable_ethtool_stats: bool,
}
impl Default for BelowConfig {
@@ -59,6 +60,7 @@ impl Default for BelowConfig {
enable_btrfs_stats: false,
btrfs_samples: btrfs::DEFAULT_SAMPLES,
btrfs_min_pct: btrfs::DEFAULT_MIN_PCT,
+ enable_ethtool_stats: false,
}
}
}
diff --git a/below/dump/src/command.rs b/below/dump/src/command.rs
index 1eba0621..b633e72c 100644
--- a/below/dump/src/command.rs
+++ b/below/dump/src/command.rs
@@ -25,6 +25,7 @@ use model::SingleCgroupModelFieldId;
use model::SingleDiskModelFieldId;
use model::SingleNetModelFieldId;
use model::SingleProcessModelFieldId;
+use model::SingleQueueModelFieldId;
use model::SystemModelFieldId;
use once_cell::sync::Lazy;
use regex::Regex;
@@ -664,11 +665,13 @@ pub enum IfaceAggField {
Rate,
Rx,
Tx,
+ Ethtool,
}
impl AggField<SingleNetModelFieldId> for IfaceAggField {
- fn expand(&self, _detail: bool) -> Vec<SingleNetModelFieldId> {
+ fn expand(&self, detail: bool) -> Vec<SingleNetModelFieldId> {
use model::SingleNetModelFieldId::*;
+
match self {
Self::Rate => vec![
RxBytesPerSec,
@@ -703,6 +706,13 @@ impl AggField<SingleNetModelFieldId> for IfaceAggField {
TxPackets,
TxWindowErrors,
],
+ Self::Ethtool => {
+ let mut fields = vec![TxTimeoutPerSec];
+ if detail {
+ fields.push(RawStats);
+ }
+ fields
+ }
}
}
}
@@ -717,6 +727,7 @@ pub static DEFAULT_IFACE_FIELDS: &[IfaceOptionField] = &[
DumpOptionField::Agg(IfaceAggField::Rate),
DumpOptionField::Agg(IfaceAggField::Rx),
DumpOptionField::Agg(IfaceAggField::Tx),
+ DumpOptionField::Agg(IfaceAggField::Ethtool),
DumpOptionField::Unit(DumpField::Common(CommonField::Timestamp)),
];
@@ -739,7 +750,9 @@ static IFACE_LONG_ABOUT: Lazy<String> = Lazy::new(|| {
* tx: includes [{agg_tx_fields}].
-* --detail: no effect.
+* ethtool: includes [{agg_ethtool_fields}].
+
+* --detail: includes `raw_stats` field.
* --default: includes [{default_fields}].
@@ -763,6 +776,7 @@ $ below dump iface -b "08:30:00" -e "08:30:30" -s interface -F eth* -O json
agg_rate_fields = join(IfaceAggField::Rate.expand(false)),
agg_rx_fields = join(IfaceAggField::Rx.expand(false)),
agg_tx_fields = join(IfaceAggField::Tx.expand(false)),
+ agg_ethtool_fields = join(IfaceAggField::Ethtool.expand(false)),
default_fields = join(DEFAULT_IFACE_FIELDS.to_owned()),
)
});
@@ -941,6 +955,83 @@ $ below dump transport -b "08:30:00" -e "08:30:30" -f tcp udp -O json
)
});
+/// Represents the ethtool queue sub-model of the network model.
+#[derive(
+ Clone,
+ Debug,
+ PartialEq,
+ below_derive::EnumFromStr,
+ below_derive::EnumToString
+)]
+pub enum EthtoolQueueAggField {
+ Queue,
+}
+
+impl AggField<SingleQueueModelFieldId> for EthtoolQueueAggField {
+ fn expand(&self, detail: bool) -> Vec<SingleQueueModelFieldId> {
+ use model::SingleQueueModelFieldId::*;
+ let mut fields = vec![
+ Interface,
+ QueueId,
+ RxBytesPerSec,
+ TxBytesPerSec,
+ RxCountPerSec,
+ TxCountPerSec,
+ TxMissedTx,
+ TxUnmaskInterrupt,
+ ];
+ if detail {
+ fields.push(RawStats);
+ }
+ match self {
+ Self::Queue => fields,
+ }
+ }
+}
+
+pub type EthtoolQueueOptionField = DumpOptionField<SingleQueueModelFieldId, EthtoolQueueAggField>;
+
+pub static DEFAULT_ETHTOOL_QUEUE_FIELDS: &[EthtoolQueueOptionField] = &[
+ DumpOptionField::Unit(DumpField::Common(CommonField::Datetime)),
+ DumpOptionField::Agg(EthtoolQueueAggField::Queue),
+ DumpOptionField::Unit(DumpField::Common(CommonField::Timestamp)),
+];
+
+const ETHTOOL_QUEUE_ABOUT: &str = "Dump network interface queue stats";
+
+/// Generated about message for Ethtool Queue dump so supported fields are up-to-date.
+static ETHTOOL_QUEUE_LONG_ABOUT: Lazy<String> = Lazy::new(|| {
+ format!(
+ r#"{about}
+
+********************** Available fields **********************
+
+{common_fields}, and expanded fields below.
+
+********************** Aggregated fields **********************
+
+* queue: includes [{agg_queue_fields}].
+
+* --detail: includes `raw_stats` field.
+
+* --default: includes [{default_fields}].
+
+* --everything: includes everything (equivalent to --default --detail).
+
+********************** Example Commands **********************
+
+Example:
+
+$ below dump ethtool-queue -b "08:30:00" -e "08:30:30" -O json
+
+"#,
+ about = ETHTOOL_QUEUE_ABOUT,
+ common_fields = join(enum_iterator::all::<CommonField>()),
+ agg_queue_fields = join(EthtoolQueueAggField::Queue.expand(false)),
+ default_fields = join(DEFAULT_ETHTOOL_QUEUE_FIELDS.to_owned()),
+ )
+});
+
make_option! (OutputFormat {
"raw": Raw,
"csv": Csv,
@@ -1113,4 +1204,15 @@ pub enum DumpCommand {
#[clap(long, short, conflicts_with("fields"))]
pattern: Option<String>,
},
+ #[clap(about = ETHTOOL_QUEUE_ABOUT, long_about = ETHTOOL_QUEUE_LONG_ABOUT.as_str())]
+ EthtoolQueue {
+ /// Select which fields to display and in what order.
+ #[clap(short, long, num_args = 1..)]
+ fields: Option<Vec<EthtoolQueueOptionField>>,
+ #[clap(flatten)]
+ opts: GeneralOpt,
+ /// Saved pattern in the dumprc file under [ethtool] section.
+ #[clap(long, short, conflicts_with("fields"))]
+ pattern: Option<String>,
+ },
}
diff --git a/below/dump/src/ethtool.rs b/below/dump/src/ethtool.rs
new file mode 100644
index 00000000..9bf37ad3
--- /dev/null
+++ b/below/dump/src/ethtool.rs
@@ -0,0 +1,110 @@
+use super::*;
+
+pub struct EthtoolQueue {
+ opts: GeneralOpt,
+ fields: Vec<EthtoolQueueField>,
+}
+
+impl EthtoolQueue {
+ pub fn new(opts: &GeneralOpt, fields: Vec<EthtoolQueueField>) -> Self {
+ Self {
+ opts: opts.to_owned(),
+ fields,
+ }
+ }
+}
+
+impl Dumper for EthtoolQueue {
+ fn dump_model(
+ &self,
+ ctx: &CommonFieldContext,
+ model: &model::Model,
+ output: &mut dyn Write,
+ round: &mut usize,
+ comma_flag: bool,
+ ) -> Result<IterExecResult> {
+ let mut queues = Vec::new();
+ for nic in model.network.interfaces.values() {
+ for queue in &nic.queues {
+ queues.push(queue);
+ }
+ }
+
+ // Return if we filtered everything.
+ if queues.is_empty() {
+ return Ok(IterExecResult::Skip);
+ }
+
+ let mut json_output = json!([]);
+
+ queues
+ .into_iter()
+ .map(|queue| {
+ match self.opts.output_format {
+ Some(OutputFormat::Raw) | None => write!(
+ output,
+ "{}",
+ print::dump_raw(
+ &self.fields,
+ ctx,
+ queue,
+ *round,
+ self.opts.repeat_title,
+ self.opts.disable_title,
+ self.opts.raw
+ )
+ )?,
+ Some(OutputFormat::Csv) => write!(
+ output,
+ "{}",
+ print::dump_csv(
+ &self.fields,
+ ctx,
+ queue,
+ *round,
+ self.opts.disable_title,
+ self.opts.raw
+ )
+ )?,
+ Some(OutputFormat::Tsv) => write!(
+ output,
+ "{}",
+ print::dump_tsv(
+ &self.fields,
+ ctx,
+ queue,
+ *round,
+ self.opts.disable_title,
+ self.opts.raw
+ )
+ )?,
+ Some(OutputFormat::KeyVal) => write!(
+ output,
+ "{}",
+ print::dump_kv(&self.fields, ctx, queue, self.opts.raw)
+ )?,
+ Some(OutputFormat::Json) => {
+ let par = print::dump_json(&self.fields, ctx, queue, self.opts.raw);
+ json_output.as_array_mut().unwrap().push(par);
+ }
+ Some(OutputFormat::OpenMetrics) => write!(
+ output,
+ "{}",
+ print::dump_openmetrics(&self.fields, ctx, queue)
+ )?,
+ }
+ *round += 1;
+ Ok(())
+ })
+ .collect::<Result<Vec<_>>>()?;
+
+ match (self.opts.output_format, comma_flag) {
+ (Some(OutputFormat::Json), true) => write!(output, ",{}", json_output)?,
+ (Some(OutputFormat::Json), false) => write!(output, "{}", json_output)?,
+ (Some(OutputFormat::OpenMetrics), _) => (),
+ _ => write!(output, "\n")?,
+ };
+
+ Ok(IterExecResult::Success)
+ }
+}
diff --git a/below/dump/src/lib.rs b/below/dump/src/lib.rs
index 541cc1b8..86f3ac01 100644
--- a/below/dump/src/lib.rs
+++ b/below/dump/src/lib.rs
@@ -46,6 +46,7 @@ pub mod btrfs;
pub mod cgroup;
pub mod command;
pub mod disk;
+pub mod ethtool;
pub mod iface;
pub mod network;
pub mod print;
@@ -115,6 +116,7 @@ pub type NetworkField = DumpField<model::NetworkModelFieldId>;
pub type IfaceField = DumpField<model::SingleNetModelFieldId>;
// Essentially the same as NetworkField
pub type TransportField = DumpField<model::NetworkModelFieldId>;
+pub type EthtoolQueueField = DumpField<model::SingleQueueModelFieldId>;
fn get_advance(
logger: slog::Logger,
@@ -520,5 +522,42 @@ pub fn run(
errs,
)
}
+ DumpCommand::EthtoolQueue {
+ fields,
+ opts,
+ pattern,
+ } => {
+ let (time_begin, time_end, advance) =
+ get_advance(logger, dir, host, port, snapshot, &opts)?;
+ let default = opts.everything || opts.default;
+ let detail = opts.everything || opts.detail;
+ let fields = if let Some(pattern_key) = pattern {
+ parse_pattern(filename, pattern_key, "ethtool_queue")
+ } else {
+ fields
+ };
+ let fields = expand_fields(
+ match fields.as_ref() {
+ Some(fields) if !default => fields,
+ _ => command::DEFAULT_ETHTOOL_QUEUE_FIELDS,
+ },
+ detail,
+ );
+ let ethtool = ethtool::EthtoolQueue::new(&opts, fields);
+ let mut output: Box<dyn Write> = match opts.output.as_ref() {
+ Some(file_path) => Box::new(File::create(file_path)?),
+ None => Box::new(io::stdout()),
+ };
+ dump_timeseries(
+ advance,
+ time_begin,
+ time_end,
+ &ethtool,
+ output.as_mut(),
+ opts.output_format,
+ opts.br,
+ errs,
+ )
+ }
}
}
diff --git a/below/dump/src/test.rs b/below/dump/src/test.rs
index 5fcdd8d7..43e5ba67 100644
--- a/below/dump/src/test.rs
+++ b/below/dump/src/test.rs
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use std::collections::BTreeMap;
+use std::time::Duration;
+
use command::expand_fields;
use command::GeneralOpt;
use command::OutputFormat;
@@ -669,6 +672,8 @@ fn test_dump_iface_titles() {
"TX Heartbeat Errors",
"TX Packets",
"TX Window Errors",
+ "TX Timeout",
+ "Raw Stats",
];
assert_eq!(titles, expected_titles);
}
@@ -895,6 +900,161 @@ fn test_dump_transport_titles() {
}
#[test]
+fn test_queue_titles() {
+ let titles = expand_fields(command::DEFAULT_ETHTOOL_QUEUE_FIELDS, true)
+ .iter()
+ .filter_map(|dump_field| match dump_field {
+ DumpField::Common(_) => None,
+ DumpField::FieldId(field_id) => Some(field_id.to_string()),
+ })
+ .collect::<Vec<_>>();
+ let expected_titles = vec![
+ "interface",
+ "queue_id",
+ "rx_bytes_per_sec",
+ "tx_bytes_per_sec",
+ "rx_count_per_sec",
+ "tx_count_per_sec",
+ "tx_missed_tx",
+ "tx_unmask_interrupt",
+ "raw_stats",
+ ];
+ assert_eq!(titles, expected_titles);
+}
+
+#[test]
+fn test_dump_queue_content() {
+ let eth0_queue_models = vec![
+ model::SingleQueueModel {
+ interface: "eth0".to_string(),
+ queue_id: 0,
+ rx_bytes_per_sec: Some(10),
+ tx_bytes_per_sec: Some(20),
+ rx_count_per_sec: Some(100),
+ tx_count_per_sec: Some(200),
+ tx_missed_tx: Some(50),
+ tx_unmask_interrupt: Some(5),
+ raw_stats: BTreeMap::from([("stat1".to_string(), 1000), ("stat2".to_string(), 2000)]),
+ },
+ model::SingleQueueModel {
+ interface: "eth0".to_string(),
+ queue_id: 1,
+ rx_bytes_per_sec: Some(20),
+ tx_bytes_per_sec: Some(10),
+ rx_count_per_sec: Some(200),
+ tx_count_per_sec: Some(100),
+ tx_missed_tx: Some(5),
+ tx_unmask_interrupt: Some(50),
+ raw_stats: BTreeMap::from([("stat1".to_string(), 2000), ("stat2".to_string(), 1000)]),
+ },
+ ];
+ let lo_queue_models = vec![model::SingleQueueModel {
+ interface: "lo".to_string(),
+ queue_id: 1,
+ rx_bytes_per_sec: Some(20),
+ tx_bytes_per_sec: Some(10),
+ rx_count_per_sec: Some(200),
+ tx_count_per_sec: Some(100),
+ tx_missed_tx: Some(5),
+ tx_unmask_interrupt: Some(50),
+ raw_stats: BTreeMap::from([("stat1".to_string(), 2000), ("stat2".to_string(), 1000)]),
+ }];
+
+ let eth0_model = model::SingleNetModel {
+ interface: "eth0".to_string(),
+ queues: eth0_queue_models.clone(),
+ ..Default::default()
+ };
+ let lo_model = model::SingleNetModel {
+ interface: "lo".to_string(),
+ queues: lo_queue_models.clone(),
+ ..Default::default()
+ };
+ let network = model::NetworkModel {
+ interfaces: BTreeMap::from([
+ ("eth0".to_string(), eth0_model),
+ ("lo".to_string(), lo_model),
+ ]),
+ ..Default::default()
+ };
+ let model = model::Model {
+ time_elapsed: Duration::from_secs(60 * 10),
+ timestamp: SystemTime::now(),
+ system: model::SystemModel::default(),
+ cgroup: model::CgroupModel::default(),
+ process: model::ProcessModel::default(),
+ network,
+ gpu: None,
+ };
+
+ let mut opts: GeneralOpt = Default::default();
+ let fields = command::expand_fields(command::DEFAULT_ETHTOOL_QUEUE_FIELDS, true);
+
+ opts.output_format = Some(OutputFormat::Json);
+ let queue_dumper = ethtool::EthtoolQueue::new(&opts, fields.clone());
+
+ let mut queue_content: Vec<u8> = Vec::new();
+ let mut round = 0;
+ let ctx = CommonFieldContext {
+ timestamp: 0,
+ hostname: "h".to_string(),
+ };
+
+ let result = queue_dumper
+ .dump_model(&ctx, &model, &mut queue_content, &mut round, false)
+ .expect("Failed to dump queue model");
+ assert!(result == tmain::IterExecResult::Success);
+
+ // verify json correctness
+ assert!(!queue_content.is_empty());
+ let jval: Value =
+ serde_json::from_slice(&queue_content).expect("Fail parse json of queue dump");
+
+ let expected_json = json!([
+ {
+ "Datetime": "1969-12-31 16:00:00",
+ "Interface": "eth0",
+ "Queue": "0",
+ "RawStats": "stat1=1000, stat2=2000",
+ "RxBytes": "10 B/s",
+ "RxCount": "100/s",
+ "Timestamp": "0",
+ "TxBytes": "20 B/s",
+ "TxCount": "200/s",
+ "TxMissedTx": "50",
+ "TxUnmaskInterrupt": "5"
+ },
+ {
+ "Datetime": "1969-12-31 16:00:00",
+ "Interface": "eth0",
+ "Queue": "1",
+ "RawStats": "stat1=2000, stat2=1000",
+ "RxBytes": "20 B/s",
+ "RxCount": "200/s",
+ "Timestamp": "0",
+ "TxBytes": "10 B/s",
+ "TxCount": "100/s",
+ "TxMissedTx": "5",
+ "TxUnmaskInterrupt": "50"
+ },
+ {
+ "Datetime": "1969-12-31 16:00:00",
+ "Interface": "lo",
+ "Queue": "1",
+ "RawStats": "stat1=2000, stat2=1000",
+ "RxBytes": "20 B/s",
+ "RxCount": "200/s",
+ "Timestamp": "0",
+ "TxBytes": "10 B/s",
+ "TxCount": "100/s",
+ "TxMissedTx": "5",
+ "TxUnmaskInterrupt": "50"
+ }
+ ]);
+ assert_eq!(jval, expected_json);
+}
+
+#[test]
// Test correctness of disk decoration
// This test will also test JSON correctness.
fn test_dump_disk_content() {
diff --git a/below/ethtool/Cargo.toml b/below/ethtool/Cargo.toml
new file mode 100644
index 00000000..29b68595
--- /dev/null
+++ b/below/ethtool/Cargo.toml
@@ -0,0 +1,15 @@
+# @generated by autocargo
+
+[package]
+name = "below-ethtool"
+version = "0.7.1"
+authors = ["Daniel Xu <dlxu@fb.com>", "Facebook"]
+edition = "2021"
+description = "Model crate for below"
+repository = "https://github.com/facebookincubator/below"
+license = "Apache-2.0"
+
+[dependencies]
+nix = "0.25"
+serde = { version = "1.0.185", features = ["derive", "rc"] }
+thiserror = "1.0.43"
diff --git a/below/ethtool/src/errors.rs b/below/ethtool/src/errors.rs
new file mode 100644
index 00000000..2eee8fb8
--- /dev/null
+++ b/below/ethtool/src/errors.rs
@@ -0,0 +1,34 @@
+use std::alloc;
+
+use nix::errno::Errno;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum EthtoolError {
+ #[error("Failed to open a socket, error={0:}")]
+ SocketError(Errno),
+
+ #[error("Failed to read interface names, error={0:}")]
+ IfNamesReadError(Errno),
+
+ #[error("Failed to initialize struct, error={0:}")]
+ CStructInitError(#[from] alloc::LayoutError),
+
+ #[error("Failed to read data from struct pointer")]
+ CStructReadError(),
+
+ #[error("Failed to read number of stats using ETHTOOL_GSSET_INFO, error={0:}")]
+ GSSetInfoReadError(Errno),
+
+ #[error("Failed to read names of stats using ETHTOOL_GSTRINGS, error={0:}")]
+ GStringsReadError(Errno),
+
+ #[error("Failed to read values of stats using ETHTOOL_GSTATS, error={0:}")]
+ GStatsReadError(Errno),
+
+ #[error("Failed to parse stats, error={0:}")]
+ ParseError(String),
+
+ #[error("Failed to allocate memory")]
+ AllocationFailure(),
+}
diff --git a/below/ethtool/src/ethtool_sys.rs b/below/ethtool/src/ethtool_sys.rs
new file mode 100644
index 00000000..a8e9da8f
--- /dev/null
+++ b/below/ethtool/src/ethtool_sys.rs
@@ -0,0 +1,4866 @@
+/* automatically generated by rust-bindgen 0.68.1 */
+#![allow(dead_code, unused_variables)]
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
+impl<T> __IncompleteArrayField<T> {
+ #[inline]
+ pub const fn new() -> Self {
+ __IncompleteArrayField(::std::marker::PhantomData, [])
+ }
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
+ }
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
+ }
+ #[inline]
+ pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+ ::std::slice::from_raw_parts(self.as_ptr(), len)
+ }
+ #[inline]
+ pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+ ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+ }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ fmt.write_str("__IncompleteArrayField")
+ }
+}
+pub const __BITS_PER_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const ETH_ALEN: u32 = 6;
+pub const ETH_TLEN: u32 = 2;
+pub const ETH_HLEN: u32 = 14;
+pub const ETH_ZLEN: u32 = 60;
+pub const ETH_DATA_LEN: u32 = 1500;
+pub const ETH_FRAME_LEN: u32 = 1514;
+pub const ETH_FCS_LEN: u32 = 4;
+pub const ETH_MIN_MTU: u32 = 68;
+pub const ETH_MAX_MTU: u32 = 65535;
+pub const ETH_P_LOOP: u32 = 96;
+pub const ETH_P_PUP: u32 = 512;
+pub const ETH_P_PUPAT: u32 = 513;
+pub const ETH_P_TSN: u32 = 8944;
+pub const ETH_P_ERSPAN2: u32 = 8939;
+pub const ETH_P_IP: u32 = 2048;
+pub const ETH_P_X25: u32 = 2053;
+pub const ETH_P_ARP: u32 = 2054;
+pub const ETH_P_BPQ: u32 = 2303;
+pub const ETH_P_IEEEPUP: u32 = 2560;
+pub const ETH_P_IEEEPUPAT: u32 = 2561;
+pub const ETH_P_BATMAN: u32 = 17157;
+pub const ETH_P_DEC: u32 = 24576;
+pub const ETH_P_DNA_DL: u32 = 24577;
+pub const ETH_P_DNA_RC: u32 = 24578;
+pub const ETH_P_DNA_RT: u32 = 24579;
+pub const ETH_P_LAT: u32 = 24580;
+pub const ETH_P_DIAG: u32 = 24581;
+pub const ETH_P_CUST: u32 = 24582;
+pub const ETH_P_SCA: u32 = 24583;
+pub const ETH_P_TEB: u32 = 25944;
+pub const ETH_P_RARP: u32 = 32821;
+pub const ETH_P_ATALK: u32 = 32923;
+pub const ETH_P_AARP: u32 = 33011;
+pub const ETH_P_8021Q: u32 = 33024;
+pub const ETH_P_ERSPAN: u32 = 35006;
+pub const ETH_P_IPX: u32 = 33079;
+pub const ETH_P_IPV6: u32 = 34525;
+pub const ETH_P_PAUSE: u32 = 34824;
+pub const ETH_P_SLOW: u32 = 34825;
+pub const ETH_P_WCCP: u32 = 34878;
+pub const ETH_P_MPLS_UC: u32 = 34887;
+pub const ETH_P_MPLS_MC: u32 = 34888;
+pub const ETH_P_ATMMPOA: u32 = 34892;
+pub const ETH_P_PPP_DISC: u32 = 34915;
+pub const ETH_P_PPP_SES: u32 = 34916;
+pub const ETH_P_LINK_CTL: u32 = 34924;
+pub const ETH_P_ATMFATE: u32 = 34948;
+pub const ETH_P_PAE: u32 = 34958;
+pub const ETH_P_AOE: u32 = 34978;
+pub const ETH_P_8021AD: u32 = 34984;
+pub const ETH_P_802_EX1: u32 = 34997;
+pub const ETH_P_PREAUTH: u32 = 35015;
+pub const ETH_P_TIPC: u32 = 35018;
+pub const ETH_P_LLDP: u32 = 35020;
+pub const ETH_P_MRP: u32 = 35043;
+pub const ETH_P_MACSEC: u32 = 35045;
+pub const ETH_P_8021AH: u32 = 35047;
+pub const ETH_P_MVRP: u32 = 35061;
+pub const ETH_P_1588: u32 = 35063;
+pub const ETH_P_NCSI: u32 = 35064;
+pub const ETH_P_PRP: u32 = 35067;
+pub const ETH_P_CFM: u32 = 35074;
+pub const ETH_P_FCOE: u32 = 35078;
+pub const ETH_P_IBOE: u32 = 35093;
+pub const ETH_P_TDLS: u32 = 35085;
+pub const ETH_P_FIP: u32 = 35092;
+pub const ETH_P_80221: u32 = 35095;
+pub const ETH_P_HSR: u32 = 35119;
+pub const ETH_P_NSH: u32 = 35151;
+pub const ETH_P_LOOPBACK: u32 = 36864;
+pub const ETH_P_QINQ1: u32 = 37120;
+pub const ETH_P_QINQ2: u32 = 37376;
+pub const ETH_P_QINQ3: u32 = 37632;
+pub const ETH_P_EDSA: u32 = 56026;
+pub const ETH_P_DSA_8021Q: u32 = 56027;
+pub const ETH_P_IFE: u32 = 60734;
+pub const ETH_P_AF_IUCV: u32 = 64507;
+pub const ETH_P_802_3_MIN: u32 = 1536;
+pub const ETH_P_802_3: u32 = 1;
+pub const ETH_P_AX25: u32 = 2;
+pub const ETH_P_ALL: u32 = 3;
+pub const ETH_P_802_2: u32 = 4;
+pub const ETH_P_SNAP: u32 = 5;
+pub const ETH_P_DDCMP: u32 = 6;
+pub const ETH_P_WAN_PPP: u32 = 7;
+pub const ETH_P_PPP_MP: u32 = 8;
+pub const ETH_P_LOCALTALK: u32 = 9;
+pub const ETH_P_CAN: u32 = 12;
+pub const ETH_P_CANFD: u32 = 13;
+pub const ETH_P_PPPTALK: u32 = 16;
+pub const ETH_P_TR_802_2: u32 = 17;
+pub const ETH_P_MOBITEX: u32 = 21;
+pub const ETH_P_CONTROL: u32 = 22;
+pub const ETH_P_IRDA: u32 = 23;
+pub const ETH_P_ECONET: u32 = 24;
+pub const ETH_P_HDLC: u32 = 25;
+pub const ETH_P_ARCNET: u32 = 26;
+pub const ETH_P_DSA: u32 = 27;
+pub const ETH_P_TRAILER: u32 = 28;
+pub const ETH_P_PHONET: u32 = 245;
+pub const ETH_P_IEEE802154: u32 = 246;
+pub const ETH_P_CAIF: u32 = 247;
+pub const ETH_P_XDSA: u32 = 248;
+pub const ETH_P_MAP: u32 = 249;
+pub const __UAPI_DEF_ETHHDR: u32 = 1;
+pub const _LIBC_LIMITS_H_: u32 = 1;
+pub const _FEATURES_H: u32 = 1;
+pub const _DEFAULT_SOURCE: u32 = 1;
+pub const __USE_ISOC11: u32 = 1;
+pub const __USE_ISOC99: u32 = 1;
+pub const __USE_ISOC95: u32 = 1;
+pub const __USE_POSIX_IMPLICITLY: u32 = 1;
+pub const _POSIX_SOURCE: u32 = 1;
+pub const _POSIX_C_SOURCE: u32 = 200809;
+pub const __USE_POSIX: u32 = 1;
+pub const __USE_POSIX2: u32 = 1;
+pub const __USE_POSIX199309: u32 = 1;
+pub const __USE_POSIX199506: u32 = 1;
+pub const __USE_XOPEN2K: u32 = 1;
+pub const __USE_XOPEN2K8: u32 = 1;
+pub const _ATFILE_SOURCE: u32 = 1;
+pub const __USE_MISC: u32 = 1;
+pub const __USE_ATFILE: u32 = 1;
+pub const __USE_FORTIFY_LEVEL: u32 = 0;
+pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
+pub const _STDC_PREDEF_H: u32 = 1;
+pub const __STDC_IEC_559__: u32 = 1;
+pub const __STDC_IEC_559_COMPLEX__: u32 = 1;
+pub const __STDC_ISO_10646__: u32 = 201706;
+pub const __GNU_LIBRARY__: u32 = 6;
+pub const __GLIBC__: u32 = 2;
+pub const __GLIBC_MINOR__: u32 = 28;
+pub const _SYS_CDEFS_H: u32 = 1;
+pub const __glibc_c99_flexarr_available: u32 = 1;
+pub const __WORDSIZE: u32 = 64;
+pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
+pub const __SYSCALL_WORDSIZE: u32 = 64;
+pub const __HAVE_GENERIC_SELECTION: u32 = 1;
+pub const __GLIBC_USE_LIB_EXT2: u32 = 0;
+pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0;
+pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0;
+pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0;
+pub const MB_LEN_MAX: u32 = 16;
+pub const _BITS_POSIX1_LIM_H: u32 = 1;
+pub const _POSIX_AIO_LISTIO_MAX: u32 = 2;
+pub const _POSIX_AIO_MAX: u32 = 1;
+pub const _POSIX_ARG_MAX: u32 = 4096;
+pub const _POSIX_CHILD_MAX: u32 = 25;
+pub const _POSIX_DELAYTIMER_MAX: u32 = 32;
+pub const _POSIX_HOST_NAME_MAX: u32 = 255;
+pub const _POSIX_LINK_MAX: u32 = 8;
+pub const _POSIX_LOGIN_NAME_MAX: u32 = 9;
+pub const _POSIX_MAX_CANON: u32 = 255;
+pub const _POSIX_MAX_INPUT: u32 = 255;
+pub const _POSIX_MQ_OPEN_MAX: u32 = 8;
+p