PageRenderTime 26ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Network/IPv6/IPv6Send.cc

https://github.com/revenant/ipv6suite
C++ | 415 lines | 282 code | 55 blank | 78 comment | 56 complexity | f95366eda7983aeee029be6e651eed7b MD5 | raw file
  1. //
  2. // Copyright (C) 2000 Institut fuer Telematik, Universitaet Karlsruhe
  3. // Copyright (C) 2001, 2003 CTIE, Monash University
  4. // Copyright (C) 2006 by Johnny Lai
  5. //
  6. // This program is free software; you can redistribute it and/or
  7. // modify it under the terms of the GNU Lesser General Public
  8. // License as published by the Free Software Foundation; either
  9. // version 2.1 of the License, or (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Lesser General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Lesser General Public
  17. // License along with this program; if not, write to the Free Software
  18. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. /**
  20. @file IPv6Send.cc
  21. @brief Implementation for IPSendCore
  22. ------
  23. Responsibilities:
  24. receive IPInterfacePacket from Transport layer or ICMP
  25. or Tunneling (IP tunneled datagram)
  26. encapsulate in IP datagram
  27. set version
  28. set hoplimit
  29. set Protocol to received value
  30. set destination address to received value
  31. send datagram to Routing
  32. if IPInterfacePacket is invalid (e.g. invalid source address),
  33. it is thrown away without feedback
  34. @author Johnny Lai
  35. based on IPSendCore by Jochen Reber
  36. */
  37. #include "sys.h"
  38. #include "debug.h"
  39. #include <boost/cast.hpp>
  40. #include <boost/bind.hpp>
  41. #include "IPv6Send.h"
  42. #include "opp_utils.h" //getParser
  43. #include "XMLOmnetParser.h"
  44. #include "IPv6Datagram.h"
  45. #include "IPv6ControlInfo_m.h"
  46. #include "ipv6addrconv.h" //ipv6/ipv4 addr trans
  47. #include "HdrExtRteProc.h"
  48. #include "InterfaceTableAccess.h"
  49. #include "IPv6InterfaceData.h"
  50. #include "RoutingTable6Access.h"
  51. #include "IPv6Mobility.h"
  52. #include "AddrResInfo_m.h"
  53. #include "IPv6CDS.h"
  54. #include "MIPv6MStateMobileNode.h"
  55. #include "MIPv6CDSMobileNode.h"
  56. Define_Module( IPv6Send );
  57. std::ostream& operator<<(std::ostream& os, SrcRoute& route)
  58. {
  59. copy(route->begin(), route->end(), ostream_iterator<
  60. _SrcRoute::value_type>(os, " >>\n"));
  61. /*
  62. _SrcRoute* sr = route.get();
  63. typedef _SrcRoute::iterator SRI;
  64. os<<"start";
  65. for (SRI it = sr->begin(); it != sr->end();it++)
  66. os<<*it<<" ";
  67. os<<endl;
  68. */
  69. return os;
  70. }
  71. void IPv6Send::initialize()
  72. {
  73. QueueBase::initialize();
  74. ift = InterfaceTableAccess().get();
  75. rt = RoutingTable6Access().get();
  76. ctrIP6OutNoRoutes = 0;
  77. defaultMCTimeToLive = par("multicastTimeToLive");
  78. ctrIP6OutRequests = 0;
  79. mob = check_and_cast<IPv6Mobility*>
  80. (OPP_Global::findModuleByType(rt, "IPv6Mobility"));
  81. parseSourceRoutes();
  82. WATCH_MAP(routes);
  83. }
  84. /*
  85. @brief Test for a preconfigured source route to a destination and insert an
  86. appropriate routing header
  87. */
  88. bool IPv6Send::insertSourceRoute(IPv6Datagram& datagram)
  89. {
  90. SRI srit = routes.find(datagram.destAddress());
  91. if (srit != routes.end() &&
  92. !datagram.findHeader(EXTHDR_ROUTING))
  93. {
  94. HdrExtRteProc* proc = datagram.acquireRoutingInterface();
  95. HdrExtRte* rt0 = proc->routingHeader();
  96. if(!rt0)
  97. {
  98. rt0 = new HdrExtRte;
  99. proc->addRoutingHeader(rt0);
  100. }
  101. Dout(dc::send, "source route triggered at "<<rt->nodeName()<<" on dgram="
  102. <<datagram);
  103. const SrcRoute& route = srit->second;
  104. for_each(route->begin()+1, route->end(),
  105. boost::bind(&HdrExtRte::addAddress, rt0, _1));
  106. assert(datagram.destAddress() == *(route->rbegin()));
  107. Dout(dc::send, "source route added for "<<rt->nodeName()<<" dgram="
  108. <<datagram<<" route="<<route);
  109. datagram.setDestAddress(*(route->begin()));
  110. return true;
  111. }
  112. return false;
  113. }
  114. void IPv6Send::parseSourceRoutes()
  115. {
  116. typedef cXMLElementList::iterator NodeIt;
  117. XMLConfiguration::XMLOmnetParser* p = OPP_Global::getParser();
  118. cXMLElement* netNode = p->getNetNode(rt->nodeName());
  119. if (!netNode)
  120. {
  121. Dout(dc::warning, rt->nodeName()<<" no XML configuration found");
  122. return;
  123. }
  124. cXMLElement* nsource = netNode->getElementByPath("./sourceRoute");
  125. if (!nsource)
  126. {
  127. Dout(dc::send, "No source routes for "<<rt->nodeName()
  128. <<" in XML config");
  129. return;
  130. }
  131. else
  132. Dout(dc::xml_addresses|flush_cf, rt->nodeName()<<" in sourceRoute");
  133. cXMLElementList sres = nsource->getChildrenByTagName("sourceRouteEntry");
  134. for (NodeIt it = sres.begin();it != sres.end();it++)
  135. {
  136. cXMLElement* nsre = *it;
  137. cXMLElementList nextHops = nsre->getChildrenByTagName("nextHop");
  138. size_t nextHopCount = nextHops.size();
  139. SrcRoute route(new _SrcRoute(nextHopCount + 1, IPv6_ADDR_UNSPECIFIED));
  140. (*route)[nextHopCount] = c_ipv6_addr(p->getNodeProperties(nsre, "finalDestination").c_str());
  141. NodeIt nextIt = nextHops.begin();
  142. for ( size_t j = 0 ; j < nextHopCount; nextIt++, j++)
  143. {
  144. cXMLElement* nnh = *nextIt;
  145. (*route)[j] = c_ipv6_addr(p->getNodeProperties(nnh, "address").c_str());
  146. }
  147. routes[*route->rbegin()] = route;
  148. }
  149. }
  150. ///sends datagram from transport or 3.5 layer onto forwarding module only
  151. ///Neighbour Discovery and Mobility skips this
  152. void IPv6Send::endService(cMessage* msg)
  153. {
  154. IPv6Datagram *datagram = encapsulatePacket(msg);
  155. if (!datagram)
  156. return;
  157. auto_ptr<IPv6Datagram> cleanup(datagram);
  158. if (!rt->localDeliver(datagram->destAddress()))
  159. {
  160. // {{{ Process outgoing packet for MIP6
  161. //binding exists for dest then swap dest==hoa to coa
  162. if (rt->mobilitySupport())
  163. {
  164. if (rt->isMobileNode())
  165. {
  166. MobileIPv6::MIPv6MStateMobileNode* mstateMN =
  167. boost::polymorphic_downcast<MobileIPv6::MIPv6MStateMobileNode*>(mob->role);
  168. mstateMN->mnSrcAddrDetermination(datagram);
  169. bool tunnel = false;
  170. if (!mstateMN->mnSendPacketCheck(*datagram, tunnel))
  171. {
  172. ctrIP6OutNoRoutes++;
  173. return;
  174. }
  175. if (tunnel)
  176. {
  177. cleanup.release();
  178. send(datagram, "tunnelEntry");
  179. return;
  180. }
  181. }
  182. (boost::polymorphic_downcast<MobileIPv6::MIPv6MStateCorrespondentNode*>(
  183. mob->role))->cnSendPacketCheck(*datagram);
  184. }
  185. // }}}
  186. insertSourceRoute(*datagram);
  187. AddrResInfo* info = new AddrResInfo;
  188. rt->conceptualSending(datagram, info);
  189. datagram->setControlInfo(info);
  190. if (rt->mobilitySupport() && rt->hmipSupport() && info->status() == 0 &&
  191. info->ifIndex() > ift->numInterfaceGates())
  192. {
  193. Dout(dc::send|flush_cf, rt->nodeName()<<":"<<datagram->inputPort()
  194. <<" vIfindex="<<hex<<info->status()<<dec<<" dgram="<<*datagram
  195. <<" hmip tunnel trig");
  196. datagram->setOutputPort(info->ifIndex());
  197. delete datagram->removeControlInfo();
  198. cleanup.release();
  199. send(datagram, "tunnelEntry");
  200. return;
  201. }
  202. //Set src address here if upper layer protocols left it up
  203. //to network layer
  204. if (datagram->srcAddress() == IPv6_ADDR_UNSPECIFIED)
  205. {
  206. datagram->setSrcAddress(rt->determineSrcAddress(
  207. datagram->destAddress(), info->ifIndex()));
  208. }
  209. // {{{ Drop packets with src addresses that are not ready yet
  210. if (rt->mobilitySupport() && info->status() == 0)
  211. {
  212. assert(ift->numInterfaceGates() > info->ifIndex());
  213. MobileIPv6::MIPv6CDSMobileNode* mipv6cdsMN = rt->mipv6cds->mipv6cdsMN;
  214. if (mipv6cdsMN && mipv6cdsMN->currentRouter().get() != 0 &&
  215. datagram->srcAddress() != mipv6cdsMN->homeAddr()
  216. )
  217. {
  218. if (
  219. (ift->interfaceByPortNo(info->ifIndex())->ipv6()->addrAssigned(
  220. datagram->srcAddress())
  221. ||
  222. (rt->odad() &&
  223. ift->interfaceByPortNo(info->ifIndex())->ipv6()->tentativeAddrAssigned(
  224. datagram->srcAddress())
  225. ))
  226. )
  227. {
  228. Dout(dc::send|flush_cf, rt->nodeName()<<" "<<simTime()
  229. <<" checking coa "<<datagram->srcAddress()
  230. <<" is onlink at correct ifIndex "<<info->ifIndex());
  231. unsigned int ifIndexTest;
  232. //outgoing interface (ifIndex) MUST have src addr (care of Addr) as on
  233. //link prefix
  234. //assert(rt->cds->lookupAddress(datagram->srcAddress(), ifIndexTest));
  235. //assert(ifIndexTest == info->ifIndex());
  236. if (!rt->cds->lookupAddress(datagram->srcAddress(), ifIndexTest))
  237. {
  238. Dout(dc::send|dc::mipv6, rt->nodeName()<<" "<<simTime()
  239. <<"No suitable src address available on foreign network as "
  240. <<"coa is old one "<<datagram->srcAddress()
  241. <<"and BA from HA not received packet dropped");
  242. datagram->setSrcAddress(IPv6_ADDR_UNSPECIFIED);
  243. }
  244. }
  245. else
  246. {
  247. InterfaceEntry *ie = ift->interfaceByPortNo(info->ifIndex());
  248. if (ie->ipv6()->tentativeAddrs.size())
  249. {
  250. ipv6_addr unready = ie->ipv6()->tentativeAddrs[ie->ipv6()->tentativeAddrs.size()-1];
  251. Dout(dc::send|dc::mipv6, rt->nodeName()<<" "<<simTime()
  252. <<"No suitable src address available on foreign network as "
  253. <<"ncoa in not ready from DAD or BA from HA/MAP not received "
  254. <<unready<<" packet dropped");
  255. }
  256. else
  257. assert(false); //should not triggger otherwise check repo as
  258. //bu should have been sen once addr assigned and hence using correct
  259. //src addr/coa
  260. datagram->setSrcAddress(IPv6_ADDR_UNSPECIFIED);
  261. }
  262. }
  263. else if (mipv6cdsMN && mipv6cdsMN->currentRouter().get() == 0)
  264. {
  265. Dout(dc::send|dc::mipv6, rt->nodeName()<<" "<<simTime()
  266. <<" No suitable src address available on foreign network as no "
  267. <<"routers recorded so far to form coa so packet dropped");
  268. datagram->setSrcAddress(IPv6_ADDR_UNSPECIFIED);
  269. }
  270. }
  271. // }}}
  272. // {{{ unspecified src addr so drop
  273. if (datagram->srcAddress() == IPv6_ADDR_UNSPECIFIED)
  274. {
  275. if (!rt->mobilitySupport())
  276. Dout(dc::warning, rt->nodeName()<<" "<<className()<<" No suitable src Address for destination "
  277. <<datagram->destAddress());
  278. ctrIP6OutNoRoutes++;
  279. //TODO probably send error message about -EADDRNOTAVAIL
  280. return;
  281. }
  282. // }}}
  283. } // if !localDeliver
  284. cleanup.release();
  285. send(datagram, "routingOut");
  286. }
  287. IPv6Datagram *IPv6Send::encapsulatePacket(cMessage *msg)
  288. {
  289. // if no interface exists, do not send datagram
  290. if (ift->numInterfaceGates() == 0 ||
  291. ift->interfaceByPortNo(0)->ipv6()->inetAddrs.size() == 0)
  292. {
  293. if ((rt->odad() &&
  294. ift->interfaceByPortNo(0)->ipv6()->tentativeAddrs.size() == 0) ||
  295. ift->numInterfaceGates() == 0)
  296. {
  297. cerr<<rt->nodeId()<<" 1st Interface is not ready yet"<<endl;
  298. Dout(dc::warning, rt->nodeName()<<" 1st Interface is not ready yet");
  299. delete msg;
  300. return NULL;
  301. }
  302. }
  303. IPv6Datagram *datagram = new IPv6Datagram();
  304. IPv6ControlInfo *ctrl = check_and_cast<IPv6ControlInfo*>(msg->removeControlInfo());
  305. datagram->encapsulate(msg);
  306. datagram->setName(msg->name());
  307. //display bit set?
  308. if (msg->kind() == 1)
  309. datagram->setKind(1);
  310. datagram->setTransportProtocol(ctrl->protocol());
  311. // set source and destination address
  312. assert(mkIpv6_addr(ctrl->destAddr()) != IPv6_ADDR_UNSPECIFIED);
  313. datagram->setDestAddress(mkIpv6_addr(ctrl->destAddr()));
  314. // when source address given in Interface Message, use it
  315. if (mkIpv6_addr(ctrl->srcAddr()) != IPv6_ADDR_UNSPECIFIED)
  316. {
  317. //Test if source address actually exists
  318. bool found = false;
  319. for (size_t ifIndex = 0; ifIndex < ift->numInterfaceGates(); ifIndex++)
  320. {
  321. InterfaceEntry *ie = ift->interfaceByPortNo(ifIndex);
  322. if (ie->ipv6()->addrAssigned(mkIpv6_addr(ctrl->srcAddr())) ||
  323. (rt->odad() && ie->ipv6()->tentativeAddrAssigned(mkIpv6_addr(ctrl->srcAddr()))))
  324. {
  325. found = true;
  326. break;
  327. }
  328. }
  329. if (!found)
  330. {
  331. Dout(dc::warning|flush_cf, rt->nodeName()<<" src addr not assigned in ifaces "<<mkIpv6_addr(ctrl->srcAddr()));
  332. //Perhaps coa not assigned yet?
  333. //opp_error(rt->nodeName()<<" src addr not found in ifaces "<<mkIpv6_addr(ctrl->srcAddr()));
  334. //assert(false);
  335. delete ctrl;
  336. delete datagram;
  337. return 0;
  338. }
  339. datagram->setSrcAddress(mkIpv6_addr(ctrl->srcAddr()));
  340. }
  341. else
  342. {
  343. //Let IPv6Routing determine src addr
  344. }
  345. datagram->setInputPort(-1);
  346. if (ctrl->timeToLive() > 0)
  347. datagram->setHopLimit(ctrl->timeToLive());
  348. datagram->setEncapLimit(ctrl->encapLimit());
  349. //TODO check dest Path MTU here
  350. ctrIP6OutRequests++;
  351. delete ctrl;
  352. return datagram;
  353. }
  354. void IPv6Send::finish()
  355. {
  356. recordScalar("IP6OutRequests", ctrIP6OutRequests);
  357. recordScalar("IP6OutNoRoutes", ctrIP6OutNoRoutes);
  358. }