iface.c 33.7 KB
Newer Older
1 2 3
/*
 *	BIRD -- OSPF
 *
4
 *	(c) 1999--2005 Ondrej Filip <feela@network.cz>
5 6
 *	(c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2009--2014 CZ.NIC z.s.p.o.
7 8 9 10 11
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"
12
#include "nest/password.h"
13

14

15 16
const char *ospf_is_names[] = {
  "Down", "Loopback", "Waiting", "PtP", "DROther", "Backup", "DR"
Ondřej Filip's avatar
Ondřej Filip committed
17
};
Ondřej Filip's avatar
Ondřej Filip committed
18

19 20 21
const char *ospf_ism_names[] = {
  "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange",
  "LoopInd", "UnloopInd", "InterfaceDown"
Ondřej Filip's avatar
Ondřej Filip committed
22
};
Ondřej Filip's avatar
Ondřej Filip committed
23

24
const char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
25

26

27
static void
Ondřej Filip's avatar
Ondřej Filip committed
28
poll_timer_hook(timer * timer)
29
{
30
  ospf_send_hello(timer->data, OHS_POLL, NULL);
31 32
}

33
static void
Ondřej Filip's avatar
Ondřej Filip committed
34
hello_timer_hook(timer * timer)
35
{
36
  ospf_send_hello(timer->data, OHS_HELLO, NULL);
37 38
}

39
static void
Ondřej Filip's avatar
Ondřej Filip committed
40
wait_timer_hook(timer * timer)
41
{
Ondřej Filip's avatar
Ondřej Filip committed
42
  struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
43
  struct ospf_proto *p = ifa->oa->po;
44

45
  OSPF_TRACE(D_EVENTS, "Wait timer fired on %s", ifa->ifname);
Ondřej Filip's avatar
Ondřej Filip committed
46
  ospf_iface_sm(ifa, ISM_WAITF);
47 48
}

49 50 51
static inline uint
ifa_tx_length(struct ospf_iface *ifa)
{
52
  return ifa->cf->tx_length ?: ifa->iface->mtu;
53
}
54

55 56 57
static inline uint
ifa_tx_hdrlen(struct ospf_iface *ifa)
{
58 59 60
  struct ospf_proto *p = ifa->oa->po;

  uint hlen = ospf_is_v2(p) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH;
61 62 63 64 65 66 67 68

  /* Relevant just for OSPFv2 */
  if (ifa->autype == OSPF_AUTH_CRYPT)
    hlen += max_mac_length(ifa->passwords);

  return hlen;
}

69 70
static inline uint
ifa_bufsize(struct ospf_iface *ifa)
71
{
72 73
  uint bsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
  return MAX(bsize, ifa->tx_length);
74 75
}

76 77 78 79 80 81
static inline uint
ifa_flood_queue_size(struct ospf_iface *ifa)
{
  return ifa->tx_length / 24;
}

82 83 84
int
ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
{
85
  plen += ifa->tx_hdrlen;
86 87 88 89 90 91 92 93 94 95 96 97 98 99

  if (plen <= ifa->sk->tbsize)
    return 0;

  if (ifa->cf->rx_buffer || (plen > 0xffff))
    return -1;

  plen = BIRD_ALIGN(plen, 1024);
  plen = MIN(plen, 0xffff);
  sk_set_tbsize(ifa->sk, plen);
  return 1;
}


100
struct nbma_node *
101
find_nbma_node_(list *nnl, ip_addr ip)
102 103
{
  struct nbma_node *nn;
104

105 106 107
  WALK_LIST(nn, *nnl)
    if (ipa_equal(nn->ip, ip))
      return nn;
108

109 110 111
  return NULL;
}

112

113
static int
114
ospf_sk_open(struct ospf_iface *ifa)
115
{
116
  struct ospf_proto *p = ifa->oa->po;
117

118
  sock *sk = sk_new(ifa->pool);
119
  sk->type = SK_IP;
120
  sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
121
  sk->dport = OSPF_PROTO;
122 123
  sk->saddr = ifa->addr->ip;
  sk->iface = ifa->iface;
124

125 126
  sk->tos = ifa->cf->tx_tos;
  sk->priority = ifa->cf->tx_priority;
127
  sk->rx_hook = ospf_rx_hook;
128
  // sk->tx_hook = ospf_tx_hook;
129
  sk->err_hook = ospf_err_hook;
130
  sk->rbsize = sk->tbsize = ifa_bufsize(ifa);
131
  sk->data = (void *) ifa;
132
  sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
133
  sk->ttl = ifa->cf->ttl_security ? 255 : 1;
134

135
  if (sk_open(sk) < 0)
136 137
    goto err;

138 139 140 141
  /* 12 is an offset of the checksum in an OSPFv3 packet */
  if (ospf_is_v3(p))
    if (sk_set_ipv6_checksum(sk, 12) < 0)
      goto err;
142

143
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
144
  {
145 146 147
    if (ifa->cf->real_bcast)
    {
      ifa->all_routers = ifa->addr->brd;
148
      ifa->des_routers = IPA_NONE;
149

150
      if (sk_setup_broadcast(sk) < 0)
151
	goto err;
152 153 154
    }
    else
    {
155 156
      ifa->all_routers = ospf_is_v2(p) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
      ifa->des_routers = ospf_is_v2(p) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
157

158
      if (sk_setup_multicast(sk) < 0)
159
	goto err;
160

161
      if (sk_join_group(sk, ifa->all_routers) < 0)
162
	goto err;
163
    }
164
  }
165

166 167 168
  ifa->sk = sk;
  ifa->sk_dr = 0;
  return 1;
169 170

 err:
171
  sk_log_error(sk, p->p.name);
172 173 174 175 176 177 178 179 180 181
  rfree(sk);
  return 0;
}

