|
| 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 | +
|
| 8 | +macro_rules! skf_value { |
| 9 | + ($name:ident) => { |
| 10 | + (libc::SKF_AD_OFF + libc::$name) as _ |
| 11 | + }; |
| 12 | +} |
| 13 | + |
| 14 | +#[derive(Clone, Copy, Debug)] |
| 15 | +pub 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 |
| 23 | +pub 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 | + |
| 50 | +pub 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] |
| 73 | +pub const fn payload_offset() -> u32 { |
| 74 | + skf_value!(SKF_AD_PAY_OFFSET) |
| 75 | +} |
| 76 | + |
| 77 | +#[inline] |
| 78 | +pub const fn raw_smp_processor_id() -> u32 { |
| 79 | + skf_value!(SKF_AD_CPU) |
| 80 | +} |
| 81 | + |
| 82 | +#[inline] |
| 83 | +pub const fn get_random_u32() -> u32 { |
| 84 | + skf_value!(SKF_AD_RANDOM) |
| 85 | +} |
| 86 | + |
| 87 | +macro_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 | +} |
0 commit comments