Add ARP Responder module - #494
Conversation
ARP responder is configured with known MAC's-IP's pairs and know to answer ARP requests depending on its configured cache. This module can be used to implement virtual routing in virtual enviorments and also as a foundation for ARP handling in general. Still todo is the ability to learn new MAC-IP pairs from the requests and replys and also removing of pairs from cache (with maybe potential timeouts)
add new lines at end of files
Codecov Report
@@ Coverage Diff @@
## master #494 +/- ##
========================================
+ Coverage 30% 58% +28%
========================================
Files 168 178 +10
Lines 8181 10203 +2022
Branches 1556 0 -1556
========================================
+ Hits 2489 5947 +3458
+ Misses 5310 4256 -1054
+ Partials 382 0 -382
Continue to review full report at Codecov.
|
| using bess::utils::Ethernet; | ||
| using bess::utils::be32_t; | ||
|
|
||
| struct arp_entry { |
| struct arp_entry { | ||
| Ethernet::Address mac_addr; | ||
| be32_t ip_addr; | ||
| uint64_t time; |
There was a problem hiding this comment.
Could you describe time, especially its units?
There was a problem hiding this comment.
Done, added that its timestamp, its currently not used but will be in future patches
| CommandResponse CommandAdd(const bess::pb::ArpResponderArg &arg); | ||
|
|
||
| private: | ||
| std::map<be32_t, arp_entry> entries; |
There was a problem hiding this comment.
Member variable comment.
Also entries should be named entries_ and by general convention perhaps use struct arp_entry rather than arp_entry.
|
|
||
| CommandResponse ArpResponder::CommandAdd(const bess::pb::ArpResponderArg &arg) { | ||
| be32_t ip_addr; | ||
| arp_entry entry; |
There was a problem hiding this comment.
See comment below
|
|
||
| entry.mac_addr.FromString(arg.mac_addr()); | ||
| entry.ip_addr = ip_addr; | ||
| entries[ip_addr] = entry; |
There was a problem hiding this comment.
You can brace initialize entry here with all of its fields.
There was a problem hiding this comment.
the mac is now filled as part of a check (see fix above) and its a bit hard to do it now
There was a problem hiding this comment.
Since you aren't brace initializing, could you explicitly initialize time? Otherwise I believe it is uninitialized.
| return CommandFailure(EINVAL, "Invalid IP Address: %s", arg.ip().c_str()); | ||
| } | ||
|
|
||
| entry.mac_addr.FromString(arg.mac_addr()); |
There was a problem hiding this comment.
Do you not want to check the MAC address just like you do the IP address?
| uint64_t time; | ||
| }; | ||
|
|
||
| class ArpResponder final : public Module { |
There was a problem hiding this comment.
Could you add a class comment. Specifically, you may want to mention here (or somewhere) that this module drops non-ARP packets.
|
|
||
| Arp *arp = reinterpret_cast<Arp *>(eth + 1); | ||
| if (arp->opcode == be16_t(Arp::Opcode::kRequest)) { | ||
| // TODO When learn is added, learn SRC MAC here |
There was a problem hiding this comment.
Could you change TODO to have your name, e.g. TODO(galsagie), here and below?
|
|
||
| struct arp_entry { | ||
| Ethernet::Address mac_addr; | ||
| be32_t ip_addr; |
There was a problem hiding this comment.
Is ip_addr redundant given that it is the key of the map below?
There was a problem hiding this comment.
It is redundant, i prefer to leave it currently for clarity and optimize in later patch
If you think strongly about it, i will use the key
| // Try to find target IP in cache, if exists convert request to reply | ||
| auto it = entries.find(arp->target_ip_addr); | ||
| if (it != entries.end()) { | ||
| struct arp_entry *entry = &it->second; |
There was a problem hiding this comment.
Prefer a const reference, e.g.:
const struct arp_entry &entry = it->second
Address code review comments
| // Try to find target IP in cache, if exists convert request to reply | ||
| auto it = entries_.find(arp->target_ip_addr); | ||
| if (it != entries_.end()) { | ||
| const struct arp_entry &entry = it->second; |
There was a problem hiding this comment.
Could you run clang-format to fix this and anything else it finds?
| struct arp_entry { | ||
| Ethernet::Address mac_addr; | ||
| be32_t ip_addr; | ||
| // timestamp used to expire cache entries |
There was a problem hiding this comment.
Minor: since the other fields don't have comments, perhaps move the comment to the same line as time. Also, could you include the units?
Address code review comments
| for (int i = 0; i < cnt; i++) { | ||
| bess::Packet *pkt = batch->pkts()[i]; | ||
|
|
||
| out_gates[i] = incoming_gate; |
There was a problem hiding this comment.
Given that the module has only one input/output gate, you can just assign 0. Unfortunately get_igate() is not free... :(
| import scapy.all as scapy | ||
|
|
||
| eth_header = scapy.Ether(src='02:1e:67:9f:4d:ae', dst='ff:ff:ff:ff:ff:ff') | ||
| arp_header = scapy.ARP(op=1, pdst='1.1.1.1') |
There was a problem hiding this comment.
Maybe we can use another IP address that is not symmetric? Just as a safety measure for subtle endianness regression bugs later any time...
| pkt = eth_header/arp_header | ||
| packets = [str(pkt)] | ||
|
|
||
| arp = ArpResponder(name="arp") |
There was a problem hiding this comment.
name="arp" is set but not used below. For conciseness, this line can be replaced with either:
arp::ArpResponder() # this is identical to the original statement
or
arp = ArpResponder() # the resulting (default) name will be arp_responder0
| packets = [str(pkt)] | ||
|
|
||
| arp = ArpResponder(name="arp") | ||
| arp.add(ip='1.1.1.1', mac_addr='11:22:33:44:55:66') |
There was a problem hiding this comment.
Really a minor thing, but the MAC address is multicast :-)
| arp->sender_ip_addr = entry.ip_addr; | ||
| } | ||
| } else if (arp->opcode == be16_t(Arp::Opcode::kReply)) { | ||
| // TODO(galsagie) When learn is added, learn SRC MAC here |
There was a problem hiding this comment.
I believe these two else blocks should discard (after learning if necessary) the packet as well...? Otherwise, its downstream modules has to figure out what to do with the packets.
| } | ||
|
|
||
| /** | ||
| * The ARP Responder module is responding to ARP requests and can optionally learn new MAC's-IP's mapping |
There was a problem hiding this comment.
The comment "can optionally learn ..." can be updated so as to be clear that it is not supported yet...? For example, "TODO:"
Q: is the ARP learning feature for proxy ARP?
There was a problem hiding this comment.
Done, yes it can be used for a proxy ARP and it can also be used later for "full" ARP layer implementation to the local host.
Address code review comments, 1) Drop ARP packets in case no cache entry is found and not an ARP request 2) Update TODO's 3) Use 0 as the default incoming gate

ARP responder is configured with known MAC's-IP's pairs
and know to answer ARP requests depending on its configured cache.
This module can be used to implement virtual routing in
virtual enviorments and also as a foundation for ARP
handling in general.
Still todo is the ability to learn new MAC-IP pairs from
the requests and replys and also removing of pairs
from cache (with maybe potential timeouts)