]> git.ipfire.org Git - thirdparty/bird.git/blob - proto/ospf/iface.c
Better packet priority and traffic class handling.
[thirdparty/bird.git] / proto / ospf / iface.c
1 /*
2 * BIRD -- OSPF
3 *
4 * (c) 1999--2005 Ondrej Filip <feela@network.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include "ospf.h"
10
11 char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother",
12 "backup", "dr"
13 };
14
15 char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen",
16 "neighbor change", "loop indicated", "unloop indicated", "interface down"
17 };
18
19 char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
20
21 static void
22 poll_timer_hook(timer * timer)
23 {
24 ospf_hello_send(timer->data, OHS_POLL, NULL);
25 }
26
27 static void
28 hello_timer_hook(timer * timer)
29 {
30 ospf_hello_send(timer->data, OHS_HELLO, NULL);
31 }
32
33 static void
34 wait_timer_hook(timer * timer)
35 {
36 struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
37 struct proto *p = &ifa->oa->po->proto;
38
39 OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name);
40 ospf_iface_sm(ifa, ISM_WAITF);
41 }
42
43 static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
44
45 u32
46 rxbufsize(struct ospf_iface *ifa)
47 {
48 switch(ifa->rxbuf)
49 {
50 case OSPF_RXBUF_NORMAL:
51 return (ifa->iface->mtu * 2);
52 break;
53 case OSPF_RXBUF_LARGE:
54 return OSPF_MAX_PKT_SIZE;
55 break;
56 default:
57 return ifa->rxbuf;
58 break;
59 }
60 }
61
62 struct nbma_node *
63 find_nbma_node_in(list *nnl, ip_addr ip)
64 {
65 struct nbma_node *nn;
66 WALK_LIST(nn, *nnl)
67 if (ipa_equal(nn->ip, ip))
68 return nn;
69 return NULL;
70 }
71
72 static int
73 ospf_sk_open(struct ospf_iface *ifa)
74 {
75 sock *sk = sk_new(ifa->pool);
76 sk->type = SK_IP;
77 sk->dport = OSPF_PROTO;
78 sk->saddr = IPA_NONE;
79
80 sk->tos = ifa->cf->tx_tos;
81 sk->priority = ifa->cf->tx_priority;
82 sk->rx_hook = ospf_rx_hook;
83 sk->tx_hook = ospf_tx_hook;
84 sk->err_hook = ospf_err_hook;
85 sk->iface = ifa->iface;
86 sk->rbsize = rxbufsize(ifa);
87 sk->tbsize = rxbufsize(ifa);
88 sk->data = (void *) ifa;
89 sk->flags = SKF_LADDR_RX;
90
91 if (sk_open(sk) != 0)
92 goto err;
93
94 #ifdef OSPFv3
95 /* 12 is an offset of the checksum in an OSPF packet */
96 if (sk_set_ipv6_checksum(sk, 12) < 0)
97 goto err;
98 #endif
99
100 /*
101 * For OSPFv2: When sending a packet, it is important to have a
102 * proper source address. We expect that when we send one-hop
103 * unicast packets, OS chooses a source address according to the
104 * destination address (to be in the same prefix). We also expect
105 * that when we send multicast packets, OS uses the source address
106 * from sk->saddr registered to OS by sk_setup_multicast(). This
107 * behavior is needed to implement multiple virtual ifaces (struct
108 * ospf_iface) on one physical iface and is signalized by
109 * CONFIG_MC_PROPER_SRC.
110 *
111 * If this behavior is not available (for example on BSD), we create
112 * non-stub iface just for the primary IP address (see
113 * ospf_iface_stubby()) and we expect OS to use primary IP address
114 * as a source address for both unicast and multicast packets.
115 *
116 * FIXME: the primary IP address is currently just the
117 * lexicographically smallest address on an interface, it should be
118 * signalized by sysdep code which one is really the primary.
119 */
120
121 sk->saddr = ifa->addr->ip;
122 if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
123 {
124 if (ifa->cf->real_bcast)
125 {
126 ifa->all_routers = ifa->addr->brd;
127
128 if (sk_set_broadcast(sk, 1) < 0)
129 goto err;
130 }
131 else
132 {
133 ifa->all_routers = AllSPFRouters;
134 sk->ttl = 1; /* Hack, this will affect just multicast packets */
135
136 if (sk_setup_multicast(sk) < 0)
137 goto err;
138
139 if (sk_join_group(sk, ifa->all_routers) < 0)
140 goto err;
141 }
142 }
143
144 ifa->sk = sk;
145 ifa->sk_dr = 0;
146 return 1;
147
148 err:
149 rfree(sk);
150 return 0;
151 }
152
153 static inline void
154 ospf_sk_join_dr(struct ospf_iface *ifa)
155 {
156 if (ifa->sk_dr)
157 return;
158
159 sk_join_group(ifa->sk, AllDRouters);
160 ifa->sk_dr = 1;
161 }
162
163 static inline void
164 ospf_sk_leave_dr(struct ospf_iface *ifa)
165 {
166 if (!ifa->sk_dr)
167 return;
168
169 sk_leave_group(ifa->sk, AllDRouters);
170 ifa->sk_dr = 0;
171 }
172
173 static void
174 ospf_iface_down(struct ospf_iface *ifa)
175 {
176 struct ospf_neighbor *n, *nx;
177 struct proto_ospf *po = ifa->oa->po;
178 struct proto *p = &po->proto;
179 struct ospf_iface *iff;
180
181 if (ifa->type != OSPF_IT_VLINK)
182 {
183 #ifdef OSPFv2
184 OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
185 ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
186 #else
187 OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
188 ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
189 #endif
190
191 /* First of all kill all the related vlinks */
192 WALK_LIST(iff, po->iface_list)
193 {
194 if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
195 ospf_iface_sm(iff, ISM_DOWN);
196 }
197 }
198
199 WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
200 {
201 OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
202 ospf_neigh_remove(n);
203 }
204
205 if (ifa->hello_timer)
206 tm_stop(ifa->hello_timer);
207
208 if (ifa->poll_timer)
209 tm_stop(ifa->poll_timer);
210
211 if (ifa->wait_timer)
212 tm_stop(ifa->wait_timer);
213
214 if (ifa->type == OSPF_IT_VLINK)
215 {
216 ifa->vifa = NULL;
217 ifa->iface = NULL;
218 ifa->addr = NULL;
219 ifa->sk = NULL;
220 ifa->cost = 0;
221 ifa->vip = IPA_NONE;
222 }
223
224 ifa->rt_pos_beg = 0;
225 ifa->rt_pos_end = 0;
226 #ifdef OSPFv3
227 ifa->px_pos_beg = 0;
228 ifa->px_pos_end = 0;
229 #endif
230 }
231
232
233 void
234 ospf_iface_remove(struct ospf_iface *ifa)
235 {
236 struct proto *p = &ifa->oa->po->proto;
237 if (ifa->type == OSPF_IT_VLINK)
238 OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
239
240 ospf_iface_sm(ifa, ISM_DOWN);
241 rem_node(NODE ifa);
242 rfree(ifa->pool);
243 }
244
245 void
246 ospf_iface_shutdown(struct ospf_iface *ifa)
247 {
248 if (ifa->state > OSPF_IS_DOWN)
249 ospf_hello_send(ifa, OHS_SHUTDOWN, NULL);
250 }
251
252 /**
253 * ospf_iface_chstate - handle changes of interface state
254 * @ifa: OSPF interface
255 * @state: new state
256 *
257 * Many actions must be taken according to interface state changes. New network
258 * LSAs must be originated, flushed, new multicast sockets to listen for messages for
259 * %ALLDROUTERS have to be opened, etc.
260 */
261 void
262 ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
263 {
264 struct proto_ospf *po = ifa->oa->po;
265 struct proto *p = &po->proto;
266 u8 oldstate = ifa->state;
267
268 if (oldstate == state)
269 return;
270
271 ifa->state = state;
272
273 if (ifa->type == OSPF_IT_VLINK)
274 OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
275 ifa->vid, ospf_is[oldstate], ospf_is[state]);
276 else
277 OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
278 ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
279
280 if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
281 {
282 if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
283 ospf_sk_join_dr(ifa);
284 else
285 ospf_sk_leave_dr(ifa);
286 }
287
288 if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
289 {
290 ifa->net_lsa->lsa.age = LSA_MAXAGE;
291 if (state >= OSPF_IS_WAITING)
292 ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
293
294 if (can_flush_lsa(po))
295 flush_lsa(ifa->net_lsa, po);
296 ifa->net_lsa = NULL;
297 }
298
299 if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
300 ospf_iface_down(ifa);
301
302 schedule_rt_lsa(ifa->oa);
303 // FIXME flushling of link LSA
304 }
305
306 /**
307 * ospf_iface_sm - OSPF interface state machine
308 * @ifa: OSPF interface
309 * @event: event comming to state machine
310 *
311 * This fully respects 9.3 of RFC 2328 except we have slightly
312 * different handling of %DOWN and %LOOP state. We remove intefaces
313 * that are %DOWN. %DOWN state is used when an interface is waiting
314 * for a lock. %LOOP state is used when an interface does not have a
315 * link.
316 */
317 void
318 ospf_iface_sm(struct ospf_iface *ifa, int event)
319 {
320 DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface",
321 ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
322
323 switch (event)
324 {
325 case ISM_UP:
326 if (ifa->state <= OSPF_IS_LOOP)
327 {
328 /* Now, nothing should be adjacent */
329 if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP) || (ifa->type == OSPF_IT_VLINK))
330 {
331 ospf_iface_chstate(ifa, OSPF_IS_PTP);
332 }
333 else
334 {
335 if (ifa->priority == 0)
336 ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
337 else
338 {
339 ospf_iface_chstate(ifa, OSPF_IS_WAITING);
340 if (ifa->wait_timer)
341 tm_start(ifa->wait_timer, ifa->waitint);
342 }
343 }
344
345 if (ifa->hello_timer)
346 tm_start(ifa->hello_timer, ifa->helloint);
347
348 if (ifa->poll_timer)
349 tm_start(ifa->poll_timer, ifa->pollint);
350
351 ospf_hello_send(ifa, OHS_HELLO, NULL);
352 schedule_link_lsa(ifa);
353 }
354 break;
355
356 case ISM_BACKS:
357 case ISM_WAITF:
358 if (ifa->state == OSPF_IS_WAITING)
359 {
360 bdr_election(ifa);
361 }
362 break;
363
364 case ISM_NEICH:
365 if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
366 (ifa->state == OSPF_IS_BACKUP))
367 {
368 bdr_election(ifa);
369 schedule_rt_lsa(ifa->oa);
370 }
371 break;
372
373 case ISM_LOOP:
374 if ((ifa->state > OSPF_IS_LOOP) && ifa->check_link)
375 ospf_iface_chstate(ifa, OSPF_IS_LOOP);
376 break;
377
378 case ISM_UNLOOP:
379 /* Immediate go UP */
380 if (ifa->state == OSPF_IS_LOOP)
381 ospf_iface_sm(ifa, ISM_UP);
382 break;
383
384 case ISM_DOWN:
385 ospf_iface_chstate(ifa, OSPF_IS_DOWN);
386 break;
387
388 default:
389 bug("OSPF_I_SM - Unknown event?");
390 break;
391 }
392
393 }
394
395 static u8
396 ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
397 {
398 if (ipa_nonzero(addr->opposite))
399 return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
400
401 if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) ==
402 (IF_MULTIACCESS | IF_MULTICAST))
403 return OSPF_IT_BCAST;
404
405 if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) == IF_MULTIACCESS)
406 return OSPF_IT_NBMA;
407
408 return OSPF_IT_PTP;
409 }
410
411 static inline u8
412 ospf_iface_classify(u8 type, struct ifa *addr)
413 {
414 return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
415 }
416
417
418 struct ospf_iface *
419 ospf_iface_find(struct proto_ospf *p, struct iface *what)
420 {
421 struct ospf_iface *i;
422
423 WALK_LIST(i, p->iface_list) if ((i->iface == what) && (i->type != OSPF_IT_VLINK))
424 return i;
425 return NULL;
426 }
427
428 static void
429 ospf_iface_add(struct object_lock *lock)
430 {
431 struct ospf_iface *ifa = lock->data;
432 struct proto_ospf *po = ifa->oa->po;
433 struct proto *p = &po->proto;
434
435 /* Open socket if interface is not stub */
436 if (! ifa->stub && ! ospf_sk_open(ifa))
437 {
438 log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->iface->name);
439 ifa->ioprob = OSPF_I_SK;
440 ifa->stub = 1;
441 }
442
443 if (! ifa->stub)
444 {
445 ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
446
447 if (ifa->type == OSPF_IT_NBMA)
448 ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);
449
450 if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
451 ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
452 }
453
454 /* Do iface UP, unless there is no link and we use link detection */
455 ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
456 }
457
458 static inline void
459 add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
460 {
461 struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
462 add_tail(&ifa->nbma_list, NODE n);
463 n->ip = src->ip;
464 n->eligible = src->eligible;
465 n->found = found;
466 }
467
468 static int
469 ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
470 {
471 if (! addr)
472 return 0;
473
474 /* a host/loopback address */
475 if (addr->flags & IA_HOST)
476 return 1;
477
478 /*
479 * We cannot properly support multiple OSPF ifaces on real iface
480 * with multiple prefixes, therefore we force OSPF ifaces with
481 * non-primary IP prefixes to be stub.
482 */
483 #if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
484 if (! (addr->flags & IA_PRIMARY))
485 return 1;
486 #endif
487
488 return ip->stub;
489 }
490
491 void
492 ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
493 {
494 struct proto *p = &oa->po->proto;
495 struct iface *iface = addr ? addr->iface : NULL;
496 struct pool *pool;
497
498 struct ospf_iface *ifa;
499 struct nbma_node *nb;
500 struct object_lock *lock;
501
502 if (ip->type == OSPF_IT_VLINK)
503 OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
504 else
505 {
506 #ifdef OSPFv2
507 OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
508 iface->name, addr->prefix, addr->pxlen, oa->areaid);
509 #else
510 OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
511 iface->name, ip->instance_id, oa->areaid);
512 #endif
513 }
514
515 pool = rp_new(p->pool, "OSPF Interface");
516 ifa = mb_allocz(pool, sizeof(struct ospf_iface));
517 ifa->iface = iface;
518 ifa->addr = addr;
519 ifa->oa = oa;
520 ifa->cf = ip;
521 ifa->pool = pool;
522
523 ifa->cost = ip->cost;
524 ifa->rxmtint = ip->rxmtint;
525 ifa->inftransdelay = ip->inftransdelay;
526 ifa->priority = ip->priority;
527 ifa->helloint = ip->helloint;
528 ifa->pollint = ip->pollint;
529 ifa->strictnbma = ip->strictnbma;
530 ifa->waitint = ip->waitint;
531 ifa->deadint = ip->deadint;
532 ifa->stub = ospf_iface_stubby(ip, addr);
533 ifa->ioprob = OSPF_I_OK;
534 ifa->rxbuf = ip->rxbuf;
535 ifa->check_link = ip->check_link;
536 ifa->ecmp_weight = ip->ecmp_weight;
537
538 #ifdef OSPFv2
539 ifa->autype = ip->autype;
540 ifa->passwords = ip->passwords;
541 ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
542 if (ip->ptp_netmask < 2)
543 ifa->ptp_netmask = ip->ptp_netmask;
544 #endif
545
546 #ifdef OSPFv3
547 ifa->instance_id = ip->instance_id;
548 #endif
549
550 ifa->type = ospf_iface_classify(ip->type, addr);
551
552 /* Check validity of interface type */
553 int old_type = ifa->type;
554 u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
555
556 #ifdef OSPFv2
557 if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
558 ifa->type = OSPF_IT_PTP;
559
560 if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
561 ifa->type = OSPF_IT_PTMP;
562 #endif
563
564 if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
565 ifa->type = OSPF_IT_NBMA;
566
567 if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag))
568 ifa->type = OSPF_IT_PTMP;
569
570 if (ifa->type != old_type)
571 log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
572 p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
573
574 /* Assign iface ID, for vlinks, this is ugly hack */
575 ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++;
576
577 init_list(&ifa->neigh_list);
578 init_list(&ifa->nbma_list);
579
580 WALK_LIST(nb, ip->nbma_list)
581 {
582 /* In OSPFv3, addr is link-local while configured neighbors could
583 have global IP (although RFC 5340 C.5 says link-local addresses
584 should be used). Because OSPFv3 iface is not subnet-specific,
585 there is no need for ipa_in_net() check */
586
587 #ifdef OSPFv2
588 if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
589 continue;
590 #else
591 if (!ipa_has_link_scope(nb->ip))
592 log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
593 #endif
594
595 add_nbma_node(ifa, nb, 0);
596 }
597
598 ifa->state = OSPF_IS_DOWN;
599 add_tail(&oa->po->iface_list, NODE ifa);
600
601 if (ifa->type == OSPF_IT_VLINK)
602 {
603 ifa->voa = ospf_find_area(oa->po, ip->voa);
604 ifa->vid = ip->vid;
605
606 ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
607
608 return; /* Don't lock, don't add sockets */
609 }
610
611 /*
612 * In some cases we allow more ospf_ifaces on one physical iface.
613 * In OSPFv2, if they use different IP address prefix.
614 * In OSPFv3, if they use different instance_id.
615 * Therefore, we store such info to lock->addr field.
616 */
617
618 lock = olock_new(pool);
619 #ifdef OSPFv2
620 lock->addr = ifa->addr->prefix;
621 #else /* OSPFv3 */
622 lock->addr = _MI(0,0,0,ifa->instance_id);
623 #endif
624 lock->type = OBJLOCK_IP;
625 lock->port = OSPF_PROTO;
626 lock->iface = iface;
627 lock->data = ifa;
628 lock->hook = ospf_iface_add;
629
630 olock_acquire(lock);
631 }
632
633 static void
634 ospf_iface_change_timer(timer *tm, unsigned val)
635 {
636 if (!tm)
637 return;
638
639 tm->recurrent = val;
640
641 if (tm->expires)
642 tm_start(tm, val);
643 }
644
645 int
646 ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
647 {
648 struct proto *p = &ifa->oa->po->proto;
649 struct nbma_node *nb, *nbx;
650 char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
651
652 /* Type could be changed in ospf_iface_new(),
653 but if config values are same then also results are same */
654 int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
655 int new_type = ospf_iface_classify(new->type, ifa->addr);
656 if (old_type != new_type)
657 return 0;
658
659 int new_stub = ospf_iface_stubby(new, ifa->addr);
660 if (ifa->stub != new_stub)
661 return 0;
662
663 /* Change of these options would require to reset the iface socket */
664 if ((new->real_bcast != ifa->cf->real_bcast) ||
665 (new->tx_tos != ifa->cf->tx_tos) ||
666 (new->tx_priority != ifa->cf->tx_priority))
667 return 0;
668
669 ifa->cf = new;
670 ifa->marked = 0;
671
672
673 /* HELLO TIMER */
674 if (ifa->helloint != new->helloint)
675 {
676 OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d",
677 ifname, ifa->helloint, new->helloint);
678
679 ifa->helloint = new->helloint;
680 ospf_iface_change_timer(ifa->hello_timer, ifa->helloint);
681 }
682
683 /* RXMT TIMER */
684 if (ifa->rxmtint != new->rxmtint)
685 {
686 OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d",
687 ifname, ifa->rxmtint, new->rxmtint);
688
689 ifa->rxmtint = new->rxmtint;
690 }
691
692 /* POLL TIMER */
693 if (ifa->pollint != new->pollint)
694 {
695 OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d",
696 ifname, ifa->pollint, new->pollint);
697
698 ifa->pollint = new->pollint;
699 ospf_iface_change_timer(ifa->poll_timer, ifa->pollint);
700 }
701
702 /* WAIT TIMER */
703 if (ifa->waitint != new->waitint)
704 {
705 OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d",
706 ifname, ifa->waitint, new->waitint);
707
708 ifa->waitint = new->waitint;
709 if (ifa->wait_timer && ifa->wait_timer->expires)
710 tm_start(ifa->wait_timer, ifa->waitint);
711 }
712
713 /* DEAD TIMER */
714 if (ifa->deadint != new->deadint)
715 {
716 OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d",
717 ifname, ifa->deadint, new->deadint);
718 ifa->deadint = new->deadint;
719 }
720
721 /* INFTRANS */
722 if (ifa->inftransdelay != new->inftransdelay)
723 {
724 OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
725 ifname, ifa->inftransdelay, new->inftransdelay);
726 ifa->inftransdelay = new->inftransdelay;
727 }
728
729 #ifdef OSPFv2
730 /* AUTHENTICATION */
731 if (ifa->autype != new->autype)
732 {
733 OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
734 ifa->autype = new->autype;
735 }
736
737 /* Update passwords */
738 ifa->passwords = new->passwords;
739 #endif
740
741 /* Remaining options are just for proper interfaces */
742 if (ifa->type == OSPF_IT_VLINK)
743 return 1;
744
745
746 /* COST */
747 if (ifa->cost != new->cost)
748 {
749 OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d",
750 ifname, ifa->cost, new->cost);
751
752 ifa->cost = new->cost;
753 }
754
755 /* PRIORITY */
756 if (ifa->priority != new->priority)
757 {
758 OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
759 ifname, ifa->priority, new->priority);
760 ifa->priority = new->priority;
761 }
762
763 /* STRICT NBMA */
764 if (ifa->strictnbma != new->strictnbma)
765 {
766 OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname);
767 ifa->strictnbma = new->strictnbma;
768 }
769
770 /* NBMA LIST - remove or update old */
771 WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
772 {
773 struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
774 if (nb2)
775 {
776 if (nb->eligible != nb2->eligible)
777 {
778 OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
779 nb->ip, ifname);
780 nb->eligible = nb2->eligible;
781 }
782 }
783 else
784 {
785 OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
786 nb->ip, ifname);
787 rem_node(NODE nb);
788 mb_free(nb);
789 }
790 }
791
792 /* NBMA LIST - add new */
793 WALK_LIST(nb, new->nbma_list)
794 {
795 /* See related note in ospf_iface_new() */
796 #ifdef OSPFv2
797 if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
798 continue;
799 #else
800 if (!ipa_has_link_scope(nb->ip))
801 log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
802 #endif
803
804 if (! find_nbma_node(ifa, nb->ip))
805 {
806 OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
807 nb->ip, ifname);
808 add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
809 }
810 }
811
812 /* RX BUFF */
813 if (ifa->rxbuf != new->rxbuf)
814 {
815 OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d",
816 ifname, ifa->rxbuf, new->rxbuf);
817 ifa->rxbuf = new->rxbuf;
818 ospf_iface_change_mtu(ifa->oa->po, ifa);
819 }
820
821 /* LINK */
822 if (ifa->check_link != new->check_link)
823 {
824 OSPF_TRACE(D_EVENTS, "%s link check on interface %s",
825 new->check_link ? "Enabling" : "Disabling", ifname);
826 ifa->check_link = new->check_link;
827
828 if (!(ifa->iface->flags & IF_LINK_UP))
829 ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
830 }
831
832 /* ECMP weight */
833 if (ifa->ecmp_weight != new->ecmp_weight)
834 {
835 OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
836 ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
837 ifa->ecmp_weight = new->ecmp_weight;
838 }
839
840 /* instance_id is not updated - it is part of key */
841
842 return 1;
843 }
844
845
846 #ifdef OSPFv2
847
848 static inline struct ospf_iface_patt *
849 ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
850 {
851 return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
852 }
853
854 void
855 ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
856 {
857 struct proto_ospf *po = (struct proto_ospf *) p;
858
859 if (a->flags & IA_SECONDARY)
860 return;
861
862 if (a->scope <= SCOPE_LINK)
863 return;
864
865 /* In OSPFv2, we create OSPF iface for each address. */
866 if (flags & IF_CHANGE_UP)
867 {
868 int done = 0;
869 struct ospf_area *oa;
870 WALK_LIST(oa, po->area_list)
871 {
872 struct ospf_iface_patt *ip;
873 if (ip = ospf_iface_patt_find(oa->ac, a))
874 {
875 if (!done)
876 ospf_iface_new(oa, a, ip);
877 done++;
878 }
879 }
880
881 if (done > 1)
882 log(L_WARN "%s: Interface %s (IP %I) matches for multiple areas", p->name, a->iface->name, a->ip);
883 }
884
885 if (flags & IF_CHANGE_DOWN)
886 {
887 struct ospf_iface *ifa, *ifx;
888 WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
889 {
890 if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
891 ospf_iface_remove(ifa);
892 /* See a note in ospf_iface_notify() */
893 }
894 }
895 }
896
897 static struct ospf_iface *
898 ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
899 {
900 struct ospf_iface *ifa;
901 WALK_LIST(ifa, oa->po->iface_list)
902 if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
903 return ifa;
904
905 return NULL;
906 }
907
908 void
909 ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
910 {
911 struct ospf_iface_patt *ip;
912 struct iface *iface;
913 struct ifa *a;
914
915 WALK_LIST(iface, iface_list)
916 {
917 if (! (iface->flags & IF_UP))
918 continue;
919
920 WALK_LIST(a, iface->addrs)
921 {
922 if (a->flags & IA_SECONDARY)
923 continue;
924
925 if (a->scope <= SCOPE_LINK)
926 continue;
927
928 if (ip = ospf_iface_patt_find(oa->ac, a))
929 {
930 /* Main inner loop */
931 struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
932 if (ifa)
933 {
934 if (ospf_iface_reconfigure(ifa, ip))
935 continue;
936
937 /* Hard restart */
938 ospf_iface_shutdown(ifa);
939 ospf_iface_remove(ifa);
940 }
941
942 ospf_iface_new(oa, a, ip);
943 }
944 }
945 }
946 }
947
948
949 #else /* OSPFv3 */
950
951 struct ospf_iface_patt *
952 ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
953 {
954 struct ospf_iface_patt *pt, *res = NULL;
955
956 WALK_LIST(pt, ac->patt_list)
957 if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
958 (!res || (pt->instance_id < res->instance_id)))
959 res = pt;
960
961 return res;
962 }
963
964 void
965 ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
966 {
967 struct proto_ospf *po = (struct proto_ospf *) p;
968
969 if (a->flags & IA_SECONDARY)
970 return;
971
972 if (a->scope < SCOPE_LINK)
973 return;
974
975 /* In OSPFv3, we create OSPF iface for link-local address,
976 other addresses are used for link-LSA. */
977 if (a->scope == SCOPE_LINK)
978 {
979 if (flags & IF_CHANGE_UP)
980 {
981 int done0 = 0;
982 struct ospf_area *oa;
983
984 WALK_LIST(oa, po->area_list)
985 {
986 int iid = 0;
987
988 struct ospf_iface_patt *ip;
989 while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
990 {
991 ospf_iface_new(oa, a, ip);
992 if (ip->instance_id == 0)
993 done0++;
994 iid = ip->instance_id + 1;
995 }
996 }
997
998 if (done0 > 1)
999 log(L_WARN "%s: Interface %s matches for multiple areas",
1000 p->name, a->iface->name);
1001 }
1002
1003 if (flags & IF_CHANGE_DOWN)
1004 {
1005 struct ospf_iface *ifa, *ifx;
1006 WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
1007 {
1008 if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
1009 ospf_iface_remove(ifa);
1010 /* See a note in ospf_iface_notify() */
1011 }
1012 }
1013 }
1014 else
1015 {
1016 struct ospf_iface *ifa;
1017 WALK_LIST(ifa, po->iface_list)
1018 {
1019 if (ifa->iface == a->iface)
1020 {
1021 schedule_rt_lsa(ifa->oa);
1022 /* Event 5 from RFC5340 4.4.3. */
1023 schedule_link_lsa(ifa);
1024 return;
1025 }
1026 }
1027 }
1028 }
1029
1030 static struct ospf_iface *
1031 ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
1032 {
1033 struct ospf_iface *ifa;
1034 WALK_LIST(ifa, oa->po->iface_list)
1035 if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
1036 return ifa;
1037
1038 return NULL;
1039 }
1040
1041 void
1042 ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
1043 {
1044 struct ospf_iface_patt *ip;
1045 struct iface *iface;
1046 struct ifa *a;
1047
1048 WALK_LIST(iface, iface_list)
1049 {
1050 if (! (iface->flags & IF_UP))
1051 continue;
1052
1053 WALK_LIST(a, iface->addrs)
1054 {
1055 if (a->flags & IA_SECONDARY)
1056 continue;
1057
1058 if (a->scope != SCOPE_LINK)
1059 continue;
1060
1061 int iid = 0;
1062 while (ip = ospf_iface_patt_find(nac, iface, iid))
1063 {
1064 iid = ip->instance_id + 1;
1065
1066 /* Main inner loop */
1067 struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
1068 if (ifa)
1069 {
1070 if (ospf_iface_reconfigure(ifa, ip))
1071 continue;
1072
1073 /* Hard restart */
1074 ospf_iface_shutdown(ifa);
1075 ospf_iface_remove(ifa);
1076 }
1077
1078 ospf_iface_new(oa, a, ip);
1079 }
1080 }
1081 }
1082 }
1083
1084 #endif
1085
1086 static void
1087 ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
1088 {
1089 struct proto *p = &po->proto;
1090 struct ospf_packet *op;
1091 struct ospf_neighbor *n;
1092 OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
1093
1094 if (ifa->sk)
1095 {
1096 ifa->sk->rbsize = rxbufsize(ifa);
1097 ifa->sk->tbsize = rxbufsize(ifa);
1098 sk_reallocate(ifa->sk);
1099 }
1100
1101 WALK_LIST(n, ifa->neigh_list)
1102 {
1103 op = (struct ospf_packet *) n->ldbdes;
1104 n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu);
1105
1106 if (ntohs(op->length) <= ifa->iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */
1107 memcpy(n->ldbdes, op, ifa->iface->mtu); /* If the packet is old is same or smaller, copy it */
1108
1109 mb_free(op);
1110 }
1111 }
1112
1113 static void
1114 ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
1115 {
1116 if (flags & IF_CHANGE_DOWN)
1117 {
1118 ospf_iface_remove(ifa);
1119 return;
1120 }
1121
1122 if (flags & IF_CHANGE_LINK)
1123 ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP);
1124
1125 if (flags & IF_CHANGE_MTU)
1126 ospf_iface_change_mtu(po, ifa);
1127 }
1128
1129 void
1130 ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
1131 {
1132 struct proto_ospf *po = (struct proto_ospf *) p;
1133
1134 /*
1135 if (iface->flags & IF_IGNORE)
1136 return;
1137 */
1138
1139 /* Going up means that there are no such ifaces yet */
1140 if (flags & IF_CHANGE_UP)
1141 return;
1142
1143 struct ospf_iface *ifa, *ifx;
1144 WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
1145 if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
1146 ospf_iface_notify(po, flags, ifa);
1147
1148 /* We use here that even shutting down iface also shuts down
1149 the vlinks, but vlinks are not freed and stays in the
1150 iface_list even when down */
1151 }
1152
1153 void
1154 ospf_iface_info(struct ospf_iface *ifa)
1155 {
1156 char *more = "";
1157
1158 if (ifa->strictnbma &&
1159 ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)))
1160 more = " (strict)";
1161
1162 if (ifa->cf->real_bcast &&
1163 ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)))
1164 more = " (real)";
1165
1166 if (ifa->type == OSPF_IT_VLINK)
1167 {
1168 cli_msg(-1015, "Virtual link to %R:", ifa->vid);
1169 cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
1170 cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid,
1171 ifa->voa->areaid);
1172 cli_msg(-1015, "\tInterface: \"%s\"",
1173 (ifa->iface ? ifa->iface->name : "(none)"));
1174 }
1175 else
1176 {
1177 #ifdef OSPFv2
1178 if (ifa->addr->flags & IA_PEER)
1179 cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
1180 else
1181 cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
1182 #else /* OSPFv3 */
1183 cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
1184 #endif
1185 cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
1186 cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
1187 }
1188 cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : "");
1189 cli_msg(-1015, "\tPriority: %u", ifa->priority);
1190 cli_msg(-1015, "\tCost: %u", ifa->cost);
1191 if (ifa->oa->po->ecmp)
1192 cli_msg(-1015, "\tECMP weight: %d", ((int) ifa->ecmp_weight) + 1);
1193 cli_msg(-1015, "\tHello timer: %u", ifa->helloint);
1194
1195 if (ifa->type == OSPF_IT_NBMA)
1196 {
1197 cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
1198 }
1199 cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
1200 cli_msg(-1015, "\tDead timer: %u", ifa->deadint);
1201 cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
1202 if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
1203 {
1204 cli_msg(-1015, "\tDesigned router (ID): %R", ifa->drid);
1205 cli_msg(-1015, "\tDesigned router (IP): %I", ifa->drip);
1206 cli_msg(-1015, "\tBackup designed router (ID): %R", ifa->bdrid);
1207 cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip);
1208 }
1209 }
1210