blob: a4f36609528005af59bc2a0481aedd37d445cfda [file] [log] [blame]
Alexander Afanasyev3ba44e52011-11-10 16:38:10 -08001// -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*-
2//
3// Copyright (c) 2008 University of Washington
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation;
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17//
18
19#include "ns3/names.h"
20#include "ns3/node.h"
21#include "ns3/log.h"
22#include "ns3/simulator.h"
23#include "ns3/object.h"
24#include "ns3/packet.h"
25#include "ns3/net-device.h"
26#include "ns3/ipv4-route.h"
27#include "ipv4-global-routing-unordered-nexthops.h"
28
29#include <iomanip>
30
Alexander Afanasyev918839c2011-11-10 17:02:06 -080031#ifndef UINT32_MAX
32# define UINT32_MAX (4294967295U)
33#endif
34
Alexander Afanasyev3ba44e52011-11-10 16:38:10 -080035NS_LOG_COMPONENT_DEFINE ("Ipv4GlobalRoutingUnorderedNexthops");
36
37namespace ns3 {
38
39NS_OBJECT_ENSURE_REGISTERED (Ipv4GlobalRoutingUnorderedNexthops);
40
41TypeId
42Ipv4GlobalRoutingUnorderedNexthops::GetTypeId (void)
43{
44 static TypeId tid = TypeId ("ns3::Ipv4GlobalRoutingUnorderedNexthops")
45 .SetParent<Ipv4GlobalRouting> ()
46 .AddConstructor<Ipv4GlobalRoutingUnorderedNexthops> ()
47 ;
48 return tid;
49}
50
51Ipv4GlobalRoutingUnorderedNexthops::Ipv4GlobalRoutingUnorderedNexthops ()
52: m_numLogicalEntries (1)
53{
54}
55
56void
57Ipv4GlobalRoutingUnorderedNexthops::FixRoutes ()
58{
59 for (Ipv4AddressTrieMap::iterator route = m_routes.begin ();
60 route != m_routes.end ();
61 route ++)
62 {
63 if (route->second->size () < m_numLogicalEntries)
64 {
65 NS_LOG_WARN ("Not all entries got a new routing entry. Making one based on previous set");
66 route->second->push_back (route->second->back ());
67 route->second->back ().SetMetric (UINT32_MAX); // just to ensure we have consistency across the sets
68 }
69 }
70 m_numLogicalEntries ++;
71}
72
73void
74Ipv4GlobalRoutingUnorderedNexthops::AddRouteTo (Ipv4Address dest,
75 Ipv4Mask destMask,
76 Ipv4Address nextHop,
77 uint32_t interface,
78 uint32_t metric/*=0*/)
79{
80 NS_LOG_FUNCTION (dest << destMask << nextHop << interface << metric);
81
82 // First, make sure we don't try to add route to ourselves
83 int32_t iface = m_ipv4->GetInterfaceForPrefix (dest, destMask);
84 NS_LOG_LOGIC ("Iface " << iface << " for " << dest);
85 if (destMask != Ipv4Mask::GetZero () && iface >= 0)
86 {
87 NS_LOG_LOGIC ("Do not add route to ourselves");
88 return;
89 }
90
91 // Second, there is no reason to add p2p route that equals to the next hop
92 if (destMask == Ipv4Mask::GetOnes () && dest == nextHop)
93 {
94 NS_LOG_LOGIC ("Ignore route to nexthop via nexhop");
95 return;
96 }
97
98 Ptr<EntryContainer> nextHops = 0;
99
100 Ipv4AddressTrieMap::iterator route =
101 m_routes.find (dest.CombineMask (destMask));
102 if (route == m_routes.end ())
103 {
104 nextHops = Create<EntryContainer> ();
105 m_routes[dest.CombineMask (destMask)] = nextHops;
106 }
107 else
108 {
109 nextHops = route->second;
110 }
111
112 // NS_LOG_ERROR ("numLogicalEntries: " << m_numLogicalEntries << ", nextHops->size: " << nextHops->size ());
113 NS_ASSERT_MSG (nextHops->size ()==m_numLogicalEntries ||
114 nextHops->size ()==m_numLogicalEntries-1,
115 "Number of entries in nextHops should be either equal to number of logical entries, or one smaller");
116
117 if (nextHops->size ()==m_numLogicalEntries-1)
118 {
119 // new entry
120 nextHops->push_back (Ipv4RoutingTableEntry::CreateNetworkRouteTo (dest, destMask, nextHop, interface, metric));
121 }
122 else
123 {
124 if (nextHops->back ().GetMetric () > metric)
125 {
126 // update entry if new metric is smaller
127 nextHops->back () = Ipv4RoutingTableEntry::CreateNetworkRouteTo (dest, destMask, nextHop, interface, metric);
128 }
129 }
130}
131
132Ptr<Ipv4Route>
133Ipv4GlobalRoutingUnorderedNexthops::LookupGlobal (uint32_t entryNum, Ipv4Address dest, Ptr<NetDevice> oif)
134{
135 NS_LOG_FUNCTION_NOARGS ();
136 NS_LOG_LOGIC ("Looking for route for destination " << dest);
137
138 NS_ASSERT_MSG (m_numLogicalEntries > 0,
139 "Number of logical entries should be at least one");
140
141 NS_ASSERT_MSG (entryNum < m_numLogicalEntries,
142 "Number of requested logical entry should be smaller than total number of logical entries");
143
Alexander Afanasyevc4f88282012-01-03 11:27:20 -0800144 // Cheating with lookups. Need to redesign Trie
145 Ipv4AddressTrieMap::const_iterator longest_prefix_map;
146 Ipv4Mask mask ("255.255.255.255");
147 do {
148 NS_LOG_DEBUG ("Try mask " << mask);
149 longest_prefix_map = m_routes.longest_prefix_match (dest.CombineMask (mask));
150 mask = Ipv4Mask (mask.Get () << 8);
151 } while (longest_prefix_map == m_routes.end () && !mask.IsEqual (Ipv4Mask::GetZero ()));
152
Alexander Afanasyev3ba44e52011-11-10 16:38:10 -0800153 if (longest_prefix_map == m_routes.end ())
154 {
Alexander Afanasyevc4f88282012-01-03 11:27:20 -0800155 NS_LOG_LOGIC ("Route not found...");
Alexander Afanasyev3ba44e52011-11-10 16:38:10 -0800156 return 0;
157 }
158
159 const Ipv4RoutingTableEntry & entry = (*longest_prefix_map->second)[entryNum];
160
161 if (oif != 0 && oif == m_ipv4->GetNetDevice (entry.GetInterface ()))
162 {
163 NS_LOG_LOGIC ("Route points to the incoming interface. Return empty route");
164 return 0;
165 }
166
167 // create a Ipv4Route object from the selected routing table entry
168 Ptr<Ipv4Route> rtentry = Create<Ipv4Route> ();
169 rtentry->SetDestination (entry.GetDest ());
170 rtentry->SetSource (m_ipv4->GetAddress (entry.GetInterface (), 0).GetLocal ());
171 rtentry->SetGateway (entry.GetGateway ());
172 rtentry->SetOutputDevice (m_ipv4->GetNetDevice (entry.GetInterface ()));
173 return rtentry;
174}
175
176void
177Ipv4GlobalRoutingUnorderedNexthops::DeleteRoutes ()
178{
179 m_routes.clear ();
180}
181
182void
183Ipv4GlobalRoutingUnorderedNexthops::PrintRoutingTable (Ptr<OutputStreamWrapper> stream) const
184{
185 std::ostream* os = stream->GetStream ();
186 if (m_routes.size () > 0)
187 {
188 *os << "Destination Iface(Metric),...,Iface(Metric)" << std::endl;
189 for (Ipv4AddressTrieMap::const_iterator i=m_routes.begin (); i != m_routes.end (); i++)
190 {
191 if (i->second->size ()==0) continue;
192 const Ipv4RoutingTableEntry &route = i->second->front ();
193
194 std::ostringstream dest;
195 dest << route.GetDest () << "/" << route.GetDestNetworkMask().GetPrefixLength ();
196 *os << std::setiosflags (std::ios::left) << std::setw (15) << dest.str ();
197
198 for (EntryContainer::iterator entry = i->second->begin ();
199 entry != i->second->end ();
200 entry ++)
201 {
202 if (entry != i->second->begin ())
203 *os << ",";
204 *os << entry->GetInterface () << "(" << entry->GetMetric () << ")";
205 }
206
207 *os << std::endl;
208 }
209 }
210}
211
212Ptr<Ipv4Route>
213Ipv4GlobalRoutingUnorderedNexthops::RouteOutput (Ptr<Packet> p, const Ipv4Header &header,
214 Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
215{
216//
217// First, see if this is a multicast packet we have a route for. If we
218// have a route, then send the packet down each of the specified interfaces.
219//
220 if (header.GetDestination ().IsMulticast ())
221 {
222 NS_LOG_LOGIC ("Multicast destination-- returning false");
223 return 0; // Let other routing protocols try to handle this
224 }
225//
226// See if this is a unicast packet we have a route for.
227//
228 NS_LOG_LOGIC ("Unicast destination- looking up");
229 Ptr<Ipv4Route> rtentry = LookupGlobal (0, header.GetDestination (), oif);
230 if (rtentry)
231 {
232 sockerr = Socket::ERROR_NOTERROR;
233 }
234 else
235 {
236 sockerr = Socket::ERROR_NOROUTETOHOST;
237 }
238 return rtentry;
239}
240
241bool
242Ipv4GlobalRoutingUnorderedNexthops::RouteInput (Ptr<const Packet> p, const Ipv4Header &header,
243 Ptr<const NetDevice> idev,
244 UnicastForwardCallback ucb, MulticastForwardCallback mcb,
245 LocalDeliverCallback lcb, ErrorCallback ecb)
246{
247
248 NS_LOG_FUNCTION (this << p << header << header.GetSource () << header.GetDestination () << idev);
249 // Check if input device supports IP
250 NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
251 uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
252
253 if (header.GetDestination ().IsMulticast ())
254 {
255 NS_LOG_LOGIC ("Multicast destination-- returning false");
256 return false; // Let other routing protocols try to handle this
257 }
258
259 if (header.GetDestination ().IsBroadcast ())
260 {
261 NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
262 // TODO: Local Deliver for broadcast
263 // TODO: Forward broadcast
264 }
265
266 // TODO: Configurable option to enable RFC 1222 Strong End System Model
267 // Right now, we will be permissive and allow a source to send us
268 // a packet to one of our other interface addresses; that is, the
269 // destination unicast address does not match one of the iif addresses,
270 // but we check our other interfaces. This could be an option
271 // (to remove the outer loop immediately below and just check iif).
272 for (uint32_t j = 0; j < m_ipv4->GetNInterfaces (); j++)
273 {
274 for (uint32_t i = 0; i < m_ipv4->GetNAddresses (j); i++)
275 {
276 Ipv4InterfaceAddress iaddr = m_ipv4->GetAddress (j, i);
277 Ipv4Address addr = iaddr.GetLocal ();
278 if (addr.IsEqual (header.GetDestination ()))
279 {
280 if (j == iif)
281 {
282 NS_LOG_LOGIC ("For me (destination " << addr << " match)");
283 }
284 else
285 {
286 NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << header.GetDestination ());
287 }
288 lcb (p, header, iif);
289 return true;
290 }
291 if (header.GetDestination ().IsEqual (iaddr.GetBroadcast ()))
292 {
293 NS_LOG_LOGIC ("For me (interface broadcast address)");
294 lcb (p, header, iif);
295 return true;
296 }
297 NS_LOG_LOGIC ("Address "<< addr << " not a match");
298 }
299 }
300 // Check if input device supports IP forwarding
301 if (m_ipv4->IsForwarding (iif) == false)
302 {
303 NS_LOG_LOGIC ("Forwarding disabled for this interface");
304 ecb (p, header, Socket::ERROR_NOROUTETOHOST);
305 return false;
306 }
307 // Next, try to find a route
308 NS_LOG_LOGIC ("Unicast destination- looking up global route");
309 Ptr<Ipv4Route> rtentry = LookupGlobal (0, header.GetDestination ());
310 if (rtentry != 0)
311 {
312 NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
313 ucb (rtentry, p, header);
314 return true;
315 }
316 else
317 {
318 NS_LOG_LOGIC ("Did not find unicast destination- returning false");
319 return false; // Let other routing protocols try to handle this
320 // route request.
321 }
322}
323
324} // namespace ns3