iface.c 34.1 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

  /* Relevant just for OSPFv2 */
  if (ifa->autype == OSPF_AUTH_CRYPT)
64 65
  {
    hlen += ospf_is_v2(p) ? 0 : sizeof(struct ospf_auth3);
66
    hlen += max_mac_length(ifa->passwords);
67
  }
68 69 70 71

  return hlen;
}

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

79 80 81 82 83 84
static inline uint
ifa_flood_queue_size(struct ospf_iface *ifa)
{
  return ifa->tx_length / 24;
}

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

  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;
}


103
struct nbma_node *
104
find_nbma_node_(list *nnl, ip_addr ip)
105 106
{
  struct nbma_node *nn;
107

108 109 110
  WALK_LIST(nn, *nnl)
    if (ipa_equal(nn->ip, ip))
      return nn;
111

112 113 114
  return NULL;
}

115

116
static int
117
ospf_sk_open(struct ospf_iface *ifa)
118
{
119
  struct ospf_proto *p = ifa->oa->po;
120

121
  sock *sk = sk_new(ifa->pool);
122
  sk->type = SK_IP;
123
  sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
124
  sk->dport = OSPF_PROTO;
125 126
  sk->saddr = ifa->addr->ip;
  sk->iface = ifa->iface;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
127
  sk->vrf = p->p.vrf;
128

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

139
  if (sk_open(sk) < 0)
140 141
    goto err;

142
  /* 12 is an offset of the checksum in an OSPFv3 packet */
143
  if (ospf_is_v3(p) && !ifa->autype)
144 145
    if (sk_set_ipv6_checksum(sk, 12) < 0)
      goto err;
146

147
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
148
  {
149 150 151
    if (ifa->cf->real_bcast)
    {
      ifa->all_routers = ifa->addr->brd;
152
      ifa->des_routers = IPA_NONE;
153

154
      if (sk_setup_broadcast(sk) < 0)
155
	goto err;
156 157 158
    }
    else
    {
159 160
      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;
161

162
      if (sk_setup_multicast(sk) < 0)
163
	goto err;
164

165
      if (sk_join_group(sk, ifa->all_routers) < 0)
166
	goto err;
167
    }
168
  }
169

170 171 172
  ifa->sk = sk;
  ifa->sk_dr = 0;
  return 1;
173 174

 err:
175
  sk_log_error(sk, p->p.name);
176 177 178 179 180 181 182 183 184 185
  rfree(sk);
  return 0;
}

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

186 187
  if (sk_join_group(ifa->sk, ifa->des_routers) < 0)
    sk_log_error(ifa->sk, ifa->oa->po->p.name);
188

189 190
  ifa->sk_dr = 1;
}
191

192 193 194 195 196 197
static inline void
ospf_sk_leave_dr(struct ospf_iface *ifa)
{
  if (!ifa->sk_dr)
    return;

198 199
  if (sk_leave_group(ifa->sk, ifa->des_routers) < 0)
    sk_log_error(ifa->sk, ifa->oa->po->p.name);
200

201 202 203
  ifa->sk_dr = 0;
}

204
void
205
ospf_open_vlink_sk(struct ospf_proto *p)
206
{
207
  sock *sk = sk_new(p->p.pool);
208
  sk->type = SK_IP;
209
  sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
210
  sk->dport = OSPF_PROTO;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
211
  sk->vrf = p->p.vrf;
212 213 214 215 216 217 218

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

  sk->rbsize = 0;
219 220
  sk->tbsize = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
  sk->data = (void *) p;
221 222 223 224 225
  sk->flags = 0;

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

226 227 228 229
  /* 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;
230

231
  p->vlink_sk = sk;
232 233 234
  return;

 err:
235 236
  sk_log_error(sk, p->p.name);
  log(L_ERR "%s: Cannot open virtual link socket", p->p.name);
237 238 239
  rfree(sk);
}

Ondřej Filip's avatar
Ondřej Filip committed
240 241
static void
ospf_iface_down(struct ospf_iface *ifa)
242
{
243
  struct ospf_proto *p = ifa->oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
244
  struct ospf_neighbor *n, *nx;
Ondřej Filip's avatar
Ondřej Filip committed
245
  struct ospf_iface *iff;
246

247 248
  if (ifa->type != OSPF_IT_VLINK)
  {
249 250 251 252 253 254 255
    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
256 257
      OSPF_TRACE(D_EVENTS, "Removing interface %s (%N) from area %R",
		 ifa->ifname, &ifa->addr->prefix, ifa->oa->areaid);
258 259

    /* First of all kill all the related vlinks */
260
    WALK_LIST(iff, p->iface_list)
261
    {
262
      if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
263
	ospf_iface_sm(iff, ISM_DOWN);
264 265 266
    }
  }