static inline void
ospf_sk_join_dr(struct ospf_iface *ifa)
{
  if (ifa->sk_dr)
    return;

182 183
  if (sk_join_group(ifa->sk, ifa->des_routers) < 0)
    sk_log_error(ifa->sk, ifa->oa->po->p.name);
184

185 186
  ifa->sk_dr = 1;
}
187

188 189 190 191 192 193
static inline void
ospf_sk_leave_dr(struct ospf_iface *ifa)
{
  if (!ifa->sk_dr)
    return;

194 195
  if (sk_leave_group(ifa->sk, ifa->des_routers) < 0)
    sk_log_error(ifa->sk, ifa->oa->po->p.name);
196

197 198 199
  ifa->sk_dr = 0;
}

200
void
201
ospf_open_vlink_sk(struct ospf_proto *p)
202
{
203
  sock *sk = sk_new(p->p.pool);
204
  sk->type = SK_IP;
205
  sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
206 207 208 209 210 211 212 213
  sk->dport = OSPF_PROTO;

  /* FIXME: configurable tos/priority ? */
  sk->tos = IP_PREC_INTERNET_CONTROL;
  sk->priority = sk_priority_control;
  sk->err_hook = ospf_verr_hook;

  sk->rbsize = 0;
214 215
  sk->tbsize = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
  sk->data = (void *) p;
216 217 218 219 220
  sk->flags = 0;

  if (sk_open(sk) < 0)
    goto err;

221 222 223 224
  /* 12 is an offset of the checksum in an OSPFv3 packet */
  if (ospf_is_v3(p))
    if (sk_set_ipv6_checksum(sk, 12) < 0)
      goto err;
225

226
  p->vlink_sk = sk;
227 228 229
  return;

 err:
230 231
  sk_log_error(sk, p->p.name);
  log(L_ERR "%s: Cannot open virtual link socket", p->p.name);
232 233 234
  rfree(sk);
}

Ondřej Filip's avatar
Ondřej Filip committed
235 236
static void
ospf_iface_down(struct ospf_iface *ifa)
237
{
238
  struct ospf_proto *p = ifa->oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
239
  struct ospf_neighbor *n, *nx;
Ondřej Filip's avatar
Ondřej Filip committed
240
  struct ospf_iface *iff;
241

242 243
  if (ifa->type != OSPF_IT_VLINK)
  {
244 245 246 247 248 249 250
    if (ospf_is_v3(ifa->oa->po))
      OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
		 ifa->ifname, ifa->instance_id, ifa->oa->areaid);
    else if (ifa->addr->flags & IA_PEER)
      OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
		 ifa->ifname, ifa->addr->opposite, ifa->oa->areaid);
    else
251 252
      OSPF_TRACE(D_EVENTS, "Removing interface %s (%N) from area %R",
		 ifa->ifname, &ifa->addr->prefix, ifa->oa->areaid);
253 254

    /* First of all kill all the related vlinks */
255
    WALK_LIST(iff, p->iface_list)
256
    {
257
      if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
258
	ospf_iface_sm(iff, ISM_DOWN);
259 260 261
    }
  }

Ondřej Filip's avatar
Ondřej Filip committed
262
  WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
263
    ospf_neigh_sm(n, INM_KILLNBR);
264

265 266 267 268 269 270 271 272 273
  if (ifa->hello_timer)
    tm_stop(ifa->hello_timer);

  if (ifa->poll_timer)
    tm_stop(ifa->poll_timer);

  if (ifa->wait_timer)
    tm_stop(ifa->wait_timer);

274 275 276 277
  ospf_flush2_lsa(p, &ifa->link_lsa);
  ospf_flush2_lsa(p, &ifa->net_lsa);
  ospf_flush2_lsa(p, &ifa->pxn_lsa);

278
  if (ifa->type == OSPF_IT_VLINK)
Ondřej Filip's avatar
Ondřej Filip committed
279
  {
280 281
    ifa->vifa = NULL;
    ifa->addr = NULL;
282
    ifa->cost = 0;
283
    ifa->vip = IPA_NONE;
Ondřej Filip's avatar
Ondřej Filip committed
284
  }
285 286 287 288 289

  ifa->rt_pos_beg = 0;
  ifa->rt_pos_end = 0;
  ifa->px_pos_beg = 0;
  ifa->px_pos_end = 0;
290 291 292
}


293
void
294 295
ospf_iface_remove(struct ospf_iface *ifa)
{
296
  struct ospf_proto *p = ifa->oa->po;
297
  int i;
298

299 300 301
  if (ifa->type == OSPF_IT_VLINK)
    OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);

302 303 304 305 306
  /* Release LSAs from flood queue */
  if (!ifa->stub)
    for (i = 0; i < ifa->flood_queue_used; i++)
      ifa->flood_queue[i]->ret_count--;

307 308 309 310 311
  ospf_iface_sm(ifa, ISM_DOWN);
  rem_node(NODE ifa);
  rfree(ifa->pool);
}

312 313 314 315
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
  if (ifa->state > OSPF_IS_DOWN)
316
    ospf_send_hello(ifa, OHS_SHUTDOWN, NULL);
317 318
}

319 320 321 322 323 324 325 326 327 328 329 330
/**
 * ospf_iface_chstate - handle changes of interface state
 * @ifa: OSPF interface
 * @state: new state
 *
 * Many actions must be taken according to interface state changes. New network
 * LSAs must be originated, flushed, new multicast sockets to listen for messages for
 * %ALLDROUTERS have to be opened, etc.
 */
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
331
  struct ospf_proto *p = ifa->oa->po;
