From 57bfd09328e4e50ea5beee9c8016710d7e02e094 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 20 Dec 2017 15:56:47 +0100 Subject: [PATCH] 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 --- repos/os/src/server/nic_router/dhcp_client.cc | 160 ++++++++-------- repos/os/src/server/nic_router/interface.cc | 179 +++++++++--------- 2 files changed, 171 insertions(+), 168 deletions(-) diff --git a/repos/os/src/server/nic_router/dhcp_client.cc b/repos/os/src/server/nic_router/dhcp_client.cc index 4be9382776..fff79d39ca 100644 --- a/repos/os/src/server/nic_router/dhcp_client.cc +++ b/repos/os/src/server/nic_router/dhcp_client.cc @@ -168,97 +168,91 @@ void Dhcp_client::_send(Message_type msg_type, Ipv4_address client_ip, Ipv4_address server_ip) { - /* allocate buffer for the request */ - enum { BUF_SIZE = 1024 }; - using Size_guard = Size_guard_tpl; - void *buf; - try { _alloc.alloc(BUF_SIZE, &buf); } - catch (...) { throw Interface::Alloc_dhcp_msg_buffer_failed(); } + enum { PKT_SIZE = 1024 }; + using Size_guard = Size_guard_tpl; Mac_address client_mac = _interface.router_mac(); + _interface.send(PKT_SIZE, [&] (void *pkt_base) { - /* create ETH header of the request */ - Size_guard size; - size.add(sizeof(Ethernet_frame)); - Ethernet_frame ð = *reinterpret_cast(buf); - eth.dst(Mac_address(0xff)); - eth.src(client_mac); - eth.type(Ethernet_frame::Type::IPV4); + /* create ETH header of the request */ + Size_guard size; + size.add(sizeof(Ethernet_frame)); + Ethernet_frame ð = *reinterpret_cast(pkt_base); + eth.dst(Mac_address(0xff)); + eth.src(client_mac); + eth.type(Ethernet_frame::Type::IPV4); - /* create IP header of the request */ - enum { IPV4_TIME_TO_LIVE = 64 }; - size_t const ip_off = size.curr(); - size.add(sizeof(Ipv4_packet)); - Ipv4_packet &ip = *eth.data(); - ip.header_length(sizeof(Ipv4_packet) / 4); - ip.version(4); - ip.diff_service(0); - ip.identification(0); - ip.flags(0); - ip.fragment_offset(0); - ip.time_to_live(IPV4_TIME_TO_LIVE); - ip.protocol(Ipv4_packet::Protocol::UDP); - ip.src(client_ip); - ip.dst(Ipv4_address(0xff)); + /* create IP header of the request */ + enum { IPV4_TIME_TO_LIVE = 64 }; + size_t const ip_off = size.curr(); + size.add(sizeof(Ipv4_packet)); + Ipv4_packet &ip = *eth.data(); + ip.header_length(sizeof(Ipv4_packet) / 4); + ip.version(4); + ip.diff_service(0); + ip.identification(0); + ip.flags(0); + ip.fragment_offset(0); + ip.time_to_live(IPV4_TIME_TO_LIVE); + ip.protocol(Ipv4_packet::Protocol::UDP); + ip.src(client_ip); + ip.dst(Ipv4_address(0xff)); - /* create UDP header of the request */ - size_t const udp_off = size.curr(); - size.add(sizeof(Udp_packet)); - Udp_packet &udp = *ip.data(); - udp.src_port(Port(Dhcp_packet::BOOTPC)); - udp.dst_port(Port(Dhcp_packet::BOOTPS)); + /* create UDP header of the request */ + size_t const udp_off = size.curr(); + size.add(sizeof(Udp_packet)); + Udp_packet &udp = *ip.data(); + udp.src_port(Port(Dhcp_packet::BOOTPC)); + udp.dst_port(Port(Dhcp_packet::BOOTPS)); - /* create mandatory DHCP fields of the request */ - size_t const dhcp_off = size.curr(); - size.add(sizeof(Dhcp_packet)); - Dhcp_packet &dhcp = *udp.data(); - dhcp.op(Dhcp_packet::REQUEST); - dhcp.htype(Dhcp_packet::Htype::ETH); - dhcp.hlen(sizeof(Mac_address)); - dhcp.hops(0); - dhcp.xid(0x12345678); - dhcp.secs(0); - dhcp.flags(0); - dhcp.ciaddr(client_ip); - dhcp.yiaddr(Ipv4_address()); - dhcp.siaddr(Ipv4_address()); - dhcp.giaddr(Ipv4_address()); - dhcp.client_mac(client_mac); - dhcp.zero_fill_sname(); - dhcp.zero_fill_file(); - dhcp.default_magic_cookie(); + /* create mandatory DHCP fields of the request */ + size_t const dhcp_off = size.curr(); + size.add(sizeof(Dhcp_packet)); + Dhcp_packet &dhcp = *udp.data(); + dhcp.op(Dhcp_packet::REQUEST); + dhcp.htype(Dhcp_packet::Htype::ETH); + dhcp.hlen(sizeof(Mac_address)); + dhcp.hops(0); + dhcp.xid(0x12345678); + dhcp.secs(0); + dhcp.flags(0); + dhcp.ciaddr(client_ip); + dhcp.yiaddr(Ipv4_address()); + dhcp.siaddr(Ipv4_address()); + dhcp.giaddr(Ipv4_address()); + dhcp.client_mac(client_mac); + dhcp.zero_fill_sname(); + dhcp.zero_fill_file(); + dhcp.default_magic_cookie(); - /* append DHCP option fields to the request */ - Dhcp_packet::Options_aggregator - dhcp_opts(dhcp, size); - dhcp_opts.append_option(msg_type); + /* append DHCP option fields to the request */ + Dhcp_packet::Options_aggregator + dhcp_opts(dhcp, size); + dhcp_opts.append_option(msg_type); - switch (msg_type) { - case Message_type::DISCOVER: - dhcp_opts.append_option(client_mac); - dhcp_opts.append_option(BUF_SIZE - dhcp_off); - break; + switch (msg_type) { + case Message_type::DISCOVER: + dhcp_opts.append_option(client_mac); + dhcp_opts.append_option(PKT_SIZE - dhcp_off); + break; - case Message_type::REQUEST: - dhcp_opts.append_option(client_mac); - dhcp_opts.append_option(BUF_SIZE - dhcp_off); - if (_state == State::REQUEST) { - dhcp_opts.append_option(client_ip); - dhcp_opts.append_option(server_ip); + case Message_type::REQUEST: + dhcp_opts.append_option(client_mac); + dhcp_opts.append_option(PKT_SIZE - dhcp_off); + if (_state == State::REQUEST) { + dhcp_opts.append_option(client_ip); + dhcp_opts.append_option(server_ip); + } + break; + + default: + throw Interface::Bad_send_dhcp_args(); } - break; + dhcp_opts.append_option(); - default: - throw Interface::Bad_send_dhcp_args(); - } - dhcp_opts.append_option(); - - /* 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); + /* 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)); + }); } diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index fd7cb76157..f40c812635 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -291,84 +291,78 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv, Dhcp_packet::Message_type msg_type, uint32_t xid) { - /* allocate buffer for the reply */ - enum { BUF_SIZE = 512 }; - using Size_guard = Size_guard_tpl; - void *buf; - try { _alloc.alloc(BUF_SIZE, &buf); } - catch (...) { throw Alloc_dhcp_msg_buffer_failed(); } + enum { PKT_SIZE = 512 }; + using Size_guard = Size_guard_tpl; + send(PKT_SIZE, [&] (void *pkt_base) { - /* create ETH header of the reply */ - Size_guard size; - size.add(sizeof(Ethernet_frame)); - Ethernet_frame ð = *reinterpret_cast(buf); - eth.dst(client_mac); - eth.src(_router_mac); - eth.type(Ethernet_frame::Type::IPV4); + /* create ETH header of the reply */ + Size_guard size; + size.add(sizeof(Ethernet_frame)); + Ethernet_frame ð = *reinterpret_cast(pkt_base); + eth.dst(client_mac); + eth.src(_router_mac); + eth.type(Ethernet_frame::Type::IPV4); - /* create IP header of the reply */ - enum { IPV4_TIME_TO_LIVE = 64 }; - size_t const ip_off = size.curr(); - size.add(sizeof(Ipv4_packet)); - Ipv4_packet &ip = *eth.data(); - ip.header_length(sizeof(Ipv4_packet) / 4); - ip.version(4); - ip.diff_service(0); - ip.identification(0); - ip.flags(0); - ip.fragment_offset(0); - ip.time_to_live(IPV4_TIME_TO_LIVE); - ip.protocol(Ipv4_packet::Protocol::UDP); - ip.src(_router_ip()); - ip.dst(client_ip); + /* create IP header of the reply */ + enum { IPV4_TIME_TO_LIVE = 64 }; + size_t const ip_off = size.curr(); + size.add(sizeof(Ipv4_packet)); + Ipv4_packet &ip = *eth.data(); + ip.header_length(sizeof(Ipv4_packet) / 4); + ip.version(4); + ip.diff_service(0); + ip.identification(0); + ip.flags(0); + ip.fragment_offset(0); + ip.time_to_live(IPV4_TIME_TO_LIVE); + ip.protocol(Ipv4_packet::Protocol::UDP); + ip.src(_router_ip()); + ip.dst(client_ip); - /* create UDP header of the reply */ - size_t const udp_off = size.curr(); - size.add(sizeof(Udp_packet)); - Udp_packet &udp = *ip.data(); - udp.src_port(Port(Dhcp_packet::BOOTPS)); - udp.dst_port(Port(Dhcp_packet::BOOTPC)); + /* create UDP header of the reply */ + size_t const udp_off = size.curr(); + size.add(sizeof(Udp_packet)); + Udp_packet &udp = *ip.data(); + udp.src_port(Port(Dhcp_packet::BOOTPS)); + udp.dst_port(Port(Dhcp_packet::BOOTPC)); - /* create mandatory DHCP fields of the reply */ - size.add(sizeof(Dhcp_packet)); - Dhcp_packet &dhcp = *udp.data(); - dhcp.op(Dhcp_packet::REPLY); - dhcp.htype(Dhcp_packet::Htype::ETH); - dhcp.hlen(sizeof(Mac_address)); - dhcp.hops(0); - dhcp.xid(xid); - dhcp.secs(0); - dhcp.flags(0); - 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.siaddr(_router_ip()); - dhcp.giaddr(Ipv4_address()); - dhcp.client_mac(client_mac); - dhcp.zero_fill_sname(); - dhcp.zero_fill_file(); - dhcp.default_magic_cookie(); + /* create mandatory DHCP fields of the reply */ + size.add(sizeof(Dhcp_packet)); + Dhcp_packet &dhcp = *udp.data(); + dhcp.op(Dhcp_packet::REPLY); + dhcp.htype(Dhcp_packet::Htype::ETH); + dhcp.hlen(sizeof(Mac_address)); + dhcp.hops(0); + dhcp.xid(xid); + dhcp.secs(0); + dhcp.flags(0); + 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.siaddr(_router_ip()); + dhcp.giaddr(Ipv4_address()); + dhcp.client_mac(client_mac); + dhcp.zero_fill_sname(); + dhcp.zero_fill_file(); + dhcp.default_magic_cookie(); - /* append DHCP option fields to the reply */ - Dhcp_packet::Options_aggregator dhcp_opts(dhcp, size); - dhcp_opts.append_option(msg_type); - dhcp_opts.append_option(_router_ip()); - dhcp_opts.append_option(dhcp_srv.ip_lease_time().value / 1000 / 1000); - dhcp_opts.append_option(_ip_config().interface.subnet_mask()); - dhcp_opts.append_option(_router_ip()); - if (dhcp_srv.dns_server().valid()) { - dhcp_opts.append_option(dhcp_srv.dns_server()); } - dhcp_opts.append_option(_ip_config().interface.broadcast_address()); - dhcp_opts.append_option(); + /* append DHCP option fields to the reply */ + Dhcp_packet::Options_aggregator dhcp_opts(dhcp, size); + dhcp_opts.append_option(msg_type); + dhcp_opts.append_option(_router_ip()); + dhcp_opts.append_option(dhcp_srv.ip_lease_time().value / 1000 / 1000); + dhcp_opts.append_option(_ip_config().interface.subnet_mask()); + dhcp_opts.append_option(_router_ip()); + if (dhcp_srv.dns_server().valid()) { + dhcp_opts.append_option(dhcp_srv.dns_server()); } + dhcp_opts.append_option(_ip_config().interface.broadcast_address()); + dhcp_opts.append_option(); - /* 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 reply to sender of request and free reply buffer */ - send(eth, size.curr()); - _alloc.free(buf, BUF_SIZE); + /* 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)); + }); } @@ -675,19 +669,34 @@ void Interface::_handle_ip(Ethernet_frame ð, void Interface::_broadcast_arp_request(Ipv4_address const &ip) { - Ethernet_frame_sized - eth(Mac_address(0xff), _router_mac, Ethernet_frame::Type::ARP); - Arp_packet &arp = *eth.data(); - 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); - send(eth, sizeof(eth)); + enum { + ETH_HDR_SZ = sizeof(Ethernet_frame), + ETH_DAT_SZ = sizeof(Arp_packet) + ETH_HDR_SZ >= Ethernet_frame::MIN_SIZE ? + sizeof(Arp_packet) : + Ethernet_frame::MIN_SIZE - ETH_HDR_SZ, + ETH_CRC_SZ = sizeof(Genode::uint32_t), + PKT_SIZE = ETH_HDR_SZ + ETH_DAT_SZ + ETH_CRC_SZ, + }; + send(PKT_SIZE, [&] (void *pkt_base) { + + /* write Ethernet header */ + Ethernet_frame ð = *reinterpret_cast(pkt_base); + eth.dst(Mac_address(0xff)); + eth.src(_router_mac); + eth.type(Ethernet_frame::Type::ARP); + + /* write ARP header */ + Arp_packet &arp = *eth.data(); + 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); + }); }