Ondřej Filip's avatar
Ondřej Filip committed
267
  WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
268
    ospf_neigh_sm(n, INM_KILLNBR);
269

270
  if (ifa->hello_timer)
271
    tm_stop(ifa->hello_timer);
272 273

  if (ifa->poll_timer)
274
    tm_stop(ifa->poll_timer);
275 276

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

279 280 281 282
  ospf_flush2_lsa(p, &ifa->link_lsa);
  ospf_flush2_lsa(p, &ifa->net_lsa);
  ospf_flush2_lsa(p, &ifa->pxn_lsa);

283
  if (ifa->type == OSPF_IT_VLINK)
Ondřej Filip's avatar
Ondřej Filip committed
284
  {
285 286
    ifa->vifa = NULL;
    ifa->addr = NULL;
287
    ifa->cost = 0;
288
    ifa->vip = IPA_NONE;
Ondřej Filip's avatar
Ondřej Filip committed
289
  }
290 291 292 293 294

  ifa->rt_pos_beg = 0;
  ifa->rt_pos_end = 0;
  ifa->px_pos_beg = 0;
  ifa->px_pos_end = 0;
295 296 297
}


298
void
299 300
ospf_iface_remove(struct ospf_iface *ifa)
{
301
  struct ospf_proto *p = ifa->oa->po;
302
  int i;
303

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

307 308 309 310 311
  /* Release LSAs from flood queue */
  if (!ifa->stub)
    for (i = 0; i < ifa->flood_queue_used; i++)
      ifa->flood_queue[i]->ret_count--;

312 313 314 315 316
  ospf_iface_sm(ifa, ISM_DOWN);
  rem_node(NODE ifa);
  rfree(ifa->pool);
}

317 318 319 320
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
  if (ifa->state > OSPF_IS_DOWN)
321
    ospf_send_hello(ifa, OHS_SHUTDOWN, NULL);
322 323
}

324 325 326 327 328 329 330 331 332 333 334 335
/**
 * 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)
{
336
  struct ospf_proto *p = ifa->oa->po;
337 338
  u8 oldstate = ifa->state;

339
  if (state == oldstate)
340 341
    return;

342 343
  OSPF_TRACE(D_EVENTS, "Interface %s changed state from %s to %s",
	     ifa->ifname, ospf_is_names[oldstate], ospf_is_names[state]);
344

345
  ifa->state = state;
346

347
  if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
348 349 350 351 352 353 354 355 356 357
  {
    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);

358 359 360 361 362 363 364 365
  /* 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);
366 367
}

Ondřej Filip's avatar
Ondřej Filip committed
368
/**
Ondřej Filip's avatar
Ondřej Filip committed
369
 * ospf_iface_sm - OSPF interface state machine
Ondřej Filip's avatar
Ondřej Filip committed
370 371 372
 * @ifa: OSPF interface
 * @event: event comming to state machine
 *
373 374 375 376 377
 * 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
378
 */
379
void
Ondřej Filip's avatar
Ondřej Filip committed
380
ospf_iface_sm(struct ospf_iface *ifa, int event)
381
{
382
  DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism_names[event]);
383

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

408
      if (ifa->hello_timer)
409
	tm_start(ifa->hello_timer, ifa->helloint S);
410 411

      if (ifa->poll_timer)
412
	tm_start(ifa->poll_timer, ifa->pollint S);
413

414
      ospf_send_hello(ifa, OHS_HELLO, NULL);
