net: implement IPv4 L3->l4 dispatching

This commit is contained in:
Avi Kivity
2014-09-01 15:19:17 +03:00
parent 93f1af6f33
commit 0a45d4d73b
2 changed files with 87 additions and 1 deletions

View File

@@ -48,7 +48,77 @@ uint16_t ip_checksum(const void* data, size_t len) {
ipv4::ipv4(interface* netif)
: _netif(netif)
, _global_arp(netif)
, _arp(_global_arp) {
, _arp(_global_arp)
, _l3(netif, 0x0800)
, _l4({}) {
run();
}
bool ipv4::in_my_netmask(ipv4_address a) const {
return !((a.ip ^ _host_address.ip) & ~_netmask.ip);
}
void ipv4::run() {
_l3.receive().then([this] (packet p, ethernet_address from) {
handle_received_packet(std::move(p), from);
run();
});
}
void ipv4::handle_received_packet(packet p, ethernet_address from) {
auto iph = p.get_header<ip_hdr>(0);
if (!iph) {
return;
}
ntoh(*iph);
// FIXME: process options
if (in_my_netmask(iph->src_ip) && iph->src_ip != _host_address) {
_arp.learn(from, iph->src_ip);
}
if (iph->frag & 0x3fff) {
// FIXME: defragment
return;
}
if (iph->dst_ip != _host_address) {
// FIXME: forward
return;
}
auto l4 = _l4[iph->ip_proto];
if (l4) {
p.trim_front(iph->ihl * 4);
l4->received(std::move(p), iph->src_ip, iph->dst_ip);
}
}
void ipv4::send(ipv4_address to, uint8_t proto_num, packet p) {
// FIXME: fragment
ip_hdr iph;
iph.ihl = sizeof(iph) / 4;
iph.ver = 4;
iph.dscp = 0;
iph.ecn = 0;
iph.len = p.len;
iph.id = 0;
iph.frag = 0;
iph.ttl = 64;
iph.ip_proto = proto_num;
iph.csum = 0;
iph.src_ip = _host_address;
// FIXME: routing
auto gw = to;
iph.dst_ip = to;
checksummer csum;
csum.sum(reinterpret_cast<char*>(&iph), sizeof(iph));
csum.sum(p);
auto q = packet(fragment{reinterpret_cast<char*>(&iph), sizeof(iph)}, std::move(p));
_arp.lookup(gw).then([this, p = std::move(q)] (ethernet_address e_dst) mutable {
_send_sem.wait().then([this, e_dst, p = std::move(p)] () mutable {
return _l3.send(e_dst, std::move(p));
}).then([this] {
_send_sem.signal();
});
});
}
void ipv4::set_host_address(ipv4_address ip) {

View File

@@ -9,6 +9,7 @@
#include <arpa/inet.h>
#include <cstdint>
#include <array>
#include "core/array_map.hh"
#include "byteorder.hh"
#include "arp.hh"
@@ -56,6 +57,12 @@ struct hash<net::ipv4_address> {
namespace net {
class ip_protocol {
public:
virtual ~ip_protocol() {}
virtual void received(packet p, ipv4_address from, ipv4_address to);
};
class ipv4 {
public:
using address_type = ipv4_address;
@@ -66,9 +73,18 @@ private:
arp _global_arp;
arp_for<ipv4> _arp;
ipv4_address _host_address;
ipv4_address _netmask = ipv4_address(0xffffff00);
l3_protocol _l3;
array_map<ip_protocol*, 256> _l4;
semaphore _send_sem;
private:
void run();
void handle_received_packet(packet p, ethernet_address from);
bool in_my_netmask(ipv4_address a) const;
public:
explicit ipv4(interface* netif);
void set_host_address(ipv4_address ip);
void send(ipv4_address to, uint8_t proto_num, packet p);
};
struct ip_hdr {