]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/ospf/rt.c
4 * (c) 2000--2004 Ondrej Filip <feela@network.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 static void add_cand(list
* l
, struct top_hash_entry
*en
,
12 struct top_hash_entry
*par
, u32 dist
,
13 struct ospf_area
*oa
);
14 static void calc_next_hop(struct ospf_area
*oa
,
15 struct top_hash_entry
*en
,
16 struct top_hash_entry
*par
);
17 static void ospf_ext_spf(struct proto_ospf
*po
);
18 static void rt_sync(struct proto_ospf
*po
);
20 /* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
21 as index, so we need to encapsulate RID to IP addresss */
23 #define ipa_from_rid(x) _MI(x)
25 #define ipa_from_rid(x) _MI(0,0,0,x)
32 get_ipv6_prefix(u32
*buf
, ip_addr
*addr
, int *pxlen
, u8
*pxopts
, u16
*rest
)
34 u8 pxl
= (*buf
>> 24);
35 *pxopts
= (*buf
>> 16);
55 get_ipv6_addr(u32
*buf
, ip_addr
*addr
)
57 *addr
= *(ip_addr
*) buf
;
67 orta
->type
= RTS_DUMMY
;
70 orta
->metric1
= LSINFINITY
;
71 orta
->metric2
= LSINFINITY
;
79 ospf_rt_initort(struct fib_node
*fn
)
83 memcpy(&ri
->o
, &ri
->n
, sizeof(orta
));
87 /* If new is better return 1 */
90 * This is hard to understand:
91 * If rfc1583 is set to 1, it work likes normal route_better()
92 * But if it is set to 0, it prunes number of AS boundary
93 * routes before it starts the router decision
96 ri_better(struct proto_ospf
*po
, orta
* new, ort
*nefn
, orta
* old
, ort
*oefn
, int rfc1583
)
98 int newtype
= new->type
;
99 int oldtype
= old
->type
;
101 if (old
->type
== RTS_DUMMY
)
104 if (old
->metric1
== LSINFINITY
)
109 if ((new->type
< RTS_OSPF_EXT1
) && (new->oa
->areaid
== 0)) newtype
= RTS_OSPF_IA
;
110 if ((old
->type
< RTS_OSPF_EXT2
) && (old
->oa
->areaid
== 0)) oldtype
= RTS_OSPF_IA
;
113 if (newtype
< oldtype
)
116 if (newtype
> oldtype
)
120 if (new->type
== RTS_OSPF_EXT2
)
122 if (new->metric2
< old
->metric2
) return 1;
123 if (new->metric2
> old
->metric2
) return 0;
126 if (((new->type
== RTS_OSPF_EXT2
) || (new->type
== RTS_OSPF_EXT1
)) && (!po
->rfc1583
))
128 newtype
= nefn
->n
.type
;
129 oldtype
= oefn
->n
.type
;
131 if (nefn
->n
.oa
->areaid
== 0) newtype
= RTS_OSPF_IA
;
132 if (oefn
->n
.oa
->areaid
== 0) oldtype
= RTS_OSPF_IA
;
134 if (newtype
< oldtype
) return 1;
135 if (newtype
> oldtype
) return 0;
138 if (new->metric1
< old
->metric1
)
141 if (new->metric1
> old
->metric1
)
144 if (new->oa
->areaid
> old
->oa
->areaid
) return 1; /* Larger AREAID is preffered */
146 return 0; /* Old is shorter or same */
150 ri_install(struct proto_ospf
*po
, ip_addr prefix
, int pxlen
, int dest
,
151 orta
* new, ort
* ipath
)
153 struct ospf_area
*oa
= new->oa
;
158 struct area_net
*anet
;
159 old
= (ort
*) fib_get(&po
->rtf
, &prefix
, pxlen
);
160 if (ri_better(po
, new, ipath
, &old
->n
, old
->efn
, 1))
162 memcpy(&old
->n
, new, sizeof(orta
));
164 if ((new->type
== RTS_OSPF
) && (anet
= (struct area_net
*)fib_route(&oa
->net_fib
, prefix
, pxlen
)))
167 if (new->metric1
> anet
->metric
) anet
->metric
= new->metric1
;
173 old
= (ort
*) fib_get(&oa
->rtr
, &prefix
, pxlen
);
175 if (ri_better(po
, new, ipath
, &old
->n
, old
->efn
, 1))
177 memcpy(&old
->n
, new, sizeof(orta
));
184 add_network(struct ospf_area
*oa
, ip_addr px
, int pxlen
, int metric
, struct top_hash_entry
*en
)
190 nf
.metric2
= LSINFINITY
;
197 /* FIXME check nf.ifa on stubs */
198 ri_install(oa
->po
, px
, pxlen
, ORT_NET
, &nf
, NULL
);
203 process_prefixes(struct ospf_area
*oa
)
205 struct proto_ospf
*po
= oa
->po
;
206 struct proto
*p
= &po
->proto
;
207 struct top_hash_entry
*en
, *src
;
208 struct ospf_lsa_prefix
*px
;
216 WALK_SLIST(en
, po
->lsal
)
218 if (en
->lsa
.type
!= LSA_T_PREFIX
)
221 if (en
->domain
!= oa
->areaid
)
224 if (en
->lsa
.age
== LSA_MAXAGE
)
228 /* FIXME: for router LSA, we should find the first one */
229 src
= ospf_hash_find(po
->gr
, oa
->areaid
,
230 ((px
->ref_type
== LSA_T_RT
) ? px
->ref_rt
: px
->ref_id
),
231 px
->ref_rt
, px
->ref_type
);
236 if (src
->lsa
.age
== LSA_MAXAGE
)
239 if ((src
->lsa
.type
!= LSA_T_RT
) && (src
->lsa
.type
!= LSA_T_NET
))
243 for (i
= 0; i
< px
->pxcount
; i
++)
245 buf
= get_ipv6_prefix(buf
, &pxa
, &pxlen
, &pxopts
, &metric
);
247 if (pxopts
& OPT_PX_NU
)
250 add_network(oa
, pxa
, pxlen
, src
->dist
+ metric
, src
);
257 ospf_rt_spfa(struct ospf_area
*oa
)
260 struct ospf_lsa_rt
*rt
;
261 struct ospf_lsa_rt_link
*rtl
, *rr
;
262 struct proto
*p
= &oa
->po
->proto
;
263 struct proto_ospf
*po
= oa
->po
;
264 struct ospf_lsa_net
*ln
;
266 struct ospf_iface
*iface
;
267 struct top_hash_entry
*act
, *tmp
;
273 OSPF_TRACE(D_EVENTS
, "Starting routing table calculation for area %R", oa
->areaid
);
275 if (oa
->rt
->dist
!= LSINFINITY
)
276 bug("Aging was not processed.");
279 init_list(&oa
->cand
); /* Empty list of candidates */
282 DBG("LSA db prepared, adding me into candidate list.\n");
285 oa
->rt
->color
= CANDIDATE
;
286 add_head(&oa
->cand
, &oa
->rt
->cn
);
287 DBG("RT LSA: rt: %R, id: %R, type: %u\n",
288 oa
->rt
->lsa
.rt
, oa
->rt
->lsa
.id
, oa
->rt
->lsa
.type
);
290 while (!EMPTY_LIST(oa
->cand
))
293 act
= SKIP_BACK(struct top_hash_entry
, cn
, n
);
296 DBG("Working on LSA: rt: %R, id: %R, type: %u\n",
297 act
->lsa
.rt
, act
->lsa
.id
, act
->lsa
.type
);
300 switch (act
->lsa
.type
)
303 /* FIXME - in OSPFv3 we should process all RT LSAs from that router */
304 rt
= (struct ospf_lsa_rt
*) act
->lsa_body
;
305 if (rt
->options
& OPT_RT_V
)
308 /* FIXME - in OSPFv3, should we add all routers, or just ABRs an ASBRs? */
309 if ((rt
->options
& OPT_RT_V
) || (rt
->options
& OPT_RT_E
))
312 nf
.options
= rt
->options
;
313 nf
.metric1
= act
->dist
;
314 nf
.metric2
= LSINFINITY
;
320 ri_install(po
, ipa_from_rid(act
->lsa
.rt
), MAX_PREFIX_LENGTH
, ORT_ROUTER
, &nf
, NULL
);
323 rr
= (struct ospf_lsa_rt_link
*) (rt
+ 1);
324 DBG(" Number of links: %u\n", rt
->links
);
325 for (i
= 0; i
< lsa_rt_count(&act
->lsa
); i
++)
329 DBG(" Working on link: %R (type: %u) ", rtl
->id
, rtl
->type
);
335 * This violates rfc2328! But it is mostly harmless.
341 nf
.metric1
= act
->dist
+ rtl
->metric
;
342 nf
.metric2
= LSINFINITY
;
351 struct ospf_iface
*iff
;
353 WALK_LIST(iff
, po
->iface_list
) /* Try to find corresponding interface */
355 if (iff
->iface
&& (iff
->type
!= OSPF_IT_VLINK
) &&
356 (rtl
->id
== (ipa_to_u32(ipa_mkmask(iff
->iface
->addr
->pxlen
))
357 & ipa_to_u32(iff
->iface
->addr
->prefix
)))) /* No VLINK and IP must match */
368 ri_install(po
, ipa_from_u32(rtl
->id
),
369 ipa_mklen(ipa_from_u32(rtl
->data
)), ORT_NET
, &nf
, NULL
);
374 /* In OSPFv2, rtl->id is IP addres of DR, router ID is not known */
375 tmp
= ospf_hash_find(po
->gr
, oa
->areaid
, rtl
->id
, 0, LSA_T_NET
);
377 tmp
= ospf_hash_find(po
->gr
, oa
->areaid
, rtl
->nif
, rtl
->id
, LSA_T_NET
);
387 /* FIXME - in OSPFv3, find lowest LSA ID */
388 tmp
= ospf_hash_find(po
->gr
, oa
->areaid
, rtl
->id
, rtl
->id
, LSA_T_RT
);
393 log("Unknown link type in router lsa. (rid = %R)", act
->lsa
.id
);
397 DBG("Going to add cand, Mydist: %u, Req: %u\n",
398 tmp
->dist
, act
->dist
+ rtl
->metric
);
399 add_cand(&oa
->cand
, tmp
, act
, act
->dist
+ rtl
->metric
, oa
);
406 add_network(oa
, ipa_and(ipa_from_u32(act
->lsa
.id
), ln
->netmask
),
407 ipa_mklen(ln
->netmask
), act
->dist
, act
);
410 rts
= (u32
*) (ln
+ 1);
411 for (i
= 0; i
< lsa_net_count(&act
->lsa
); i
++)
413 DBG(" Working on router %R ", rts
[i
]);
414 /* FIXME - in OSPFv3, find any LSA ID */
415 tmp
= ospf_hash_find(po
->gr
, oa
->areaid
, rts
[i
], rts
[i
], LSA_T_RT
);
420 add_cand(&oa
->cand
, tmp
, act
, act
->dist
, oa
);
427 process_prefixes(oa
);
430 /* Find new/lost VLINK peers */
431 WALK_LIST(iface
, po
->iface_list
)
433 if ((iface
->type
== OSPF_IT_VLINK
) && (iface
->voa
== oa
))
435 /* FIXME in OSPFv3, different LSAID */
436 if ((tmp
= ospf_hash_find(po
->gr
, oa
->areaid
, iface
->vid
, iface
->vid
, LSA_T_RT
)) &&
437 (!ipa_equal(tmp
->lb
, IPA_NONE
)))
439 if ((iface
->state
!= OSPF_IS_PTP
) || (iface
->iface
!= tmp
->nhi
->iface
) || (!ipa_equal(iface
->vip
, tmp
->lb
)))
441 OSPF_TRACE(D_EVENTS
, "Vlink peer %R found", tmp
->lsa
.id
);
442 ospf_iface_sm(iface
, ISM_DOWN
);
443 iface
->iface
= tmp
->nhi
->iface
;
444 iface
->vip
= tmp
->lb
;
445 ospf_iface_sm(iface
, ISM_UP
);
450 if (iface
->state
> OSPF_IS_DOWN
)
452 OSPF_TRACE(D_EVENTS
, "Vlink peer %R lost", iface
->vid
);
453 ospf_iface_sm(iface
, ISM_DOWN
);
462 link_back(struct ospf_area
*oa
, struct top_hash_entry
*fol
, struct top_hash_entry
*pre
)
465 struct ospf_lsa_net
*ln
;
466 struct ospf_lsa_rt
*rt
;
467 struct ospf_lsa_rt_link
*rtl
, *rr
;
468 struct proto_ospf
*po
= oa
->po
;
472 switch (fol
->lsa
.type
)
475 rt
= (struct ospf_lsa_rt
*) fol
->lsa_body
;
476 rr
= (struct ospf_lsa_rt_link
*) (rt
+ 1);
477 for (i
= 0; i
< lsa_rt_count(&fol
->lsa
); i
++)
485 if (ospf_hash_find(po
->gr
, oa
->areaid
, rtl
->id
, rtl
->id
, LSA_T_NET
) == pre
)
487 fol
->lb
= ipa_from_u32(rtl
->data
);
493 if (ospf_hash_find(po
->gr
, oa
->areaid
, rtl
->id
, rtl
->id
, LSA_T_RT
) == pre
)
495 fol
->lb
= ipa_from_u32(rtl
->data
);
500 log("Unknown link type in router lsa. (rid = %R)", fol
->lsa
.id
);
507 rts
= (u32
*) (ln
+ 1);
508 for (i
= 0; i
< lsa_net_count(&fol
->lsa
); i
++)
510 if (ospf_hash_find(po
->gr
, oa
->areaid
, *(rts
+ i
), *(rts
+ i
), LSA_T_RT
) == pre
)
517 bug("Unknown lsa type. (id = %R)", fol
->lsa
.id
);
524 ospf_rt_sum_tr(struct ospf_area
*oa
)
526 struct proto
*p
= &oa
->po
->proto
;
527 struct proto_ospf
*po
= oa
->po
;
528 struct ospf_area
*bb
= po
->backbone
;
530 struct top_hash_entry
*en
;
531 u32 dst_rid
, metric
, options
;
532 int pxlen
= -1, type
= -1;
533 ort
*re
= NULL
, *abr
;
538 WALK_SLIST(en
, po
->lsal
)
540 if ((en
->lsa
.type
!= LSA_T_SUM_RT
) && (en
->lsa
.type
!= LSA_T_SUM_NET
))
543 if (en
->domain
!= oa
->areaid
)
546 if (en
->lsa
.age
== LSA_MAXAGE
)
549 if (en
->dist
== LSINFINITY
)
552 if (en
->lsa
.rt
== p
->cf
->global
->router_id
)
556 if (en
->lsa
.type
== LSA_T_SUM_NET
)
559 struct ospf_lsa_sum
*ls
= en
->lsa_body
;
560 pxlen
= ipa_mklen(ls
->netmask
);
561 ip
= ipa_and(ipa_from_u32(en
->lsa
.id
), ls
->netmask
);
565 struct ospf_lsa_sum_net
*ls
= en
->lsa_body
;
566 get_ipv6_prefix(ls
->prefix
, &ip
, &pxlen
, &pxopts
, &rest
);
568 if (pxopts
& OPT_PX_NU
)
572 metric
= ls
->metric
& METRIC_MASK
;
575 re
= (ort
*) fib_find(&po
->rtf
, &ip
, pxlen
);
577 else if (en
->lsa
.type
== LSA_T_SUM_RT
)
580 struct ospf_lsa_sum
*ls
= en
->lsa_body
;
581 dst_rid
= en
->lsa
.id
;
584 struct ospf_lsa_sum_rt
*ls
= en
->lsa_body
;
586 options
= ls
->options
& OPTIONS_MASK
;
589 ip
= ipa_from_rid(dst_rid
);
590 pxlen
= MAX_PREFIX_LENGTH
;
591 metric
= ls
->metric
& METRIC_MASK
;
592 options
|= ORTA_ASBR
;
594 re
= (ort
*) fib_find(&bb
->rtr
, &ip
, pxlen
);
598 if (re
->n
.oa
->areaid
!= 0) continue;
599 if ((re
->n
.type
!= RTS_OSPF
) && (re
->n
.type
!= RTS_OSPF_IA
)) continue;
601 abrip
= ipa_from_rid(en
->lsa
.rt
);
603 abr
= fib_find(&oa
->rtr
, &abrip
, MAX_PREFIX_LENGTH
);
606 nf
.type
= re
->n
.type
;
607 nf
.options
= options
;
608 nf
.metric1
= abr
->n
.metric1
+ metric
;
609 nf
.metric2
= LSINFINITY
;
615 ri_install(po
, ip
, pxlen
, type
, &nf
, NULL
);
621 ospf_rt_sum(struct ospf_area
*oa
)
623 struct proto_ospf
*po
= oa
->po
;
624 struct proto
*p
= &po
->proto
;
625 struct top_hash_entry
*en
;
626 ip_addr ip
, abrip
; /* abrIP is actually ID */
627 u32 dst_rid
, metric
, options
;
628 struct area_net
*anet
;
631 int pxlen
= -1, type
= -1;
633 OSPF_TRACE(D_EVENTS
, "Starting routing table calculation for inter-area (area %R)", oa
->areaid
);
635 WALK_SLIST(en
, po
->lsal
)
637 if ((en
->lsa
.type
!= LSA_T_SUM_RT
) && (en
->lsa
.type
!= LSA_T_SUM_NET
))
640 if (en
->domain
!= oa
->areaid
)
644 if (en
->lsa
.age
== LSA_MAXAGE
)
648 if (en
->lsa
.rt
== p
->cf
->global
->router_id
)
652 if (en
->lsa
.type
== LSA_T_SUM_NET
)
654 struct ospf_area
*oaa
;
658 struct ospf_lsa_sum
*ls
= en
->lsa_body
;
659 pxlen
= ipa_mklen(ls
->netmask
);
660 ip
= ipa_and(ipa_from_u32(en
->lsa
.id
), ls
->netmask
);
664 struct ospf_lsa_sum_net
*ls
= en
->lsa_body
;
665 get_ipv6_prefix(ls
->prefix
, &ip
, &pxlen
, &pxopts
, &rest
);
667 if (pxopts
& OPT_PX_NU
)
671 metric
= ls
->metric
& METRIC_MASK
;
676 WALK_LIST(oaa
, po
->area_list
)
678 if ((anet
= fib_find(&oaa
->net_fib
, &ip
, pxlen
)) && anet
->active
)
689 struct ospf_lsa_sum
*ls
= en
->lsa_body
;
690 dst_rid
= en
->lsa
.id
;
693 struct ospf_lsa_sum_rt
*ls
= en
->lsa_body
;
695 options
= ls
->options
& OPTIONS_MASK
;
698 ip
= ipa_from_rid(dst_rid
);
699 pxlen
= MAX_PREFIX_LENGTH
;
700 metric
= ls
->metric
& METRIC_MASK
;
701 options
|= ORTA_ASBR
;
706 if (metric
== LSINFINITY
)
710 abrip
= ipa_from_rid(en
->lsa
.rt
);
711 if (!(abr
= (ort
*) fib_find(&oa
->rtr
, &abrip
, MAX_PREFIX_LENGTH
))) continue;
712 if (abr
->n
.metric1
== LSINFINITY
) continue;
713 if (!(abr
->n
.options
& ORTA_ABR
)) continue;
715 nf
.type
= RTS_OSPF_IA
;
716 nf
.options
= options
;
717 nf
.metric1
= abr
->n
.metric1
+ metric
;
718 nf
.metric2
= LSINFINITY
;
724 ri_install(po
, ip
, pxlen
, type
, &nf
, NULL
);
729 * ospf_rt_spf - calculate internal routes
732 * Calculation of internal paths in an area is described in 16.1 of RFC 2328.
733 * It's based on Dijkstra's shortest path tree algorithms.
734 * This function is invoked from ospf_disp().
737 ospf_rt_spf(struct proto_ospf
*po
)
739 struct proto
*p
= &po
->proto
;
740 struct ospf_area
*oa
;
742 struct area_net
*anet
;
744 if (po
->areano
== 0) return;
748 OSPF_TRACE(D_EVENTS
, "Starting routing table calculation");
750 /* 16. (1) - Invalidate old routing table */
751 FIB_WALK(&po
->rtf
, nftmp
)
754 memcpy(&ri
->o
, &ri
->n
, sizeof(orta
)); /* Backup old data */
760 WALK_LIST(oa
, po
->area_list
)
762 FIB_WALK(&oa
->rtr
, nftmp
)
765 memcpy(&ri
->o
, &ri
->n
, sizeof(orta
)); /* Backup old data */
770 FIB_WALK(&oa
->net_fib
, nftmp
)
772 anet
= (struct area_net
*) nftmp
;
783 if ((po
->areano
== 1) || (!po
->backbone
))
785 ospf_rt_sum(HEAD(po
->area_list
));
789 ospf_rt_sum(po
->backbone
);
793 WALK_LIST(oa
, po
->area_list
)
795 if (oa
->trcap
&& (oa
->areaid
!= 0))
811 * ospf_ext_spf - calculate external paths
814 * After routing table for any area is calculated, calculation of external
815 * path is invoked. This process is described in 16.4 of RFC 2328.
816 * Inter- and Intra-area paths are always prefered over externals.
819 ospf_ext_spf(struct proto_ospf
*po
)
821 ort
*nf1
, *nf2
, *nfh
;
823 struct top_hash_entry
*en
;
824 struct proto
*p
= &po
->proto
;
825 struct ospf_lsa_ext
*le
;
826 int pxlen
, ebit
, rt_fwaddr_valid
;
827 ip_addr ip
, nh
, rtid
, rt_fwaddr
;
828 struct ospf_iface
*nhi
= NULL
;
829 u32 br_metric
, rt_metric
, rt_tag
;
831 struct ospf_area
*atmp
;
833 OSPF_TRACE(D_EVENTS
, "Starting routing table calculation for ext routes");
835 WALK_SLIST(en
, po
->lsal
)
838 if (en
->lsa
.type
!= LSA_T_EXT
)
840 if (en
->lsa
.age
== LSA_MAXAGE
)
844 if (en
->lsa
.rt
== p
->cf
->global
->router_id
)
847 DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
848 p
->name
, en
->lsa
.id
, en
->lsa
.rt
, en
->lsa
.type
);
852 rt_metric
= le
->metric
& METRIC_MASK
;
853 ebit
= le
->metric
& LSA_EXT_EBIT
;
855 if (rt_metric
== LSINFINITY
)
859 ip
= ipa_and(ipa_from_u32(en
->lsa
.id
), le
->netmask
);
860 pxlen
= ipa_mklen(le
->netmask
);
861 rt_fwaddr
= le
->fwaddr
;
862 rt_fwaddr_valid
= !ipa_equal(rt_fwaddr
, IPA_NONE
);
868 buf
= get_ipv6_prefix(buf
, &ip
, &pxlen
, &pxopts
, &rest
);
870 if (pxopts
& OPT_PX_NU
)
873 rt_fwaddr_valid
= le
->metric
& LSA_EXT_FBIT
;
875 buf
= get_ipv6_addr(buf
, &rt_fwaddr
);
877 rt_fwaddr
= IPA_NONE
;
879 if (le
->metric
& LSA_EXT_TBIT
)
887 log("%s: Invalid mask in LSA. ID: %R, RT: %R, Type: %u",
888 p
->name
, en
->lsa
.id
, en
->lsa
.rt
, en
->lsa
.type
);
895 rtid
= ipa_from_rid(en
->lsa
.rt
);
897 WALK_LIST(atmp
, po
->area_list
)
899 nfh
= fib_find(&atmp
->rtr
, &rtid
, MAX_PREFIX_LENGTH
);
900 if (nfh
== NULL
) continue;
901 if (nf1
== NULL
) nf1
= nfh
;
902 else if (ri_better(po
, &nfh
->n
, NULL
, &nf1
->n
, NULL
, po
->rfc1583
)) nf1
= nfh
;
906 continue; /* No AS boundary router found */
908 if (nf1
->n
.metric1
== LSINFINITY
)
909 continue; /* distance is INF */
911 if (!(nf1
->n
.options
& ORTA_ASBR
))
912 continue; /* It is not ASBR */
914 if (!rt_fwaddr_valid
)
919 br_metric
= nf1
->n
.metric1
;
923 nf2
= fib_route(&po
->rtf
, rt_fwaddr
, MAX_PREFIX_LENGTH
);
927 DBG("Cannot find network route (GW=%I)\n", rt_fwaddr
);
931 if ((nn
= neigh_find(p
, &rt_fwaddr
, 0)) != NULL
)
934 nhi
= ospf_iface_find(po
, nn
->iface
);
942 br_metric
= nf2
->n
.metric1
;
943 if (br_metric
== LSINFINITY
)
944 continue; /* distance is INF */
949 nfa
.type
= RTS_OSPF_EXT2
;
950 nfa
.metric1
= br_metric
;
951 nfa
.metric2
= rt_metric
;
955 nfa
.type
= RTS_OSPF_EXT1
;
956 nfa
.metric1
= br_metric
+ rt_metric
;
957 nfa
.metric2
= LSINFINITY
;
962 nfa
.oa
= (po
->backbone
== NULL
) ? HEAD(po
->area_list
) : po
->backbone
;
966 ri_install(po
, ip
, pxlen
, ORT_NET
, &nfa
, nfh
);
971 /* Add LSA into list of candidates in Dijkstra's algorithm */
973 add_cand(list
* l
, struct top_hash_entry
*en
, struct top_hash_entry
*par
,
974 u32 dist
, struct ospf_area
*oa
)
978 struct top_hash_entry
*act
;
983 if (en
->lsa
.age
== LSA_MAXAGE
)
987 if (en
->lsa
.type
== LSA_T_RT
)
989 struct ospf_lsa_rt
*rt
= en
->lsa_body
;
990 if (!(rt
->options
& OPT_V6
) || !(rt
->options
& OPT_R
))
996 if (en
->color
== INSPF
)
1000 if (dist
>= en
->dist
)
1003 * FIXME The line above (=) is not a bug, but we don't support multiple
1004 * next hops. I'll start as soon as nest will
1007 /* FIXME - fix link_back()
1008 if (!link_back(oa, en, par))
1012 DBG(" Adding candidate: rt: %R, id: %R, type: %u\n",
1013 en
->lsa
.rt
, en
->lsa
.id
, en
->lsa
.type
);
1015 calc_next_hop(oa
, en
, par
);
1018 return; /* We cannot find next hop, ignore it */
1020 if (en
->color
== CANDIDATE
)
1021 { /* We found a shorter path */
1025 en
->color
= CANDIDATE
;
1031 add_head(l
, &en
->cn
);
1037 act
= SKIP_BACK(struct top_hash_entry
, cn
, n
);
1038 if ((act
->dist
> dist
) ||
1039 ((act
->dist
== dist
) && (act
->lsa
.type
== LSA_T_NET
)))
1040 /* FIXME - shouldn't be here LSA_T_RT ??? */
1043 add_head(l
, &en
->cn
);
1045 insert_node(&en
->cn
, prev
);
1054 add_tail(l
, &en
->cn
);
1061 match_dr(struct ospf_iface
*ifa
, struct top_hash_entry
*en
)
1064 return (ifa
->drid
== en
->lsa
.rt
) && (ipa_to_u32(ifa
->drip
) == en
->lsa
.id
);
1066 return (ifa
->drid
== en
->lsa
.rt
) && (ifa
->dr_iface_id
== en
->lsa
.id
);
1071 calc_next_hop(struct ospf_area
*oa
, struct top_hash_entry
*en
,
1072 struct top_hash_entry
*par
)
1074 struct ospf_neighbor
*neigh
;
1075 struct proto
*p
= &oa
->po
->proto
;
1076 struct proto_ospf
*po
= oa
->po
;
1077 struct ospf_iface
*ifa
;
1082 /* 16.1.1. The next hop calculation */
1083 DBG(" Next hop called.\n");
1084 if (ipa_equal(par
->nh
, IPA_NONE
))
1086 DBG(" Next hop calculating for id: %R rt: %R type: %u\n",
1087 en
->lsa
.id
, en
->lsa
.rt
, en
->lsa
.type
);
1089 /* The parent vertex is the root */
1092 if (en
->lsa
.type
== LSA_T_NET
)
1094 WALK_LIST(ifa
, po
->iface_list
)
1095 if (match_dr(ifa
, en
))
1104 if ((neigh
= find_neigh_noifa(po
, en
->lsa
.rt
)) == NULL
)
1106 en
->nhi
= neigh
->ifa
;
1108 /* Yes, neighbor is it's own next hop */
1113 /* The parent vertex is a network that directly connects the
1114 calculating router to the destination router. */
1115 if (par
->lsa
.type
== LSA_T_NET
)
1117 if (en
->lsa
.type
== LSA_T_NET
)
1118 bug("Parent for net is net?");
1119 if ((en
->nhi
= par
->nhi
) == NULL
)
1120 bug("Did not find next hop interface for INSPF lsa!");
1122 if ((neigh
= find_neigh_noifa(po
, en
->lsa
.rt
)) == NULL
)
1124 en
->nhi
= neigh
->ifa
;
1126 /* Yes, neighbor is it's own next hop */
1130 { /* Parent is some RT neighbor */
1131 log(L_ERR
"Router's parent has no next hop. (EN=%R, PAR=%R)",
1132 en
->lsa
.id
, par
->lsa
.id
);
1133 /* I hope this would never happen */
1139 DBG(" Next hop calculated: %I.\n", en
->nh
);
1143 rt_sync(struct proto_ospf
*po
)
1145 struct proto
*p
= &po
->proto
;
1146 struct fib_iterator fit
;
1147 struct fib
*fib
= &po
->rtf
;
1149 struct ospf_area
*oa
, *oaa
;
1150 struct area_net
*anet
;
1153 OSPF_TRACE(D_EVENTS
, "Starting routing table synchronisation");
1155 DBG("Now syncing my rt table with nest's\n");
1156 FIB_ITERATE_INIT(&fit
, fib
);
1158 FIB_ITERATE_START(fib
, &fit
, nftmp
)
1161 check_sum_lsa(po
, nf
, ORT_NET
);
1162 if (memcmp(&nf
->n
, &nf
->o
, sizeof(orta
)))
1163 { /* Some difference */
1168 bzero(&a0
, sizeof(a0
));
1171 a0
.source
= nf
->n
.type
;
1172 a0
.scope
= SCOPE_UNIVERSE
;
1173 a0
.cast
= RTC_UNICAST
;
1174 a0
.dest
= RTD_ROUTER
;
1178 if (nf
->n
.ifa
) a0
.iface
= nf
->n
.ifa
->iface
;
1181 if ((!ipa_equal(nf
->n
.nh
, IPA_NONE
)) && (!neigh_find(p
, &nf
->n
.nh
, 0)))
1184 struct ospf_iface
*ifa
;
1185 struct top_hash_entry
*en
;
1186 OSPF_TRACE(D_EVENTS
, "Trying to find correct next hop %I/%d via %I", nf
->fn
.prefix
, nf
->fn
.pxlen
, nf
->n
.nh
);
1187 WALK_LIST(ifa
, po
->iface_list
)
1189 if ((ifa
->type
== OSPF_IT_VLINK
) && ipa_equal(ifa
->vip
, nf
->n
.nh
))
1191 /* FIXME in OSPFv3, may be different LSA ID */
1192 if ((en
= ospf_hash_find(po
->gr
, ifa
->voa
->areaid
, ifa
->vid
, ifa
->vid
, LSA_T_RT
))
1193 && (!ipa_equal(en
->nh
, IPA_NONE
)))
1201 if (!found
) nf
->n
.metric1
= LSINFINITY
; /* Delete it */
1204 if (ipa_equal(nf
->n
.nh
, IPA_NONE
)) a0
.dest
= RTD_DEVICE
;
1206 if (!a0
.iface
) /* Still no match? Can this really happen? */
1207 nf
->n
.metric1
= LSINFINITY
;
1209 ne
= net_get(p
->table
, nf
->fn
.prefix
, nf
->fn
.pxlen
);
1210 if (nf
->n
.metric1
< LSINFINITY
)
1212 e
= rte_get_temp(&a0
);
1213 e
->u
.ospf
.metric1
= nf
->n
.metric1
;
1214 e
->u
.ospf
.metric2
= nf
->n
.metric2
;
1215 e
->u
.ospf
.tag
= nf
->n
.tag
;
1218 e
->pref
= p
->preference
;
1219 DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n",
1220 a0
.source
, nf
->fn
.prefix
, nf
->fn
.pxlen
, a0
.gw
, a0
.iface
? a0
.iface
->name
: "(none)", nf
->n
.metric1
);
1221 rte_update(p
->table
, ne
, p
, p
, e
);
1225 rte_update(p
->table
, ne
, p
, p
, NULL
);
1226 FIB_ITERATE_PUT(&fit
, nftmp
);
1227 fib_delete(fib
, nftmp
);
1232 FIB_ITERATE_END(nftmp
);
1234 WALK_LIST(oa
, po
->area_list
)
1236 FIB_ITERATE_INIT(&fit
, &oa
->rtr
);
1238 FIB_ITERATE_START(&oa
->rtr
, &fit
, nftmp
)
1241 if (memcmp(&nf
->n
, &nf
->o
, sizeof(orta
)))
1242 { /* Some difference */
1243 check_sum_lsa(po
, nf
, ORT_ROUTER
);
1244 if (nf
->n
.metric1
>= LSINFINITY
)
1246 FIB_ITERATE_PUT(&fit
, nftmp
);
1247 fib_delete(&oa
->rtr
, nftmp
);
1252 FIB_ITERATE_END(nftmp
);
1254 /* Check condensed summary LSAs */
1255 FIB_WALK(&oa
->net_fib
, nftmp
)
1258 anet
= (struct area_net
*) nftmp
;
1259 if ((!anet
->hidden
) && anet
->active
)
1262 WALK_LIST(oaa
, po
->area_list
)
1266 if (oaa
== oa
) continue;
1268 if ((oa
== po
->backbone
) && oaa
->trcap
) fl
= 1;
1270 if (oaa
->stub
) fl
= 1;
1272 if (fl
) flush_sum_lsa(oaa
, &anet
->fn
, ORT_NET
);
1273 else originate_sum_lsa(oaa
, &anet
->fn
, ORT_NET
, anet
->metric
, 0);
1278 /* Check default summary LSA for stub areas
1279 * just for router connected to backbone */
1282 struct fib_node fnn
;
1284 fnn
.prefix
= IPA_NONE
;
1286 if (oa
->stub
) originate_sum_lsa(oa
, &fnn
, ORT_NET
, oa
->stub
, 0);
1287 else flush_sum_lsa(oa
, &fnn
, ORT_NET
);