blob: 720be8d23aaa25358062f195b0c7307bdc9eee2b [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
31NS_LOG_COMPONENT_DEFINE ("Ipv4GlobalRoutingUnorderedNexthops");
32
33namespace ns3 {
34
35NS_OBJECT_ENSURE_REGISTERED (Ipv4GlobalRoutingUnorderedNexthops);
36
37TypeId
38Ipv4GlobalRoutingUnorderedNexthops::GetTypeId (void)
39{
40 static TypeId tid = TypeId ("ns3::Ipv4GlobalRoutingUnorderedNexthops")
41 .SetParent<Ipv4GlobalRouting> ()
42 .AddConstructor<Ipv4GlobalRoutingUnorderedNexthops> ()
43 ;
44 return tid;
45}
46
47Ipv4GlobalRoutingUnorderedNexthops::Ipv4GlobalRoutingUnorderedNexthops ()
48: m_numLogicalEntries (1)
49{
50}
51
52void
53Ipv4GlobalRoutingUnorderedNexthops::FixRoutes ()
54{
55 for (Ipv4AddressTrieMap::iterator route = m_routes.begin ();
56 route != m_routes.end ();
57 route ++)
58 {
59 if (route->second->size () < m_numLogicalEntries)
60 {
61 NS_LOG_WARN ("Not all entries got a new routing entry. Making one based on previous set");
62 route->second->push_back (route->second->back ());
63 route->second->back ().SetMetric (UINT32_MAX); // just to ensure we have consistency across the sets
64 }
65 }
66 m_numLogicalEntries ++;
67}
68
69void
70Ipv4GlobalRoutingUnorderedNexthops::AddRouteTo (Ipv4Address dest,
71 Ipv4Mask destMask,
72 Ipv4Address nextHop,
73 uint32_t interface,
74 uint32_t metric/*=0*/)
75{
76 NS_LOG_FUNCTION (dest << destMask << nextHop << interface << metric);
77
78 // First, make sure we don't try to add route to ourselves
79 int32_t iface = m_ipv4->GetInterfaceForPrefix (dest, destMask);
80 NS_LOG_LOGIC ("Iface " << iface << " for " << dest);
81 if (destMask != Ipv4Mask::GetZero () && iface >= 0)
82 {
83 NS_LOG_LOGIC ("Do not add route to ourselves");
84 return;
85 }
86
87 // Second, there is no reason to add p2p route that equals to the next hop
88 if (destMask == Ipv4Mask::GetOnes () && dest == nextHop)
89 {
90 NS_LOG_LOGIC ("Ignore route to nexthop via nexhop");
91 return;
92 }
93
94 Ptr<EntryContainer> nextHops = 0;
95
96 Ipv4AddressTrieMap::iterator route =
97 m_routes.find (dest.CombineMask (destMask));
98 if (route == m_routes.end ())
99 {
100 nextHops = Create<EntryContainer> ();
101 m_routes[dest.CombineMask (destMask)] = nextHops;
102 }
103 else
104 {
105 nextHops = route->second;
106 }
107
108 // NS_LOG_ERROR ("numLogicalEntries: " << m_numLogicalEntries << ", nextHops->size: " << nextHops->size ());
109 NS_ASSERT_MSG (nextHops->size ()==m_numLogicalEntries ||
110 nextHops->size ()==m_numLogicalEntries-1,
111 "Number of entries in nextHops should be either equal to number of logical entries, or one smaller");
112
113 if (nextHops->size ()==m_numLogicalEntries-1)
114 {
115 // new entry
116 nextHops->push_back (Ipv4RoutingTableEntry::CreateNetworkRouteTo (dest, destMask, nextHop, interface, metric));
117 }
118 else
119 {
120 if (nextHops->back ().GetMetric () > metric)
121 {
122 // update entry if new metric is smaller
123 nextHops->back () = Ipv4RoutingTableEntry::CreateNetworkRouteTo (dest, destMask, nextHop, interface, metric);
124 }
125 }
126}
127
128Ptr<Ipv4Route>
129Ipv4GlobalRoutingUnorderedNexthops::LookupGlobal (uint32_t entryNum, Ipv4Address dest, Ptr<NetDevice> oif)
130{
131 NS_LOG_FUNCTION_NOARGS ();
132 NS_LOG_LOGIC ("Looking for route for destination " << dest);
133
134 NS_ASSERT_MSG (m_numLogicalEntries > 0,
135 "Number of logical entries should be at least one");
136
137 NS_ASSERT_MSG (entryNum < m_numLogicalEntries,
138 "Number of requested logical entry should be smaller than total number of logical entries");
139
140 Ipv4AddressTrieMap::const_iterator longest_prefix_map = m_routes.longest_prefix_match (dest);
141 if (longest_prefix_map == m_routes.end ())
142 {
143 return 0;
144 }
145
146 const Ipv4RoutingTableEntry & entry = (*longest_prefix_map->second)[entryNum];
147
148 if (oif != 0 && oif == m_ipv4->GetNetDevice (entry.GetInterface ()))
149 {
150 NS_LOG_LOGIC ("Route points to the incoming interface. Return empty route");
151 return 0;
152 }
153
154 // create a Ipv4Route object from the selected routing table entry
155 Ptr<Ipv4Route> rtentry = Create<Ipv4Route> ();
156 rtentry->SetDestination (entry.GetDest ());
157 rtentry->SetSource (m_ipv4->GetAddress (entry.GetInterface (), 0).GetLocal ());
158 rtentry->SetGateway (entry.GetGateway ());
159 rtentry->SetOutputDevice (m_ipv4->GetNetDevice (entry.GetInterface ()));
160 return rtentry;
161}
162
163void
164Ipv4GlobalRoutingUnorderedNexthops::DeleteRoutes ()
165{
166 m_routes.clear ();
167}
168
169void
170Ipv4GlobalRoutingUnorderedNexthops::PrintRoutingTable (Ptr<OutputStreamWrapper> stream) const
171{
172 std::ostream* os = stream->GetStream ();
173 if (m_routes.size () > 0)
174 {
175 *os << "Destination Iface(Metric),...,Iface(Metric)" << std::endl;
176 for (Ipv4AddressTrieMap::const_iterator i=m_routes.begin (); i != m_routes.end (); i++)
177 {
178 if (i->second->size ()==0) continue;
179 const Ipv4RoutingTableEntry &route = i->second->front ();
180
181 std::ostringstream dest;
182 dest << route.GetDest () << "/" << route.GetDestNetworkMask().GetPrefixLength ();
183 *os << std::setiosflags (std::ios::left) << std::setw (15) << dest.str ();
184
185 for (EntryContainer::iterator entry = i->second->begin ();
186 entry != i->second->end ();
187 entry ++)
188 {
189 if (entry != i->second->begin ())
190 *os << ",";
191 *os << entry->GetInterface () << "(" << entry->GetMetric () << ")";
192 }
193
194 *os << std::endl;
195 }
196 }
197}
198
199Ptr<Ipv4Route>
200Ipv4GlobalRoutingUnorderedNexthops::RouteOutput (Ptr<Packet> p, const Ipv4Header &header,
201 Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
202{
203//
204// First, see if this is a multicast packet we have a route for. If we
205// have a route, then send the packet down each of the specified interfaces.
206//
207 if (header.GetDestination ().IsMulticast ())
208 {
209 NS_LOG_LOGIC ("Multicast destination-- returning false");
210 return 0; // Let other routing protocols try to handle this
211 }
212//
213// See if this is a unicast packet we have a route for.
214//
215 NS_LOG_LOGIC ("Unicast destination- looking up");
216 Ptr<Ipv4Route> rtentry = LookupGlobal (0, header.GetDestination (), oif);
217 if (rtentry)
218 {
219 sockerr = Socket::ERROR_NOTERROR;
220 }
221 else
222 {
223 sockerr = Socket::ERROR_NOROUTETOHOST;
224 }
225 return rtentry;
226}
227
228bool
229Ipv4GlobalRoutingUnorderedNexthops::RouteInput (Ptr<const Packet> p, const Ipv4Header &header,
230 Ptr<const NetDevice> idev,
231 UnicastForwardCallback ucb, MulticastForwardCallback mcb,
232 LocalDeliverCallback lcb, ErrorCallback ecb)
233{
234
235 NS_LOG_FUNCTION (this << p << header << header.GetSource () << header.GetDestination () << idev);
236 // Check if input device supports IP
237 NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
238 uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
239
240 if (header.GetDestination ().IsMulticast ())
241 {
242 NS_LOG_LOGIC ("Multicast destination-- returning false");
243 return false; // Let other routing protocols try to handle this
244 }
245
246 if (header.GetDestination ().IsBroadcast ())
247 {
248 NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
249 // TODO: Local Deliver for broadcast
250 // TODO: Forward broadcast
251 }
252
253 // TODO: Configurable option to enable RFC 1222 Strong End System Model
254 // Right now, we will be permissive and allow a source to send us
255 // a packet to one of our other interface addresses; that is, the
256 // destination unicast address does not match one of the iif addresses,
257 // but we check our other interfaces. This could be an option
258 // (to remove the outer loop immediately below and just check iif).
259 for (uint32_t j = 0; j < m_ipv4->GetNInterfaces (); j++)
260 {
261 for (uint32_t i = 0; i < m_ipv4->GetNAddresses (j); i++)
262 {
263 Ipv4InterfaceAddress iaddr = m_ipv4->GetAddress (j, i);
264 Ipv4Address addr = iaddr.GetLocal ();
265 if (addr.IsEqual (header.GetDestination ()))
266 {
267 if (j == iif)
268 {
269 NS_LOG_LOGIC ("For me (destination " << addr << " match)");
270 }
271 else
272 {
273 NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << header.GetDestination ());
274 }
275 lcb (p, header, iif);
276 return true;
277 }
278 if (header.GetDestination ().IsEqual (iaddr.GetBroadcast ()))
279 {
280 NS_LOG_LOGIC ("For me (interface broadcast address)");
281 lcb (p, header, iif);
282 return true;
283 }
284 NS_LOG_LOGIC ("Address "<< addr << " not a match");
285 }
286 }
287 // Check if input device supports IP forwarding
288 if (m_ipv4->IsForwarding (iif) == false)
289 {
290 NS_LOG_LOGIC ("Forwarding disabled for this interface");
291 ecb (p, header, Socket::ERROR_NOROUTETOHOST);
292 return false;
293 }
294 // Next, try to find a route
295 NS_LOG_LOGIC ("Unicast destination- looking up global route");
296 Ptr<Ipv4Route> rtentry = LookupGlobal (0, header.GetDestination ());
297 if (rtentry != 0)
298 {
299 NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
300 ucb (rtentry, p, header);
301 return true;
302 }
303 else
304 {
305 NS_LOG_LOGIC ("Did not find unicast destination- returning false");
306 return false; // Let other routing protocols try to handle this
307 // route request.
308 }
309}
310
311} // namespace ns3