Ondřej Filip's avatar
Ondřej Filip committed
415 416
    }
    break;
417

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

Ondřej Filip's avatar
Ondřej Filip committed
424
  case ISM_NEICH:
425 426
    if (ifa->state >= OSPF_IS_DROTHER)
      ospf_dr_election(ifa);
Ondřej Filip's avatar
Ondřej Filip committed
427
    break;
428

429
  case ISM_LOOP:
430
    if ((ifa->state > OSPF_IS_LOOP) && ifa->check_link)
431
      ospf_iface_chstate(ifa, OSPF_IS_LOOP);
Ondřej Filip's avatar
Ondřej Filip committed
432
    break;
433

Ondřej Filip's avatar
Ondřej Filip committed
434
  case ISM_UNLOOP:
435 436 437 438 439 440
    /* 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
441 442
    ospf_iface_chstate(ifa, OSPF_IS_DOWN);
    break;
443

Ondřej Filip's avatar
Ondřej Filip committed
444 445 446
  default:
    bug("OSPF_I_SM - Unknown event?");
    break;
447
  }
Ondřej Filip's avatar
Ondřej Filip committed
448

449 450
}

451
static u8
452
ospf_iface_classify_(struct iface *ifa, struct ifa *addr)
453
{
454
  if (ipa_nonzero(addr->opposite))
455
    return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP :  OSPF_IT_PTMP;
456

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

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

464 465 466
  return OSPF_IT_PTP;
}

467 468 469
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
470
  return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_(addr->iface, addr);
471 472 473
}


Ondřej Filip's avatar
Ondřej Filip committed
474
struct ospf_iface *
475
ospf_iface_find(struct ospf_proto *p, struct iface *what)
476
{
477 478 479 480 481
  struct ospf_iface *ifa;

  WALK_LIST(ifa, p->iface_list)
    if ((ifa->iface == what) && (ifa->type != OSPF_IT_VLINK))
      return ifa;
482 483 484 485

  return NULL;
}

Ondřej Filip's avatar
Ondřej Filip committed
486 487 488 489
static void
ospf_iface_add(struct object_lock *lock)
{
  struct ospf_iface *ifa = lock->data;
490
  struct ospf_proto *p = ifa->oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
491

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

500 501
  if (! ifa->stub)
  {
502
    ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
503 504

    if (ifa->type == OSPF_IT_NBMA)
505
      ifa->poll_timer = tm_new_init(ifa->pool, poll_timer_hook, ifa, ifa->pollint S, 0);
506 507

    if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
508
      ifa->wait_timer = tm_new_init(ifa->pool, wait_timer_hook, ifa, 0, 0);
509 510 511

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

514 515 516 517 518
  /* 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
519 520
}

521 522 523 524 525 526 527 528 529 530 531 532 533
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)
{
534
  /* a host address */
535 536 537
  if (addr->flags & IA_HOST)
    return 1;

538 539 540 541
  /* a loopback iface */
  if (addr->iface->flags & IF_LOOPBACK)
    return 1;

542 543 544
  return ip->stub;
}

