- Notifications
You must be signed in to change notification settings - Fork471
smoltcp-rs/smoltcp
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
smoltcp is a standalone, event-driven TCP/IP stack that is designed for bare-metal,real-time systems. Its design goals are simplicity and robustness. Its design anti-goalsinclude complicated compile-time computations, such as macro or type tricks, evenat cost of performance degradation.
smoltcp does not need heap allocationat all, isextensively documented,and compiles on stable Rust 1.81 and later.
smoltcp achieves~Gbps of throughput when tested againstthe Linux TCP stack in loopback mode.
smoltcp is missing many widely deployed features, usually because no one implemented them yet.To set expectations right, both implemented and omitted features are listed.
There are 3 supported mediums.
- Ethernet
- Regular Ethernet II frames are supported.
- Unicast, broadcast and multicast packets are supported.
- ARP packets (including gratuitous requests and replies) are supported.
- ARP requests are sent at a rate not exceeding one per second.
- Cached ARP entries expire after one minute.
- 802.3 frames and 802.1Q arenot supported.
- Jumbo frames arenot supported.
- IP
- Unicast, broadcast and multicast packets are supported.
- IEEE 802.15.4
- Only support for data frames.
- IPv4 header checksum is generated and validated.
- IPv4 time-to-live value is configurable per socket, set to 64 by default.
- IPv4 default gateway is supported.
- Routing outgoing IPv4 packets is supported, through a default gateway or a CIDR route table.
- IPv4 fragmentation and reassembly is supported.
- IPv4 options arenot supported and are silently ignored.
- IPv6 hop-limit value is configurable per socket, set to 64 by default.
- Routing outgoing IPv6 packets is supported, through a default gateway or a CIDR route table.
- IPv6 hop-by-hop header is supported.
- ICMPv6 parameter problem message is generated in response to an unrecognized IPv6 next header.
- ICMPv6 parameter problem message isnot generated in response to an unknown IPv6hop-by-hop option.
- Implementation ofRFC6282.
- Fragmentation is supported, as defined inRFC4944.
- UDP header compression/decompression is supported.
- Extension header compression/decompression is supported.
- Uncompressed IPv6 Extension Headers arenot supported.
The IGMPv1 and IGMPv2 protocols are supported, and IPv4 multicast is available.
- Membership reports are sent in response to membership queries atequal intervals equal to the maximum response time divided by thenumber of groups to be reported.
The ICMPv4 protocol is supported, and ICMP sockets are available.
- ICMPv4 header checksum is supported.
- ICMPv4 echo replies are generated in response to echo requests.
- ICMP sockets can listen to ICMPv4 Port Unreachable messages, or any ICMPv4 messages witha given IPv4 identifier field.
- ICMPv4 protocol unreachable messages arenot passed to higher layers when received.
- ICMPv4 parameter problem messages arenot generated.
The ICMPv6 protocol is supported, and ICMP sockets are available.
- ICMPv6 header checksum is supported.
- ICMPv6 echo replies are generated in response to echo requests.
- ICMPv6 protocol unreachable messages arenot passed to higher layers when received.
- Neighbor Advertisement messages are generated in response to Neighbor Solicitations.
- Router Advertisement messages arenot generated or read.
- Router Solicitation messages arenot generated or read.
- Redirected Header messages arenot generated or read.
The UDP protocol is supported over IPv4 and IPv6, and UDP sockets are available.
- Header checksum is always generated and validated.
- In response to a packet arriving at a port without a listening socket,an ICMP destination unreachable message is generated.
The TCP protocol is supported over IPv4 and IPv6, and server and client TCP sockets are available.
- Header checksum is generated and validated.
- Maximum segment size is negotiated.
- Window scaling is negotiated.
- Multiple packets are transmitted without waiting for an acknowledgement.
- Reassembly of out-of-order segments is supported, with no more than 4 or 32 gaps in sequence space.
- Keep-alive packets may be sent at a configurable interval.
- Retransmission timeout starts at at an estimate of RTT, and doubles every time.
- Time-wait timeout has a fixed interval of 10 s.
- User timeout has a configurable interval.
- Delayed acknowledgements are supported, with configurable delay.
- Nagle's algorithm is implemented.
- Selective acknowledgements arenot implemented.
- Silly window syndrome avoidance isnot implemented.
- Congestion control isnot implemented.
- Timestamping isnot supported.
- Urgent pointer isignored.
- Probing Zero Windows isnot implemented.
- Packetization Layer Path MTU DiscoveryPLPMTU isnot implemented.
To use thesmoltcp library in your project, add the following toCargo.toml
:
[dependencies]smoltcp ="0.10.0"
The default configuration assumes a hosted environment, for ease of evaluation.You probably want to disable default features and configure them one by one:
[dependencies]smoltcp = {version ="0.10.0",default-features =false,features = ["log"] }
Thestd
feature enables use of objects and slices owned by the networking stack through adependency onstd::boxed::Box
andstd::vec::Vec
.
This feature is enabled by default.
Thealloc
feature enables use of objects owned by the networking stack through a dependencyon collections from thealloc
crate. This only works on nightly rustc.
This feature is disabled by default.
Thelog
feature enables logging of events within the networking stack throughthelog crate. Normal events (e.g. buffer level or TCP state changes) are emitted withthe TRACE log level. Exceptional events (e.g. malformed packets) are emitted withthe DEBUG log level.
This feature is enabled by default.
Thedefmt
feature enables logging of events with thedefmt crate.
This feature is disabled by default, and cannot be used at the same time aslog
.
Theverbose
feature enables logging of events where the logging itself may incur very highoverhead. For example, emitting a log line every time an application reads or writes as littleas 1 octet from a socket is likely to overwhelm the application logic unless aBufReader
orBufWriter
is used, which are of course not available on heap-less systems.
This feature is disabled by default.
Enablesmoltcp::phy::RawSocket
andsmoltcp::phy::TunTapInterface
, respectively.
These features are enabled by default.
Enable the corresponding socket type.
These features are enabled by default.
EnableIPv4,IPv6 and6LoWPAN respectively.
smoltcp has some configuration settings that are set at compile time, affecting sizesand counts of buffers.
They can be set in two ways:
- Via Cargo features: enable a feature like
<name>-<value>
.name
must be in lowercase anduse dashes instead of underscores. For example.iface-max-addr-count-3
. Only a selection of valuesis available, checkCargo.toml
for the list. - Via environment variables at build time: set the variable named
SMOLTCP_<value>
. For exampleSMOLTCP_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 settingwith different values, compilation fails.
Max amount of IP addresses that can be assigned to one interface (counting both IPv4 and IPv6 addresses). Default: 2.
Max amount of multicast groups that can be joined by one interface. Default: 4.
Max amount of 6LoWPAN address contexts that can be assigned to one interface. Default: 4.
Amount of "IP address -> hardware address" entries the neighbor cache (also known as the "ARP cache" or the "ARP table") holds. Default: 4.
Max amount of routes that can be added to one interface. Includes the default route. Includes both IPv4 and IPv6. Default: 2.
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.
Maximum number of non-contiguous segments the assembler can hold. Used for both packet reassembly and TCP stream reassembly. Default: 4.
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.
Number of reassembly buffers, i.e how many different incoming packets can be reassembled at the same time. Default: 1.
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 4A
records, only the first 2 will be returned. Default: 1.
Maximum amount of DNS servers that can be configured in one DNS socket. Default: 1.
Maximum length of DNS names that can be queried. Default: 255.
The maximum amount of parsed options the IPv6 Hop-by-Hop header can hold. Default: 4.
smoltcp, being a freestanding networking stack, needs to be able to transmit and receiveraw frames. For testing purposes, we will use a regular OS, and runsmoltcp ina userspace process. Only Linux is supported (right now).
On *nix OSes, transmitting and receiving raw frames normally requires superuser privileges, buton Linux it is possible to create apersistent tap interface that can be manipulated bya specific user:
sudo ip tuntap add name tap0 mode tap user$USERsudo ip linkset tap0 upsudo ip addr add 192.168.69.100/24 dev tap0sudo ip -6 addr add fe80::100/64 dev tap0sudo ip -6 addr add fdaa::100/64 dev tap0sudo ip -6 route add fe80::/64 dev tap0sudo ip -6 route add fdaa::/64 dev tap0
It's possible to letsmoltcp access Internet by enabling routing for the tap interface:
sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADEsudo sysctl net.ipv4.ip_forward=1sudo ip6tables -t nat -A POSTROUTING -s fdaa::/64 -j MASQUERADEsudo sysctl -w net.ipv6.conf.all.forwarding=1# Some distros have a default policy of DROP. This allows the traffic.sudo iptables -A FORWARD -i tap0 -s 192.168.69.0/24 -j ACCEPTsudo iptables -A FORWARD -o tap0 -d 192.168.69.0/24 -j ACCEPT
Instead of the routed connection above, you may also set up a bridged (switched)connection. This will make smoltcp speak directly to your LAN, with real ARP, etc.It is needed to run the DHCP example.
NOTE: In this case, the examples' IP configuration must match your LAN's!
NOTE: this ONLY works with actual wired Ethernet connections. Itwill NOT work on a WiFi connection.
# Replace with your wired Ethernet interface nameETH=enp0s20f0u1u1sudo modprobe bridgesudo modprobe br_netfiltersudo sysctl -w net.bridge.bridge-nf-call-arptables=0sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0sudo sysctl -w net.bridge.bridge-nf-call-iptables=0sudo ip tuntap add name tap0 mode tap user$USERsudo brctl addbr br0sudo brctl addif br0 tap0sudo brctl addif br0$ETHsudo ip linkset tap0 upsudo ip linkset$ETH upsudo ip linkset br0 up# This connects your host system to the internet, so you can use it# at the same time you run the examples.sudo dhcpcd br0
To tear down:
sudo killall dhcpcdsudo ip link set br0 downsudo brctl delbr br0
In order to demonstrate the response ofsmoltcp to adverse network conditions, all examplesimplement fault injection, available through command-line options:
- The
--drop-chance
option randomly drops packets, with given probability in percents. - The
--corrupt-chance
option randomly mutates one octet in a packet, with givenprobability in percents. - The
--size-limit
option drops packets larger than specified size. - The
--tx-rate-limit
and--rx-rate-limit
options set the amount of tokens fora token bucket rate limiter, in packets per bucket. - The
--shaping-interval
option sets the refill interval of a token bucket rate limiter,in milliseconds.
A good starting value for--drop-chance
and--corrupt-chance
is 15%. A good startingvalue for--?x-rate-limit
is 4 and--shaping-interval
is 50 ms.
Note that packets dropped by the fault injector still get traced;therx: randomly dropping a packet
message indicates that the packetabove it got dropped,and thetx: randomly dropping a packet
message indicates that the packetbelow it was.
All examples provide a--pcap
option that writes alibpcap file containing a view of everypacket as it is seen bysmoltcp.
examples/tcpdump.rs is a tiny clone of thetcpdump utility.
Unlike the rest of the examples, it uses raw sockets, and so it can be used on regular interfaces,e.g.eth0
orwlan0
, as well as thetap0
interface we've created above.
Read itssource code, then run it as:
cargo build --example tcpdumpsudo ./target/debug/examples/tcpdump eth0
examples/httpclient.rs emulates a network host that can initiate HTTP requests.
The host is assigned the hardware address02-00-00-00-00-02
, IPv4 address192.168.69.1
, and IPv6 addressfdaa::1
.
Read itssource code, then run it as:
cargo run --example httpclient -- --tap tap0 ADDRESS URL
For example:
cargo run --example httpclient -- --tap tap0 93.184.216.34 http://example.org/
or:
cargo run --example httpclient -- --tap tap0 2606:2800:220:1:248:1893:25c8:1946 http://example.org/
It connects to the given address (not a hostname) and URL, and prints any returned response data.The TCP socket buffers are limited to 1024 bytes to make packet traces more interesting.
examples/ping.rs implements a minimal version of theping
utility using raw sockets.
The host is assigned the hardware address02-00-00-00-00-02
and IPv4 address192.168.69.1
.
Read itssource code, then run it as:
cargo run --example ping -- --tap tap0 ADDRESS
It sends a series of 4 ICMP ECHO_REQUEST packets to the given address at one second intervals andprints out a status line on each valid ECHO_RESPONSE received.
The first ECHO_REQUEST packet is expected to be lost since arp_cache is empty after startup;the ECHO_REQUEST packet is dropped and an ARP request is sent instead.
Currently, netmasks are not implemented, and so the only address this example can reachis the other endpoint of the tap interface,192.168.69.100
. It cannot reach itself becausepackets entering a tap interface do not loop back.
examples/server.rs emulates a network host that can respond to basic requests.
The host is assigned the hardware address02-00-00-00-00-01
and IPv4 address192.168.69.1
.
Read itssource code, then run it as:
cargo run --example server -- --tap tap0
It responds to:
- pings (
ping 192.168.69.1
); - UDP packets on port 6969 (
socat stdio udp4-connect:192.168.69.1:6969 <<<"abcdefg"
),where it will respond with reversed chunks of the input indefinitely; - TCP connections on port 6969 (
socat stdio tcp4-connect:192.168.69.1:6969
),where it will respond "hello" to any incoming connection and immediately close it; - TCP connections on port 6970 (
socat stdio tcp4-connect:192.168.69.1:6970 <<<"abcdefg"
),where it will respond with reversed chunks of the input indefinitely. - TCP connections on port 6971 (
socat stdio tcp4-connect:192.168.69.1:6971 </dev/urandom
),which will sink data. Also, keep-alive packets (every 1 s) and a user timeout (at 2 s)are enabled on this port; try to trigger them using fault injection. - TCP connections on port 6972 (
socat stdio tcp4-connect:192.168.69.1:6972 >/dev/null
),which will source data.
Except for the socket on port 6971. the buffers are only 64 bytes long, for convenienceof testing resource exhaustion conditions.
examples/client.rs emulates a network host that can initiate basic requests.
The host is assigned the hardware address02-00-00-00-00-02
and IPv4 address192.168.69.2
.
Read itssource code, then run it as:
cargo run --example client -- --tap tap0 ADDRESS PORT
It connects to the given address (not a hostname) and port (e.g.socat stdio tcp4-listen:1234
),and will respond with reversed chunks of the input indefinitely.
examples/benchmark.rs implements a simple throughput benchmark.
Read itssource code, then run it as:
cargo run --release --example benchmark -- --tap tap0 [reader|writer]
It establishes a connection to itself from a different thread and reads or writes a large amountof data in one direction.
A typical result (achieved on a Intel Core i5-13500H CPU and a Linux 6.9.9 x86_64 kernel runningon a LENOVO XiaoXinPro 14 IRH8 laptop) is as follows:
$ cargo run -q --release --example benchmark -- --tap tap0 readerthroughput: 3.673 Gbps$ cargo run -q --release --example benchmark -- --tap tap0 writerthroughput: 7.905 Gbps
Examples that use no services from the host OS are necessarily less illustrative than examplesthat do. Because of this, only one such example is provided.
examples/loopback.rs sets upsmoltcp to talk with itself via a loopback interface.Although it does not requirestd
, this example still requires thealloc
feature to run, as well aslog
,proto-ipv4
andsocket-tcp
.
Read itssource code, then run it withoutstd
:
cargo run --example loopback --no-default-features --features="log proto-ipv4 socket-tcp alloc"
... or withstd
(in this case the features don't have to be explicitly listed):
cargo run --example loopback -- --pcap loopback.pcap
It opens a server and a client TCP socket, and transfers a chunk of data. You can examinethe packet exchange by openingloopback.pcap
inWireshark.
If thestd
feature is enabled, it will print logs and packet dumps, and fault injectionis possible; otherwise, nothing at all will be displayed and no options are accepted.
examples/loopback_benchmark.rs is another simple throughput benchmark.
Read itssource code, then run it as:
cargo run --release --example loopback_benchmark
It establishes a connection to itself via a loopback interface and transfers a large amountof data in one direction.
A typical result (achieved on a Intel Core i5-13500H CPU and a Linux 6.9.9 x86_64 kernel runningon a LENOVO XiaoXinPro 14 IRH8 laptop) is as follows:
$ cargo run --release --example loopback_benchmarkdone in 0.558 s, bandwidth is 15.395083 Gbps
Note: Although the loopback interface can be used in bare-metal environments,this benchmarkdoes rely onstd
to be able to measure the time cost.
smoltcp is distributed under the terms of 0-clause BSD license.
SeeLICENSE-0BSD for details.
About
a smol tcp/ip stack
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.