From 9a899b14b124c35e6778d48677cdc92c2b438852 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 12 Feb 2007 15:55:49 +0100 Subject: [PATCH] add arp stack --- SConstruct | 14 +- src/node/arp-cache.cc | 238 ++++++++++++++++++++++++++++++++ src/node/arp-cache.h | 104 ++++++++++++++ src/node/arp-header.cc | 144 +++++++++++++++++++ src/node/arp-header.h | 69 +++++++++ src/node/arp-ipv4-interface.cc | 51 +++++++ src/node/arp-ipv4-interface.h | 45 ++++++ src/node/arp-l3-protocol.cc | 53 +++++++ src/node/arp-l3-protocol.h | 49 +++++++ src/node/arp.cc | 196 ++++++++++++++++++++++++++ src/node/arp.h | 58 ++++++++ src/node/header-utils.cc | 49 +++++++ src/node/header-utils.h | 38 +++++ src/node/internet-node.cc | 22 ++- src/node/internet-node.h | 4 +- src/node/ipv4.cc | 13 +- src/node/ipv4.h | 1 + src/node/mac-address.cc | 36 ++--- src/node/mac-address.h | 13 +- src/node/node.cc | 6 +- src/node/node.h | 2 + src/node/sgi-hashmap.h | 32 +++++ src/node/udp-ipv4-l4-protocol.h | 2 +- 23 files changed, 1206 insertions(+), 33 deletions(-) create mode 100644 src/node/arp-cache.cc create mode 100644 src/node/arp-cache.h create mode 100644 src/node/arp-header.cc create mode 100644 src/node/arp-header.h create mode 100644 src/node/arp-ipv4-interface.cc create mode 100644 src/node/arp-ipv4-interface.h create mode 100644 src/node/arp-l3-protocol.cc create mode 100644 src/node/arp-l3-protocol.h create mode 100644 src/node/arp.cc create mode 100644 src/node/arp.h create mode 100644 src/node/header-utils.cc create mode 100644 src/node/header-utils.h create mode 100644 src/node/sgi-hashmap.h diff --git a/SConstruct b/SConstruct index caee3c4b5..4aff78b36 100644 --- a/SConstruct +++ b/SConstruct @@ -164,6 +164,11 @@ node.add_sources ([ 'udp-end-point.cc', 'udp-socket.cc', 'udp.cc', + 'arp-header.cc', + 'arp-l3-protocol.cc', + 'arp-cache.cc', + 'arp-ipv4-interface.cc', + 'arp.cc', ]) node.add_headers ([ 'ipv4-address.h', @@ -172,13 +177,20 @@ node.add_headers ([ 'ipv4-checksum.h', 'ipv4.h', 'udp.h', + 'ipv4-l4-protocol.h', + 'udp-ipv4-l4-protocol.h', + 'ipv4-l3-protocol.h', + 'arp-l3-protocol.h', + 'arp-header.h', + 'arp-cache-cache.h', + 'arp-ipv4-interface.h', + 'arp.h', ]) node.add_inst_headers ([ 'node.h', 'l3-demux.h', 'l3-protocol.h', 'ipv4-l4-demux.h', - 'ipv4-l4-protocol.h', 'net-device-list.h', 'internet-node.h', 'net-device.h', diff --git a/src/node/arp-cache.cc b/src/node/arp-cache.cc new file mode 100644 index 000000000..5c140e259 --- /dev/null +++ b/src/node/arp-cache.cc @@ -0,0 +1,238 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include + +#include "ns3/packet.h" +#include "ns3/simulator.h" + +#include "arp-cache.h" +#include "arp-cache-entry.h" +#include "arp-header.h" + +#ifdef TRACE_ARP +#include +#include "simulator.h" +# define TRACE(x) \ +std::cout << "ARP TRACE " << Simulator::Now () << " " \ + << x << std::endl; +#else /* TRACE_ARP */ +# define TRACE(format,...) +#endif /* TRACE_ARP */ + + +namespace ns3 { + +ArpCache::ArpCache (NetDevice *device, Ipv4Interface *interface) + : m_device (device), + m_interface (interface), + m_aliveTimeout (Seconds (120)), + m_deadTimeout (Seconds (100)), + m_waitReplyTimeout (Seconds (1)) +{} + +ArpCache::~ArpCache () +{ + Flush (); +} + +NetDevice * +ArpCache::GetDevice (void) const +{ + return m_device; +} + +Ipv4Interface * +ArpCache::GetInterface (void) const +{ + return m_interface; +} + +void +ArpCache::SetAliveTimeout (Time aliveTimeout) +{ + m_aliveTimeout = aliveTimeout; +} +void +ArpCache::SetDeadTimeout (Time deadTimeout) +{ + m_deadTimeout = deadTimeout; +} +void +ArpCache::SetWaitReplyTimeout (Time waitReplyTimeout) +{ + m_waitReplyTimeout = waitReplyTimeout; +} + +Time +ArpCache::GetAliveTimeout (void) const +{ + return m_aliveTimeout; +} +Time +ArpCache::GetDeadTimeout (void) const +{ + return m_deadTimeout; +} +Time +ArpCache::GetWaitReplyTimeout (void) const +{ + return m_waitReplyTimeout; +} + +void +ArpCache::Flush (void) +{ + for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++) + { + delete (*i).second; + } + m_arpCache.erase (m_arpCache.begin (), m_arpCache.end ()); +} + +ArpCache::Entry * +ArpCache::Lookup (Ipv4Address to) +{ + if (m_arpCache.find (to) != m_arpCache.end ()) + { + ArpCache::Entry *entry = m_arpCache[to]; + return entry; + } + return 0; +} + +ArpCache::Entry * +ArpCache::Add (Ipv4Address to) +{ + ArpCache::Entry *entry = new ArpCache::Entry (this); + m_arpCache[to] = entry; + return entry; +} + +ArpCache::Entry::Entry (ArpCache *arp) + : m_arp (arp), + m_state (ALIVE), + m_waiting () +{} + + +bool +ArpCache::Entry::IsDead (void) +{ + return (m_state == DEAD)?true:false; +} +bool +ArpCache::Entry::IsAlive (void) +{ + return (m_state == ALIVE)?true:false; +} +bool +ArpCache::Entry::IsWaitReply (void) +{ + return (m_state == WAIT_REPLY)?true:false; +} + + +void +ArpCache::Entry::MarkDead (void) +{ + m_state = DEAD; + //assert (m_waiting != 0); + UpdateSeen (); +} +Packet +ArpCache::Entry::MarkAlive (MacAddress macAddress) +{ + assert (m_state == WAIT_REPLY); + //assert (m_waiting != 0); + m_macAddress = macAddress; + m_state = ALIVE; + UpdateSeen (); + Packet waiting = m_waiting; + //m_waiting = 0; + return waiting; +} + +Packet +ArpCache::Entry::UpdateWaitReply (Packet waiting) +{ + assert (m_state == WAIT_REPLY); + /* We are already waiting for an answer so + * we dump the previously waiting packet and + * replace it with this one. + */ + Packet old = m_waiting; + m_waiting = waiting; + return old; +} +void +ArpCache::Entry::MarkWaitReply (Packet waiting) +{ + assert (m_state == ALIVE || m_state == DEAD); + //assert (m_waiting == 0); + m_state = WAIT_REPLY; + m_waiting = waiting; + UpdateSeen (); +} + +MacAddress +ArpCache::Entry::GetMacAddress (void) +{ + assert (m_state == ALIVE); + return m_macAddress; +} +bool +ArpCache::Entry::IsExpired (void) +{ + Time timeout; + switch (m_state) { + case ArpCache::Entry::WAIT_REPLY: + timeout = m_arp->GetWaitReplyTimeout (); + break; + case ArpCache::Entry::DEAD: + timeout = m_arp->GetDeadTimeout (); + break; + case ArpCache::Entry::ALIVE: + timeout = m_arp->GetAliveTimeout (); + break; + default: + assert (false); + timeout = Seconds (0); + /* NOTREACHED */ + break; + } + Time delta = Simulator::Now () - m_lastSeen; + if (delta >= timeout) + { + return true; + } + else + { + return false; + } +} +void +ArpCache::Entry::UpdateSeen (void) +{ + m_lastSeen = Simulator::Now (); +} + +} // namespace ns3 + diff --git a/src/node/arp-cache.h b/src/node/arp-cache.h new file mode 100644 index 000000000..f71e9ce9a --- /dev/null +++ b/src/node/arp-cache.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef ARP_CACHE_H +#define ARP_CACHE_H + +#include +#include "ns3/packet.h" +#include "ns3/nstime.h" +#include "ipv4-address.h" +#include "mac-address.h" +#include "sgi-hashmap.h" + +namespace ns3 { + +class NetDevice; +class Ipv4Interface; + +class ArpCache { +public: + class Entry; + + ArpCache (NetDevice *device, Ipv4Interface *interface); + ~ArpCache (); + + NetDevice *GetDevice (void) const; + Ipv4Interface *GetInterface (void) const; + + void SetAliveTimeout (Time aliveTimeout); + void SetDeadTimeout (Time deadTimeout); + void SetWaitReplyTimeout (Time waitReplyTimeout); + Time GetAliveTimeout (void) const; + Time GetDeadTimeout (void) const; + Time GetWaitReplyTimeout (void) const; + + + ArpCache::Entry *Lookup (Ipv4Address destination); + ArpCache::Entry *Add (Ipv4Address to); + void Flush (void); + + + class Entry { + public: + Entry (ArpCache *arp); + + void MarkDead (void); + Packet MarkAlive (MacAddress macAddress); + void MarkWaitReply (Packet waiting); + Packet UpdateWaitReply (Packet waiting); + + bool IsDead (void); + bool IsAlive (void); + bool IsWaitReply (void); + + MacAddress GetMacAddress (void); + bool IsExpired (void); + private: + enum ArpCacheEntryState_e { + ALIVE, + WAIT_REPLY, + DEAD + }; + + void UpdateSeen (void); + ArpCache *m_arp; + ArpCacheEntryState_e m_state; + Time m_lastSeen; + MacAddress m_macAddress; + Packet m_waiting; + }; + +private: + typedef sgi::hash_map Cache; + typedef sgi::hash_map::iterator CacheI; + + NetDevice *m_device; + Ipv4Interface *m_interface; + Time m_aliveTimeout; + Time m_deadTimeout; + Time m_waitReplyTimeout; + Cache m_arpCache; +}; + + +}; // namespace ns3 + +#endif /* ARP_CACHE_H */ diff --git a/src/node/arp-header.cc b/src/node/arp-header.cc new file mode 100644 index 000000000..f8d53c1b2 --- /dev/null +++ b/src/node/arp-header.cc @@ -0,0 +1,144 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include +#include "arp-header.h" +#include "header-utils.h" + +namespace ns3 { + +ArpHeader::~ArpHeader () +{} + +void +ArpHeader::SetRequest (MacAddress sourceHardwareAddress, + Ipv4Address sourceProtocolAddress, + MacAddress destinationHardwareAddress, + Ipv4Address destinationProtocolAddress) +{ + m_type = ARP_TYPE_REQUEST; + m_macSource = sourceHardwareAddress; + m_macDest = destinationHardwareAddress; + m_ipv4Source = sourceProtocolAddress; + m_ipv4Dest = destinationProtocolAddress; +} +void +ArpHeader::SetReply (MacAddress sourceHardwareAddress, + Ipv4Address sourceProtocolAddress, + MacAddress destinationHardwareAddress, + Ipv4Address destinationProtocolAddress) +{ + m_type = ARP_TYPE_REPLY; + m_macSource = sourceHardwareAddress; + m_macDest = destinationHardwareAddress; + m_ipv4Source = sourceProtocolAddress; + m_ipv4Dest = destinationProtocolAddress; +} +bool +ArpHeader::IsRequest (void) const +{ + return (m_type == ARP_TYPE_REQUEST)?true:false; +} +bool +ArpHeader::IsReply (void) const +{ + return (m_type == ARP_TYPE_REPLY)?true:false; +} +MacAddress +ArpHeader::GetSourceHardwareAddress (void) +{ + return m_macSource; +} +MacAddress +ArpHeader::GetDestinationHardwareAddress (void) +{ + return m_macDest; +} +Ipv4Address +ArpHeader::GetSourceIpv4Address (void) +{ + return m_ipv4Source; +} +Ipv4Address +ArpHeader::GetDestinationIpv4Address (void) +{ + return m_ipv4Dest; +} + + +void +ArpHeader::PrintTo (std::ostream &os) const +{ + os << "(arp)"; + if (IsRequest ()) + { + os << " source mac: " << m_macSource + << " source ipv4: " << m_ipv4Source + << " dest ipv4: " << m_ipv4Dest; + } + else + { + assert (IsReply ()); + os << " source mac: " << m_macSource + << " source ipv4: " << m_ipv4Source + << " dest mac: " << m_macDest + << " dest ipv4: " < + */ + +#ifndef ARP_HEADER_H +#define ARP_HEADER_H + +#include "ns3/header.h" +#include "mac-address.h" +#include "ipv4-address.h" + +namespace ns3 { + +class ArpHeader : public Header { + public: + virtual ~ArpHeader (); + + void SetRequest (MacAddress sourceHardwareAddress, + Ipv4Address sourceProtocolAddress, + MacAddress destinationHardwareAddress, + Ipv4Address destinationProtocolAddress); + void SetReply (MacAddress sourceHardwareAddress, + Ipv4Address sourceProtocolAddress, + MacAddress destinationHardwareAddress, + Ipv4Address destinationProtocolAddress); + bool IsRequest (void) const; + bool IsReply (void) const; + MacAddress GetSourceHardwareAddress (void); + MacAddress GetDestinationHardwareAddress (void); + Ipv4Address GetSourceIpv4Address (void); + Ipv4Address GetDestinationIpv4Address (void); + +private: + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual void DeserializeFrom (Buffer::Iterator start); + + enum ArpType_e { + ARP_TYPE_REQUEST = 1, + ARP_TYPE_REPLY = 2 + }; + uint16_t m_type; + MacAddress m_macSource; + MacAddress m_macDest; + Ipv4Address m_ipv4Source; + Ipv4Address m_ipv4Dest; +}; + +}; // namespace ns3 + +#endif /* ARP_HEADER_H */ diff --git a/src/node/arp-ipv4-interface.cc b/src/node/arp-ipv4-interface.cc new file mode 100644 index 000000000..391903e7a --- /dev/null +++ b/src/node/arp-ipv4-interface.cc @@ -0,0 +1,51 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Mathieu Lacage , + */ + +#include "ns3/packet.h" + +#include "arp-ipv4-interface.h" +#include "arp.h" +#include "node.h" +#include "net-device.h" + +namespace ns3 { + +ArpIpv4Interface::ArpIpv4Interface (Node *node, NetDevice *device) + : Ipv4Interface (device), + m_node (node) +{} +ArpIpv4Interface::~ArpIpv4Interface () +{} + +void +ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest) +{ + Arp * arp = m_node->GetArp (); + MacAddress hardwareDestination; + bool found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination); + if (found) + { + GetDevice ()->Send (p, hardwareDestination, 0x0800 /* XXX */); + } +} + +}//namespace ns3 diff --git a/src/node/arp-ipv4-interface.h b/src/node/arp-ipv4-interface.h new file mode 100644 index 000000000..9a40789ae --- /dev/null +++ b/src/node/arp-ipv4-interface.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Mathieu Lacage , + */ +#ifndef ARP_IPV4_INTERFACE_H +#define ARP_IPV4_INTERFACE_H + +#include "ipv4-interface.h" + +namespace ns3 { + +class Node; + +class ArpIpv4Interface : public Ipv4Interface +{ + public: + ArpIpv4Interface (Node *node, NetDevice *device); + virtual ~ArpIpv4Interface (); + + private: + virtual void SendTo (Packet p, Ipv4Address dest); + Node *m_node; +}; + +}//namespace ns3 + + +#endif /* ARP_IPV4_INTERFACE_H */ diff --git a/src/node/arp-l3-protocol.cc b/src/node/arp-l3-protocol.cc new file mode 100644 index 000000000..e32df81e3 --- /dev/null +++ b/src/node/arp-l3-protocol.cc @@ -0,0 +1,53 @@ +// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: George F. Riley +// + +// NS3 - Layer 3 Protocol base class +// George F. Riley, Georgia Tech, Spring 2007 + +#include "arp-l3-protocol.h" +#include "arp.h" +#include "node.h" + +namespace ns3 { + +ArpL3Protocol::ArpL3Protocol (Node *node) + : L3Protocol (0x0806, 0/* XXX: correct version number ? */ ), + m_node (node) +{} +ArpL3Protocol::~ArpL3Protocol () +{} + +ArpL3Protocol * +ArpL3Protocol::Copy (Node *node) const +{ + return new ArpL3Protocol (node); +} +void +ArpL3Protocol::Receive(Packet& p, NetDevice &device) +{ + Arp * arp = m_node->GetArp (); + if (arp != 0) + { + arp->Receive (p, &device); + } +} + +}//namespace ns3 diff --git a/src/node/arp-l3-protocol.h b/src/node/arp-l3-protocol.h new file mode 100644 index 000000000..7b76563bf --- /dev/null +++ b/src/node/arp-l3-protocol.h @@ -0,0 +1,49 @@ +// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: George F. Riley +// + +// NS3 - Layer 3 Protocol base class +// George F. Riley, Georgia Tech, Spring 2007 +#ifndef ARP_L3_PROTOCOL_H +#define ARP_L3_PROTOCOL_H + +#include "l3-protocol.h" + +namespace ns3 { + +class Node; +class NetDevice; +class Packet; + +class ArpL3Protocol : public L3Protocol +{ + public: + ArpL3Protocol (Node *node); + virtual ~ArpL3Protocol (); + + virtual ArpL3Protocol *Copy (Node *node) const; + virtual void Receive(Packet& p, NetDevice &device); +private: + Node *m_node; +}; + +}//namespace ns3 + +#endif /* ARP_L3_PROTOCOL_H */ diff --git a/src/node/arp.cc b/src/node/arp.cc new file mode 100644 index 000000000..ca3b39439 --- /dev/null +++ b/src/node/arp.cc @@ -0,0 +1,196 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "ns3/packet.h" +#include "arp.h" +#include "arp-header.h" +#include "arp-cache.h" +#include "net-device.h" +#include "ipv4-interface.h" +#include "node.h" +#include "ipv4.h" + +#define TRACE(x) + +namespace ns3 { + +Arp::Arp (Node *node) + : m_node (node) +{} + +Arp * +Arp::Copy (Node *node) +{ + return new Arp (node); +} + +ArpCache * +Arp::FindCache (NetDevice *device) +{ + for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++) + { + if ((*i)->GetDevice () == device) + { + return *i; + } + } + Ipv4Interface *interface = m_node->GetIpv4 ()->FindInterfaceForDevice (device); + ArpCache * cache = new ArpCache (device, interface); + assert (device->IsBroadcast ()); + device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache)); + m_cacheList.push_back (cache); + return cache; +} + +void +Arp::Receive(Packet& packet, NetDevice *device) +{ + ArpCache *cache = FindCache (device); + ArpHeader arp; + packet.Peek (arp); + packet.Remove (arp); + if (arp.IsRequest () && + arp.GetDestinationIpv4Address () == cache->GetInterface ()->GetAddress ()) + { + TRACE ("got request from " << arp.GetSourceIpv4Address () << " -- send reply"); + SendArpReply (cache, arp.GetSourceIpv4Address (), + arp.GetSourceHardwareAddress ()); + } + else if (arp.IsReply () && + arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) && + arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ())) + { + Ipv4Address from = arp.GetSourceIpv4Address (); + ArpCache::Entry *entry = cache->Lookup (from); + if (entry != 0) + { + if (entry->IsWaitReply ()) + { + TRACE ("got reply from " << arp.GetSourceIpv4Address () + << " for waiting entry -- flush"); + MacAddress from_mac = arp.GetSourceHardwareAddress (); + Packet waiting = entry->MarkAlive (from_mac); + cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ()); + } + else + { + // ignore this reply which might well be an attempt + // at poisening my arp cache. + TRACE ("got reply from " << arp.GetSourceIpv4Address () << + " for non-waiting entry -- drop"); + // XXX report packet as dropped. + } + } + else + { + TRACE ("got reply for unknown entry -- drop"); + // XXX report packet as dropped. + } + } +} +bool +Arp::Lookup (Packet &packet, Ipv4Address destination, + NetDevice *device, + MacAddress *hardwareDestination) +{ + ArpCache *cache = FindCache (device); + ArpCache::Entry *entry = cache->Lookup (destination); + if (entry != 0) + { + if (entry->IsExpired ()) + { + if (entry->IsDead ()) + { + TRACE ("dead entry for " << destination << " expired -- send arp request"); + entry->MarkWaitReply (packet); + SendArpRequest (cache, destination); + } + else if (entry->IsAlive ()) + { + TRACE ("alive entry for " << destination << " expired -- send arp request"); + entry->MarkWaitReply (packet); + SendArpRequest (cache, destination); + } + else if (entry->IsWaitReply ()) + { + TRACE ("wait reply for " << destination << " expired -- drop"); + entry->MarkDead (); + // XXX report packet as 'dropped' + } + } + else + { + if (entry->IsDead ()) + { + TRACE ("dead entry for " << destination << " valid -- drop"); + // XXX report packet as 'dropped' + } + else if (entry->IsAlive ()) + { + TRACE ("alive entry for " << destination << " valid -- send"); + *hardwareDestination = entry->GetMacAddress (); + return true; + } + else if (entry->IsWaitReply ()) + { + TRACE ("wait reply for " << destination << " valid -- drop previous"); + Packet old = entry->UpdateWaitReply (packet); + // XXX report 'old' packet as 'dropped' + } + } + + } + else + { + // This is our first attempt to transmit data to this destination. + TRACE ("no entry for " << to << " -- send arp request"); + entry = cache->Add (destination); + entry->MarkWaitReply (packet); + SendArpRequest (cache, destination); + } + return false; +} + +void +Arp::SendArpRequest (ArpCache const *cache, Ipv4Address to) +{ + ArpHeader arp; + arp.SetRequest (cache->GetDevice ()->GetAddress (), + cache->GetInterface ()->GetAddress (), + cache->GetDevice ()->GetBroadcast (), + to); + Packet packet; + packet.Add (arp); + cache->GetDevice ()->Send (packet, cache->GetDevice ()->GetBroadcast (), 0x0806); +} + +void +Arp::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac) +{ + ArpHeader arp; + arp.SetReply (cache->GetDevice ()->GetAddress (), + cache->GetInterface ()->GetAddress (), + toMac, toIp); + Packet packet; + packet.Add (arp); + cache->GetDevice ()->Send (packet, toMac, 0x0806); +} + +}//namespace ns3 diff --git a/src/node/arp.h b/src/node/arp.h new file mode 100644 index 000000000..a325da23e --- /dev/null +++ b/src/node/arp.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef ARP_H +#define ARP_H + +#include +#include "ipv4-address.h" +#include "mac-address.h" + +namespace ns3 { + +class ArpCache; +class NetDevice; +class Node; +class Packet; + +class Arp +{ +public: + Arp (Node *node); + ~Arp (); + Arp *Copy (Node *node); + + void Receive(Packet& p, NetDevice *device); + bool Lookup (Packet &p, Ipv4Address destination, + NetDevice *device, + MacAddress *hardwareDestination); +private: + typedef std::list CacheList; + ArpCache *FindCache (NetDevice *device); + void SendArpRequest (ArpCache const *cache, Ipv4Address to); + void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac); + CacheList m_cacheList; + Node *m_node; +}; + +}//namespace ns3 + + +#endif /* ARP_H */ diff --git a/src/node/header-utils.cc b/src/node/header-utils.cc new file mode 100644 index 000000000..9d8e1203e --- /dev/null +++ b/src/node/header-utils.cc @@ -0,0 +1,49 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "chunk-utils.h" + +namespace ns3 { + +void WriteTo (Buffer::Iterator &i, Ipv4Address ad) +{ + i.WriteHtonU32 (ad.GetHostOrder ()); +} +void WriteTo (Buffer::Iterator &i, MacAddress ad) +{ + uint8_t mac[MacAddress::MAX_LEN]; + ad.Peek (mac); + i.Write (mac, ad.GetLen ()); +} + +void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad) +{ + ad.SetHostOrder (i.ReadNtohU32 ()); +} +void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len) +{ + uint8_t mac[MacAddress::MAX_LEN]; + i.Read (mac, len); + ad.Set (mac); +} + + + +}; // namespace ns3 diff --git a/src/node/header-utils.h b/src/node/header-utils.h new file mode 100644 index 000000000..bdfd9a45d --- /dev/null +++ b/src/node/header-utils.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef HEADER_UTILS_H +#define HEADER_UTILS_H + +#include "ns3/buffer.h" +#include "ipv4-address.h" +#include "mac-address.h" + +namespace ns3 { + +void WriteTo (Buffer::Iterator &i, Ipv4Address ad); +void WriteTo (Buffer::Iterator &i, MacAddress ad); + +void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad); +void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len); + +}; + +#endif /* HEADER_UTILS_H */ diff --git a/src/node/internet-node.cc b/src/node/internet-node.cc index fde1b1fc5..6fa45227b 100644 --- a/src/node/internet-node.cc +++ b/src/node/internet-node.cc @@ -28,6 +28,9 @@ #include "internet-node.h" #include "udp.h" #include "ipv4.h" +#include "arp.h" +#include "udp-ipv4-l4-protocol.h" +#include "arp-l3-protocol.h" namespace ns3 { @@ -39,17 +42,28 @@ InternetNode::InternetNode() m_ipv4L4Demux = new Ipv4L4Demux(this); m_udp = new Udp (this); m_ipv4 = new Ipv4 (this); + m_arp = new Arp (this); m_l3Demux->Insert (Ipv4L3Protocol (this)); - // add a udp protocol handler. - //m_ipv4L4Demux->Insert (udp); + m_l3Demux->Insert (ArpL3Protocol (this)); + m_ipv4L4Demux->Insert (UdpIpv4L4Protocol (this)); +} + +InternetNode::InternetNode (InternetNode const &o) +{ + m_netDevices = new NetDeviceList (); + m_l3Demux = o.m_l3Demux->Copy (this); + m_ipv4L4Demux = o.m_ipv4L4Demux->Copy (this); + m_udp = o.m_udp->Copy (this); + m_ipv4 = o.m_ipv4->Copy (this); + m_arp = o.m_arp->Copy (this); } // Copy this node InternetNode* InternetNode::Copy() const { - //return new InternetNode(*this); - return 0; + InternetNode *copy = new InternetNode (*this); + return copy; } diff --git a/src/node/internet-node.h b/src/node/internet-node.h index 2f8be8840..c1827962d 100644 --- a/src/node/internet-node.h +++ b/src/node/internet-node.h @@ -43,6 +43,7 @@ public: virtual Ipv4L4Demux* GetIpv4L4Demux() const; virtual Ipv4 * GetIpv4 (void) const; virtual Udp * GetUdp (void) const; + virtual Arp * GetArp (void) const; private: // Capabilities @@ -51,7 +52,8 @@ private: Ipv4L4Demux* m_ipv4L4Demux; Ipv4 * m_ipv4; Udp * m_udp; - }; + Arp * m_arp; +}; }//namespace ns3 diff --git a/src/node/ipv4.cc b/src/node/ipv4.cc index 8ba04ecd4..8fba973e6 100644 --- a/src/node/ipv4.cc +++ b/src/node/ipv4.cc @@ -276,7 +276,18 @@ Ipv4::GetNInterfaces (void) const return m_nInterfaces; } - +Ipv4Interface * +Ipv4::FindInterfaceForDevice (NetDevice const*device) +{ + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) + { + if ((*i)->GetDevice () == device) + { + return *i; + } + } + return 0; +} Ipv4* Ipv4::Copy(Node *node) const diff --git a/src/node/ipv4.h b/src/node/ipv4.h index b8556498e..ff7f86523 100644 --- a/src/node/ipv4.h +++ b/src/node/ipv4.h @@ -85,6 +85,7 @@ public: uint32_t AddInterface (Ipv4Interface *interface); Ipv4Interface * GetInterface (uint32_t i); uint32_t GetNInterfaces (void) const; + Ipv4Interface *FindInterfaceForDevice (NetDevice const*device); Ipv4* Copy(Node *node) const; diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc index 0a8a97cf6..a02cbd13c 100644 --- a/src/node/mac-address.cc +++ b/src/node/mac-address.cc @@ -48,7 +48,7 @@ AsciiToLowCase (char c) MacAddress::MacAddress () : m_len(0) { - for (int i=0; i < MAX_ADDR_LEN; i++) + for (int i=0; i < MacAddress::MAX_LEN; i++) { m_address[i] = 0; } @@ -56,22 +56,22 @@ MacAddress::MacAddress () : m_len(0) MacAddress::MacAddress (uint8_t const *address, uint8_t len) { - assert(len <= MAX_ADDR_LEN); - for (int i=0; i < len; i++) - { - m_address[i] = address[i]; - } - for (int i=len; i < MAX_ADDR_LEN; i++) - { - m_address[i] = 0; - } - m_len = len; + assert(len <= MacAddress::MAX_LEN); + for (int i=0; i < len; i++) + { + m_address[i] = address[i]; + } + for (int i=len; i < MacAddress::MAX_LEN; i++) + { + m_address[i] = 0; + } + m_len = len; } MacAddress::MacAddress (char const *str) { int i = 0; - while (*str != 0 && i < MAX_ADDR_LEN) { + while (*str != 0 && i < MacAddress::MAX_LEN) { uint8_t byte = 0; while (*str != ASCII_COLON && *str != 0) { byte <<= 4; @@ -137,14 +137,14 @@ MacAddress::GetLength () const } void -MacAddress::Peek (uint8_t ad[MAX_ADDR_LEN]) const +MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const { - memcpy (ad, m_address, MAX_ADDR_LEN); + memcpy (ad, m_address, MacAddress::MAX_LEN); } void -MacAddress::Set (uint8_t const ad[MAX_ADDR_LEN]) +MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN]) { - memcpy (m_address, ad, MAX_ADDR_LEN); + memcpy (m_address, ad, MacAddress::MAX_LEN); } bool operator == (MacAddress const&a, MacAddress const&b) @@ -159,8 +159,8 @@ bool operator != (MacAddress const&a, MacAddress const&b) bool operator < (MacAddress const&a, MacAddress const&b) { - uint8_t a_p[MAX_ADDR_LEN]; - uint8_t b_p[MAX_ADDR_LEN]; + uint8_t a_p[MacAddress::MAX_LEN]; + uint8_t b_p[MacAddress::MAX_LEN]; a.Peek (a_p); b.Peek (b_p); assert(a.GetLength() == b.GetLength()); diff --git a/src/node/mac-address.h b/src/node/mac-address.h index 8bb911d70..cecaee0c9 100644 --- a/src/node/mac-address.h +++ b/src/node/mac-address.h @@ -31,8 +31,6 @@ namespace ns3 { -const int MAX_ADDR_LEN = 32; - /** * \brief base class for Network Device addresses * @@ -43,6 +41,9 @@ const int MAX_ADDR_LEN = 32; */ class MacAddress { public: + enum { + MAX_LEN = 32 + }; MacAddress (void); /* * low byte should be first. @@ -60,11 +61,11 @@ public: void Print (std::ostream &os) const; uint8_t GetLength() const; - void Peek (uint8_t ad[MAX_ADDR_LEN]) const; - void Set (uint8_t const ad[MAX_ADDR_LEN]); - + void Peek (uint8_t ad[MAX_LEN]) const; + void Set (uint8_t const ad[MAX_LEN]); + private: - uint8_t m_address[MAX_ADDR_LEN]; + uint8_t m_address[MAX_LEN]; uint8_t m_len; }; diff --git a/src/node/node.cc b/src/node/node.cc index c96233d61..18a5bfff2 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -73,6 +73,10 @@ Node::GetUdp (void) const return 0; } - +Arp * +Node::GetArp (void) const +{ + return 0; +} }//namespace ns3 diff --git a/src/node/node.h b/src/node/node.h index 35283b287..9cf8ae5e8 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -98,6 +98,7 @@ class Ipv4L4Demux; class NetDeviceList; class Ipv4; class Udp; +class Arp; class Node { public: @@ -122,6 +123,7 @@ public: virtual NetDeviceList* GetNetDeviceList() const; virtual Ipv4 * GetIpv4 (void) const; virtual Udp * GetUdp (void) const; + virtual Arp * GetArp (void) const; private: Id_t m_id; // Node id for this node diff --git a/src/node/sgi-hashmap.h b/src/node/sgi-hashmap.h new file mode 100644 index 000000000..375d25fee --- /dev/null +++ b/src/node/sgi-hashmap.h @@ -0,0 +1,32 @@ +/* This code snippet was ripped out of the gcc + * documentation and slightly modified to work + * with gcc 4.x + */ +#ifndef SGI_HASHMAP_H +#define SGI_HASHMAP_H + +/* To use gcc extensions. + */ +#ifdef __GNUC__ + #if __GNUC__ < 3 + #include +namespace sgi { using ::hash_map; }; // inherit globals + #else + #if __GNUC__ < 4 + #include + #if __GNUC_MINOR__ == 0 +namespace sgi = std; // GCC 3.0 + #else +namespace sgi = ::__gnu_cxx; // GCC 3.1 and later + #endif + #else // gcc 4.x and later + #include + namespace sgi = ::__gnu_cxx; + #endif + #endif +#else // ... there are other compilers, right? +namespace sgi = std; +#endif + + +#endif /* SGI_HASHMAP_H */ diff --git a/src/node/udp-ipv4-l4-protocol.h b/src/node/udp-ipv4-l4-protocol.h index 071b3cf26..124d6fe8b 100644 --- a/src/node/udp-ipv4-l4-protocol.h +++ b/src/node/udp-ipv4-l4-protocol.h @@ -34,7 +34,7 @@ class Node; class Packet; class Ipv4Address; -class UdpIpv4L4Protocol : Ipv4L4Protocol { +class UdpIpv4L4Protocol : public Ipv4L4Protocol { public: UdpIpv4L4Protocol(Node *node); virtual ~UdpIpv4L4Protocol ();