332 333
  u8 oldstate = ifa->state;

334
  if (state == oldstate)
335 336
    return;

337 338
  OSPF_TRACE(D_EVENTS, "Interface %s changed state from %s to %s",
	     ifa->ifname, ospf_is_names[oldstate], ospf_is_names[state]);
339

340
  ifa->state = state;
341

342
  if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
343 344 345 346 347 348 349 350 351 352
  {
    if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
      ospf_sk_join_dr(ifa);
    else
      ospf_sk_leave_dr(ifa);
  }

  if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
    ospf_iface_down(ifa);

353 354 355 356 357 358 359 360
  /* RFC 2328 12.4 Event 2 - iface state change */
  ospf_notify_rt_lsa(ifa->oa);

  /* RFC 5340 4.4.3 Event 1 - iface state change */
  ospf_notify_link_lsa(ifa);

  /* RFC 2328 12.4 Event 3 - iface enters/leaves DR state */
  ospf_notify_net_lsa(ifa);
361 362
}

Ondřej Filip's avatar
Ondřej Filip committed
363
/**
Ondřej Filip's avatar
Ondřej Filip committed
364
 * ospf_iface_sm - OSPF interface state machine
Ondřej Filip's avatar
Ondřej Filip committed
365 366 367
 * @ifa: OSPF interface
 * @event: event comming to state machine
 *
368 369 370 371 372
 * This fully respects 9.3 of RFC 2328 except we have slightly
 * different handling of %DOWN and %LOOP state. We remove intefaces
 * that are %DOWN. %DOWN state is used when an interface is waiting
 * for a lock. %LOOP state is used when an interface does not have a
 * link.
Ondřej Filip's avatar
Ondřej Filip committed
373
 */
374
void
Ondřej Filip's avatar
Ondřej Filip committed
375
ospf_iface_sm(struct ospf_iface *ifa, int event)
376
{
377
  DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism_names[event]);
378

Ondřej Filip's avatar
Ondřej Filip committed
379
  switch (event)
380
  {
Ondřej Filip's avatar
Ondřej Filip committed
381
  case ISM_UP:
382
    if (ifa->state <= OSPF_IS_LOOP)
Ondřej Filip's avatar
Ondřej Filip committed
383 384
    {
      /* Now, nothing should be adjacent */
385 386 387
      if ((ifa->type == OSPF_IT_PTP) ||
	  (ifa->type == OSPF_IT_PTMP) ||
	  (ifa->type == OSPF_IT_VLINK))
388
      {
Ondřej Filip's avatar
Ondřej Filip committed
389
	ospf_iface_chstate(ifa, OSPF_IS_PTP);
390
      }
Ondřej Filip's avatar
Ondřej Filip committed
391
      else
392
      {
Ondřej Filip's avatar
Ondřej Filip committed
393 394 395 396 397
	if (ifa->priority == 0)
	  ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
	else
	{
	  ospf_iface_chstate(ifa, OSPF_IS_WAITING);
398 399
	  if (ifa->wait_timer)
	    tm_start(ifa->wait_timer, ifa->waitint);
Ondřej Filip's avatar
Ondřej Filip committed
400
	}
401
      }
402

403 404
      if (ifa->hello_timer)
	tm_start(ifa->hello_timer, ifa->helloint);
405 406 407 408

      if (ifa->poll_timer)
	tm_start(ifa->poll_timer, ifa->pollint);

409
      ospf_send_hello(ifa, OHS_HELLO, NULL);
Ondřej Filip's avatar
Ondřej Filip committed
410 411
    }
    break;
412

Ondřej Filip's avatar
Ondřej Filip committed
413 414 415
  case ISM_BACKS:
  case ISM_WAITF:
    if (ifa->state == OSPF_IS_WAITING)
416
      ospf_dr_election(ifa);
Ondřej Filip's avatar
Ondřej Filip committed
417
    break;
418

Ondřej Filip's avatar
Ondřej Filip committed
419
  case ISM_NEICH:
420 421
    if (ifa->state >= OSPF_IS_DROTHER)
      ospf_dr_election(ifa);
Ondřej Filip's avatar
Ondřej Filip committed
422
    break;
423

424
  case ISM_LOOP:
425
    if ((ifa->state > OSPF_IS_LOOP) && ifa->check_link)
426
      ospf_iface_chstate(ifa, OSPF_IS_LOOP);
Ondřej Filip's avatar
Ondřej Filip committed
427
    break;
428

Ondřej Filip's avatar
Ondřej Filip committed
429
  case ISM_UNLOOP:
430 431 432 433 434 435
    /* Immediate go UP */
    if (ifa->state == OSPF_IS_LOOP)
      ospf_iface_sm(ifa, ISM_UP);
    break;

  case ISM_DOWN:
Ondřej Filip's avatar
Ondřej Filip committed
436 437
    ospf_iface_chstate(ifa, OSPF_IS_DOWN);
    break;
438

Ondřej Filip's avatar
Ondřej Filip committed
439 440 441
  default:
    bug("OSPF_I_SM - Unknown event?");
    break;
442
  }
Ondřej Filip's avatar
Ondřej Filip committed
443

444 445
}