Ondřej Filip's avatar
Ondřej Filip committed
545
void
546
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
Ondřej Filip's avatar
Ondřej Filip committed
547
{
548
  struct ospf_proto *p = oa->po;
549
  struct iface *iface = addr->iface;
Ondřej Filip's avatar
Ondřej Filip committed
550
  struct ospf_iface *ifa;
551
  struct pool *pool;
Ondřej Filip's avatar
Ondřej Filip committed
552

553 554 555 556 557 558 559
  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
560 561
    OSPF_TRACE(D_EVENTS, "Adding interface %s (%N) to area %R",
	       iface->name, &addr->prefix, oa->areaid);
562

563
  pool = rp_new(p->p.pool, "OSPF Interface");
564
  ifa = mb_allocz(pool, sizeof(struct ospf_iface));
Ondřej Filip's avatar
Ondřej Filip committed
565
  ifa->iface = iface;
566
  ifa->addr = addr;
567 568
  ifa->oa = oa;
  ifa->cf = ip;
569
  ifa->pool = pool;
Ondřej Filip's avatar
Ondřej Filip committed
570

571 572 573
  ifa->iface_id = iface->index;
  ifa->ifname = iface->name;

Ondřej Filip's avatar
Ondřej Filip committed
574 575 576 577 578 579 580 581
  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;
582
  ifa->deadint = ip->deadint;
583
  ifa->stub = ospf_iface_stubby(ip, addr);
584
  ifa->ioprob = OSPF_I_OK;
585
  ifa->tx_length = ifa_tx_length(ifa);
586
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
587
  ifa->check_link = ip->check_link;
588
  ifa->ecmp_weight = ip->ecmp_weight;
589
  ifa->check_ttl = (ip->ttl_security == 1);
590
  ifa->bfd = ip->bfd;
Ondřej Filip's avatar
Ondřej Filip committed
591
  ifa->autype = ip->autype;
592
  ifa->passwords = ip->passwords;
593 594
  ifa->instance_id = ip->instance_id;

595
  ifa->ptp_netmask = !(addr->flags & IA_PEER);
596 597
  if (ip->ptp_netmask < 2)
    ifa->ptp_netmask = ip->ptp_netmask;
598

599
  ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
600

601
  ifa->type = ospf_iface_classify(ip->type, addr);
602

603 604
  /* Check validity of interface type */
  int old_type = ifa->type;
605
  u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
606

607
  if (ospf_is_v2(p) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
608
    ifa->type = OSPF_IT_PTP;
609

610
  if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
611
    ifa->type = OSPF_IT_PTMP;
612

613
  if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag) && !ifa->stub)
614 615
    ifa->type = OSPF_IT_NBMA;

616
  if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag) && !ifa->stub)
617 618 619 620
    ifa->type = OSPF_IT_PTMP;

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

623

624 625
  if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP))
    ifa->link_lsa_suppression = ip->link_lsa_suppression;
626

627
  ifa->state = OSPF_IS_DOWN;
Ondřej Filip's avatar
Ondřej Filip committed
628 629
  init_list(&ifa->neigh_list);
  init_list(&ifa->nbma_list);
630

631
  struct nbma_node *nb;
Ondřej Filip's avatar
Ondřej Filip committed
632
  WALK_LIST(nb, ip->nbma_list)
633 634 635 636 637 638
  {
    /* 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 */

639
    if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &addr->prefix))
640
      continue;
641 642

    if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
643 644
      log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
	  p->p.name, nb->ip);
645 646 647

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

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

651
  struct object_lock *lock = olock_new(pool);
652
  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
653 654
  lock->type = OBJLOCK_IP;
  lock->port = OSPF_PROTO;
655
  lock->inst = ifa->instance_id;
Ondřej Filip's avatar
Ondřej Filip committed
656 657 658 659 660 661 662
  lock->iface = iface;
  lock->data = ifa;
  lock->hook = ospf_iface_add;

  olock_acquire(lock);
}

663
void
664
ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
665 666 667 668
{
  struct ospf_iface *ifa;
  struct pool *pool;

669
  if (!p->vlink_sk)
670 671 672 673 674 675
    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 */

676
  pool = rp_new(p->p.pool, "OSPF Vlink");
677
  ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
678
  ifa->oa = p->backbone;
679 680 681 682
  ifa->cf = ip;
  ifa->pool = pool;

  /* Assign iface ID, for vlinks, this is ugly hack */
683
  u32 vlink_id = p->last_vlink_id++;
684 685 686 687
  ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
  ifa->ifname = (void *) (ifa + 1);
  bsprintf(ifa->ifname, "vlink%d", vlink_id);

688
  ifa->voa = ospf_find_area(p, ip->voa);
689
  ifa->vid = ip->vid;
690
  ifa->sk = p->vlink_sk;
691 692 693 694 695 696

  ifa->helloint = ip->helloint;
  ifa->rxmtint = ip->rxmtint;
  ifa->waitint = ip->waitint;
  ifa->deadint = ip->deadint;
  ifa->inftransdelay = ip->inftransdelay;
697
  ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
698
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
699 700 701 702 703 704 705 706 707 708
  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);

