|
| 1 | +#include "arp_responder.h" |
| 2 | + |
| 3 | +#include "../utils/arp.h" |
| 4 | + |
| 5 | +using bess::utils::Arp; |
| 6 | +using bess::utils::be16_t; |
| 7 | + |
| 8 | +const Commands ArpResponder::cmds = { |
| 9 | + {"add", "ArpResponderArg", MODULE_CMD_FUNC(&ArpResponder::CommandAdd), 0}}; |
| 10 | + |
| 11 | +CommandResponse ArpResponder::CommandAdd(const bess::pb::ArpResponderArg &arg) { |
| 12 | + be32_t ip_addr; |
| 13 | + arp_entry entry; |
| 14 | + |
| 15 | + if (!arg.ip().length()) { |
| 16 | + return CommandFailure(EINVAL, "IP address is missing"); |
| 17 | + } |
| 18 | + if (!bess::utils::ParseIpv4Address(arg.ip(), &ip_addr)) { |
| 19 | + return CommandFailure(EINVAL, "Invalid IP Address: %s", arg.ip().c_str()); |
| 20 | + } |
| 21 | + |
| 22 | + if (!entry.mac_addr.FromString(arg.mac_addr())) { |
| 23 | + return CommandFailure(EINVAL, "Invalid MAC Address: %s", |
| 24 | + arg.mac_addr().c_str()); |
| 25 | + } |
| 26 | + |
| 27 | + entry.ip_addr = ip_addr; |
| 28 | + entries_[ip_addr] = entry; |
| 29 | + return CommandSuccess(); |
| 30 | +} |
| 31 | + |
| 32 | +void ArpResponder::ProcessBatch(bess::PacketBatch *batch) { |
| 33 | + gate_idx_t out_gates[bess::PacketBatch::kMaxBurst]; |
| 34 | + |
| 35 | + int cnt = batch->cnt(); |
| 36 | + for (int i = 0; i < cnt; i++) { |
| 37 | + bess::Packet *pkt = batch->pkts()[i]; |
| 38 | + |
| 39 | + out_gates[i] = 0; |
| 40 | + |
| 41 | + Ethernet *eth = pkt->head_data<Ethernet *>(); |
| 42 | + if (eth->ether_type != be16_t(Ethernet::Type::kArp)) { |
| 43 | + // Currently drop all non ARP packets, but can also just continue |
| 44 | + out_gates[i] = DROP_GATE; |
| 45 | + continue; |
| 46 | + } |
| 47 | + |
| 48 | + Arp *arp = reinterpret_cast<Arp *>(eth + 1); |
| 49 | + if (arp->opcode == be16_t(Arp::Opcode::kRequest)) { |
| 50 | + // TODO(galsagie) When learn is added, learn SRC MAC here |
| 51 | + |
| 52 | + // Try to find target IP in cache, if exists convert request to reply |
| 53 | + auto it = entries_.find(arp->target_ip_addr); |
| 54 | + if (it != entries_.end()) { |
| 55 | + const struct arp_entry &entry = it->second; |
| 56 | + arp->opcode = be16_t(Arp::Opcode::kReply); |
| 57 | + |
| 58 | + eth->dst_addr = eth->src_addr; |
| 59 | + eth->src_addr = entry.mac_addr; |
| 60 | + |
| 61 | + arp->target_hw_addr = arp->sender_hw_addr; |
| 62 | + arp->sender_hw_addr = entry.mac_addr; |
| 63 | + |
| 64 | + arp->target_ip_addr = arp->sender_ip_addr; |
| 65 | + arp->sender_ip_addr = entry.ip_addr; |
| 66 | + } else { |
| 67 | + // Did not find an ARP entry in cache, drop packet |
| 68 | + // TODO(galsagie) Optinally continue packet to next module here |
| 69 | + out_gates[i] = DROP_GATE; |
| 70 | + } |
| 71 | + } else if (arp->opcode == be16_t(Arp::Opcode::kReply)) { |
| 72 | + // TODO(galsagie) When learn is added, learn SRC MAC here |
| 73 | + out_gates[i] = DROP_GATE; |
| 74 | + } else { |
| 75 | + // TODO(galsagie) Other opcodes are not handled yet. |
| 76 | + out_gates[i] = DROP_GATE; |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + RunSplit(out_gates, batch); |
| 81 | +} |
| 82 | + |
| 83 | +ADD_MODULE(ArpResponder, "arp_responder", |
| 84 | + "Respond to ARP requests and learns new MAC's") |
0 commit comments