446
static u8
447
ospf_iface_classify_(struct iface *ifa, struct ifa *addr)
448
{
449
  if (ipa_nonzero(addr->opposite))
450
    return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP :  OSPF_IT_PTMP;
451

Ondřej Filip's avatar
Ondřej Filip committed
452 453 454 455 456
  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) ==
      (IF_MULTIACCESS | IF_MULTICAST))
    return OSPF_IT_BCAST;

  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) == IF_MULTIACCESS)
457
    return OSPF_IT_NBMA;
Ondřej Filip's avatar
Ondřej Filip committed
458

459 460 461
  return OSPF_IT_PTP;
}

462 463 464
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
465
  return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_(addr->iface, addr);
466 467 468
}


Ondřej Filip's avatar
Ondřej Filip committed
469
struct ospf_iface *
470
ospf_iface_find(struct ospf_proto *p, struct iface *what)
471
{
472 473 474 475 476
  struct ospf_iface *ifa;

  WALK_LIST(ifa, p->iface_list)
    if ((ifa->iface == what) && (ifa->type != OSPF_IT_VLINK))
      return ifa;
477 478 479 480

  return NULL;
}

Ondřej Filip's avatar
Ondřej Filip committed
481 482 483 484
static void
ospf_iface_add(struct object_lock *lock)
{
  struct ospf_iface *ifa = lock->data;
485
  struct ospf_proto *p = ifa->oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
486

487 488
  /* Open socket if interface is not stub */
  if (! ifa->stub && ! ospf_sk_open(ifa))
489
  {
490
    log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->p.name, ifa->ifname);
491
    ifa->ioprob = OSPF_I_SK;
Ondřej Filip's avatar
Ondřej Filip committed
492 493 494
    ifa->stub = 1;
  }

495 496 497 498 499 500 501 502 503
  if (! ifa->stub)
  {
    ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);

    if (ifa->type == OSPF_IT_NBMA)
      ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);

    if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
      ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
504 505 506

    ifa->flood_queue_size = ifa_flood_queue_size(ifa);
    ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
507 508
  }

509 510 511 512 513
  /* Do iface UP, unless there is no link (then wait in LOOP state) */
  if (!ifa->check_link || (ifa->iface->flags & IF_LINK_UP))
    ospf_iface_sm(ifa, ISM_UP);
  else
    ospf_iface_chstate(ifa, OSPF_IS_LOOP);
Ondřej Filip's avatar
Ondřej Filip committed
514 515
}

516 517 518 519 520 521 522 523 524 525 526 527 528
static inline void
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
{
  struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
  add_tail(&ifa->nbma_list, NODE n);
  n->ip = src->ip;
  n->eligible = src->eligible;
  n->found = found;
}

static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
529
  /* a host address */
530 531 532
  if (addr->flags & IA_HOST)
    return 1;

533 534 535 536
  /* a loopback iface */
  if (addr->iface->flags & IF_LOOPBACK)
    return 1;

537 538 539
  return ip->stub;
}

Ondřej Filip's avatar
Ondřej Filip committed
540
void
541
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
Ondřej Filip's avatar
Ondřej Filip committed
542
{
543
  struct ospf_proto *p = oa->po;
544
  struct iface *iface = addr->iface;
Ondřej Filip's avatar
Ondřej Filip committed
545
  struct ospf_iface *ifa;
546
  struct pool *pool;
Ondřej Filip's avatar
Ondřej Filip committed
547

548 549 550 551 552 553 554
  if (ospf_is_v3(p))
    OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
	       iface->name, ip->instance_id, oa->areaid);
  else if (addr->flags & IA_PEER)
    OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
	       iface->name, addr->opposite, oa->areaid);
  else
555 556
    OSPF_TRACE(D_EVENTS, "Adding interface %s (%N) to area %R",
	       iface->name, &addr->prefix, oa->areaid);
557

558
  pool = rp_new(p->p.pool, "OSPF Interface");
559
  ifa = mb_allocz(pool, sizeof(struct ospf_iface));
Ondřej Filip's avatar
Ondřej Filip committed
560
  ifa->iface = iface;
561
  ifa->addr = addr;
562 563
  ifa->oa = oa;
  ifa->cf = ip;
564
  ifa->pool = pool;
Ondřej Filip's avatar
Ondřej Filip committed
565

566 567 568
  ifa->iface_id = iface->index;
  ifa->ifname = iface->name;

Ondřej Filip's avatar
Ondřej Filip committed
569 570 571 572 573 574 575 576
  ifa->cost = ip->cost;
  ifa->rxmtint = ip->rxmtint;
  ifa->inftransdelay = ip->inftransdelay;
  ifa->priority = ip->priority;
  ifa->helloint = ip->helloint;
  ifa->pollint = ip->pollint;
  ifa->strictnbma = ip->strictnbma;
  ifa->waitint = ip->waitint;
577
  ifa->deadint = ip->deadint;
578
  ifa->stub = ospf_iface_stubby(ip, addr);
579
  ifa->ioprob = OSPF_I_OK;
580
  ifa->tx_length = ifa_tx_length(ifa);
581
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
582
  ifa->check_link = ip->check_link;
583
  ifa->ecmp_weight = ip->ecmp_weight;
584
  ifa->check_ttl = (ip->ttl_security == 1);
585
  ifa->bfd = ip->bfd;
Ondřej Filip's avatar
Ondřej Filip committed
586
  ifa->autype = ip->autype;
587
  ifa->passwords = ip->passwords;
588 589
  ifa->instance_id = ip->instance_id;

590
  ifa->ptp_netmask = !(addr->flags & IA_PEER);
591 592
  if (ip->ptp_netmask < 2)
    ifa->ptp_netmask = ip->ptp_netmask;
593

594
  ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
595

596
  ifa->type = ospf_iface_classify(ip->type, addr);
