Add support for IPv6 gateways.

Closes: #207
Approved by: dlrobertson
This commit is contained in:
Valentin Lorentz 2018-05-13 20:22:18 +02:00 committed by Homu
parent 2afc538fd9
commit 2d716883b6
6 changed files with 157 additions and 40 deletions

View File

@ -57,7 +57,7 @@ required-features = ["std", "phy-raw_socket", "proto-ipv4"]
[[example]] [[example]]
name = "httpclient" name = "httpclient"
required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp"] required-features = ["std", "phy-tap_interface", "proto-ipv4", "proto-ipv6", "socket-tcp"]
[[example]] [[example]]
name = "ping" name = "ping"

View File

@ -190,6 +190,10 @@ a specific user:
sudo ip tuntap add name tap0 mode tap user $USER sudo ip tuntap add name tap0 mode tap user $USER
sudo ip link set tap0 up sudo ip link set tap0 up
sudo ip addr add 192.168.69.100/24 dev tap0 sudo ip addr add 192.168.69.100/24 dev tap0
sudo ip -6 addr add fe80::100/64 dev tap0
sudo ip -6 addr add fdaa::100/64 dev tap0
sudo ip -6 route add fe80::/64 dev tap0
sudo ip -6 route add fdaa::/64 dev tap0
``` ```
It's possible to let _smoltcp_ access Internet by enabling routing for the tap interface: It's possible to let _smoltcp_ access Internet by enabling routing for the tap interface:
@ -197,6 +201,8 @@ It's possible to let _smoltcp_ access Internet by enabling routing for the tap i
```sh ```sh
sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADE sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADE
sudo sysctl net.ipv4.ip_forward=1 sudo sysctl net.ipv4.ip_forward=1
sudo ip6tables -t nat -A POSTROUTING -s fdaa::/64 -j MASQUERADE
sudo sysctl -w net.ipv6.conf.all.forwarding=1
``` ```
### Fault injection ### Fault injection
@ -245,7 +251,7 @@ sudo ./target/debug/examples/tcpdump eth0
_examples/httpclient.rs_ emulates a network host that can initiate HTTP requests. _examples/httpclient.rs_ emulates a network host that can initiate HTTP requests.
The host is assigned the hardware address `02-00-00-00-00-02` and IPv4 address `192.168.69.1`. The host is assigned the hardware address `02-00-00-00-00-02`, IPv4 address `192.168.69.1`, and IPv6 address `fdaa::1`.
Read its [source code](/examples/httpclient.rs), then run it as: Read its [source code](/examples/httpclient.rs), then run it as:
@ -259,6 +265,12 @@ For example:
cargo run --example httpclient -- tap0 93.184.216.34 http://example.org/ cargo run --example httpclient -- tap0 93.184.216.34 http://example.org/
``` ```
or:
```sh
cargo run --example httpclient -- 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. 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. The TCP socket buffers are limited to 1024 bytes to make packet traces more interesting.

View File

@ -13,7 +13,7 @@ use std::collections::BTreeMap;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use url::Url; use url::Url;
use smoltcp::phy::wait as phy_wait; use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr}; use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv6Address, IpAddress, IpCidr};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder}; use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer}; use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use smoltcp::time::Instant; use smoltcp::time::Instant;
@ -42,13 +42,17 @@ fn main() {
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]); let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24)]; let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24),
IpCidr::new(IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1), 64),
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100); let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
let mut iface = EthernetInterfaceBuilder::new(device) let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.ipv4_gateway(default_v4_gw) .ipv4_gateway(default_v4_gw)
.ipv6_gateway(default_v6_gw)
.finalize(); .finalize();
let mut sockets = SocketSet::new(vec![]); let mut sockets = SocketSet::new(vec![]);

View File

@ -15,12 +15,47 @@ use smoltcp::time::{Duration, Instant};
use smoltcp::phy::Device; use smoltcp::phy::Device;
use smoltcp::phy::wait as phy_wait; use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
Ipv6Address, Icmpv6Repr, Icmpv6Packet,
Ipv4Address, Icmpv4Repr, Icmpv4Packet}; Ipv4Address, Icmpv4Repr, Icmpv4Packet};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder}; use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint}; use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
use std::collections::HashMap; use std::collections::HashMap;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
macro_rules! send_icmp_ping {
( $repr_type:ident, $packet_type:ident, $ident:expr, $seq_no:expr,
$echo_payload:expr, $socket:expr, $remote_addr:expr ) => {{
let icmp_repr = $repr_type::EchoRequest {
ident: $ident,
seq_no: $seq_no,
data: &$echo_payload,
};
let icmp_payload = $socket
.send(icmp_repr.buffer_len(), $remote_addr)
.unwrap();
let mut icmp_packet = $packet_type::new(icmp_payload);
(icmp_repr, icmp_packet)
}}
}
macro_rules! get_icmp_pong {
( $repr_type:ident, $repr:expr, $payload:expr, $waiting_queue:expr, $remote_addr:expr,
$timestamp:expr, $received:expr ) => {{
if let $repr_type::EchoReply { seq_no, data, .. } = $repr {
if let Some(_) = $waiting_queue.get(&seq_no) {
let packet_timestamp_ms = NetworkEndian::read_i64(data);
println!("{} bytes from {}: icmp_seq={}, time={}ms",
data.len(), $remote_addr, seq_no,
$timestamp.total_millis() - packet_timestamp_ms);
$waiting_queue.remove(&seq_no);
$received += 1;
}
}
}}
}
fn main() { fn main() {
utils::setup_logging("warn"); utils::setup_logging("warn");
@ -40,7 +75,7 @@ fn main() {
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false); let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
let device_caps = device.capabilities(); let device_caps = device.capabilities();
let address = Ipv4Address::from_str(&matches.free[0]).expect("invalid address format"); let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
let count = matches.opt_str("count").map(|s| usize::from_str(&s).unwrap()).unwrap_or(4); let count = matches.opt_str("count").map(|s| usize::from_str(&s).unwrap()).unwrap_or(4);
let interval = matches.opt_str("interval") let interval = matches.opt_str("interval")
.map(|s| Duration::from_secs(u64::from_str(&s).unwrap())) .map(|s| Duration::from_secs(u64::from_str(&s).unwrap()))
@ -52,19 +87,23 @@ fn main() {
let neighbor_cache = NeighborCache::new(BTreeMap::new()); let neighbor_cache = NeighborCache::new(BTreeMap::new());
let remote_addr = address; let remote_addr = address;
let local_addr = Ipv4Address::new(192, 168, 69, 1);
let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]); let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]); let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer); let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer);
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]); let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24); let src_ipv6 = IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24),
IpCidr::new(src_ipv6, 64),
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100); let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
let mut iface = EthernetInterfaceBuilder::new(device) let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
.ip_addrs([ip_addr]) .ip_addrs(ip_addrs)
.ipv4_gateway(default_v4_gw) .ipv4_gateway(default_v4_gw)
.ipv6_gateway(default_v6_gw)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize(); .finalize();
@ -77,7 +116,6 @@ fn main() {
let mut echo_payload = [0xffu8; 40]; let mut echo_payload = [0xffu8; 40];
let mut waiting_queue = HashMap::new(); let mut waiting_queue = HashMap::new();
let ident = 0x22b; let ident = 0x22b;
let endpoint = IpAddress::Ipv4(remote_addr);
loop { loop {
iface.poll(&mut sockets, Instant::now()).unwrap(); iface.poll(&mut sockets, Instant::now()).unwrap();
@ -93,18 +131,23 @@ fn main() {
if socket.can_send() && seq_no < count as u16 && if socket.can_send() && seq_no < count as u16 &&
send_at <= timestamp { send_at <= timestamp {
NetworkEndian::write_i64(&mut echo_payload, timestamp.total_millis()); NetworkEndian::write_i64(&mut echo_payload, timestamp.total_millis());
let icmp_repr = Icmpv4Repr::EchoRequest {
ident: ident,
seq_no,
data: &echo_payload,
};
let icmp_payload = socket match remote_addr {
.send(icmp_repr.buffer_len(), endpoint) IpAddress::Ipv4(_) => {
.unwrap(); let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
Icmpv4Repr, Icmpv4Packet, ident, seq_no,
let mut icmp_packet = Icmpv4Packet::new(icmp_payload); echo_payload, socket, remote_addr);
icmp_repr.emit(&mut icmp_packet, &device_caps.checksum); icmp_repr.emit(&mut icmp_packet, &device_caps.checksum);
},
IpAddress::Ipv6(_) => {
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
Icmpv6Repr, Icmpv6Packet, ident, seq_no,
echo_payload, socket, remote_addr);
icmp_repr.emit(&src_ipv6, &remote_addr,
&mut icmp_packet, &device_caps.checksum);
},
_ => unimplemented!()
}
waiting_queue.insert(seq_no, timestamp); waiting_queue.insert(seq_no, timestamp);
seq_no += 1; seq_no += 1;
@ -113,18 +156,22 @@ fn main() {
if socket.can_recv() { if socket.can_recv() {
let (payload, _) = socket.recv().unwrap(); let (payload, _) = socket.recv().unwrap();
let icmp_packet = Icmpv4Packet::new(&payload);
let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &device_caps.checksum).unwrap();
if let Icmpv4Repr::EchoReply { seq_no, data, .. } = icmp_repr { match remote_addr {
if let Some(_) = waiting_queue.get(&seq_no) { IpAddress::Ipv4(_) => {
let packet_timestamp_ms = NetworkEndian::read_i64(data); let icmp_packet = Icmpv4Packet::new(&payload);
println!("{} bytes from {}: icmp_seq={}, time={}ms", let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &device_caps.checksum).unwrap();
data.len(), remote_addr, seq_no, get_icmp_pong!(Icmpv4Repr, icmp_repr, payload,
timestamp.total_millis() - packet_timestamp_ms); waiting_queue, remote_addr, timestamp, received);
waiting_queue.remove(&seq_no);
received += 1;
} }
IpAddress::Ipv6(_) => {
let icmp_packet = Icmpv6Packet::new(&payload);
let icmp_repr = Icmpv6Repr::parse(&remote_addr, &src_ipv6,
&icmp_packet, &device_caps.checksum).unwrap();
get_icmp_pong!(Icmpv6Repr, icmp_repr, payload,
waiting_queue, remote_addr, timestamp, received);
},
_ => unimplemented!()
} }
} }

View File

@ -65,6 +65,8 @@ struct InterfaceInner<'b, 'c> {
ip_addrs: ManagedSlice<'c, IpCidr>, ip_addrs: ManagedSlice<'c, IpCidr>,
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
ipv4_gateway: Option<Ipv4Address>, ipv4_gateway: Option<Ipv4Address>,
#[cfg(feature = "proto-ipv6")]
ipv6_gateway: Option<Ipv6Address>,
device_capabilities: DeviceCapabilities, device_capabilities: DeviceCapabilities,
} }
@ -77,6 +79,8 @@ pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
ip_addrs: ManagedSlice<'c, IpCidr>, ip_addrs: ManagedSlice<'c, IpCidr>,
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
ipv4_gateway: Option<Ipv4Address>, ipv4_gateway: Option<Ipv4Address>,
#[cfg(feature = "proto-ipv6")]
ipv6_gateway: Option<Ipv6Address>,
} }
impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
@ -113,7 +117,9 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
neighbor_cache: None, neighbor_cache: None,
ip_addrs: ManagedSlice::Borrowed(&mut []), ip_addrs: ManagedSlice::Borrowed(&mut []),
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
ipv4_gateway: None ipv4_gateway: None,
#[cfg(feature = "proto-ipv6")]
ipv6_gateway: None,
} }
} }
@ -158,11 +164,28 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
where T: Into<Ipv4Address> where T: Into<Ipv4Address>
{ {
let addr = gateway.into(); let addr = gateway.into();
InterfaceInner::check_gateway_addr(&addr); InterfaceInner::check_ipv4_gateway_addr(&addr);
self.ipv4_gateway = Some(addr); self.ipv4_gateway = Some(addr);
self self
} }
/// Set the IPv6 gateway the interface will use. See also
/// [ipv6_gateway].
///
/// # Panics
/// This function panics if the given address is not unicast.
///
/// [ipv6_gateway]: struct.EthernetInterface.html#method.ipv6_gateway
#[cfg(feature = "proto-ipv6")]
pub fn ipv6_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
where T: Into<Ipv6Address>
{
let addr = gateway.into();
InterfaceInner::check_ipv6_gateway_addr(&addr);
self.ipv6_gateway = Some(addr);
self
}
/// Set the Neighbor Cache the interface will use. /// Set the Neighbor Cache the interface will use.
pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) -> pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) ->
InterfaceBuilder<'b, 'c, DeviceT> { InterfaceBuilder<'b, 'c, DeviceT> {
@ -192,6 +215,8 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
ip_addrs: self.ip_addrs, ip_addrs: self.ip_addrs,
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
ipv4_gateway: self.ipv4_gateway, ipv4_gateway: self.ipv4_gateway,
#[cfg(feature = "proto-ipv6")]
ipv6_gateway: self.ipv6_gateway,
} }
} }
}, },
@ -299,7 +324,24 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
pub fn set_ipv4_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT) pub fn set_ipv4_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
where GatewayAddrT: Into<Option<Ipv4Address>> { where GatewayAddrT: Into<Option<Ipv4Address>> {
self.inner.ipv4_gateway = gateway.into(); self.inner.ipv4_gateway = gateway.into();
self.inner.ipv4_gateway.map(|addr| InterfaceInner::check_gateway_addr(&addr)); self.inner.ipv4_gateway.map(|addr| InterfaceInner::check_ipv4_gateway_addr(&addr));
}
/// Get the IPv6 gateway of the interface.
#[cfg(feature = "proto-ipv6")]
pub fn ipv6_gateway(&self) -> Option<Ipv6Address> {
self.inner.ipv6_gateway
}
/// Set the IPv6 gateway of the interface.
///
/// # Panics
/// This function panics if the given address is not unicast.
#[cfg(feature = "proto-ipv6")]
pub fn set_ipv6_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
where GatewayAddrT: Into<Option<Ipv6Address>> {
self.inner.ipv6_gateway = gateway.into();
self.inner.ipv6_gateway.map(|addr| InterfaceInner::check_ipv6_gateway_addr(&addr));
} }
/// Transmit packets queued in the given sockets, and receive packets queued /// Transmit packets queued in the given sockets, and receive packets queued
@ -490,7 +532,14 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
} }
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
fn check_gateway_addr(addr: &Ipv4Address) { fn check_ipv4_gateway_addr(addr: &Ipv4Address) {
if !addr.is_unicast() {
panic!("gateway IP address {} is not unicast", addr);
}
}
#[cfg(feature = "proto-ipv6")]
fn check_ipv6_gateway_addr(addr: &Ipv6Address) {
if !addr.is_unicast() { if !addr.is_unicast() {
panic!("gateway IP address {} is not unicast", addr); panic!("gateway IP address {} is not unicast", addr);
} }
@ -1146,6 +1195,11 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
Some(gateway) => Ok(gateway.into()), Some(gateway) => Ok(gateway.into()),
None => Err(Error::Unaddressable), None => Err(Error::Unaddressable),
} }
#[cfg(feature = "proto-ipv6")]
&IpAddress::Ipv6(_) => match self.ipv6_gateway {
Some(gateway) => Ok(gateway.into()),
None => Err(Error::Unaddressable),
}
_ => Err(Error::Unaddressable) _ => Err(Error::Unaddressable)
} }
} }

View File

@ -341,7 +341,7 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
let ip_repr = IpRepr::Ipv6(Ipv6Repr { let ip_repr = IpRepr::Ipv6(Ipv6Repr {
src_addr: src_addr, src_addr: src_addr,
dst_addr: ipv6_addr, dst_addr: ipv6_addr,
next_header: IpProtocol::Icmp, next_header: IpProtocol::Icmpv6,
payload_len: repr.buffer_len(), payload_len: repr.buffer_len(),
hop_limit: hop_limit, hop_limit: hop_limit,
}); });
@ -609,7 +609,7 @@ mod test_ipv6 {
static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr { static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
src_addr: Ipv6Address::UNSPECIFIED, src_addr: Ipv6Address::UNSPECIFIED,
dst_addr: REMOTE_IPV6, dst_addr: REMOTE_IPV6,
next_header: IpProtocol::Icmp, next_header: IpProtocol::Icmpv6,
payload_len: 24, payload_len: 24,
hop_limit: 0x40 hop_limit: 0x40
}); });
@ -617,7 +617,7 @@ mod test_ipv6 {
static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr { static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
src_addr: REMOTE_IPV6, src_addr: REMOTE_IPV6,
dst_addr: LOCAL_IPV6, dst_addr: LOCAL_IPV6,
next_header: IpProtocol::Icmp, next_header: IpProtocol::Icmpv6,
payload_len: 24, payload_len: 24,
hop_limit: 0x40 hop_limit: 0x40
}); });
@ -683,7 +683,7 @@ mod test_ipv6 {
assert_eq!(ip_repr, IpRepr::Ipv6(Ipv6Repr { assert_eq!(ip_repr, IpRepr::Ipv6(Ipv6Repr {
src_addr: Ipv6Address::UNSPECIFIED, src_addr: Ipv6Address::UNSPECIFIED,
dst_addr: REMOTE_IPV6, dst_addr: REMOTE_IPV6,
next_header: IpProtocol::Icmp, next_header: IpProtocol::Icmpv6,
payload_len: ECHOV6_REPR.buffer_len(), payload_len: ECHOV6_REPR.buffer_len(),
hop_limit: 0x2a, hop_limit: 0x2a,
})); }));
@ -757,7 +757,7 @@ mod test_ipv6 {
header: Ipv6Repr { header: Ipv6Repr {
src_addr: LOCAL_IPV6, src_addr: LOCAL_IPV6,
dst_addr: REMOTE_IPV6, dst_addr: REMOTE_IPV6,
next_header: IpProtocol::Icmp, next_header: IpProtocol::Icmpv6,
payload_len: 12, payload_len: 12,
hop_limit: 0x40 hop_limit: 0x40
}, },
@ -766,7 +766,7 @@ mod test_ipv6 {
let ip_repr = IpRepr::Unspecified { let ip_repr = IpRepr::Unspecified {
src_addr: REMOTE_IPV6.into(), src_addr: REMOTE_IPV6.into(),
dst_addr: LOCAL_IPV6.into(), dst_addr: LOCAL_IPV6.into(),
protocol: IpProtocol::Icmp, protocol: IpProtocol::Icmpv6,
payload_len: icmp_repr.buffer_len(), payload_len: icmp_repr.buffer_len(),
hop_limit: 0x40 hop_limit: 0x40
}; };