s2n_quic_platform/bpf/
ancillary.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Ancillary data extensions are used to look up additional information about a packet
5//!
6//! See <https://docs.kernel.org/networking/filter.html#bpf-engine-and-instruction-set>
7
8macro_rules! skf_value {
9    ($name:ident) => {
10        (libc::SKF_AD_OFF + libc::$name) as _
11    };
12}
13
14#[derive(Clone, Copy, Debug)]
15pub struct Info {
16    /// The special extension name used in `bpf_asm`
17    pub extension: &'static str,
18    /// The `C` interface
19    pub capi: &'static str,
20}
21
22/// Returns the [`Info`] for a given offset
23pub const fn lookup(offset: u32) -> Option<Info> {
24    macro_rules! map {
25        ($(($value:expr, $extension:expr, $capi:expr),)*) => {
26            match offset {
27                $(_ if offset == $value => Some(Info { extension: $extension, capi: $capi }),)*
28                _ => None,
29            }
30        };
31    }
32
33    map!(
34        (skb::protocol(), "proto", "skb->protocol"),
35        (skb::pkt_type(), "type", "skb->pkt_type"),
36        (skb::ifindex(), "ifidx", "skb->dev->ifindex"),
37        (skb::mark(), "mark", "skb->mark"),
38        (skb::queue_mapping(), "queue", "skb->queue_mapping"),
39        (skb::dev_type(), "hatype", "skb->dev->type"),
40        (skb::hash(), "rxhash", "skb->hash"),
41        (skb::vlan_tci(), "vlan_tci", "skb_vlan_tag_get(skb)"),
42        (skb::vlan_avail(), "vlan_avail", "skb_vlan_tag_present(skb)"),
43        (skb::vlan_proto(), "vlan_tpid", "skb->vlan_tproto"),
44        (payload_offset(), "poff", "payload_offset()"),
45        (raw_smp_processor_id(), "cpu", "raw_smp_processor_id()"),
46        (get_random_u32(), "rand", "get_random_u32()"),
47    )
48}
49
50pub mod skb {
51    macro_rules! skb_value {
52        ($name:ident, $value:ident) => {
53            #[inline]
54            pub const fn $name() -> u32 {
55                skf_value!($value)
56            }
57        };
58    }
59
60    skb_value!(protocol, SKF_AD_PROTOCOL);
61    skb_value!(pkt_type, SKF_AD_PKTTYPE);
62    skb_value!(ifindex, SKF_AD_IFINDEX);
63    skb_value!(mark, SKF_AD_MARK);
64    skb_value!(queue_mapping, SKF_AD_QUEUE);
65    skb_value!(dev_type, SKF_AD_HATYPE);
66    skb_value!(hash, SKF_AD_RXHASH);
67    skb_value!(vlan_tci, SKF_AD_VLAN_TAG);
68    skb_value!(vlan_avail, SKF_AD_VLAN_TAG_PRESENT);
69    skb_value!(vlan_proto, SKF_AD_VLAN_TPID);
70}
71
72#[inline]
73pub const fn payload_offset() -> u32 {
74    skf_value!(SKF_AD_PAY_OFFSET)
75}
76
77#[inline]
78pub const fn raw_smp_processor_id() -> u32 {
79    skf_value!(SKF_AD_CPU)
80}
81
82#[inline]
83pub const fn get_random_u32() -> u32 {
84    skf_value!(SKF_AD_RANDOM)
85}
86
87macro_rules! impl_ancillary {
88    () => {
89        /// Ancillary data extensions are used to look up additional information about a packet
90        ///
91        /// See <https://docs.kernel.org/networking/filter.html#bpf-engine-and-instruction-set>
92        pub mod ancillary {
93            use super::{super::ancillary, *};
94
95            /// Data associated with the socket buffer (skb)
96            pub mod skb {
97                use super::{ancillary::skb, *};
98
99                /// Loads the `skb->len` into the `A` register
100                pub const fn len() -> K {
101                    // use the dialect-specific instruction to load the skb len
102                    //
103                    // in the case of CBPF, there is a single `Mode` for `LEN`
104                    super::super::len()
105                }
106
107                /// Loads the `skb->protocol` into the `A` register
108                pub const fn protocol() -> K {
109                    abs(skb::protocol())
110                }
111
112                /// Loads the `skb->pkt_type` into the `A` register
113                pub const fn pkt_type() -> K {
114                    abs(skb::pkt_type())
115                }
116
117                /// Loads the `skb->ifindex` into the `A` register
118                pub const fn ifindex() -> K {
119                    abs(skb::ifindex())
120                }
121
122                /// Loads the `skb->mark` into the `A` register
123                pub const fn mark() -> K {
124                    abs(skb::mark())
125                }
126
127                /// Loads the `skb->queue_mapping` into the `A` register
128                pub const fn queue_mapping() -> K {
129                    abs(skb::queue_mapping())
130                }
131
132                /// Loads the `skb->dev->type` into the `A` register
133                pub const fn dev_type() -> K {
134                    abs(skb::dev_type())
135                }
136
137                /// Loads the `skb->hash` into the `A` register
138                pub const fn hash() -> K {
139                    abs(skb::hash())
140                }
141
142                /// Loads the VLAN Tag value into the `A` register
143                pub const fn vlan_tci() -> K {
144                    abs(skb::vlan_tci())
145                }
146
147                /// Loads the VLAN Tag value into the `A` register
148                ///
149                /// This is used for compatibility with the C API
150                pub const fn vlan_tag_get() -> K {
151                    vlan_tci()
152                }
153
154                /// Loads if the VLAN Tag is present into the `A` register
155                pub const fn vlan_avail() -> K {
156                    abs(skb::vlan_avail())
157                }
158
159                /// Loads if the VLAN Tag is present into the `A` register
160                ///
161                /// This is used for compatibility with the C API
162                pub const fn vlan_tag_present() -> K {
163                    vlan_avail()
164                }
165
166                /// Loads the `skb->vlan_proto` (VLAN Protocol) into the `A` register
167                pub const fn vlan_proto() -> K {
168                    abs(skb::vlan_proto())
169                }
170            }
171
172            /// Loads the payload offset into the `A` register
173            pub const fn payload_offset() -> K {
174                abs(ancillary::payload_offset())
175            }
176
177            /// Loads the CPU ID into the `A` register
178            pub const fn raw_smp_processor_id() -> K {
179                abs(ancillary::raw_smp_processor_id())
180            }
181
182            /// Loads a random `u32` into the `A` register
183            pub const fn get_random_u32() -> K {
184                abs(ancillary::get_random_u32())
185            }
186        }
187    };
188}