597

598 599
  /* Check validity of interface type */
  int old_type = ifa->type;
600
  u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
601

602
  if (ospf_is_v2(p) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
603
    ifa->type = OSPF_IT_PTP;
604

605
  if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
606
    ifa->type = OSPF_IT_PTMP;
607

608
  if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag) && !ifa->stub)
609 610
    ifa->type = OSPF_IT_NBMA;

611
  if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag) && !ifa->stub)
612 613 614 615
    ifa->type = OSPF_IT_PTMP;

  if (ifa->type != old_type)
    log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
616 617
	p->p.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);

618

619 620
  if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP))
    ifa->link_lsa_suppression = ip->link_lsa_suppression;
621

622
  ifa->state = OSPF_IS_DOWN;
Ondřej Filip's avatar
Ondřej Filip committed
623 624
  init_list(&ifa->neigh_list);
  init_list(&ifa->nbma_list);
625

626
  struct nbma_node *nb;
Ondřej Filip's avatar
Ondřej Filip committed
627
  WALK_LIST(nb, ip->nbma_list)
628 629 630 631 632 633
  {
    /* In OSPFv3, addr is link-local while configured neighbors could
       have global IP (although RFC 5340 C.5 says link-local addresses
       should be used). Because OSPFv3 iface is not subnet-specific,
       there is no need for ipa_in_net() check */

634
    if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &addr->prefix))
635
      continue;
636 637

    if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
638 639
      log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
	  p->p.name, nb->ip);
640 641 642

    add_nbma_node(ifa, nb, 0);
  }
Ondřej Filip's avatar
Ondřej Filip committed
643

644
  add_tail(&oa->po->iface_list, NODE ifa);
Ondřej Filip's avatar
Ondřej Filip committed
645

646
  struct object_lock *lock = olock_new(pool);
647
  lock->addr = ospf_is_v2(p) ? ipa_from_ip4(net4_prefix(&ifa->addr->prefix)) : IPA_NONE;
Ondřej Filip's avatar
Ondřej Filip committed
648 649
  lock->type = OBJLOCK_IP;
  lock->port = OSPF_PROTO;
650
  lock->inst = ifa->instance_id;
Ondřej Filip's avatar
Ondřej Filip committed
651 652 653 654 655 656 657
  lock->iface = iface;
  lock->data = ifa;
  lock->hook = ospf_iface_add;

  olock_acquire(lock);
}

658
void
659
ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
660 661 662 663
{
  struct ospf_iface *ifa;
  struct pool *pool;

664
  if (!p->vlink_sk)
665 666 667 668 669 670
    return;

  OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);

  /* Vlink ifname is stored just after the ospf_iface structure */

671
  pool = rp_new(p->p.pool, "OSPF Vlink");
672
  ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
673
  ifa->oa = p->backbone;
674 675 676 677
  ifa->cf = ip;
  ifa->pool = pool;

  /* Assign iface ID, for vlinks, this is ugly hack */
678
  u32 vlink_id = p->last_vlink_id++;
679 680 681 682
  ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
  ifa->ifname = (void *) (ifa + 1);
  bsprintf(ifa->ifname, "vlink%d", vlink_id);

683
  ifa->voa = ospf_find_area(p, ip->voa);
684
  ifa->vid = ip->vid;
685
  ifa->sk = p->vlink_sk;
686 687 688 689 690 691

  ifa->helloint = ip->helloint;
  ifa->rxmtint = ip->rxmtint;
  ifa->waitint = ip->waitint;
  ifa->deadint = ip->deadint;
  ifa->inftransdelay = ip->inftransdelay;
692
  ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
693
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
694 695 696 697 698 699 700 701 702 703
  ifa->autype = ip->autype;
  ifa->passwords = ip->passwords;
  ifa->instance_id = ip->instance_id;

  ifa->type = OSPF_IT_VLINK;

  ifa->state = OSPF_IS_DOWN;
  init_list(&ifa->neigh_list);
  init_list(&ifa->nbma_list);

704
  add_tail(&p->iface_list, NODE ifa);
705 706

  ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
707 708 709

  ifa->flood_queue_size = ifa_flood_queue_size(ifa);
  ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
710 711
}

712
static void
713
ospf_iface_change_timer(timer *tm, uint val)
714 715 716 717 718 719 720 721 722 723
{
  if (!tm)
    return;

  tm->recurrent = val;

  if (tm->expires)
    tm_start(tm, val);
}

724 725 726 727 728 729 730 731 732 733 734 735 736 737
static inline void
ospf_iface_update_flood_queue_size(struct ospf_iface *ifa)
{
  uint old_size = ifa->flood_queue_size;
  uint new_size = ifa_flood_queue_size(ifa);

  if (new_size <= old_size)
    return;

  ifa->flood_queue_size = new_size;
  ifa->flood_queue = mb_realloc(ifa->flood_queue, new_size * sizeof(void *));
  bzero(ifa->flood_queue + old_size, (new_size - old_size) * sizeof(void *));
}

738 739 740
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
741
  struct ospf_proto *p = ifa->oa->po;
742 743
  struct ospf_iface_patt *old = ifa->cf;
  char *ifname = ifa->ifname;
744 745 746

  /* Type could be changed in ospf_iface_new(),
     but if config values are same then also results are same */
747
  int old_type = ospf_iface_classify(old->type, ifa->addr);
748 749 750 751 752 753 754 755
  int new_type = ospf_iface_classify(new->type, ifa->addr);
  if (old_type != new_type)
    return 0;

  int new_stub = ospf_iface_stubby(new, ifa->addr);
  if (ifa->stub != new_stub)
    return 0;