709
  add_tail(&p->iface_list, NODE ifa);
710

711
  ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
712 713 714

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

717
static void
718
ospf_iface_change_timer(timer *tm, uint val)
719 720 721 722
{
  if (!tm)
    return;

723
  tm->recurrent = val S;
724

725 726
  if (tm_active(tm))
    tm_start(tm, val S);
727 728
}

729 730 731 732 733 734 735 736 737 738 739 740 741 742
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 *));
}

743 744 745
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
746
  struct ospf_proto *p = ifa->oa->po;
747 748
  struct ospf_iface_patt *old = ifa->cf;
  char *ifname = ifa->ifname;
749 750 751

  /* Type could be changed in ospf_iface_new(),
     but if config values are same then also results are same */
752
  int old_type = ospf_iface_classify(old->type, ifa->addr);
753 754 755 756 757 758 759 760
  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;

761
  /* Change of these options would require to reset the iface socket */
762 763 764 765
  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))
766 767
    return 0;

768 769 770 771 772 773 774
  ifa->cf = new;
  ifa->marked = 0;


  /* HELLO TIMER */
  if (ifa->helloint != new->helloint)
  {
775
    OSPF_TRACE(D_EVENTS, "Changing hello interval of %s from %d to %d",
776 777 778
	       ifname, ifa->helloint, new->helloint);

    ifa->helloint = new->helloint;
779
    ospf_iface_change_timer(ifa->hello_timer, ifa->helloint);
780 781 782 783 784
  }

  /* RXMT TIMER */
  if (ifa->rxmtint != new->rxmtint)
  {
785
    OSPF_TRACE(D_EVENTS, "Changing retransmit interval of %s from %d to %d",
786 787 788
	       ifname, ifa->rxmtint, new->rxmtint);

    ifa->rxmtint = new->rxmtint;
789
    /* FIXME: Update neighbors' timers */
790 791 792 793 794
  }

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

798 799
    ifa->pollint = new->pollint;
    ospf_iface_change_timer(ifa->poll_timer, ifa->pollint);
800 801 802 803 804
  }

  /* WAIT TIMER */
  if (ifa->waitint != new->waitint)
  {
805
    OSPF_TRACE(D_EVENTS, "Changing wait interval of %s from %d to %d",
806 807 808
	       ifname, ifa->waitint, new->waitint);

    ifa->waitint = new->waitint;
809 810
    if (ifa->wait_timer && tm_active(ifa->wait_timer))
      tm_start(ifa->wait_timer, ifa->waitint S);
811 812 813 814 815
  }

  /* DEAD TIMER */
  if (ifa->deadint != new->deadint)
  {
816
    OSPF_TRACE(D_EVENTS, "Changing dead interval of %s from %d to %d",
817 818 819 820 821 822 823
	       ifname, ifa->deadint, new->deadint);
    ifa->deadint = new->deadint;
  }

  /* INFTRANS */
  if (ifa->inftransdelay != new->inftransdelay)
  {
824
    OSPF_TRACE(D_EVENTS, "Changing transmit delay of %s from %d to %d",
825 826 827 828 829 830 831
		     ifname, ifa->inftransdelay, new->inftransdelay);
    ifa->inftransdelay = new->inftransdelay;
  }

  /* AUTHENTICATION */
  if (ifa->autype != new->autype)
  {
832
    OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname);
833
    ifa->autype = new->autype;
834 835 836 837 838 839 840 841

    /* For OSPFv3, we need to update checksum calculation by OS */
    if (ospf_is_v3(p) && ifa->sk)
      if (sk_set_ipv6_checksum(ifa->sk, ifa->autype ? -1 : 12) < 0)
      {
	sk_log_error(ifa->sk, p->p.name);
	return 0;
      }
842 843 844 845 846
  }

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

847 848 849
  /* Update header length */
  ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);

