NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
OSPF_SPF.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* Author: Shashi Kant Suman *
12* *
13* ---------------------------------------------------------------------------------*/
14#include "main.h"
15#include "../IP/IP.h"
16#include "OSPF.h"
17#include "OSPF_Neighbor.h"
18#include "OSPF_Msg.h"
19#include "OSPF_Enum.h"
20#include "OSPF_Interface.h"
21#include "OSPF_List.h"
22#include "OSPF_RoutingTable.h"
23
24static ptrOSPFVERTEX OSPF_SPF_COPY_VERTEX(ptrOSPFVERTEX vertex)
25{
26 ptrOSPFVERTEX v = calloc(1, sizeof* v);
27 memcpy(v, vertex, sizeof* v);
28 v->nextHopList = ospf_list_copyAll(vertex->nextHopList);
29 return v;
30}
31
32static void OSPF_SPF_FREE_VERTEX(ptrOSPFVERTEX vertex)
33{
34 ospf_list_delete_all(vertex->nextHopList);
35 free(vertex);
36}
37
38//Print function
39static void ospf_spf_printVertexList(ptrOSPF_PDS ospf, ptrOSPFLIST shortestPathList)
40{
41 ptrOSPFVERTEX entry;
42 void* pass = ospf_list_newIterator();
43 while ((entry = ospf_list_iterate_mem(shortestPathList,pass)) != NULL)
44 {
45 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tVertex Id = %s", entry->vertexId->str_ip);
46 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tVertex Type = %s",strOSPFVERTEXTYPE[entry->vertexType]);
47 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tMetric = %d", entry->distance);
48
49 ptrOSPFNEXTHOPLISTITEM nextHopItem;
50 void* npass = ospf_list_newIterator();
51 UINT i = 0;
52 while ((nextHopItem = ospf_list_iterate_mem(entry->nextHopList, npass)) != NULL)
53 {
54 if(nextHopItem->nextHop)
55 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tNext Hop[%d] = %s",
56 i,
57 nextHopItem->nextHop->str_ip);
58 else
59 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tNext Hop[%d] = Directly connected",
60 i);
61 i++;
62 }
63 ospf_list_deleteIterator(npass);
64 }
65 ospf_list_deleteIterator(pass);
66}
67
68static void ospf_spf_printShortestpath(ptrOSPF_PDS ospf,
69 ptrOSPFAREA_DS area)
70{
71 ptrOSPFLIST shortestPathList = area->shortestPathList;
72 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Shortest path list for router %u, area %s",
73 ospf->myId,
74 area->areaId->str_ip);
75 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), " size = %d", ospf_list_get_size(shortestPathList));
76
77 ospf_spf_printVertexList(ospf, shortestPathList);
78}
79
80void ospf_spf_scheduleCalculation(ptrOSPF_PDS ospf)
81{
82 if (ospf->SPFTimer > pstruEventDetails->dEventTime)
83 return;
84 double t = pstruEventDetails->dEventTime;
85 t += ospf->spfCalcDelay*NETSIM_RAND_01();
86
87 ospf_event_add(t,
88 pstruEventDetails->nDeviceId,
89 0,
90 OSPF_CALCULATESPF,
91 NULL,
92 NULL);
93}
94
95static void ospf_spf_invalidateRoutingTable(ptrOSPF_PDS ospf)
96{
97 ptrOSPFROUTINGTABLEROW* rowPtr = ospf->routingTable->rows;
98 UINT i;
99 for (i = 0; i < ospf->routingTable->numRow; i++)
100 {
101 rowPtr[i]->flag = OSPFROUTEFLAG_INVALID;
102 }
103}
104
105static void ospf_spf_updateCandidateListUsingNWLSA(ptrOSPF_PDS ospf,
106 ptrOSPFAREA_DS area,
107 ptrOSPFLIST candidateList,
108 ptrOSPFVERTEX vertex)
109{
110 (void)ospf;
111 (void)area;
112 (void)candidateList;
113 (void)vertex;
114 fnNetSimError("Implement after NWLSA implementation");
115#pragma message(__LOC__"Implement after NWLSA implementation")
116}
117
118static bool ospf_spf_isInShortestPathList(ptrOSPF_PDS ospf,
119 ptrOSPFLIST shortestPathList,
120 OSPFVERTEXTYPE vertexType,
121 NETSIM_IPAddress vertexId)
122{
123 (void)ospf;
124
125 ptrOSPFVERTEX vertex;
126 void* pass = ospf_list_newIterator();
127 while ((vertex = ospf_list_iterate_mem(shortestPathList, pass)) != NULL)
128 {
129 // Found it.
130 if (vertex->vertexType == vertexType &&
131 !IP_COMPARE(vertex->vertexId, vertexId))
132 {
133 ospf_list_deleteIterator(pass);
134 return true;
135 }
136 }
137 ospf_list_deleteIterator(pass);
138 return false;
139}
140
141static ptrOSPFVERTEX ospf_spf_findCandidate(ptrOSPF_PDS ospf,
142 ptrOSPFLIST candidateList,
143 OSPFVERTEXTYPE vertexType,
144 NETSIM_IPAddress vertexId)
145{
146 (void)ospf;
147
148 ptrOSPFVERTEX vertex;
149 void* pass = ospf_list_newIterator();
150 while ((vertex = ospf_list_iterate_mem(candidateList, pass)) != NULL)
151 {
152 if (vertex->vertexType == vertexType &&
153 !IP_COMPARE(vertex->vertexId, vertexId))
154 {
155 ospf_list_deleteIterator(pass);
156 return vertex;
157 }
158 }
159 ospf_list_deleteIterator(pass);
160 return NULL;
161}
162
163static NETSIM_IPAddress ospf_spf_getLinkDataForThisVertex(ptrOSPF_PDS ospf,
164 ptrOSPFVERTEX vertex,
165 ptrOSPFVERTEX parent)
166{
167 (void)ospf;
168
169 ptrOSPFLSAHDR lsa = parent->lsa;
170 ptrOSPFRLSA rtrLSA = lsa->lsaInfo;
171 UINT i;
172
173 for (i = 0; i < rtrLSA->linksCount; i++)
174 {
175 ptrOSPFRLSALINK link = rtrLSA->rlsaLink[i];
176 if (link->type != OSPFLINKTYPE_STUB &&
177 !IP_COMPARE(link->linkId, vertex->vertexId))
178 return link->linkData;
179 }
180 // Shouldn't get here
181 fnNetSimError("Not get link data from the associated link "
182 "for this vertex %s\n",
183 vertex->vertexId->str_ip);
184 return NULL;
185}
186
187static bool ospf_spf_haveLinkWithNetworkVertex(ptrOSPF_PDS ospf,
188 ptrOSPFVERTEX vertex)
189{
190 NETSIM_ID d = ospf->myId;
191 UINT i;
192 for (i = 0; i < ospf->ifCount; i++)
193 {
194 ptrOSPF_IF thisInterface = ospf->ospfIf[i];
195 NETSIM_ID in = thisInterface->id;
196 NETSIM_IPAddress subnetMask = DEVICE_SUBNETMASK(d, in);
197 NETSIM_IPAddress netAddr = DEVICE_NWADDRESS(d, in);
198
199 if (IP_IS_IN_SAME_NETWORK_IPV4(vertex->vertexId,
200 netAddr,
201 subnetMask) &&
202 thisInterface->State != OSPFIFSTATE_DOWN)
203 return true;
204 }
205 return false;
206}
207
208static bool ospf_spf_isPresentinNextHopList(ptrOSPFLIST nextHopList,
209 ptrOSPFNEXTHOPLISTITEM item)
210{
211 ptrOSPFNEXTHOPLISTITEM i;
212 void* pass = ospf_list_newIterator();
213 while ((i = ospf_list_iterate_mem(nextHopList,pass)) != NULL)
214 {
215 if (i == item)
216 {
217 ospf_list_deleteIterator(pass);
218 return true;
219 }
220 }
221 ospf_list_deleteIterator(pass);
222 return false;
223}
224
225static bool ospf_spf_setNextHopForThisVertex(ptrOSPF_PDS ospf,
226 ptrOSPFVERTEX vertex,
227 ptrOSPFVERTEX parent)
228{
229 ptrOSPFNEXTHOPLISTITEM nextHopItem;
230 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Parent = %s, Vertex = %s",
231 parent->vertexId->str_ip,
232 vertex->vertexId->str_ip);
233 if (parent->vertexType == OSPFVERTEXTYPE_ROUTER &&
234 !IP_COMPARE(parent->vertexId, ospf->routerId))
235 {
236 NETSIM_IPAddress linkData = NULL;
237 NETSIM_ID interfaceId;
238
239 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Parent is ROOT");
240 linkData = ospf_spf_getLinkDataForThisVertex(ospf, vertex, parent);
241 interfaceId = fn_NetSim_Stack_GetInterfaceIdFromIP(ospf->myId, linkData);
242
243 ptrOSPF_IF thisInterface = OSPF_IF_GET(ospf, interfaceId);
244 if (thisInterface->State == OSPFIFSTATE_DOWN)
245 return false;
246
247 nextHopItem = calloc(1, sizeof* nextHopItem);
248 nextHopItem->outIntf = interfaceId;
249
250 if (vertex->vertexType == OSPFVERTEXTYPE_ROUTER)
251 {
252 int in;
253 ptrOSPF_NEIGHBOR neigh;
254 NETSIM_IPAddress nbrIPAddress = NULL;
255
256 in = fn_NetSim_Stack_GetInterfaceIdFromIP(ospf->myId, linkData);
257 ptrOSPF_IF cif = OSPF_IF_GET(ospf, in);
258 neigh = OSPF_NEIGHBOR_FIND(cif, vertex->vertexId);
259 if (!neigh &&
260 !nbrIPAddress)
261 {
262 free(nextHopItem);
263 return false;
264 }
265 else if (neigh)
266 {
267 nbrIPAddress = neigh->neighborIPAddr;
268 }
269 nextHopItem->nextHop = nbrIPAddress;
270 }
271 else
272 {
273 // Vertex is directly connected network
274 nextHopItem->nextHop = NULL;
275 }
276
277 if (!ospf_spf_isPresentinNextHopList(vertex->nextHopList, nextHopItem))
278 {
279 ospf_list_add_mem(vertex->nextHopList, nextHopItem);
280 }
281 else
282 {
283 free(nextHopItem);
284 return false;
285 }
286 }
287 else if (parent->vertexType == OSPFVERTEXTYPE_NETWORK &&
288 ospf_spf_haveLinkWithNetworkVertex(ospf, parent))
289 {
290 // If parent is root, vertex is either directly connected router
291 // or network
292 // Else if parent is network that directly connects with root
293
294 NETSIM_IPAddress linkData = NULL;
295 NETSIM_ID interfaceId;
296
297 linkData = ospf_spf_getLinkDataForThisVertex(ospf, vertex, parent);
298 interfaceId = fn_NetSim_Stack_GetInterfaceIdFromIP(ospf->myId,
299 linkData);
300
301 if (!interfaceId)
302 return false;
303
304 ptrOSPF_IF thisInterface = OSPF_IF_GET(ospf, interfaceId);
305 if (thisInterface->State == OSPFIFSTATE_DOWN)
306 return false;
307
308 nextHopItem = calloc(1, sizeof* nextHopItem);
309 nextHopItem->nextHop = linkData;
310 nextHopItem->outIntf = interfaceId;
311
312 if (!ospf_spf_isPresentinNextHopList(vertex->nextHopList, nextHopItem))
313 {
314 ospf_list_add_mem(vertex->nextHopList, nextHopItem);
315 }
316 else
317 {
318 free(nextHopItem);
319 return false;
320 }
321 }
322 else
323 {
324 // There should be an intervening router. So inherits the set
325 // of next hops from parent
326 bool inserted = false;
327
328 ptrOSPFNEXTHOPLISTITEM listItem;
329 void* pass = ospf_list_newIterator();
330 while ((listItem=ospf_list_iterate_mem(parent->nextHopList,pass))!=NULL)
331 {
332 nextHopItem = calloc(1, sizeof* nextHopItem);
333 memcpy(nextHopItem, listItem, sizeof* nextHopItem);
334
335 if (!ospf_spf_isPresentinNextHopList(vertex->nextHopList,
336 nextHopItem))
337 {
338 ospf_list_add_mem(vertex->nextHopList, nextHopItem);
339 inserted = true;
340 }
341 else
342 {
343 free(nextHopItem);
344 }
345 }
346 ospf_list_deleteIterator(pass);
347 return inserted;
348 }
349 return true;
350}
351
352static void ospf_spf_updateCandidateListUsingRouterLSA(ptrOSPF_PDS ospf,
353 ptrOSPFAREA_DS area,
354 ptrOSPFLIST candidateList,
355 ptrOSPFVERTEX vertex)
356{
357 ptrOSPFRLSA vlsa = vertex->lsa->lsaInfo;
358 ptrOSPFLSAHDR wlsa;
359
360 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tLooking for vertex %s from router LSA",
361 vertex->vertexId->str_ip);
362
363 UINT i;
364 for (i = 0; i < vlsa->linksCount; i++)
365 {
366 OSPFVERTEXTYPE newVertexType;
367 NETSIM_IPAddress newVertexId;
368 UINT newVertexDistance;
369 ptrOSPFVERTEX candidateListItem = NULL;
370 ptrOSPFRLSALINK link = vlsa->rlsaLink[i];
371 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tExamine link %s, link type %s",
372 link->linkId->str_ip, strOSPFLINKTYPE[link->type]);
373
374 if (link->type == OSPFLINKTYPE_POINT_TO_POINT)
375 {
376 wlsa = ospf_lsdb_lookup_lsaList(area->routerLSAList,
377 link->linkId,
378 link->linkId);
379
380 newVertexType = OSPFVERTEXTYPE_ROUTER;
381 }
382 else if (link->type == OSPFLINKTYPE_TRANSIT)
383 {
384 wlsa = ospf_lsdb_lookup_lsaListByID(area->nwLSAList, link->linkId);
385 newVertexType = OSPFVERTEXTYPE_NETWORK;
386 }
387 else
388 {
389 continue;
390 }
391
392 // RFC2328, Sec-16.1 (2.b & 2.c)
393 if (wlsa == NULL ||
394 ospf_lsa_hasMaxAge(ospf, wlsa) ||
395 /*!ospf_rlsa_hasLink(ospf, wlsa, vertex->lsa) ||*/ // don't understand why this is not working here!! :(
396 ospf_spf_isInShortestPathList(ospf,
397 area->shortestPathList,
398 newVertexType,
399 link->linkId))
400 {
401 if (wlsa == NULL)
402 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\twlsa is NULL");
403 else if (ospf_lsa_hasMaxAge(ospf, wlsa))
404 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tWLSA has MAX AGE");
405 else if (!ospf_rlsa_hasLink(ospf, wlsa, vertex->lsa))
406 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tNo Link between wLSA and vLSA");
407 continue;
408 }
409
410 newVertexId = wlsa->LinkStateID;
411 newVertexDistance = vertex->distance + link->metric;
412
413 candidateListItem = ospf_spf_findCandidate(ospf,
414 candidateList,
415 newVertexType,
416 newVertexId);
417 if (!candidateListItem)
418 {
419 // Insert new candidate
420 candidateListItem = calloc(1, sizeof* candidateListItem);
421
422 candidateListItem->vertexId = newVertexId;
423 candidateListItem->vertexType = newVertexType;
424 candidateListItem->lsa = wlsa;
425 candidateListItem->distance = newVertexDistance;
426 candidateListItem->nextHopList = ospf_list_init(NULL, NULL);
427 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\n\tPossible new candidate is %s", newVertexId->str_ip);
428 if (ospf_spf_setNextHopForThisVertex(ospf,candidateListItem,vertex))
429 {
430 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tInserting new vertex %s\n", newVertexId->str_ip);
431 ospf_list_add_mem(candidateList, candidateListItem);
432 }
433 else
434 {
435 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "\tSet next hop is FALSE for candidate %s\n", newVertexId->str_ip);
436 ospf_list_delete_all(candidateListItem->nextHopList);
437 free(candidateListItem);
438 }
439 }
440 else if (candidateListItem->distance > newVertexDistance)
441 {
442 // update
443 candidateListItem->distance = newVertexDistance;
444
445 // Free old next hop items
446 ospf_list_delete_all(candidateListItem->nextHopList);
447 ospf_spf_setNextHopForThisVertex(ospf, candidateListItem, vertex);
448 }
449 else if (candidateListItem->distance == newVertexDistance)
450 {
451 // Add new set of next hop values
452 ospf_spf_setNextHopForThisVertex(ospf, candidateListItem, vertex);
453 }
454 else
455 {
456 // Examine next link
457 continue;
458 }
459 }
460}
461
462static void ospf_spf_updateCandidateList(ptrOSPF_PDS ospf,
463 ptrOSPFAREA_DS area,
464 ptrOSPFLIST candidateList,
465 ptrOSPFVERTEX vertex)
466{
467 if (vertex->vertexType == OSPFVERTEXTYPE_NETWORK)
468 ospf_spf_updateCandidateListUsingNWLSA(ospf, area, candidateList, vertex);
469 else
470 ospf_spf_updateCandidateListUsingRouterLSA(ospf, area, candidateList, vertex);
471}
472
473static void ospf_spf_updateIntraAreaRoute(ptrOSPF_PDS ospf,
474 ptrOSPFAREA_DS area,
475 ptrOSPFVERTEX vertex)
476{
477 OSPFROUTINGTABLEROW newRow;
478 ptrOSPFNEXTHOPLISTITEM nextHopItem = NULL;
479 ptrOSPF_IF thisInterface = NULL;
480 if (!ospf_list_is_empty(vertex->nextHopList))
481 {
482 nextHopItem = ospf_list_get_headptr(vertex->nextHopList);
483 thisInterface = OSPF_IF_GET(ospf, nextHopItem->outIntf);
484 }
485
486 // If vertex is router
487 if (vertex->vertexType == OSPFVERTEXTYPE_ROUTER)
488 {
489 ptrOSPFLSAHDR lsa = vertex->lsa;
490 ptrOSPFRLSA routerLSA = vertex->lsa->lsaInfo;
491
492 if(Ospf_rlsa_getASBRouter(routerLSA->VEB) ||
493 Ospf_rlsa_getABRouter(routerLSA->VEB))
494 {
495 // Add entry of vertex to routing table
496 if (Ospf_rlsa_getABRouter(routerLSA->VEB) &&
497 Ospf_rlsa_getASBRouter(routerLSA->VEB))
498 newRow.destType = OSPFDESTTYPE_ABR_ASBR;
499 else if(Ospf_rlsa_getABRouter(routerLSA->VEB))
500 newRow.destType = OSPFDESTTYPE_ABR;
501 else
502 newRow.destType = OSPFDESTTYPE_ASBR;
503
504 newRow.destAddr = vertex->vertexId;
505 newRow.addrMask = ANY_DEST;
506
507 newRow.option = lsa->Options;
508
509 newRow.areaId = area->areaId;
510 newRow.pathType = OSPFPATHTYPE_INTRA_AREA;
511 newRow.metric = vertex->distance;
512 newRow.type2Metric = 0;
513 newRow.LSOrigin = (void*)vertex->lsa;
514 newRow.advertisingRouter = lsa->AdvertisingRouter;
515 if (nextHopItem)
516 {
517 newRow.nextHop = nextHopItem->nextHop;
518 newRow.outInterface = DEVICE_NWADDRESS(ospf->myId, nextHopItem->outIntf);
519 newRow.outInterfaceId = nextHopItem->outIntf;
520 }
521
522 ospf_rtTable_addRoute(ospf, &newRow);
523 }
524 }
525 // Else it must be a transit network vertex
526 else if (nextHopItem != NULL &&
527 thisInterface->includeSubnetRts)
528 {
529 fnNetSimError("Reserved for future use. This will work after network LSA implementation.\n");
530#pragma message(__LOC__"Implement after network LSA implementation")
531 }
532}
533
534static ptrOSPFVERTEX ospf_spf_updateShortestPathList(ptrOSPF_PDS ospf,
535 ptrOSPFAREA_DS area,
536 ptrOSPFLIST candidateList)
537{
538 UINT lowestMetric = OSPF_LS_INFINITY;
539 ptrOSPFVERTEX candidateEntry;
540 ptrOSPFVERTEX closestCandidate = NULL;
541 void* pass = ospf_list_newIterator();
542
543 // Get the vertex with the smallest metric from the candidate list...
544 while ((candidateEntry = ospf_list_iterate_mem(candidateList, pass)) != NULL)
545 {
546 if (candidateEntry->distance < lowestMetric)
547 {
548 lowestMetric = candidateEntry->distance;
549
550 // Keep track of closest vertex
551 closestCandidate = candidateEntry;
552 }
553
554 else if (candidateEntry->distance == lowestMetric &&
555 closestCandidate &&
556 closestCandidate->vertexType == OSPFVERTEXTYPE_ROUTER &&
557 candidateEntry->vertexType == OSPFVERTEXTYPE_NETWORK)
558 {
559 // Network vertex get preference over router vertex
560 // Keep track of closest vertex
561 closestCandidate = candidateEntry;
562 }
563 }
564 ospf_list_deleteIterator(pass);
565
566 ptrOSPFVERTEX shortestPathListItem = closestCandidate;
567
568 // Now insert it into the shortest path list...
569 ospf_list_add_mem(area->shortestPathList, shortestPathListItem);
570
571 // And remove it from the candidate list since no longer available.
572 ospf_list_remove_mem(candidateList, closestCandidate, NULL);
573
574 // Update my routing table to reflect the new shortest path list.
575 ospf_spf_updateIntraAreaRoute(ospf, area, shortestPathListItem);
576
577 return shortestPathListItem;
578}
579
580static bool ospf_spf_removeLSAFromShortestPathList(ptrOSPF_PDS ospf,
581 ptrOSPFLIST shortestPathList,
582 ptrOSPFLSAHDR lsa)
583{
584 (void)ospf;
585
586 ptrOSPFVERTEX vertex = NULL;
587 void* pass = ospf_list_newIterator();
588 while ((vertex = ospf_list_iterate_mem(shortestPathList, pass)) != NULL)
589 {
590 if (lsa == vertex->lsa)
591 {
592 if (vertex->nextHopList)
593 ospf_list_delete_all(vertex->nextHopList);
594 ospf_list_remove_mem(shortestPathList, lsa, pass);
595 ospf_list_deleteIterator(pass);
596 return true;
597 }
598 }
599 ospf_list_deleteIterator(pass);
600 return false;
601}
602
603static void ospf_spf_addStubRouteToshortestPath(ptrOSPF_PDS ospf,
604 ptrOSPFAREA_DS thisArea)
605{
606 UINT i;
607 ptrOSPFVERTEX tempV = NULL;
608 UINT distance;
609
610 void* pass = ospf_list_newIterator();
611 while ((tempV = ospf_list_iterate_mem(thisArea->shortestPathList, pass)) != NULL)
612 {
613 // Examine router vertex only
614 if (tempV->vertexType != OSPFVERTEXTYPE_ROUTER)
615 continue;
616
617 ptrOSPFLSAHDR lsaHdr = tempV->lsa;
618 ptrOSPFRLSA rlsa = lsaHdr->lsaInfo;
619
620 // Skip LSA if max age is reached and examine the next LSA.
621 if (ospf_lsa_maskDoNotAge(ospf, lsaHdr->LSAge) >= ospf->LSAMaxAge)
622 continue;
623
624 for (i = 0; i < rlsa->linksCount; i++)
625 {
626 ptrOSPFRLSALINK link = rlsa->rlsaLink[i];
627
628 // Examine stub network only
629 if (link->type != OSPFLINKTYPE_STUB)
630 continue;
631
632 // Don't process if this indicates to my address
633 if (ospf_isMyAddr(ospf->myId, link->linkId))
634 {
635 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "%s is my address. Not processing this link", link->linkId->str_ip);
636 continue;
637 }
638
639 // Calculate distance from root.
640 distance = link->metric + tempV->distance;
641
642 ptrOSPFROUTINGTABLEROW rowPtr;
643 // Get this route from routing table
644 // handling for host route
645 if (!IP_COMPARE(link->linkData, ANY_DEST))
646 rowPtr = ospf_rtTable_getValidHostRoute(ospf,
647 link->linkId,
648 OSPFDESTTYPE_NETWORK);
649 else
650 rowPtr = ospf_rtTable_getValidRoute(ospf,
651 link->linkId,
652 OSPFDESTTYPE_NETWORK);
653
654 OSPFROUTINGTABLEROW newRow;
655
656 if (rowPtr)
657 {
658 // If the calculated distance is larger than previous,
659 // examine next stub link
660
661 if (distance >= rowPtr->metric)
662 continue;
663
664 ospf_rtTable_freeRoute(ospf, rowPtr);
665 }
666
667 // Add new route
668 newRow.destType = OSPFDESTTYPE_NETWORK;
669 newRow.destAddr = link->linkId;
670 newRow.addrMask = link->linkData;
671 newRow.option = 0;
672 newRow.areaId = thisArea->areaId;
673 newRow.pathType = OSPFPATHTYPE_INTRA_AREA;
674 newRow.metric = distance;
675 newRow.type2Metric = 0;
676 newRow.LSOrigin = (void*)tempV->lsa;
677 newRow.advertisingRouter = lsaHdr->AdvertisingRouter;
678
679 // If stub network is part of the node's interfaces
680 if (!OSPFID_COMPARE(tempV->vertexId, ospf->routerId))
681 {
682 NETSIM_ID intfId;
683
684 // handling for host route
685 if (link->linkData->int_ip[0] != 0xffffffff)
686 {
687 intfId = ospf_neighbor_getInterfaceIdforThisNeighbor(ospf,
688 link->linkId);
689 }
690 else
691 {
692 intfId = ospf_getInterfaceIdForNextHop(ospf->myId,
693 link->linkId);
694 }
695
696 if (!intfId)
697 {
698 ptrOSPFLSAHDR LSHeader = NULL;
699
700 LSHeader = ospf_lsdb_lookup_lsaList(thisArea->routerLSAList,
701 link->linkId,
702 link->linkId);
703
704 if (LSHeader)
705 {
706 ospf_lsdb_removeLSA(ospf,
707 thisArea,
708 LSHeader);
709
710 ospf_spf_removeLSAFromShortestPathList(ospf,
711 thisArea->shortestPathList,
712 LSHeader);
713
714 }
715 continue;
716 }
717
718 newRow.outInterface = DEVICE_NWADDRESS(ospf->myId, intfId);
719 newRow.outInterfaceId = intfId;
720 newRow.nextHop = NULL;
721 }
722 else
723 {
724 if (!tempV->nextHopList)
725 continue;
726
727 if (ospf_list_is_empty(tempV->nextHopList))
728 continue;
729
730 ptrOSPFNEXTHOPLISTITEM nextHopItem = ospf_list_get_headptr(tempV->nextHopList);
731 newRow.nextHop = nextHopItem->nextHop;
732 newRow.outInterface = DEVICE_NWADDRESS(ospf->myId, nextHopItem->outIntf);
733 newRow.outInterfaceId = nextHopItem->outIntf;
734
735 }
736
737 ospf_rtTable_addRoute(ospf, &newRow);
738 }
739 }
740 ospf_list_deleteIterator(pass);
741}
742
743static void ospf_spf_printCandidateList(ptrOSPF_PDS ospf,
744 ptrOSPFLIST candidateList)
745{
746 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Candidate list for router %d", ospf->myId);
747 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), " size = %d", ospf_list_get_size(candidateList));
748
749 ospf_spf_printVertexList(ospf, candidateList);
750}
751
752static void ospf_spf_findShrotestPathForThisArea(ptrOSPF_PDS ospf,
753 ptrOSPFAREA_DS area)
754{
755 ptrOSPFLIST candidateList = ospf_list_init(OSPF_SPF_FREE_VERTEX, OSPF_SPF_COPY_VERTEX);
756 ptrOSPFVERTEX tempV = calloc(1, sizeof* tempV);
757
758 area->shortestPathList = ospf_list_init(OSPF_SPF_FREE_VERTEX, OSPF_SPF_COPY_VERTEX);
759
760 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Calculating shortest path for area %s",
761 area->areaId->str_ip);
762
763 // The shortest path starts with myself as the root.
764 tempV->vertexId = ospf->routerId;
765 tempV->vertexType = OSPFVERTEXTYPE_ROUTER;
766 tempV->lsa = ospf_lsdb_lookup_lsaList(area->routerLSAList,
767 ospf->routerId,
768 ospf->routerId);
769
770 if (!tempV->lsa ||
771 ospf_lsa_hasMaxAge(ospf, tempV->lsa))
772 {
773 free(tempV);
774 ospf_list_delete_all(candidateList);
775 ospf_list_delete_all(area->shortestPathList);
776 return;
777 }
778 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Examine LSA of type %s, Id %s, seq num %u",
779 strLSTYPE[tempV->lsa->LSType],
780 tempV->lsa->LinkStateID->str_ip,
781 tempV->lsa->LSSequenceNumber - OSPF_INITIAL_SEQUENCE_NUMBER);
782
783 tempV->nextHopList = ospf_list_init(NULL, NULL);
784
785 // Insert myself (root) to the shortest path list.
786 ospf_list_add_mem(area->shortestPathList, tempV);
787
788 // Find candidates to be considered for the shortest path list.
789 ospf_spf_updateCandidateList(ospf, area, candidateList, tempV);
790
791 ospf_spf_printCandidateList(ospf, candidateList);
792
793 // Keep calculating shortest path until the candidate list is empty.
794 while (!ospf_list_is_empty(candidateList))
795 {
796 // Select the next best node in the candidate list into
797 // the shortest path list. That node is tempV.
798 tempV = ospf_spf_updateShortestPathList(ospf, area, candidateList);
799
800 ospf_spf_printShortestpath(ospf, area);
801
802 // Find more candidates to be considered for the shortest path list.
803 ospf_spf_updateCandidateList(ospf, area, candidateList, tempV);
804
805 ospf_spf_printCandidateList(ospf, candidateList);
806 }
807
808 // Add stub routes to the shortest path list.
809 ospf_spf_addStubRouteToshortestPath(ospf, area);
810
811 ospf_spf_printShortestpath(ospf, area);
812
813 ospf_list_delete_all(area->shortestPathList);
814 ospf_list_delete_all(candidateList);
815}
816
817static void ospf_spf_findInterAreaPath(ptrOSPF_PDS ospf)
818{
819 (void)ospf;
820
821 fnNetSimError("Implement %s after area implementation -- 22645", __FUNCTION__);
822#pragma message("Implement %s after area implementation -- 22645")
823}
824
825static void ospf_spf_findShortestPath(ptrOSPF_PDS ospf)
826{
827 ospf_spf_invalidateRoutingTable(ospf);
828
829 UINT i;
830 for (i = 0; i < ospf->areaCount; i++)
831 {
832 ptrOSPFAREA_DS area = ospf->areaDS[i];
833 ospf_spf_findShrotestPathForThisArea(ospf, area);
834 }
835
836 // Calculate Inter Area routes
837 if (ospf->isPartitionedIntoArea)
838 ospf_spf_findInterAreaPath(ospf);
839
840
841 if (ospf->isPartitionedIntoArea == TRUE &&
842 ospf->routerType == OSPFRTYPE_ABR)
843 ospf_area_handleABRTask(ospf);
844
845 ospf_rtTable_freeAllInvalidRoute(ospf);
846
847 // Update IP forwarding table using new shortest path.
848 ospf_rtTable_updateIPTable(ospf);
849}
850
851void ospf_spf_handleCalculateSPFEvent()
852{
853 ptrOSPF_PDS ospf = OSPF_PDS_CURRENT();
854 ospf->SPFTimer = OSPF_CURR_TIME();
855 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "Calculating shortest path for router %d at time %0.3lf",
856 ospf->myId, ospf->SPFTimer / MILLISECOND);
857 ospf_spf_findShortestPath(ospf);
858#pragma message(__LOC__"Uncomment after bug correction of link failure.")
859 iptable_delete_by_type(IP_WRAPPER_GET(ospf->myId),"OSPF");
860 ptrOSPF_COST_LIST ospf_cost_list = NULL;
861 ospf_cost_list = fn_NetSim_App_Routing_Init(ospf->myId, ospf_cost_list);
862 ospf_Table_updateIPTable_Dijkstra(ospf,ospf_cost_list);
863
864 ptrOSPF_PATH temp_ospf_path = ospf_cost_list->path;
865 ptrOSPF_PATH prev_temp_ospf_path;
866 while (temp_ospf_path)
867 {
868 prev_temp_ospf_path = temp_ospf_path;
869 prev_temp_ospf_path->next = NULL;
870 temp_ospf_path = temp_ospf_path->next;
871 free(prev_temp_ospf_path);
872 }
873 ospf_cost_list->path = NULL;
874
875 while (ospf_cost_list) {
876 ptrOSPF_COST_LIST temp = ospf_cost_list;
877 ospf_cost_list = ospf_cost_list->next;
878 temp->next = NULL;
879 free(temp);
880 }
881 print_ospf_Dlog(form_dlogId("OSPFSPF", ospf->myId), "");
882}