756
  /* Change of these options would require to reset the iface socket */
757 758 759 760
  if ((new->real_bcast != old->real_bcast) ||
      (new->tx_tos != old->tx_tos) ||
      (new->tx_priority != old->tx_priority) ||
      (new->ttl_security != old->ttl_security))
761 762
    return 0;

763 764 765 766 767 768 769
  ifa->cf = new;
  ifa->marked = 0;


  /* HELLO TIMER */
  if (ifa->helloint != new->helloint)
  {
770
    OSPF_TRACE(D_EVENTS, "Changing hello interval of %s from %d to %d",
771 772 773
	       ifname, ifa->helloint, new->helloint);

    ifa->helloint = new->helloint;
774
    ospf_iface_change_timer(ifa->hello_timer, ifa->helloint);
775 776 777 778 779
  }

  /* RXMT TIMER */
  if (ifa->rxmtint != new->rxmtint)
  {
780
    OSPF_TRACE(D_EVENTS, "Changing retransmit interval of %s from %d to %d",
781 782 783
	       ifname, ifa->rxmtint, new->rxmtint);

    ifa->rxmtint = new->rxmtint;
784
    /* FIXME: Update neighbors' timers */
785 786 787 788 789
  }

  /* POLL TIMER */
  if (ifa->pollint != new->pollint)
  {
790
    OSPF_TRACE(D_EVENTS, "Changing poll interval of %s from %d to %d",
791 792
	       ifname, ifa->pollint, new->pollint);

793 794
    ifa->pollint = new->pollint;
    ospf_iface_change_timer(ifa->poll_timer, ifa->pollint);
795 796 797 798 799
  }

  /* WAIT TIMER */
  if (ifa->waitint != new->waitint)
  {
800
    OSPF_TRACE(D_EVENTS, "Changing wait interval of %s from %d to %d",
801 802 803
	       ifname, ifa->waitint, new->waitint);

    ifa->waitint = new->waitint;
804
    if (ifa->wait_timer && ifa->wait_timer->expires)
805 806 807 808 809 810
      tm_start(ifa->wait_timer, ifa->waitint);
  }

  /* DEAD TIMER */
  if (ifa->deadint != new->deadint)
  {
811
    OSPF_TRACE(D_EVENTS, "Changing dead interval of %s from %d to %d",
812 813 814 815 816 817 818
	       ifname, ifa->deadint, new->deadint);
    ifa->deadint = new->deadint;
  }

  /* INFTRANS */
  if (ifa->inftransdelay != new->inftransdelay)
  {
819
    OSPF_TRACE(D_EVENTS, "Changing transmit delay of %s from %d to %d",
820 821 822 823 824 825 826
		     ifname, ifa->inftransdelay, new->inftransdelay);
    ifa->inftransdelay = new->inftransdelay;
  }

  /* AUTHENTICATION */
  if (ifa->autype != new->autype)
  {
827
    OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname);
828 829 830 831 832 833
    ifa->autype = new->autype;
  }

  /* Update passwords */
  ifa->passwords = new->passwords;

834 835 836
  /* Update header length */
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);

837 838 839 840 841 842 843 844
  /* Remaining options are just for proper interfaces */
  if (ifa->type == OSPF_IT_VLINK)
    return 1;


  /* COST */
  if (ifa->cost != new->cost)
  {
845
    OSPF_TRACE(D_EVENTS, "Changing cost of %s from %d to %d",
846 847 848 849 850 851 852 853
	       ifname, ifa->cost, new->cost);

    ifa->cost = new->cost;
  }

  /* PRIORITY */
  if (ifa->priority != new->priority)
  {
854
    OSPF_TRACE(D_EVENTS, "Changing priority of %s from %d to %d",
855
	       ifname, ifa->priority, new->priority);
856

857
    ifa->priority = new->priority;
858
    ospf_notify_link_lsa(ifa);
859 860 861 862 863
  }

  /* STRICT NBMA */
  if (ifa->strictnbma != new->strictnbma)
  {
864 865
    OSPF_TRACE(D_EVENTS, "Changing NBMA strictness of %s from %d to %d",
	       ifname, ifa->strictnbma, new->strictnbma);
866 867 868
    ifa->strictnbma = new->strictnbma;
  }

869 870
  struct nbma_node *nb, *nbx;

871 872 873
  /* NBMA LIST - remove or update old */
  WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
  {
874
    struct nbma_node *nb2 = find_nbma_node_(&new->nbma_list, nb->ip);
875 876 877 878
    if (nb2)
    {
      if (nb->eligible != nb2->eligible)
      {
879
	OSPF_TRACE(D_EVENTS, "Changing eligibility of NBMA neighbor %I on %s",
880 881 882 883 884 885
		   nb->ip, ifname);
	nb->eligible = nb2->eligible;
      }
    }
    else
    {
886
      OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on %s",
887 888 889 890 891 892 893 894 895
		       nb->ip, ifname);
      rem_node(NODE nb);
      mb_free(nb);
    }
  }

  /* NBMA LIST - add new */
  WALK_LIST(nb, new->nbma_list)
  {
896
    /* See related note in ospf_iface_new() */
897
    if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &ifa->addr->prefix))
898
      continue;
899 900

    if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
901 902
      log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
	  p->p.name, nb->ip);
903 904 905

    if (! find_nbma_node(ifa, nb->ip))
    {
906
      OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on %s",
907 908 909 910 911
		 nb->ip, ifname);
      add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
    }
  }