850 851 852 853 854 855 856 857
  /* Remaining options are just for proper interfaces */
  if (ifa->type == OSPF_IT_VLINK)
    return 1;


  /* COST */
  if (ifa->cost != new->cost)
  {
858
    OSPF_TRACE(D_EVENTS, "Changing cost of %s from %d to %d",
859 860 861 862 863 864 865 866
	       ifname, ifa->cost, new->cost);

    ifa->cost = new->cost;
  }

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

870
    ifa->priority = new->priority;
871
    ospf_notify_link_lsa(ifa);
872 873 874 875 876
  }

  /* STRICT NBMA */
  if (ifa->strictnbma != new->strictnbma)
  {
877 878
    OSPF_TRACE(D_EVENTS, "Changing NBMA strictness of %s from %d to %d",
	       ifname, ifa->strictnbma, new->strictnbma);
879 880 881
    ifa->strictnbma = new->strictnbma;
  }

882 883
  struct nbma_node *nb, *nbx;

884 885 886
  /* NBMA LIST - remove or update old */
  WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
  {
887
    struct nbma_node *nb2 = find_nbma_node_(&new->nbma_list, nb->ip);
888 889 890 891
    if (nb2)
    {
      if (nb->eligible != nb2->eligible)
      {
892
	OSPF_TRACE(D_EVENTS, "Changing eligibility of NBMA neighbor %I on %s",
893 894 895 896 897 898
		   nb->ip, ifname);
	nb->eligible = nb2->eligible;
      }
    }
    else
    {
899
      OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on %s",
900 901 902 903 904 905 906 907 908
		       nb->ip, ifname);
      rem_node(NODE nb);
      mb_free(nb);
    }
  }

  /* NBMA LIST - add new */
  WALK_LIST(nb, new->nbma_list)
  {
909
    /* See related note in ospf_iface_new() */
910
    if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &ifa->addr->prefix))
911
      continue;
912 913

    if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
914 915
      log(L_WARN "%s: Configured neighbor address (%I) should be link-local",
	  p->p.name, nb->ip);
916 917 918

    if (! find_nbma_node(ifa, nb->ip))
    {
919
      OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on %s",
920 921 922 923 924
		 nb->ip, ifname);
      add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
    }
  }

925 926 927 928 929
  int update_buffers = 0;

  /* TX LENGTH */
  if (old->tx_length != new->tx_length)
  {
930
    OSPF_TRACE(D_EVENTS, "Changing TX length of %s from %d to %d",
931 932 933 934 935
	       ifname, old->tx_length, new->tx_length);

    /* ifa cannot be vlink */
    ifa->tx_length = ifa_tx_length(ifa);
    update_buffers = 1;
936 937 938

    if (!ifa->stub)
      ospf_iface_update_flood_queue_size(ifa);
939 940 941 942 943
  }

  /* RX BUFFER */
  if (old->rx_buffer != new->rx_buffer)
  {
944
    OSPF_TRACE(D_EVENTS, "Changing buffer size of %s from %d to %d",
945 946 947 948 949 950 951 952
	       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)
953
  {
954 955 956
    uint bsize = ifa_bufsize(ifa);
    sk_set_rbsize(ifa->sk, bsize);
    sk_set_tbsize(ifa->sk, bsize);
957 958 959 960 961
  }

  /* LINK */
  if (ifa->check_link != new->check_link)
  {
962
    OSPF_TRACE(D_EVENTS, "%s link check for %s",
963 964 965
	       new->check_link ? "Enabling" : "Disabling", ifname);
    ifa->check_link = new->check_link;

966
    /* ifa cannot be vlink */
967 968 969 970 971 972 973
    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)
  {
974
    OSPF_TRACE(D_EVENTS, "Changing ECMP weight of %s from %d to %d",
975 976 977 978
	       ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
    ifa->ecmp_weight = new->ecmp_weight;
  }

979 980 981 982 983 984 985 986 987 988 989
  /* 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);
  }

990 991 992
  /* BFD */
  if (ifa->bfd != new->bfd)
  {
993
    OSPF_TRACE(D_EVENTS, "%s BFD for %s",
994 995 996 997 998 999 1000 1001 1002
	       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);
  }


1003 1004 1005 1006 1007
  /* instance_id is not updated - it is part of key */

  return 1;
}

1008

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
/*
 * 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.
 */
1023

1024 1025 1026 1027 1028 1029 1030 1031 1032
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 */
};
1033

