Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / iface.c @ 48e5f32d

History | View | Annotate | Download (31.1 KB)

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