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