nic_router: update checksums only once per packet

The NIC router used to update IPv4 and layer 4 checksums of a packet for each
interface it was sent to (say, all interfaces of the domain the packet was
routed to). However, there was and is no technical reason for not doing it
only once and then iterating over the interfaces with the already updated
packet. This is what this commit does in an intent to raise the router's
performance.

Ref #4555
This commit is contained in:
Martin Stein 2022-07-13 19:11:15 +02:00 committed by Christian Helmuth
parent 01c9c32573
commit 95b3b36cd9
2 changed files with 37 additions and 45 deletions

View File

@ -293,28 +293,26 @@ void Interface::_destroy_link(Link &link)
}
void Interface::_pass_prot(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
size_t const prot_size)
void Interface::_pass_prot_to_domain(Domain &domain,
Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
size_t const prot_size)
{
eth.src(_router_mac);
if (!_domain().use_arp()) {
eth.dst(_router_mac);
}
_update_checksum(prot, prot_base, prot_size, ip.src(), ip.dst(), ip.total_length());
_pass_ip(eth, size_guard, ip);
}
_update_checksum(
prot, prot_base, prot_size, ip.src(), ip.dst(), ip.total_length());
void Interface::_pass_ip(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip)
{
ip.update_checksum();
send(eth, size_guard);
domain.interfaces().for_each([&] (Interface &interface)
{
eth.src(interface._router_mac);
if (!domain.use_arp()) {
eth.dst(interface._router_mac);
}
interface.send(eth, size_guard);
});
}
@ -606,9 +604,9 @@ void Interface::_nat_link_and_pass(Ethernet_frame &eth,
Link_side_id const remote_id = { ip.dst(), _dst_port(prot, prot_base),
ip.src(), _src_port(prot, prot_base) };
_new_link(prot, local_id, remote_port_alloc, remote_domain, remote_id);
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(eth, size_guard, ip, prot, prot_base, prot_size);
});
_pass_prot_to_domain(
remote_domain, eth, size_guard, ip, prot, prot_base, prot_size);
} catch (Port_allocator_guard::Out_of_indices) {
switch (prot) {
case L3_protocol::TCP: _tcp_stats.refused_for_ports++; break;
@ -1001,11 +999,10 @@ void Interface::_handle_icmp_query(Ethernet_frame &eth,
ip.dst(remote_side.src_ip());
_src_port(prot, prot_base, remote_side.dst_port());
_dst_port(prot, prot_base, remote_side.src_port());
_pass_prot_to_domain(
remote_domain, eth, size_guard, ip, prot, prot_base,
prot_size);
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(
eth, size_guard, ip, prot, prot_base, prot_size);
});
_link_packet(prot, prot_base, link, client);
done = true;
},
@ -1249,11 +1246,10 @@ void Interface::_handle_ip(Ethernet_frame &eth,
ip.dst(remote_side.src_ip());
_src_port(prot, prot_base, remote_side.dst_port());
_dst_port(prot, prot_base, remote_side.src_port());
_pass_prot_to_domain(
remote_domain, eth, size_guard, ip, prot, prot_base,
prot_size);
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(
eth, size_guard, ip, prot, prot_base, prot_size);
});
_link_packet(prot, prot_base, link, client);
done = true;
},
@ -1330,11 +1326,10 @@ void Interface::_handle_ip(Ethernet_frame &eth,
Domain &remote_domain = rule.domain();
_adapt_eth(eth, ip.dst(), pkt, remote_domain);
remote_domain.interfaces().for_each(
[&] (Interface &interface) {
interface._pass_ip(eth, size_guard, ip);
}
);
ip.update_checksum();
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface.send(eth, size_guard);
});
done = true;
},
[&] /* handle_no_match */ () { }

View File

@ -276,16 +276,13 @@ class Net::Interface : private Interface_list::Element
Size_guard &size_guard,
Domain &local_domain);
void _pass_prot(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
Genode::size_t const prot_size);
void _pass_ip(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip);
void _pass_prot_to_domain(Domain &domain,
Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
Genode::size_t const prot_size);
void _handle_pkt();