1034 1035
static int
ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s)
1036
{
1037
  int id;
1038

1039 1040
  if (s->ip)
    goto step;
1041

1042
  WALK_LIST(s->oa, p->area_list)
1043
  {
1044 1045 1046
    if (s->oa->marked)
      continue;

1047
    WALK_LIST(s->ip, s->oa->ac->patt_list)
1048
    {
1049 1050 1051 1052 1053
      id = s->ip->instance_id;
      if (BIT32_TEST(s->ignore, id))
	continue;

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

1058
	/* If we already found it in previous areas, ignore it and add warning */
1059
	if (BIT32_TEST(s->active, id))
1060
	  { s->warn = 1; continue; }
1061

1062 1063 1064 1065 1066
	BIT32_SET(s->active, id);
	return 1;
      step:
	;
      }
1067
    }
1068
    BIT32_ZERO(s->ignore, 256);
1069
  }
1070 1071 1072 1073 1074

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

  return 0;
1075 1076
}

1077

1078
static struct ospf_iface *
1079
ospf_iface_find_by_key(struct ospf_proto *p, struct ifa *a, int instance_id)
1080 1081
{
  struct ospf_iface *ifa;
1082 1083 1084 1085

  WALK_LIST(ifa, p->iface_list)
    if ((ifa->addr == a) && (ifa->instance_id == instance_id) &&
	(ifa->type != OSPF_IT_VLINK))
1086 1087 1088 1089
      return ifa;

  return NULL;
}
1090

1091

1092
void
1093
ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
1094
{
1095
  struct ospf_proto *p = (struct ospf_proto *) P;
1096

1097 1098 1099
  if (a->prefix.type != NET_IP4)
    return;

1100 1101
  if (a->flags & IA_SECONDARY)
    return;
1102

1103 1104
  if (a->scope <= SCOPE_LINK)
    return;
1105

1106 1107 1108 1109 1110
  /* 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))
1111
      ospf_iface_new(s.oa, a, s.ip);
1112
  }
1113

1114 1115 1116 1117 1118 1119 1120 1121
  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() */
  }
1122 1123 1124
}

void
1125
ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
1126
{
1127
  struct ospf_proto *p = (struct ospf_proto *) P;
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

  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)
  {
1139 1140 1141
    if (a->prefix.type != NET_IP6)
      return;

1142 1143
    if (flags & IF_CHANGE_UP)
    {
1144 1145
      struct ospf_mip_walk s = { .iface = a->iface };
      while (ospf_walk_matching_iface_patts(p, &s))
1146
	ospf_iface_new(s.oa, a, s.ip);
1147 1148 1149 1150 1151
    }

    if (flags & IF_CHANGE_DOWN)
    {
      struct ospf_iface *ifa, *ifx;
1152 1153
      WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
	if ((ifa->addr == a) && (ifa->type != OSPF_IT_VLINK))
1154
	  ospf_iface_remove(ifa);
1155 1156 1157 1158
    }
  }
  else
  {
1159 1160 1161
    if (a->prefix.type != ospf_get_af(p))
      return;

1162
    struct ospf_iface *ifa;
1163
    WALK_LIST(ifa, p->iface_list)
1164 1165
      if (ifa->iface == a->iface)
      {
1166 1167 1168
	/* RFC 5340 4.4.3 Event 5 - prefix added/deleted */
	ospf_notify_link_lsa(ifa);
	ospf_notify_rt_lsa(ifa->oa);
1169 1170 1171 1172
      }
  }
}

1173 1174 1175

static void
ospf_reconfigure_ifaces2(struct ospf_proto *p)
1176
{
1177 1178
  struct iface *iface;
  struct ifa *a;
1179

1180 1181 1182 1183 1184 1185 1186
  WALK_LIST(iface, iface_list)
  {
    if (! (iface->flags & IF_UP))
      continue;

    WALK_LIST(a, iface->addrs)
    {
1187 1188 1189
      if (a->prefix.type != NET_IP4)
	continue;