ctest arp pass
This commit is contained in:
parent
86ab4dfba4
commit
fe97e171b4
@ -32,15 +32,121 @@ NetworkInterface::NetworkInterface(const EthernetAddress ðernet_address, cons
|
|||||||
void NetworkInterface::send_datagram(const InternetDatagram &dgram, const Address &next_hop) {
|
void NetworkInterface::send_datagram(const InternetDatagram &dgram, const Address &next_hop) {
|
||||||
// convert IP address of next hop to raw 32-bit representation (used in ARP header)
|
// convert IP address of next hop to raw 32-bit representation (used in ARP header)
|
||||||
const uint32_t next_hop_ip = next_hop.ipv4_numeric();
|
const uint32_t next_hop_ip = next_hop.ipv4_numeric();
|
||||||
|
auto const &itr_next_hop_eth = _arp_cache.find(next_hop_ip);
|
||||||
DUMMY_CODE(dgram, next_hop, next_hop_ip);
|
if (itr_next_hop_eth != _arp_cache.end()) {
|
||||||
|
// found
|
||||||
|
auto const &next_hop_eth = itr_next_hop_eth->second;
|
||||||
|
if (next_hop_eth.first.has_value()) {
|
||||||
|
// a valid arp cache entry
|
||||||
|
EthernetFrame frame;
|
||||||
|
EthernetHeader hdr;
|
||||||
|
hdr.dst = next_hop_eth.first.value();
|
||||||
|
hdr.src = _ethernet_address;
|
||||||
|
hdr.type = EthernetHeader::TYPE_IPv4;
|
||||||
|
frame.header() = hdr;
|
||||||
|
frame.payload() = dgram.serialize();
|
||||||
|
_frames_out.push(frame);
|
||||||
|
} else {
|
||||||
|
// an arp has been sent for it within 5 seconds
|
||||||
|
_suspended_datagrams.push_back(std::make_pair(dgram, next_hop));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not found and no arp has been sent for the ip
|
||||||
|
_suspended_datagrams.push_back(std::make_pair(dgram, next_hop));
|
||||||
|
ARPMessage arpmsg;
|
||||||
|
arpmsg.opcode = ARPMessage::OPCODE_REQUEST;
|
||||||
|
arpmsg.sender_ethernet_address = _ethernet_address;
|
||||||
|
arpmsg.sender_ip_address = _ip_address.ipv4_numeric();
|
||||||
|
arpmsg.target_ip_address = next_hop_ip;
|
||||||
|
EthernetFrame frame;
|
||||||
|
EthernetHeader hdr;
|
||||||
|
hdr.dst = ETHERNET_BROADCAST;
|
||||||
|
hdr.src = _ethernet_address;
|
||||||
|
hdr.type = EthernetHeader::TYPE_ARP;
|
||||||
|
frame.header() = hdr;
|
||||||
|
frame.payload() = arpmsg.serialize();
|
||||||
|
_frames_out.push(frame);
|
||||||
|
_arp_cache[next_hop_ip] = std::make_pair(std::optional<EthernetAddress>{}, 5 * 1000);
|
||||||
|
// allocate an entry for the ARP Req we sent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \param[in] frame the incoming Ethernet frame
|
//! \param[in] frame the incoming Ethernet frame
|
||||||
optional<InternetDatagram> NetworkInterface::recv_frame(const EthernetFrame &frame) {
|
optional<InternetDatagram> NetworkInterface::recv_frame(const EthernetFrame &frame) {
|
||||||
DUMMY_CODE(frame);
|
if (frame.header().dst != _ethernet_address && frame.header().dst != ETHERNET_BROADCAST)
|
||||||
|
return {};
|
||||||
|
if (frame.header().type == EthernetHeader::TYPE_IPv4) {
|
||||||
|
auto payload = frame.payload();
|
||||||
|
InternetDatagram dgram;
|
||||||
|
auto parse_res = dgram.parse(payload);
|
||||||
|
if (parse_res == ParseResult::NoError) {
|
||||||
|
return dgram;
|
||||||
|
}
|
||||||
|
} else if (frame.header().type == EthernetHeader::TYPE_ARP) {
|
||||||
|
if (frame.header().src == _ethernet_address) {
|
||||||
|
cerr << "receive loopback arp req\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
ARPMessage arpmsg;
|
||||||
|
auto parse_res = arpmsg.parse(frame.payload());
|
||||||
|
if (parse_res != ParseResult::NoError) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (arpmsg.opcode != ARPMessage::OPCODE_REPLY && arpmsg.opcode != ARPMessage::OPCODE_REQUEST) {
|
||||||
|
cerr << "unknown ARP opcode\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (arpmsg.opcode == ARPMessage::OPCODE_REQUEST && arpmsg.target_ip_address == _ip_address.ipv4_numeric()) {
|
||||||
|
ARPMessage arpreply;
|
||||||
|
arpreply.opcode = ARPMessage::OPCODE_REPLY;
|
||||||
|
arpreply.sender_ethernet_address = _ethernet_address;
|
||||||
|
arpreply.sender_ip_address = _ip_address.ipv4_numeric();
|
||||||
|
arpreply.target_ip_address = arpmsg.sender_ip_address;
|
||||||
|
arpreply.target_ethernet_address = arpmsg.sender_ethernet_address;
|
||||||
|
// i think this should be directly the requester's EA
|
||||||
|
EthernetFrame framereply;
|
||||||
|
EthernetHeader hdr;
|
||||||
|
hdr.dst = arpmsg.sender_ethernet_address;
|
||||||
|
hdr.src = _ethernet_address;
|
||||||
|
hdr.type = EthernetHeader::TYPE_ARP;
|
||||||
|
framereply.header() = hdr;
|
||||||
|
framereply.payload() = arpreply.serialize();
|
||||||
|
_frames_out.push(framereply);
|
||||||
|
}
|
||||||
|
// no matter what type of arp it is, learn from it
|
||||||
|
_arp_cache[arpmsg.sender_ip_address] =
|
||||||
|
std::make_pair(std::optional<EthernetAddress>{arpmsg.sender_ethernet_address}, 30 * 1000);
|
||||||
|
auto itr_dgram = _suspended_datagrams.begin();
|
||||||
|
|
||||||
|
while (itr_dgram != _suspended_datagrams.end()) {
|
||||||
|
if (_arp_cache.find(itr_dgram->second.ipv4_numeric()) != _arp_cache.end()) {
|
||||||
|
auto dgram = itr_dgram->first;
|
||||||
|
auto next_hop = itr_dgram->second;
|
||||||
|
itr_dgram = _suspended_datagrams.erase(itr_dgram);
|
||||||
|
this->send_datagram(dgram, next_hop);
|
||||||
|
} else {
|
||||||
|
itr_dgram++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
|
//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
|
||||||
void NetworkInterface::tick(const size_t ms_since_last_tick) { DUMMY_CODE(ms_since_last_tick); }
|
void NetworkInterface::tick(const size_t ms_since_last_tick) {
|
||||||
|
for (auto &arp_entry : _arp_cache) {
|
||||||
|
if (arp_entry.second.second >= ms_since_last_tick)
|
||||||
|
arp_entry.second.second -= ms_since_last_tick;
|
||||||
|
else
|
||||||
|
arp_entry.second.second = 0;
|
||||||
|
}
|
||||||
|
auto arp_entry = _arp_cache.begin();
|
||||||
|
while (arp_entry != _arp_cache.end()) {
|
||||||
|
if (arp_entry->second.second == 0) {
|
||||||
|
arp_entry = _arp_cache.erase(arp_entry);
|
||||||
|
} else {
|
||||||
|
arp_entry++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: maybe drop packets that couldn't get ARP reply, though not required in this lab
|
||||||
|
}
|
||||||
|
|||||||
@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
//! \brief A "network interface" that connects IP (the internet layer, or network layer)
|
//! \brief A "network interface" that connects IP (the internet layer, or network layer)
|
||||||
//! with Ethernet (the network access layer, or link layer).
|
//! with Ethernet (the network access layer, or link layer).
|
||||||
@ -40,6 +43,13 @@ class NetworkInterface {
|
|||||||
//! outbound queue of Ethernet frames that the NetworkInterface wants sent
|
//! outbound queue of Ethernet frames that the NetworkInterface wants sent
|
||||||
std::queue<EthernetFrame> _frames_out{};
|
std::queue<EthernetFrame> _frames_out{};
|
||||||
|
|
||||||
|
//! internal map as arp cache, holding mapping from ipv4(numerical form) to MAC addr with expire time.
|
||||||
|
//! if optinal<EthnernetAddress> has no value, it means that a ARP has been sent for the IP within 5 seconds
|
||||||
|
std::map<uint32_t, std::pair<std::optional<EthernetAddress>, size_t> > _arp_cache{};
|
||||||
|
|
||||||
|
//! queue the IP datagrams waiting for ARP reply
|
||||||
|
std::list<std::pair<InternetDatagram, Address> >_suspended_datagrams{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! \brief Construct a network interface with given Ethernet (network-access-layer) and IP (internet-layer) addresses
|
//! \brief Construct a network interface with given Ethernet (network-access-layer) and IP (internet-layer) addresses
|
||||||
NetworkInterface(const EthernetAddress ðernet_address, const Address &ip_address);
|
NetworkInterface(const EthernetAddress ðernet_address, const Address &ip_address);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user