Add compile-time configuration options for counts and buffer sizes.

This commit is contained in:
Dario Nieuwenhuis 2023-02-06 19:48:48 +01:00
parent a656ab0c08
commit b047cbeade
12 changed files with 466 additions and 85 deletions

View File

@ -80,6 +80,141 @@ default = [
"_proto-fragmentation" = []
# BEGIN AUTOGENERATED CONFIG FEATURES
# Generated by gen_config.py. DO NOT EDIT.
iface-max-addr-count-1 = []
iface-max-addr-count-2 = [] # Default
iface-max-addr-count-3 = []
iface-max-addr-count-4 = []
iface-max-addr-count-5 = []
iface-max-addr-count-6 = []
iface-max-addr-count-7 = []
iface-max-addr-count-8 = []
iface-max-multicast-group-count-1 = []
iface-max-multicast-group-count-2 = []
iface-max-multicast-group-count-3 = []
iface-max-multicast-group-count-4 = [] # Default
iface-max-multicast-group-count-5 = []
iface-max-multicast-group-count-6 = []
iface-max-multicast-group-count-7 = []
iface-max-multicast-group-count-8 = []
iface-max-multicast-group-count-16 = []
iface-max-multicast-group-count-32 = []
iface-max-multicast-group-count-64 = []
iface-max-multicast-group-count-128 = []
iface-max-multicast-group-count-256 = []
iface-max-multicast-group-count-512 = []
iface-max-multicast-group-count-1024 = []
iface-max-sixlowpan-address-context-count-1 = []
iface-max-sixlowpan-address-context-count-2 = []
iface-max-sixlowpan-address-context-count-3 = []
iface-max-sixlowpan-address-context-count-4 = [] # Default
iface-max-sixlowpan-address-context-count-5 = []
iface-max-sixlowpan-address-context-count-6 = []
iface-max-sixlowpan-address-context-count-7 = []
iface-max-sixlowpan-address-context-count-8 = []
iface-max-sixlowpan-address-context-count-16 = []
iface-max-sixlowpan-address-context-count-32 = []
iface-max-sixlowpan-address-context-count-64 = []
iface-max-sixlowpan-address-context-count-128 = []
iface-max-sixlowpan-address-context-count-256 = []
iface-max-sixlowpan-address-context-count-512 = []
iface-max-sixlowpan-address-context-count-1024 = []
iface-neighbor-cache-count-1 = []
iface-neighbor-cache-count-2 = []
iface-neighbor-cache-count-3 = []
iface-neighbor-cache-count-4 = [] # Default
iface-neighbor-cache-count-5 = []
iface-neighbor-cache-count-6 = []
iface-neighbor-cache-count-7 = []
iface-neighbor-cache-count-8 = []
iface-neighbor-cache-count-16 = []
iface-neighbor-cache-count-32 = []
iface-neighbor-cache-count-64 = []
iface-neighbor-cache-count-128 = []
iface-neighbor-cache-count-256 = []
iface-neighbor-cache-count-512 = []
iface-neighbor-cache-count-1024 = []
iface-max-route-count-1 = []
iface-max-route-count-2 = [] # Default
iface-max-route-count-3 = []
iface-max-route-count-4 = []
iface-max-route-count-5 = []
iface-max-route-count-6 = []
iface-max-route-count-7 = []
iface-max-route-count-8 = []
iface-max-route-count-16 = []
iface-max-route-count-32 = []
iface-max-route-count-64 = []
iface-max-route-count-128 = []
iface-max-route-count-256 = []
iface-max-route-count-512 = []
iface-max-route-count-1024 = []
fragmentation-buffer-size-256 = []
fragmentation-buffer-size-512 = []
fragmentation-buffer-size-1024 = []
fragmentation-buffer-size-1500 = [] # Default
fragmentation-buffer-size-2048 = []
fragmentation-buffer-size-4096 = []
fragmentation-buffer-size-8192 = []
fragmentation-buffer-size-16384 = []
fragmentation-buffer-size-32768 = []
fragmentation-buffer-size-65536 = []
assembler-max-segment-count-1 = []
assembler-max-segment-count-2 = []
assembler-max-segment-count-3 = []
assembler-max-segment-count-4 = [] # Default
assembler-max-segment-count-8 = []
assembler-max-segment-count-16 = []
assembler-max-segment-count-32 = []
reassembly-buffer-size-256 = []
reassembly-buffer-size-512 = []
reassembly-buffer-size-1024 = []
reassembly-buffer-size-1500 = [] # Default
reassembly-buffer-size-2048 = []
reassembly-buffer-size-4096 = []
reassembly-buffer-size-8192 = []
reassembly-buffer-size-16384 = []
reassembly-buffer-size-32768 = []
reassembly-buffer-size-65536 = []
reassembly-buffer-count-1 = [] # Default
reassembly-buffer-count-2 = []
reassembly-buffer-count-3 = []
reassembly-buffer-count-4 = []
reassembly-buffer-count-8 = []
reassembly-buffer-count-16 = []
reassembly-buffer-count-32 = []
dns-max-result-count-1 = [] # Default
dns-max-result-count-2 = []
dns-max-result-count-3 = []
dns-max-result-count-4 = []
dns-max-result-count-8 = []
dns-max-result-count-16 = []
dns-max-result-count-32 = []
dns-max-server-count-1 = [] # Default
dns-max-server-count-2 = []
dns-max-server-count-3 = []
dns-max-server-count-4 = []
dns-max-server-count-8 = []
dns-max-server-count-16 = []
dns-max-server-count-32 = []
dns-max-name-size-64 = []
dns-max-name-size-128 = []
dns-max-name-size-255 = [] # Default
# END AUTOGENERATED CONFIG FEATURES
[[example]]
name = "packet2pcap"
path = "utils/packet2pcap.rs"

View File

@ -147,6 +147,8 @@ You probably want to disable default features and configure them one by one:
smoltcp = { version = "0.8.0", default-features = false, features = ["log"] }
```
## Feature flags
### Feature `std`
The `std` feature enables use of objects and slices owned by the networking stack through a
@ -195,7 +197,7 @@ Enable `smoltcp::phy::RawSocket` and `smoltcp::phy::TunTapInterface`, respective
These features are enabled by default.
### Features `socket-raw`, `socket-udp`, `socket-tcp`, `socket-icmp`, `socket-dhcpv4`
### Features `socket-raw`, `socket-udp`, `socket-tcp`, `socket-icmp`, `socket-dhcpv4`, `socket-dns`
Enable the corresponding socket type.
@ -208,6 +210,73 @@ Enable [IPv4] and [IPv6] respectively.
[IPv4]: https://tools.ietf.org/rfc/rfc791.txt
[IPv6]: https://tools.ietf.org/rfc/rfc8200.txt
## Configuration
_smoltcp_ has some configuration settings that are set at compile time, affecting sizes
and counts of buffers.
They can be set in two ways:
- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and
use dashes instead of underscores. For example. `iface-max-addr-count-3`. Only a selection of values
is available, check `Cargo.toml` for the list.
- Via environment variables at build time: set the variable named `SMOLTCP_<value>`. For example
`SMOLTCP_IFACE_MAX_ADDR_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
Any value can be set, unlike with Cargo features.
Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
with different values, compilation fails.
### IFACE_MAX_ADDR_COUNT
Max amount of IP addresses that can be assigned to one interface (counting both IPv4 and IPv6 addresses). Default: 2.
### IFACE_MAX_MULTICAST_GROUP_COUNT
Max amount of multicast groups that can be joined by one interface. Default: 4.
### IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT
Max amount of 6LoWPAN address contexts that can be assigned to one interface. Default: 4.
### IFACE_NEIGHBOR_CACHE_COUNT
Amount of "IP address -> hardware address" entries the neighbor cache (also known as the "ARP cache" or the "ARP table") holds. Default: 4.
### IFACE_MAX_ROUTE_COUNT
Max amount of routes that can be added to one interface. Includes the default route. Includes both IPv4 and IPv6. Default: 2.
### FRAGMENTATION_BUFFER_SIZE
Size of the buffer used for fragmenting outgoing packets larger than the MTU. Packets larger than this setting will be dropped instead of fragmented. Default: 1500.
### ASSEMBLER_MAX_SEGMENT_COUNT
Maximum number of non-contiguous segments the assembler can hold. Used for both packet reassembly and TCP stream reassembly. Default: 4.
### REASSEMBLY_BUFFER_SIZE
Size of the buffer used for reassembling (de-fragmenting) incoming packets. If the reassembled packet is larger than this setting, it will be dropped instead of reassembled. Default: 1500.
### REASSEMBLY_BUFFER_COUNT
Number of reassembly buffers, i.e how many different incoming packets can be reassembled at the same time. Default: 1.
### DNS_MAX_RESULT_COUNT
Maximum amount of address results for a given DNS query that will be kept. For example, if this is set to 2 and the queried name has 4 `A` records, only the first 2 will be returned. Default: 1.
### DNS_MAX_SERVER_COUNT
Maximum amount of DNS servers that can be configured in one DNS socket. Default: 1.
### DNS_MAX_NAME_SIZE
Maximum length of DNS names that can be queried. Default: 255.
## Hosted usage examples
_smoltcp_, being a freestanding networking stack, needs to be able to transmit and receive

101
build.rs Normal file
View File

@ -0,0 +1,101 @@
use std::collections::HashMap;
use std::fmt::Write;
use std::path::PathBuf;
use std::{env, fs};
static CONFIGS: &[(&str, usize)] = &[
// BEGIN AUTOGENERATED CONFIG FEATURES
// Generated by gen_config.py. DO NOT EDIT.
("IFACE_MAX_ADDR_COUNT", 2),
("IFACE_MAX_MULTICAST_GROUP_COUNT", 4),
("IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT", 4),
("IFACE_NEIGHBOR_CACHE_COUNT", 4),
("IFACE_MAX_ROUTE_COUNT", 2),
("FRAGMENTATION_BUFFER_SIZE", 1500),
("ASSEMBLER_MAX_SEGMENT_COUNT", 4),
("REASSEMBLY_BUFFER_SIZE", 1500),
("REASSEMBLY_BUFFER_COUNT", 1),
("DNS_MAX_RESULT_COUNT", 1),
("DNS_MAX_SERVER_COUNT", 1),
("DNS_MAX_NAME_SIZE", 255),
// END AUTOGENERATED CONFIG FEATURES
];
struct ConfigState {
value: usize,
seen_feature: bool,
seen_env: bool,
}
fn main() {
// only rebuild if build.rs changed. Otherwise Cargo will rebuild if any
// other file changed.
println!("cargo:rerun-if-changed=build.rs");
// Rebuild if config envvar changed.
for (name, _) in CONFIGS {
println!("cargo:rerun-if-env-changed=SMOLTCP_{name}");
}
let mut configs = HashMap::new();
for (name, default) in CONFIGS {
configs.insert(
*name,
ConfigState {
value: *default,
seen_env: false,
seen_feature: false,
},
);
}
for (var, value) in env::vars() {
if let Some(name) = var.strip_prefix("SMOLTCP_") {
let Some(cfg) = configs.get_mut(name) else {
panic!("Unknown env var {name}")
};
let Ok(value) = value.parse::<usize>() else {
panic!("Invalid value for env var {name}: {value}")
};
cfg.value = value;
cfg.seen_env = true;
}
if let Some(feature) = var.strip_prefix("CARGO_FEATURE_") {
if let Some(i) = feature.rfind('_') {
let name = &feature[..i];
let value = &feature[i + 1..];
if let Some(cfg) = configs.get_mut(name) {
let Ok(value) = value.parse::<usize>() else {
panic!("Invalid value for feature {name}: {value}")
};
// envvars take priority.
if !cfg.seen_env {
if cfg.seen_feature {
panic!(
"multiple values set for feature {}: {} and {}",
name, cfg.value, value
);
}
cfg.value = value;
cfg.seen_feature = true;
}
}
}
}
}
let mut data = String::new();
for (name, cfg) in &configs {
writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap();
}
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
fs::write(out_file, data).unwrap();
}

83
gen_config.py Normal file
View File

@ -0,0 +1,83 @@
import os
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
features = []
def feature(name, default, min, max, pow2=None):
vals = set()
val = min
while val <= max:
vals.add(val)
if pow2 == True or (isinstance(pow2, int) and val >= pow2):
val *= 2
else:
val += 1
vals.add(default)
features.append(
{
"name": name,
"default": default,
"vals": sorted(list(vals)),
}
)
feature("iface_max_addr_count", default=2, min=1, max=8)
feature("iface_max_multicast_group_count", default=4, min=1, max=1024, pow2=8)
feature("iface_max_sixlowpan_address_context_count", default=4, min=1, max=1024, pow2=8)
feature("iface_neighbor_cache_count", default=4, min=1, max=1024, pow2=8)
feature("iface_max_route_count", default=2, min=1, max=1024, pow2=8)
feature("fragmentation_buffer_size", default=1500, min=256, max=65536, pow2=True)
feature("assembler_max_segment_count", default=4, min=1, max=32, pow2=4)
feature("reassembly_buffer_size", default=1500, min=256, max=65536, pow2=True)
feature("reassembly_buffer_count", default=1, min=1, max=32, pow2=4)
feature("dns_max_result_count", default=1, min=1, max=32, pow2=4)
feature("dns_max_server_count", default=1, min=1, max=32, pow2=4)
feature("dns_max_name_size", default=255, min=64, max=255, pow2=True)
# ========= Update Cargo.toml
things = ""
for f in features:
name = f["name"].replace("_", "-")
for val in f["vals"]:
things += f"{name}-{val} = []"
if val == f["default"]:
things += " # Default"
things += "\n"
things += "\n"
SEPARATOR_START = "# BEGIN AUTOGENERATED CONFIG FEATURES\n"
SEPARATOR_END = "# END AUTOGENERATED CONFIG FEATURES\n"
HELP = "# Generated by gen_config.py. DO NOT EDIT.\n"
with open("Cargo.toml", "r") as f:
data = f.read()
before, data = data.split(SEPARATOR_START, maxsplit=1)
_, after = data.split(SEPARATOR_END, maxsplit=1)
data = before + SEPARATOR_START + HELP + things + SEPARATOR_END + after
with open("Cargo.toml", "w") as f:
f.write(data)
# ========= Update build.rs
things = ""
for f in features:
name = f["name"].upper()
things += f' ("{name}", {f["default"]}),\n'
SEPARATOR_START = "// BEGIN AUTOGENERATED CONFIG FEATURES\n"
SEPARATOR_END = "// END AUTOGENERATED CONFIG FEATURES\n"
HELP = " // Generated by gen_config.py. DO NOT EDIT.\n"
with open("build.rs", "r") as f:
data = f.read()
before, data = data.split(SEPARATOR_START, maxsplit=1)
_, after = data.split(SEPARATOR_END, maxsplit=1)
data = before + SEPARATOR_START + HELP + things + " " + SEPARATOR_END + after
with open("build.rs", "w") as f:
f.write(data)

View File

@ -4,18 +4,14 @@ use core::fmt;
use managed::{ManagedMap, ManagedSlice};
use crate::config::{REASSEMBLY_BUFFER_COUNT, REASSEMBLY_BUFFER_SIZE};
use crate::storage::Assembler;
use crate::time::{Duration, Instant};
// TODO: make configurable.
const BUFFER_SIZE: usize = 1500;
#[cfg(feature = "alloc")]
type Buffer = alloc::vec::Vec<u8>;
#[cfg(not(feature = "alloc"))]
type Buffer = [u8; BUFFER_SIZE];
const PACKET_ASSEMBLER_COUNT: usize = 4;
type Buffer = [u8; REASSEMBLY_BUFFER_SIZE];
/// Problem when assembling: something was out of bounds.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -44,14 +40,14 @@ pub struct PacketAssembler<K> {
impl<K> PacketAssembler<K> {
/// Create a new empty buffer for fragments.
pub fn new() -> Self {
pub const fn new() -> Self {
Self {
key: None,
#[cfg(feature = "alloc")]
buffer: Buffer::new(),
#[cfg(not(feature = "alloc"))]
buffer: [0u8; BUFFER_SIZE],
buffer: [0u8; REASSEMBLY_BUFFER_SIZE],
assembler: Assembler::new(),
total_size: None,
@ -172,20 +168,16 @@ impl<K> PacketAssembler<K> {
/// Set holding multiple [`PacketAssembler`].
#[derive(Debug)]
pub struct PacketAssemblerSet<K: Eq + Copy> {
assemblers: [PacketAssembler<K>; PACKET_ASSEMBLER_COUNT],
assemblers: [PacketAssembler<K>; REASSEMBLY_BUFFER_COUNT],
}
impl<K: Eq + Copy> PacketAssemblerSet<K> {
const NEW_PA: PacketAssembler<K> = PacketAssembler::new();
/// Create a new set of packet assemblers.
pub fn new() -> Self {
Self {
// TODO: support any PACKET_ASSEMBLER_COUNT
assemblers: [
PacketAssembler::new(),
PacketAssembler::new(),
PacketAssembler::new(),
PacketAssembler::new(),
],
assemblers: [Self::NEW_PA; REASSEMBLY_BUFFER_COUNT],
}
}
@ -291,10 +283,9 @@ mod tests {
#[test]
fn packet_assembler_set_full() {
let mut set = PacketAssemblerSet::new();
set.get(&Key { id: 0 }, Instant::ZERO).unwrap();
set.get(&Key { id: 1 }, Instant::ZERO).unwrap();
set.get(&Key { id: 2 }, Instant::ZERO).unwrap();
set.get(&Key { id: 3 }, Instant::ZERO).unwrap();
for i in 0..REASSEMBLY_BUFFER_COUNT {
set.get(&Key { id: i }, Instant::ZERO).unwrap();
}
assert!(set.get(&Key { id: 4 }, Instant::ZERO).is_err());
}

View File

@ -27,6 +27,10 @@ use super::fragmentation::PacketAssemblerSet;
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
use super::neighbor::{Answer as NeighborAnswer, Cache as NeighborCache};
use super::socket_set::SocketSet;
use crate::config::{
FRAGMENTATION_BUFFER_SIZE, IFACE_MAX_ADDR_COUNT, IFACE_MAX_MULTICAST_GROUP_COUNT,
IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT,
};
use crate::iface::Routes;
use crate::phy::{ChecksumCapabilities, Device, DeviceCapabilities, Medium, RxToken, TxToken};
use crate::rand::Rand;
@ -36,13 +40,6 @@ use crate::socket::*;
use crate::time::{Duration, Instant};
use crate::wire::*;
const MAX_IP_ADDR_COUNT: usize = 5;
#[cfg(feature = "proto-igmp")]
const MAX_IPV4_MULTICAST_GROUPS: usize = 4;
const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
#[cfg(feature = "proto-sixlowpan")]
const SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
#[cfg(feature = "_proto-fragmentation")]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -248,15 +245,16 @@ pub struct InterfaceInner {
#[cfg(feature = "proto-ipv4-fragmentation")]
ipv4_id: u16,
#[cfg(feature = "proto-sixlowpan")]
sixlowpan_address_context: Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
sixlowpan_address_context:
Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
#[cfg(feature = "proto-sixlowpan-fragmentation")]
tag: u16,
ip_addrs: Vec<IpCidr, MAX_IP_ADDR_COUNT>,
ip_addrs: Vec<IpCidr, IFACE_MAX_ADDR_COUNT>,
#[cfg(feature = "proto-ipv4")]
any_ip: bool,
routes: Routes,
#[cfg(feature = "proto-igmp")]
ipv4_multicast_groups: LinearMap<Ipv4Address, (), MAX_IPV4_MULTICAST_GROUPS>,
ipv4_multicast_groups: LinearMap<Ipv4Address, (), IFACE_MAX_MULTICAST_GROUP_COUNT>,
/// When to report for (all or) the next multicast group membership via IGMP
#[cfg(feature = "proto-igmp")]
igmp_report_state: IgmpReportState,
@ -642,7 +640,7 @@ impl Interface {
///
/// # Panics
/// This function panics if any of the addresses are not unicast.
pub fn update_ip_addrs<F: FnOnce(&mut Vec<IpCidr, MAX_IP_ADDR_COUNT>)>(&mut self, f: F) {
pub fn update_ip_addrs<F: FnOnce(&mut Vec<IpCidr, IFACE_MAX_ADDR_COUNT>)>(&mut self, f: F) {
f(&mut self.inner.ip_addrs);
InterfaceInner::flush_cache(&mut self.inner);
InterfaceInner::check_ip_addrs(&self.inner.ip_addrs)
@ -690,7 +688,7 @@ impl Interface {
#[cfg(feature = "proto-sixlowpan")]
pub fn sixlowpan_address_context(
&self,
) -> &Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
) -> &Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
&self.inner.sixlowpan_address_context
}
@ -698,7 +696,7 @@ impl Interface {
#[cfg(feature = "proto-sixlowpan")]
pub fn sixlowpan_address_context_mut(
&mut self,
) -> &mut Vec<SixlowpanAddressContext, SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
) -> &mut Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
&mut self.inner.sixlowpan_address_context
}

View File

@ -1012,7 +1012,7 @@ fn test_icmpv4_socket() {
#[cfg(feature = "proto-ipv6")]
fn test_solicited_node_addrs() {
let (mut iface, _, _device) = create(MEDIUM);
let mut new_addrs = heapless::Vec::<IpCidr, MAX_IP_ADDR_COUNT>::new();
let mut new_addrs = heapless::Vec::<IpCidr, IFACE_MAX_ADDR_COUNT>::new();
new_addrs
.push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 1, 2, 0, 2), 64))
.unwrap();

View File

@ -3,14 +3,10 @@
use heapless::LinearMap;
use crate::config::IFACE_NEIGHBOR_CACHE_COUNT;
use crate::time::{Duration, Instant};
use crate::wire::{HardwareAddress, IpAddress};
#[cfg(not(test))]
pub const NEIGHBOR_CACHE_SIZE: usize = 16;
#[cfg(test)]
pub const NEIGHBOR_CACHE_SIZE: usize = 3;
/// A cached neighbor.
///
/// A neighbor mapping translates from a protocol address to a hardware address,
@ -48,7 +44,7 @@ impl Answer {
/// A neighbor cache backed by a map.
#[derive(Debug)]
pub struct Cache {
storage: LinearMap<IpAddress, Neighbor, NEIGHBOR_CACHE_SIZE>,
storage: LinearMap<IpAddress, Neighbor, IFACE_NEIGHBOR_CACHE_COUNT>,
silent_until: Instant,
}

View File

@ -1,14 +1,13 @@
use crate::time::Instant;
use heapless::Vec;
use crate::config::IFACE_MAX_ROUTE_COUNT;
use crate::time::Instant;
use crate::wire::{IpAddress, IpCidr};
#[cfg(feature = "proto-ipv4")]
use crate::wire::{Ipv4Address, Ipv4Cidr};
#[cfg(feature = "proto-ipv6")]
use crate::wire::{Ipv6Address, Ipv6Cidr};
pub const MAX_ROUTE_COUNT: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RouteTableFull;
@ -58,7 +57,7 @@ impl Route {
/// A routing table.
#[derive(Debug)]
pub struct Routes {
storage: Vec<Route, MAX_ROUTE_COUNT>,
storage: Vec<Route, IFACE_MAX_ROUTE_COUNT>,
}
impl Routes {
@ -70,7 +69,7 @@ impl Routes {
}
/// Update the routes of this node.
pub fn update<F: FnOnce(&mut Vec<Route, MAX_ROUTE_COUNT>)>(&mut self, f: F) {
pub fn update<F: FnOnce(&mut Vec<Route, IFACE_MAX_ROUTE_COUNT>)>(&mut self, f: F) {
f(&mut self.storage);
}

View File

@ -129,6 +129,29 @@ mod macros;
mod parsers;
mod rand;
#[cfg(test)]
mod config {
#![allow(unused)]
pub const ASSEMBLER_MAX_SEGMENT_COUNT: usize = 4;
pub const DNS_MAX_NAME_SIZE: usize = 255;
pub const DNS_MAX_RESULT_COUNT: usize = 1;
pub const DNS_MAX_SERVER_COUNT: usize = 1;
pub const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
pub const IFACE_MAX_ADDR_COUNT: usize = 8;
pub const IFACE_MAX_MULTICAST_GROUP_COUNT: usize = 4;
pub const IFACE_MAX_ROUTE_COUNT: usize = 4;
pub const IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
pub const IFACE_NEIGHBOR_CACHE_COUNT: usize = 3;
pub const REASSEMBLY_BUFFER_COUNT: usize = 4;
pub const REASSEMBLY_BUFFER_SIZE: usize = 1500;
}
#[cfg(not(test))]
mod config {
#![allow(unused)]
include!(concat!(env!("OUT_DIR"), "/config.rs"));
}
#[cfg(any(
feature = "medium-ethernet",
feature = "medium-ip",

View File

@ -4,6 +4,7 @@ use core::task::Waker;
use heapless::Vec;
use managed::ManagedSlice;
use crate::config::{DNS_MAX_NAME_SIZE, DNS_MAX_RESULT_COUNT, DNS_MAX_SERVER_COUNT};
use crate::socket::{Context, PollAt};
use crate::time::{Duration, Instant};
use crate::wire::dns::{Flags, Opcode, Packet, Question, Rcode, Record, RecordData, Repr, Type};
@ -12,12 +13,8 @@ use crate::wire::{self, IpAddress, IpProtocol, IpRepr, UdpRepr};
#[cfg(feature = "async")]
use super::WakerRegistration;
pub const MAX_ADDRESS_COUNT: usize = 4;
pub const MAX_SERVER_COUNT: usize = 4;
const DNS_PORT: u16 = 53;
const MDNS_DNS_PORT: u16 = 5353;
const MAX_NAME_LEN: usize = 255;
const RETRANSMIT_DELAY: Duration = Duration::from_millis(1_000);
const MAX_RETRANSMIT_DELAY: Duration = Duration::from_millis(10_000);
const RETRANSMIT_TIMEOUT: Duration = Duration::from_millis(10_000); // Should generally be 2-10 secs
@ -79,7 +76,7 @@ enum State {
#[derive(Debug)]
struct PendingQuery {
name: Vec<u8, MAX_NAME_LEN>,
name: Vec<u8, DNS_MAX_NAME_SIZE>,
type_: Type,
port: u16, // UDP port (src for request, dst for response)
@ -102,7 +99,7 @@ pub enum MulticastDns {
#[derive(Debug)]
struct CompletedQuery {
addresses: Vec<IpAddress, MAX_ADDRESS_COUNT>,
addresses: Vec<IpAddress, DNS_MAX_RESULT_COUNT>,
}
/// A handle to an in-progress DNS query.
@ -115,7 +112,7 @@ pub struct QueryHandle(usize);
/// packet buffers.
#[derive(Debug)]
pub struct Socket<'a> {
servers: Vec<IpAddress, MAX_SERVER_COUNT>,
servers: Vec<IpAddress, DNS_MAX_SERVER_COUNT>,
queries: ManagedSlice<'a, Option<DnsQuery>>,
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
@ -216,7 +213,7 @@ impl<'a> Socket<'a> {
name = &name[..name.len() - 1];
}
let mut raw_name: Vec<u8, MAX_NAME_LEN> = Vec::new();
let mut raw_name: Vec<u8, DNS_MAX_NAME_SIZE> = Vec::new();
let mut mdns = MulticastDns::Disabled;
#[cfg(feature = "socket-mdns")]
@ -292,7 +289,7 @@ impl<'a> Socket<'a> {
pub fn get_query_result(
&mut self,
handle: QueryHandle,
) -> Result<Vec<IpAddress, MAX_ADDRESS_COUNT>, GetQueryResultError> {
) -> Result<Vec<IpAddress, DNS_MAX_RESULT_COUNT>, GetQueryResultError> {
let slot = &mut self.queries[handle.0];
let q = slot.as_mut().unwrap();
match &mut q.state {

View File

@ -1,5 +1,7 @@
use core::fmt;
use crate::config::ASSEMBLER_MAX_SEGMENT_COUNT;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TooManyHolesError;
@ -27,7 +29,7 @@ impl fmt::Display for Contig {
}
impl Contig {
fn empty() -> Contig {
const fn empty() -> Contig {
Contig {
hole_size: 0,
data_size: 0,
@ -66,24 +68,13 @@ impl Contig {
}
}
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
const CONTIG_COUNT: usize = 32;
#[cfg(not(feature = "alloc"))]
const CONTIG_COUNT: usize = 4;
/// A buffer (re)assembler.
///
/// Currently, up to a hardcoded limit of 4 or 32 holes can be tracked in the buffer.
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Assembler {
#[cfg(not(feature = "alloc"))]
contigs: [Contig; CONTIG_COUNT],
#[cfg(feature = "alloc")]
contigs: Box<[Contig; CONTIG_COUNT]>,
contigs: [Contig; ASSEMBLER_MAX_SEGMENT_COUNT],
}
impl fmt::Display for Assembler {
@ -106,12 +97,11 @@ impl fmt::Display for Assembler {
impl Assembler {
/// Create a new buffer assembler.
pub fn new() -> Assembler {
#[cfg(not(feature = "alloc"))]
let contigs = [Contig::empty(); CONTIG_COUNT];
#[cfg(feature = "alloc")]
let contigs = Box::new([Contig::empty(); CONTIG_COUNT]);
Assembler { contigs }
pub const fn new() -> Assembler {
const EMPTY: Contig = Contig::empty();
Assembler {
contigs: [EMPTY; ASSEMBLER_MAX_SEGMENT_COUNT],
}
}
pub fn clear(&mut self) {
@ -355,10 +345,9 @@ mod test {
impl From<Vec<(usize, usize)>> for Assembler {
fn from(vec: Vec<(usize, usize)>) -> Assembler {
#[cfg(not(feature = "alloc"))]
let mut contigs = [Contig::empty(); CONTIG_COUNT];
#[cfg(feature = "alloc")]
let mut contigs = Box::new([Contig::empty(); CONTIG_COUNT]);
const EMPTY: Contig = Contig::empty();
let mut contigs = [EMPTY; ASSEMBLER_MAX_SEGMENT_COUNT];
for (i, &(hole_size, data_size)) in vec.iter().enumerate() {
contigs[i] = Contig {
hole_size,
@ -468,7 +457,7 @@ mod test {
#[test]
fn test_rejected_add_keeps_state() {
let mut assr = Assembler::new();
for c in 1..=CONTIG_COUNT {
for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
assert_eq!(assr.add(c * 10, 3), Ok(()));
}
// Maximum of allowed holes is reached
@ -499,12 +488,12 @@ mod test {
#[test]
fn test_boundary_case_remove_front() {
let mut vec = vec![(1, 1); CONTIG_COUNT];
let mut vec = vec![(1, 1); ASSEMBLER_MAX_SEGMENT_COUNT];
vec[0] = (0, 2);
let mut assr = Assembler::from(vec);
assert_eq!(assr.remove_front(), 2);
let mut vec = vec![(1, 1); CONTIG_COUNT];
vec[CONTIG_COUNT - 1] = (0, 0);
let mut vec = vec![(1, 1); ASSEMBLER_MAX_SEGMENT_COUNT];
vec[ASSEMBLER_MAX_SEGMENT_COUNT - 1] = (0, 0);
let exp_assr = Assembler::from(vec);
assert_eq!(assr, exp_assr);
}
@ -648,7 +637,7 @@ mod test {
#[test]
fn test_add_then_remove_front_at_front_full() {
let mut assr = Assembler::new();
for c in 1..=CONTIG_COUNT {
for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
assert_eq!(assr.add(c * 10, 3), Ok(()));
}
// Maximum of allowed holes is reached
@ -660,7 +649,7 @@ mod test {
#[test]
fn test_add_then_remove_front_at_front_full_offset_0() {
let mut assr = Assembler::new();
for c in 1..=CONTIG_COUNT {
for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
assert_eq!(assr.add(c * 10, 3), Ok(()));
}
assert_eq!(assr.add_then_remove_front(0, 3), Ok(3));
@ -708,7 +697,7 @@ mod test {
}
// Compare.
let wanted_res = if contigs.len() > CONTIG_COUNT {
let wanted_res = if contigs.len() > ASSEMBLER_MAX_SEGMENT_COUNT {
Err(TooManyHolesError)
} else {
Ok(())