mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
nic_router: no memcpy on self-written packets
Previously, all packets that the router wanted to sent were first prepared to their final state and then copied at once into the packet stream RAM. This is fine for packets that the router only passes through with modifying merely a few values. But for packets that the router writes from scratch on its own, it is better to compose the packet directly in the packet stream RAM. Fix #2626
This commit is contained in:
committed by
Christian Helmuth
parent
b6991f9c03
commit
57bfd09328
@@ -168,97 +168,91 @@ void Dhcp_client::_send(Message_type msg_type,
|
|||||||
Ipv4_address client_ip,
|
Ipv4_address client_ip,
|
||||||
Ipv4_address server_ip)
|
Ipv4_address server_ip)
|
||||||
{
|
{
|
||||||
/* allocate buffer for the request */
|
enum { PKT_SIZE = 1024 };
|
||||||
enum { BUF_SIZE = 1024 };
|
using Size_guard = Size_guard_tpl<PKT_SIZE, Interface::Dhcp_msg_buffer_too_small>;
|
||||||
using Size_guard = Size_guard_tpl<BUF_SIZE, Interface::Dhcp_msg_buffer_too_small>;
|
|
||||||
void *buf;
|
|
||||||
try { _alloc.alloc(BUF_SIZE, &buf); }
|
|
||||||
catch (...) { throw Interface::Alloc_dhcp_msg_buffer_failed(); }
|
|
||||||
Mac_address client_mac = _interface.router_mac();
|
Mac_address client_mac = _interface.router_mac();
|
||||||
|
_interface.send(PKT_SIZE, [&] (void *pkt_base) {
|
||||||
|
|
||||||
/* create ETH header of the request */
|
/* create ETH header of the request */
|
||||||
Size_guard size;
|
Size_guard size;
|
||||||
size.add(sizeof(Ethernet_frame));
|
size.add(sizeof(Ethernet_frame));
|
||||||
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(buf);
|
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(pkt_base);
|
||||||
eth.dst(Mac_address(0xff));
|
eth.dst(Mac_address(0xff));
|
||||||
eth.src(client_mac);
|
eth.src(client_mac);
|
||||||
eth.type(Ethernet_frame::Type::IPV4);
|
eth.type(Ethernet_frame::Type::IPV4);
|
||||||
|
|
||||||
/* create IP header of the request */
|
/* create IP header of the request */
|
||||||
enum { IPV4_TIME_TO_LIVE = 64 };
|
enum { IPV4_TIME_TO_LIVE = 64 };
|
||||||
size_t const ip_off = size.curr();
|
size_t const ip_off = size.curr();
|
||||||
size.add(sizeof(Ipv4_packet));
|
size.add(sizeof(Ipv4_packet));
|
||||||
Ipv4_packet &ip = *eth.data<Ipv4_packet>();
|
Ipv4_packet &ip = *eth.data<Ipv4_packet>();
|
||||||
ip.header_length(sizeof(Ipv4_packet) / 4);
|
ip.header_length(sizeof(Ipv4_packet) / 4);
|
||||||
ip.version(4);
|
ip.version(4);
|
||||||
ip.diff_service(0);
|
ip.diff_service(0);
|
||||||
ip.identification(0);
|
ip.identification(0);
|
||||||
ip.flags(0);
|
ip.flags(0);
|
||||||
ip.fragment_offset(0);
|
ip.fragment_offset(0);
|
||||||
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
||||||
ip.protocol(Ipv4_packet::Protocol::UDP);
|
ip.protocol(Ipv4_packet::Protocol::UDP);
|
||||||
ip.src(client_ip);
|
ip.src(client_ip);
|
||||||
ip.dst(Ipv4_address(0xff));
|
ip.dst(Ipv4_address(0xff));
|
||||||
|
|
||||||
/* create UDP header of the request */
|
/* create UDP header of the request */
|
||||||
size_t const udp_off = size.curr();
|
size_t const udp_off = size.curr();
|
||||||
size.add(sizeof(Udp_packet));
|
size.add(sizeof(Udp_packet));
|
||||||
Udp_packet &udp = *ip.data<Udp_packet>();
|
Udp_packet &udp = *ip.data<Udp_packet>();
|
||||||
udp.src_port(Port(Dhcp_packet::BOOTPC));
|
udp.src_port(Port(Dhcp_packet::BOOTPC));
|
||||||
udp.dst_port(Port(Dhcp_packet::BOOTPS));
|
udp.dst_port(Port(Dhcp_packet::BOOTPS));
|
||||||
|
|
||||||
/* create mandatory DHCP fields of the request */
|
/* create mandatory DHCP fields of the request */
|
||||||
size_t const dhcp_off = size.curr();
|
size_t const dhcp_off = size.curr();
|
||||||
size.add(sizeof(Dhcp_packet));
|
size.add(sizeof(Dhcp_packet));
|
||||||
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>();
|
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>();
|
||||||
dhcp.op(Dhcp_packet::REQUEST);
|
dhcp.op(Dhcp_packet::REQUEST);
|
||||||
dhcp.htype(Dhcp_packet::Htype::ETH);
|
dhcp.htype(Dhcp_packet::Htype::ETH);
|
||||||
dhcp.hlen(sizeof(Mac_address));
|
dhcp.hlen(sizeof(Mac_address));
|
||||||
dhcp.hops(0);
|
dhcp.hops(0);
|
||||||
dhcp.xid(0x12345678);
|
dhcp.xid(0x12345678);
|
||||||
dhcp.secs(0);
|
dhcp.secs(0);
|
||||||
dhcp.flags(0);
|
dhcp.flags(0);
|
||||||
dhcp.ciaddr(client_ip);
|
dhcp.ciaddr(client_ip);
|
||||||
dhcp.yiaddr(Ipv4_address());
|
dhcp.yiaddr(Ipv4_address());
|
||||||
dhcp.siaddr(Ipv4_address());
|
dhcp.siaddr(Ipv4_address());
|
||||||
dhcp.giaddr(Ipv4_address());
|
dhcp.giaddr(Ipv4_address());
|
||||||
dhcp.client_mac(client_mac);
|
dhcp.client_mac(client_mac);
|
||||||
dhcp.zero_fill_sname();
|
dhcp.zero_fill_sname();
|
||||||
dhcp.zero_fill_file();
|
dhcp.zero_fill_file();
|
||||||
dhcp.default_magic_cookie();
|
dhcp.default_magic_cookie();
|
||||||
|
|
||||||
/* append DHCP option fields to the request */
|
/* append DHCP option fields to the request */
|
||||||
Dhcp_packet::Options_aggregator<Size_guard>
|
Dhcp_packet::Options_aggregator<Size_guard>
|
||||||
dhcp_opts(dhcp, size);
|
dhcp_opts(dhcp, size);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
||||||
|
|
||||||
switch (msg_type) {
|
switch (msg_type) {
|
||||||
case Message_type::DISCOVER:
|
case Message_type::DISCOVER:
|
||||||
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(BUF_SIZE - dhcp_off);
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Message_type::REQUEST:
|
case Message_type::REQUEST:
|
||||||
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(BUF_SIZE - dhcp_off);
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
||||||
if (_state == State::REQUEST) {
|
if (_state == State::REQUEST) {
|
||||||
dhcp_opts.append_option<Dhcp_packet::Requested_addr>(client_ip);
|
dhcp_opts.append_option<Dhcp_packet::Requested_addr>(client_ip);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(server_ip);
|
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(server_ip);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Interface::Bad_send_dhcp_args();
|
||||||
}
|
}
|
||||||
break;
|
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||||
|
|
||||||
default:
|
/* fill in header values that need the packet to be complete already */
|
||||||
throw Interface::Bad_send_dhcp_args();
|
udp.length(size.curr() - udp_off);
|
||||||
}
|
udp.update_checksum(ip.src(), ip.dst());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
ip.total_length(size.curr() - ip_off);
|
||||||
|
ip.checksum(Ipv4_packet::calculate_checksum(ip));
|
||||||
/* fill in header values that need the packet to be complete already */
|
});
|
||||||
udp.length(size.curr() - udp_off);
|
|
||||||
udp.update_checksum(ip.src(), ip.dst());
|
|
||||||
ip.total_length(size.curr() - ip_off);
|
|
||||||
ip.checksum(Ipv4_packet::calculate_checksum(ip));
|
|
||||||
|
|
||||||
/* send request to sender of request and free request buffer */
|
|
||||||
_interface.send(eth, size.curr());
|
|
||||||
_alloc.free(buf, BUF_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,84 +291,78 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
|||||||
Dhcp_packet::Message_type msg_type,
|
Dhcp_packet::Message_type msg_type,
|
||||||
uint32_t xid)
|
uint32_t xid)
|
||||||
{
|
{
|
||||||
/* allocate buffer for the reply */
|
enum { PKT_SIZE = 512 };
|
||||||
enum { BUF_SIZE = 512 };
|
using Size_guard = Size_guard_tpl<PKT_SIZE, Dhcp_msg_buffer_too_small>;
|
||||||
using Size_guard = Size_guard_tpl<BUF_SIZE, Dhcp_msg_buffer_too_small>;
|
send(PKT_SIZE, [&] (void *pkt_base) {
|
||||||
void *buf;
|
|
||||||
try { _alloc.alloc(BUF_SIZE, &buf); }
|
|
||||||
catch (...) { throw Alloc_dhcp_msg_buffer_failed(); }
|
|
||||||
|
|
||||||
/* create ETH header of the reply */
|
/* create ETH header of the reply */
|
||||||
Size_guard size;
|
Size_guard size;
|
||||||
size.add(sizeof(Ethernet_frame));
|
size.add(sizeof(Ethernet_frame));
|
||||||
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(buf);
|
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(pkt_base);
|
||||||
eth.dst(client_mac);
|
eth.dst(client_mac);
|
||||||
eth.src(_router_mac);
|
eth.src(_router_mac);
|
||||||
eth.type(Ethernet_frame::Type::IPV4);
|
eth.type(Ethernet_frame::Type::IPV4);
|
||||||
|
|
||||||
/* create IP header of the reply */
|
/* create IP header of the reply */
|
||||||
enum { IPV4_TIME_TO_LIVE = 64 };
|
enum { IPV4_TIME_TO_LIVE = 64 };
|
||||||
size_t const ip_off = size.curr();
|
size_t const ip_off = size.curr();
|
||||||
size.add(sizeof(Ipv4_packet));
|
size.add(sizeof(Ipv4_packet));
|
||||||
Ipv4_packet &ip = *eth.data<Ipv4_packet>();
|
Ipv4_packet &ip = *eth.data<Ipv4_packet>();
|
||||||
ip.header_length(sizeof(Ipv4_packet) / 4);
|
ip.header_length(sizeof(Ipv4_packet) / 4);
|
||||||
ip.version(4);
|
ip.version(4);
|
||||||
ip.diff_service(0);
|
ip.diff_service(0);
|
||||||
ip.identification(0);
|
ip.identification(0);
|
||||||
ip.flags(0);
|
ip.flags(0);
|
||||||
ip.fragment_offset(0);
|
ip.fragment_offset(0);
|
||||||
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
||||||
ip.protocol(Ipv4_packet::Protocol::UDP);
|
ip.protocol(Ipv4_packet::Protocol::UDP);
|
||||||
ip.src(_router_ip());
|
ip.src(_router_ip());
|
||||||
ip.dst(client_ip);
|
ip.dst(client_ip);
|
||||||
|
|
||||||
/* create UDP header of the reply */
|
/* create UDP header of the reply */
|
||||||
size_t const udp_off = size.curr();
|
size_t const udp_off = size.curr();
|
||||||
size.add(sizeof(Udp_packet));
|
size.add(sizeof(Udp_packet));
|
||||||
Udp_packet &udp = *ip.data<Udp_packet>();
|
Udp_packet &udp = *ip.data<Udp_packet>();
|
||||||
udp.src_port(Port(Dhcp_packet::BOOTPS));
|
udp.src_port(Port(Dhcp_packet::BOOTPS));
|
||||||
udp.dst_port(Port(Dhcp_packet::BOOTPC));
|
udp.dst_port(Port(Dhcp_packet::BOOTPC));
|
||||||
|
|
||||||
/* create mandatory DHCP fields of the reply */
|
/* create mandatory DHCP fields of the reply */
|
||||||
size.add(sizeof(Dhcp_packet));
|
size.add(sizeof(Dhcp_packet));
|
||||||
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>();
|
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>();
|
||||||
dhcp.op(Dhcp_packet::REPLY);
|
dhcp.op(Dhcp_packet::REPLY);
|
||||||
dhcp.htype(Dhcp_packet::Htype::ETH);
|
dhcp.htype(Dhcp_packet::Htype::ETH);
|
||||||
dhcp.hlen(sizeof(Mac_address));
|
dhcp.hlen(sizeof(Mac_address));
|
||||||
dhcp.hops(0);
|
dhcp.hops(0);
|
||||||
dhcp.xid(xid);
|
dhcp.xid(xid);
|
||||||
dhcp.secs(0);
|
dhcp.secs(0);
|
||||||
dhcp.flags(0);
|
dhcp.flags(0);
|
||||||
dhcp.ciaddr(msg_type == Dhcp_packet::Message_type::INFORM ? client_ip : Ipv4_address());
|
dhcp.ciaddr(msg_type == Dhcp_packet::Message_type::INFORM ? client_ip : Ipv4_address());
|
||||||
dhcp.yiaddr(msg_type == Dhcp_packet::Message_type::INFORM ? Ipv4_address() : client_ip);
|
dhcp.yiaddr(msg_type == Dhcp_packet::Message_type::INFORM ? Ipv4_address() : client_ip);
|
||||||
dhcp.siaddr(_router_ip());
|
dhcp.siaddr(_router_ip());
|
||||||
dhcp.giaddr(Ipv4_address());
|
dhcp.giaddr(Ipv4_address());
|
||||||
dhcp.client_mac(client_mac);
|
dhcp.client_mac(client_mac);
|
||||||
dhcp.zero_fill_sname();
|
dhcp.zero_fill_sname();
|
||||||
dhcp.zero_fill_file();
|
dhcp.zero_fill_file();
|
||||||
dhcp.default_magic_cookie();
|
dhcp.default_magic_cookie();
|
||||||
|
|
||||||
/* append DHCP option fields to the reply */
|
/* append DHCP option fields to the reply */
|
||||||
Dhcp_packet::Options_aggregator<Size_guard> dhcp_opts(dhcp, size);
|
Dhcp_packet::Options_aggregator<Size_guard> dhcp_opts(dhcp, size);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(_router_ip());
|
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(_router_ip());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(_ip_config().interface.subnet_mask());
|
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(_ip_config().interface.subnet_mask());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(_router_ip());
|
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(_router_ip());
|
||||||
if (dhcp_srv.dns_server().valid()) {
|
if (dhcp_srv.dns_server().valid()) {
|
||||||
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dhcp_srv.dns_server()); }
|
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dhcp_srv.dns_server()); }
|
||||||
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(_ip_config().interface.broadcast_address());
|
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(_ip_config().interface.broadcast_address());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||||
|
|
||||||
/* fill in header values that need the packet to be complete already */
|
/* fill in header values that need the packet to be complete already */
|
||||||
udp.length(size.curr() - udp_off);
|
udp.length(size.curr() - udp_off);
|
||||||
udp.update_checksum(ip.src(), ip.dst());
|
udp.update_checksum(ip.src(), ip.dst());
|
||||||
ip.total_length(size.curr() - ip_off);
|
ip.total_length(size.curr() - ip_off);
|
||||||
ip.checksum(Ipv4_packet::calculate_checksum(ip));
|
ip.checksum(Ipv4_packet::calculate_checksum(ip));
|
||||||
|
});
|
||||||
/* send reply to sender of request and free reply buffer */
|
|
||||||
send(eth, size.curr());
|
|
||||||
_alloc.free(buf, BUF_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -675,19 +669,34 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
|||||||
|
|
||||||
void Interface::_broadcast_arp_request(Ipv4_address const &ip)
|
void Interface::_broadcast_arp_request(Ipv4_address const &ip)
|
||||||
{
|
{
|
||||||
Ethernet_frame_sized<sizeof(Arp_packet)>
|
enum {
|
||||||
eth(Mac_address(0xff), _router_mac, Ethernet_frame::Type::ARP);
|
ETH_HDR_SZ = sizeof(Ethernet_frame),
|
||||||
Arp_packet &arp = *eth.data<Arp_packet>();
|
ETH_DAT_SZ = sizeof(Arp_packet) + ETH_HDR_SZ >= Ethernet_frame::MIN_SIZE ?
|
||||||
arp.hardware_address_type(Arp_packet::ETHERNET);
|
sizeof(Arp_packet) :
|
||||||
arp.protocol_address_type(Arp_packet::IPV4);
|
Ethernet_frame::MIN_SIZE - ETH_HDR_SZ,
|
||||||
arp.hardware_address_size(sizeof(Mac_address));
|
ETH_CRC_SZ = sizeof(Genode::uint32_t),
|
||||||
arp.protocol_address_size(sizeof(Ipv4_address));
|
PKT_SIZE = ETH_HDR_SZ + ETH_DAT_SZ + ETH_CRC_SZ,
|
||||||
arp.opcode(Arp_packet::REQUEST);
|
};
|
||||||
arp.src_mac(_router_mac);
|
send(PKT_SIZE, [&] (void *pkt_base) {
|
||||||
arp.src_ip(_router_ip());
|
|
||||||
arp.dst_mac(Mac_address(0xff));
|
/* write Ethernet header */
|
||||||
arp.dst_ip(ip);
|
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(pkt_base);
|
||||||
send(eth, sizeof(eth));
|
eth.dst(Mac_address(0xff));
|
||||||
|
eth.src(_router_mac);
|
||||||
|
eth.type(Ethernet_frame::Type::ARP);
|
||||||
|
|
||||||
|
/* write ARP header */
|
||||||
|
Arp_packet &arp = *eth.data<Arp_packet>();
|
||||||
|
arp.hardware_address_type(Arp_packet::ETHERNET);
|
||||||
|
arp.protocol_address_type(Arp_packet::IPV4);
|
||||||
|
arp.hardware_address_size(sizeof(Mac_address));
|
||||||
|
arp.protocol_address_size(sizeof(Ipv4_address));
|
||||||
|
arp.opcode(Arp_packet::REQUEST);
|
||||||
|
arp.src_mac(_router_mac);
|
||||||
|
arp.src_ip(_router_ip());
|
||||||
|
arp.dst_mac(Mac_address(0xff));
|
||||||
|
arp.dst_ip(ip);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user