912 913 914 915 916
  int update_buffers = 0;

  /* TX LENGTH */
  if (old->tx_length != new->tx_length)
  {
917
    OSPF_TRACE(D_EVENTS, "Changing TX length of %s from %d to %d",
918 919 920 921 922
	       ifname, old->tx_length, new->tx_length);

    /* ifa cannot be vlink */
    ifa->tx_length = ifa_tx_length(ifa);
    update_buffers = 1;
923 924 925

    if (!ifa->stub)
      ospf_iface_update_flood_queue_size(ifa);
926 927 928 929 930
  }

  /* RX BUFFER */
  if (old->rx_buffer != new->rx_buffer)
  {
931
    OSPF_TRACE(D_EVENTS, "Changing buffer size of %s from %d to %d",
932 933 934 935 936 937 938 939
	       ifname, old->rx_buffer, new->rx_buffer);

    /* ifa cannot be vlink */
    update_buffers = 1;
  }

  /* Buffer size depends on both tx_length and rx_buffer options */
  if (update_buffers && ifa->sk)
940
  {
941 942 943
    uint bsize = ifa_bufsize(ifa);
    sk_set_rbsize(ifa->sk, bsize);
    sk_set_tbsize(ifa->sk, bsize);
944 945 946 947 948
  }

  /* LINK */
  if (ifa->check_link != new->check_link)
  {
949
    OSPF_TRACE(D_EVENTS, "%s link check for %s",
950 951 952
	       new->check_link ? "Enabling" : "Disabling", ifname);
    ifa->check_link = new->check_link;

953
    /* ifa cannot be vlink */
954 955 956 957 958 959 960
    if (!(ifa->iface->flags & IF_LINK_UP))
      ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
  }

  /* ECMP weight */
  if (ifa->ecmp_weight != new->ecmp_weight)
  {
961
    OSPF_TRACE(D_EVENTS, "Changing ECMP weight of %s from %d to %d",
962 963 964 965
	       ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
    ifa->ecmp_weight = new->ecmp_weight;
  }

966 967 968 969 970 971 972 973 974 975 976
  /* Link LSA suppression */
  if (((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP)) &&
      (ifa->link_lsa_suppression != new->link_lsa_suppression))
  {
    OSPF_TRACE(D_EVENTS, "Changing link LSA suppression of %s from %d to %d",
	       ifname, ifa->link_lsa_suppression, new->link_lsa_suppression);

    ifa->link_lsa_suppression = new->link_lsa_suppression;
    ospf_notify_link_lsa(ifa);
  }

977 978 979
  /* BFD */
  if (ifa->bfd != new->bfd)
  {
980
    OSPF_TRACE(D_EVENTS, "%s BFD for %s",
981 982 983 984 985 986 987 988 989
	       new->bfd ? "Enabling" : "Disabling", ifname);
    ifa->bfd = new->bfd;

    struct ospf_neighbor *n;
    WALK_LIST(n, ifa->neigh_list)
      ospf_neigh_update_bfd(n, ifa->bfd);
  }


990 991 992 993 994
  /* instance_id is not updated - it is part of key */

  return 1;
}

995

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
/*
 * State for matching iface pattterns walk
 *
 * This is significantly different in OSPFv2 and OSPFv3.
 * In OSPFv2, OSPF ifaces are created for each IP prefix (struct ifa)
 * In OSPFv3, OSPF ifaces are created based on real iface (struct iface)
 * We support instance_id for both OSPFv2 (RFC 6549) and OSPFv3.
 *
 * We process one ifa/iface and match it for all configured instance IDs. We
 * maintain bitfields to track whether given instance ID was already matched.
 * We have two bitfields, one global (active) and one per area (ignore), to
 * detect misconfigured cases where one iface with one instance ID matches in
 * multiple areas.
 */
1010

1011 1012 1013 1014 1015 1016 1017 1018 1019
struct ospf_mip_walk {
  u32 active[8];		/* Bitfield of active instance IDs */
  u32 ignore[8];		/* Bitfield of instance IDs matched in current area */
  struct ospf_area *oa;		/* Current area */
  struct ospf_iface_patt *ip;	/* Current iface pattern */
  struct iface *iface;		/* Specified iface (input) */
  struct ifa *a;		/* Specified ifa (input) */
  int warn;			/* Whether iface matched in multiple areas */
};
1020

1021 1022
static int
ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s)
1023
{
1024
  int id;
1025

1026 1027
  if (s->ip)
    goto step;
1028

1029
  WALK_LIST(s->oa, p->area_list)
1030
  {
1031 1032 1033
    if (s->oa->marked)
      continue;

1034
    WALK_LIST(s->ip, s->oa->ac->patt_list)
1035
    {
1036 1037 1038 1039 1040
      id = s->ip->instance_id;
      if (BIT32_TEST(s->ignore, id))
	continue;

      if (iface_patt_match(&s->ip->i, s->iface, s->a))
1041
      {
1042 1043
	/* Now we matched ifa/iface/instance_id for the first time in current area */
	BIT32_SET(s->ignore, id);
1044

1045
	/* If we already found it in previous areas, ignore it and add warning */
1046
	if (BIT32_TEST(s->active, id))
1047
	  { s->warn = 1; continue; }
1048

1049 1050 1051 1052 1053
	BIT32_SET(s->active, id);
	return 1;
      step:
	;
      }
1054
    }
1055
    BIT32_ZERO(s->ignore, 256);
1056
  }
1057 1058 1059 1060 1061

  if (s->warn)
    log(L_WARN "%s: Interface %s matches for multiple areas", p->p.name, s->iface->name);

  return 0;
1062 1063
}

