int Arp::transmit(Packet_ptr pckt){ assert(pckt->size()); /** Get destination IP from IP header */ IP4::ip_header* iphdr = (IP4::ip_header*)(pckt->buffer() + sizeof(Ethernet::header)); IP4::addr sip = iphdr->saddr; IP4::addr dip = pckt->next_hop(); debug2("<ARP -> physical> Transmitting %i bytes to %s \n", pckt->size(),dip.str().c_str()); Ethernet::addr mac; if (iphdr->daddr == IP4::INADDR_BCAST) { // when broadcasting our source IP should be either // our own IP or 0.0.0.0 static const IP4::addr INADDR_NONE {{0}}; if (sip != ip_ && sip != INADDR_NONE) { debug2("<ARP> Dropping outbound broadcast packet due to " "invalid source IP %s\n", sip.str().c_str()); return -1; } mac = Ethernet::addr::BROADCAST_FRAME; } else { if (sip != ip_) { debug2("<ARP -> physical> Not bound to source IP %s. My IP is %s. DROP!\n", sip.str().c_str(), ip_.str().c_str()); return -1; } // If we don't have a cached IP, get mac from next-hop (HĂ„reks c001 hack) if (!is_valid_cached(dip)) return arp_resolver_(pckt); // Get mac from cache mac = cache_[dip].mac_; } /** Attach next-hop mac and ethertype to ethernet header */ Ethernet::header* ethhdr = (Ethernet::header*)pckt->buffer(); ethhdr->src = mac_; ethhdr->dest.major = mac.major; ethhdr->dest.minor = mac.minor; ethhdr->type = Ethernet::ETH_IP4; debug2("<ARP -> physical> Sending packet to %s \n",mac.str().c_str()); return linklayer_out_(pckt); }
virtual void network_config(IP4::addr addr, IP4::addr nmask, IP4::addr router, IP4::addr dns) override { INFO("Inet4", "Reconfiguring network. New IP: %s", addr.str().c_str()); this->ip4_addr_ = addr; this->netmask_ = nmask; this->router_ = router; this->dns_server = dns; }
void Arp::arp_resolve(IP4::addr next_hop) { PRINT("<ARP RESOLVE> %s\n", next_hop.str().c_str()); auto req = static_unique_ptr_cast<PacketArp>(inet_.create_packet()); req->init(mac_, inet_.ip_addr(), next_hop); req->set_dest_mac(MAC::BROADCAST); req->set_opcode(H_request); // Stat increment requests sent requests_tx_++; linklayer_out_(std::move(req), MAC::BROADCAST, Ethertype::ARP); }
void Arp::cache(IP4::addr& ip, Ethernet::addr& mac){ debug2("Caching IP %s for %s \n",ip.str().c_str(),mac.str().c_str()); auto entry = cache_.find(ip); if (entry != cache_.end()){ debug2("Cached entry found: %s recorded @ %llu. Updating timestamp \n", entry->second.mac_.str().c_str(), entry->second.t_); // Update entry->second.update(); }else cache_[ip] = mac; // Insert }
void Arp::await_resolution(Packet_ptr pckt, IP4::addr next_hop) { auto queue = waiting_packets_.find(next_hop); PRINT("<ARP await> Waiting for resolution of %s\n", next_hop.str().c_str()); if (queue != waiting_packets_.end()) { PRINT("\t * Packets already queueing for this IP\n"); queue->second.pckt->chain(std::move(pckt)); } else { PRINT("\t *This is the first packet going to that IP\n"); waiting_packets_.emplace(std::make_pair(next_hop, Queue_entry{std::move(pckt)})); // Try resolution immediately arp_resolver_(next_hop); // Retry later resolve_timer_.start(1s); } }
void Arp::cache(IP4::addr ip, MAC::Addr mac) { PRINT("<Arp> Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); auto entry = cache_.find(ip); if (entry != cache_.end()) { PRINT("Cached entry found: %s recorded @ %llu. Updating timestamp\n", entry->second.mac().str().c_str(), entry->second.timestamp()); if (entry->second.mac() != mac) { cache_.erase(entry); cache_[ip] = mac; } else { entry->second.update(); } } else { cache_[ip] = mac; // Insert if (UNLIKELY(not flush_timer_.is_running())) { flush_timer_.start(flush_interval_); } } }
void Arp::transmit(Packet_ptr pckt, IP4::addr next_hop) { Expects(pckt->size()); PRINT("<ARP -> physical> Transmitting %u bytes to %s\n", (uint32_t) pckt->size(), next_hop.str().c_str()); MAC::Addr dest_mac; if (next_hop == IP4::ADDR_BCAST) { dest_mac = MAC::BROADCAST; } else { #ifdef ARP_PASSTHROUGH extern MAC::Addr linux_tap_device; dest_mac = linux_tap_device; #else // If we don't have a cached IP, perform address resolution auto cache_entry = cache_.find(next_hop); if (UNLIKELY(cache_entry == cache_.end())) { PRINT("<ARP> No cache entry for IP %s. Resolving. \n", next_hop.to_string().c_str()); await_resolution(std::move(pckt), next_hop); return; } // Get MAC from cache dest_mac = cache_[next_hop].mac(); #endif PRINT("<ARP> Found cache entry for IP %s -> %s \n", next_hop.to_string().c_str(), dest_mac.to_string().c_str()); } // Move chain to linklayer linklayer_out_(std::move(pckt), dest_mac, Ethertype::IP4); }
void Arp::transmit(Packet_ptr pckt) { assert(pckt->size()); /** Get destination IP from IP header */ IP4::ip_header* iphdr = reinterpret_cast<IP4::ip_header*>(pckt->buffer() + sizeof(Ethernet::header)); IP4::addr sip = iphdr->saddr; IP4::addr dip = pckt->next_hop(); debug2("<ARP -> physical> Transmitting %i bytes to %s\n", pckt->size(), dip.str().c_str()); Ethernet::addr dest_mac; if (iphdr->daddr == IP4::INADDR_BCAST) { // When broadcasting our source IP should be either // our own IP or 0.0.0.0 if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { debug2("<ARP> Dropping outbound broadcast packet due to " "invalid source IP %s\n", sip.str().c_str()); return; } // mui importante dest_mac = Ethernet::BROADCAST_FRAME; } else { if (sip != inet_.ip_addr()) { debug2("<ARP -> physical> Not bound to source IP %s. My IP is %s. DROP!\n", sip.str().c_str(), inet_.ip_addr().str().c_str()); return; } // If we don't have a cached IP, perform address resolution if (!is_valid_cached(dip)) { arp_resolver_(std::move(pckt)); return; } // Get MAC from cache dest_mac = cache_[dip].mac_; } /** Attach next-hop mac and ethertype to ethernet header */ auto* ethhdr = reinterpret_cast<Ethernet::header*>(pckt->buffer()); ethhdr->src = mac_; ethhdr->dest = dest_mac; ethhdr->type = Ethernet::ETH_IP4; /** Update chain as well */ auto* next = pckt->tail(); while(next) { auto* headur = reinterpret_cast<Ethernet::header*>(next->buffer()); headur->src = mac_; headur->dest = dest_mac; headur->type = Ethernet::ETH_IP4; next = next->tail(); } debug2("<ARP -> physical> Sending packet to %s\n", mac_.str().c_str()); linklayer_out_(std::move(pckt)); }