1064

1065
static struct ospf_iface *
1066
ospf_iface_find_by_key(struct ospf_proto *p, struct ifa *a, int instance_id)
1067 1068
{
  struct ospf_iface *ifa;
1069 1070 1071 1072

  WALK_LIST(ifa, p->iface_list)
    if ((ifa->addr == a) && (ifa->instance_id == instance_id) &&
	(ifa->type != OSPF_IT_VLINK))
1073 1074 1075 1076
      return ifa;

  return NULL;
}
1077

1078

1079
void
1080
ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
1081
{
1082
  struct ospf_proto *p = (struct ospf_proto *) P;
1083

1084 1085 1086
  if (a->prefix.type != NET_IP4)
    return;

1087 1088
  if (a->flags & IA_SECONDARY)
    return;
1089

1090 1091
  if (a->scope <= SCOPE_LINK)
    return;
1092

1093 1094 1095 1096 1097
  /* In OSPFv2, we create OSPF iface for each address. */
  if (flags & IF_CHANGE_UP)
  {
    struct ospf_mip_walk s = { .iface = a->iface, .a = a };
    while (ospf_walk_matching_iface_patts(p, &s))
1098
      ospf_iface_new(s.oa, a, s.ip);
1099
  }
1100

1101 1102 1103 1104 1105 1106 1107 1108
  if (flags & IF_CHANGE_DOWN)
  {
    struct ospf_iface *ifa, *ifx;
    WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
      if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
	ospf_iface_remove(ifa);
    /* See a note in ospf_iface_notify() */
  }
1109 1110 1111
}

void
1112
ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
1113
{
1114
  struct ospf_proto *p = (struct ospf_proto *) P;
1115

1116 1117 1118
  if (a->prefix.type != NET_IP6)
    return;

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
  if (a->flags & IA_SECONDARY)
    return;

  if (a->scope < SCOPE_LINK)
    return;

  /* In OSPFv3, we create OSPF iface for link-local address,
     other addresses are used for link-LSA. */
  if (a->scope == SCOPE_LINK)
  {
    if (flags & IF_CHANGE_UP)
    {
1131 1132
      struct ospf_mip_walk s = { .iface = a->iface };
      while (ospf_walk_matching_iface_patts(p, &s))
1133
	ospf_iface_new(s.oa, a, s.ip);
1134 1135 1136 1137 1138
    }

    if (flags & IF_CHANGE_DOWN)
    {
      struct ospf_iface *ifa, *ifx;
1139 1140
      WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
	if ((ifa->addr == a) && (ifa->type != OSPF_IT_VLINK))
1141
	  ospf_iface_remove(ifa);
1142 1143 1144 1145 1146
    }
  }
  else
  {
    struct ospf_iface *ifa;
1147
    WALK_LIST(ifa, p->iface_list)
1148 1149
      if (ifa->iface == a->iface)
      {
1150 1151 1152
	/* RFC 5340 4.4.3 Event 5 - prefix added/deleted */
	ospf_notify_link_lsa(ifa);
	ospf_notify_rt_lsa(ifa->oa);
1153 1154 1155 1156
      }
  }
}

1157 1158 1159

static void
ospf_reconfigure_ifaces2(struct ospf_proto *p)
1160
{
1161 1162
  struct iface *iface;
  struct ifa *a;
1163

1164 1165 1166 1167 1168 1169 1170
  WALK_LIST(iface, iface_list)
  {
    if (! (iface->flags & IF_UP))
      continue;

    WALK_LIST(a, iface->addrs)
    {
1171 1172 1173
      if (a->prefix.type != NET_IP4)
	continue;

1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
      if (a->flags & IA_SECONDARY)
	continue;

      if (a->scope <= SCOPE_LINK)
	continue;

      struct ospf_mip_walk s = { .iface = iface, .a = a };
      while (ospf_walk_matching_iface_patts(p, &s))
      {
	/* Main inner loop */
	struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
	if (ifa)
	{
	  if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
	      ospf_iface_reconfigure(ifa, s.ip))
	    continue;

	  /* Hard restart */
1192 1193
	  log(L_INFO "%s: Restarting interface %s (%N) in area %R",
	      p->p.name, ifa->ifname, &a->prefix, s.oa->areaid);
1194 1195 1196
	  ospf_iface_shutdown(ifa);
	  ospf_iface_remove(ifa);
	}
1197

1198 1199 1200 1201
	ospf_iface_new(s.oa, a, s.ip);
      }
    }
  }
1202
}
1203

1204 1205
static void
ospf_reconfigure_ifaces3(struct ospf_proto *p)
1206 1207 1208 1209 1210
{
  struct iface *iface;
  struct ifa *a;

  WALK_LIST(iface, iface_list)
1211 1212 1213 1214
  {
    if (! (iface->flags & IF_UP))
      continue;

1215 1216
    WALK_LIST(a, iface->addrs)
    {
1217 1218 1219
      if (a->prefix.type != NET_IP6)
	continue;

1220 1221 1222 1223 1224 1225
      if (a->flags & IA_SECONDARY)
	continue;

      if (a->scope != SCOPE_LINK)
	continue;

1226 1227
      struct ospf_mip_walk s = { .iface = iface };
      while (ospf_walk_matching_iface_patts(p, &s))
1228 1229
      {
	/* Main inner loop */
1230
	struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
1231 1232
	if (ifa)
	{
1233 1234
	  if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
	      ospf_iface_reconfigure(ifa, s.ip))
1235 1236 1237
	    continue;

	  /* Hard restart */
1238
	  log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
Ondřej Zajíček's avatar