Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / dbdes.c @ 6f8bbaa1

History | View | Annotate | Download (11.2 KB)

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

    
11
#include "ospf.h"
12

    
13

    
14
struct ospf_dbdes2_packet
15
{
16
  struct ospf_packet hdr;
17
  union ospf_auth auth;
18

    
19
  u16 iface_mtu;
20
  u8 options;
21
  u8 imms;                        /* I, M, MS bits */
22
  u32 ddseq;
23

    
24
  struct ospf_lsa_header lsas[];
25
};
26

    
27
struct ospf_dbdes3_packet
28
{
29
  struct ospf_packet hdr;
30

    
31
  u32 options;
32
  u16 iface_mtu;
33
  u8 padding;
34
  u8 imms;                        /* I, M, MS bits */
35
  u32 ddseq;
36

    
37
  struct ospf_lsa_header lsas[];
38
};
39

    
40

    
41
static inline uint
42
ospf_dbdes_hdrlen(struct ospf_proto *p)
43
{
44
  return ospf_is_v2(p) ?
45
    sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
46
}
47

    
48

    
49
static void
50
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
51
                struct ospf_lsa_header **body, uint *count)
52
{
53
  uint plen = ntohs(pkt->length);
54
  uint hlen = ospf_dbdes_hdrlen(p);
55

    
56
  *body = ((void *) pkt) + hlen;
57
  *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
58
}
59

    
60
static void
61
ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
62
{
63
  struct ospf_lsa_header *lsas;
64
  uint i, lsa_count;
65
  u32 pkt_ddseq;
66
  u16 pkt_iface_mtu;
67
  u8 pkt_imms;
68

    
69
  ASSERT(pkt->type == DBDES_P);
70
  ospf_dump_common(p, pkt);
71

    
72
  if (ospf_is_v2(p))
73
  {
74
    struct ospf_dbdes2_packet *ps = (void *) pkt;
75
    pkt_iface_mtu = ntohs(ps->iface_mtu);
76
    pkt_imms = ps->imms;
77
    pkt_ddseq = ntohl(ps->ddseq);
78
  }
79
  else /* OSPFv3 */
80
  {
81
    struct ospf_dbdes3_packet *ps = (void *) pkt;
82
    pkt_iface_mtu = ntohs(ps->iface_mtu);
83
    pkt_imms = ps->imms;
84
    pkt_ddseq = ntohl(ps->ddseq);
85
  }
86

    
87
  log(L_TRACE "%s:     mtu      %u", p->p.name, pkt_iface_mtu);
88
  log(L_TRACE "%s:     imms     %s%s%s", p->p.name,
89
      (pkt_imms & DBDES_I) ? "I " : "",
90
      (pkt_imms & DBDES_M) ? "M " : "",
91
      (pkt_imms & DBDES_MS) ? "MS" : "");
92
  log(L_TRACE "%s:     ddseq    %u", p->p.name, pkt_ddseq);
93

    
94
  ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
95
  for (i = 0; i < lsa_count; i++)
96
    ospf_dump_lsahdr(p, lsas + i);
97
}
98

    
99

    
100
static void
101
ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
102
{
103
  struct ospf_iface *ifa = n->ifa;
104
  struct ospf_packet *pkt;
105
  uint length;
106

    
107
  u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
108

    
109
  /* Update DBDES buffer */
110
  if (n->ldd_bsize != ifa->tx_length)
111
  {
112
    mb_free(n->ldd_buffer);
113
    n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
114
    n->ldd_bsize = ifa->tx_length;
115
  }
116

    
117
  pkt = n->ldd_buffer;
118
  ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
119

    
120
  if (ospf_is_v2(p))
121
  {
122
    struct ospf_dbdes2_packet *ps = (void *) pkt;
123
    ps->iface_mtu = htons(iface_mtu);
124
    ps->options = ifa->oa->options;
125
    ps->imms = 0;        /* Will be set later */
126
    ps->ddseq = htonl(n->dds);
127
    length = sizeof(struct ospf_dbdes2_packet);
128
  }
129
  else /* OSPFv3 */
130
  {
131
    struct ospf_dbdes3_packet *ps = (void *) pkt;
132
    ps->options = htonl(ifa->oa->options);
133
    ps->iface_mtu = htons(iface_mtu);
134
    ps->padding = 0;
135
    ps->imms = 0;        /* Will be set later */
136
    ps->ddseq = htonl(n->dds);
137
    length = sizeof(struct ospf_dbdes3_packet);
138
  }
139

    
140
  /* Prepare DBDES body */
141
  if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
142
  {
143
    struct ospf_lsa_header *lsas;
144
    struct top_hash_entry *en;
145
    uint i = 0, lsa_max;
146

    
147
    ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
148
    en = (void *) s_get(&(n->dbsi));
149

    
150
    while (i < lsa_max)
151
    {
152
      if (!SNODE_VALID(en))
153
      {
154
        n->myimms &= ~DBDES_M;        /* Unset More bit */
155
        break;
156
      }
157

    
158
      if ((en->lsa.age < LSA_MAXAGE) &&
159
          lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
160
      {
161
        lsa_hton_hdr(&(en->lsa), lsas + i);
162
        i++;
163
      }
164

    
165
      en = SNODE_NEXT(en);
166
    }
167

    
168
    s_put(&(n->dbsi), SNODE en);
169

    
170
    length += i * sizeof(struct ospf_lsa_header);
171
  }
172

    
173
  if (ospf_is_v2(p))
174
    ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
175
  else
176
    ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
177

    
178
  pkt->length = htons(length);
179
}
180

    
181
static void
182
ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
183
{
184
  struct ospf_iface *ifa = n->ifa;
185

    
186
  OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
187
              "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
188
  sk_set_tbuf(ifa->sk, n->ldd_buffer);
189
  ospf_send_to(ifa, n->ip);
190
  sk_set_tbuf(ifa->sk, NULL);
191
}
192

    
193
/**
194
 * ospf_send_dbdes - transmit database description packet
195
 * @n: neighbor
196
 *
197
 * Sending of a database description packet is described in 10.8 of RFC 2328.
198
 * Reception of each packet is acknowledged in the sequence number of another.
199
 * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
200
 * does not reply, I don't create a new packet but just send the content
201
 * of the buffer.
202
 */
203
void
204
ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
205
{
206
  /* RFC 2328 10.8 */
207

    
208
  ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
209

    
210
  if (n->ifa->oa->rt == NULL)
211
    return;
212

    
213
  ospf_prepare_dbdes(p, n);
214
  ospf_do_send_dbdes(p, n);
215
}
216

    
217
void
218
ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
219
{
220
  ASSERT(n->state > NEIGHBOR_EXSTART);
221

    
222
  if (!n->ldd_buffer)
223
  {
224
    log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
225
    ospf_neigh_sm(n, INM_SEQMIS);
226
    return;
227
  }
228

    
229
  /* Send last packet */
230
  ospf_do_send_dbdes(p, n);
231
}
232

    
233
static int
234
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
235
{
236
  struct ospf_iface *ifa = n->ifa;
237
  struct ospf_lsa_header *lsas, lsa;
238
  struct top_hash_entry *en, *req;
239
  const char *err_dsc = NULL;
240
  u32 lsa_type, lsa_domain;
241
  uint i, lsa_count;
242

    
243
  ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
244

    
245
  for (i = 0; i < lsa_count; i++)
246
  {
247
    lsa_ntoh_hdr(lsas + i, &lsa);
248
    lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
249

    
250
    /* RFC 2328 10.6 and RFC 5340 4.2.2 */
251

    
252
    if (!lsa_type)
253
      DROP1("LSA of unknown type");
254

    
255
    if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
256
      DROP1("LSA with AS scope in stub area");
257

    
258
    /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
259
    if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
260
      DROP1("rt-summary-LSA in stub area");
261

    
262
    /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
263
    if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
264
      DROP1("LSA with invalid scope");
265

    
266
    en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
267
    if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
268
    {
269
      /* This should be splitted to ospf_lsa_lsrq_up() */
270
      req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
271

    
272
      if (!SNODE_VALID(req))
273
        s_add_tail(&n->lsrql, SNODE req);
274

    
275
      if (!SNODE_VALID(n->lsrqi))
276
        n->lsrqi = req;
277

    
278
      req->lsa = lsa;
279
      req->lsa_body = LSA_BODY_DUMMY;
280

    
281
      if (!tm_active(n->lsrq_timer))
282
        tm_start(n->lsrq_timer, 0);
283
    }
284
  }
285

    
286
  return 0;
287

    
288
drop:
289
  LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
290
  LOG_LSA2("  received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
291

    
292
  ospf_neigh_sm(n, INM_SEQMIS);
293
  return -1;
294
}
295

    
296
void
297
ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
298
                   struct ospf_neighbor *n)
299
{
300
  struct ospf_proto *p = ifa->oa->po;
301
  const char *err_dsc = NULL;
302
  u32 rcv_ddseq, rcv_options;
303
  u16 rcv_iface_mtu;
304
  u8 rcv_imms;
305
  uint plen, err_val = 0;
306

    
307
  /* RFC 2328 10.6 */
308

    
309
  plen = ntohs(pkt->length);
310
  if (plen < ospf_dbdes_hdrlen(p))
311
  {
312
    LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
313
    return;
314
  }
315

    
316
  OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
317

    
318
  ospf_neigh_sm(n, INM_HELLOREC);
319

    
320
  if (ospf_is_v2(p))
321
  {
322
    struct ospf_dbdes2_packet *ps = (void *) pkt;
323
    rcv_iface_mtu = ntohs(ps->iface_mtu);
324
    rcv_options = ps->options;
325
    rcv_imms = ps->imms;
326
    rcv_ddseq = ntohl(ps->ddseq);
327
  }
328
  else /* OSPFv3 */
329
  {
330
    struct ospf_dbdes3_packet *ps = (void *) pkt;
331
    rcv_options = ntohl(ps->options);
332
    rcv_iface_mtu = ntohs(ps->iface_mtu);
333
    rcv_imms = ps->imms;
334
    rcv_ddseq = ntohl(ps->ddseq);
335
  }
336

    
337
  switch (n->state)
338
  {
339
  case NEIGHBOR_DOWN:
340
  case NEIGHBOR_ATTEMPT:
341
  case NEIGHBOR_2WAY:
342
    OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
343
    return;
344

    
345
  case NEIGHBOR_INIT:
346
    ospf_neigh_sm(n, INM_2WAYREC);
347
    if (n->state != NEIGHBOR_EXSTART)
348
      return;
349

    
350
  case NEIGHBOR_EXSTART:
351
    if ((ifa->type != OSPF_IT_VLINK) &&
352
        (rcv_iface_mtu != ifa->iface->mtu) &&
353
        (rcv_iface_mtu != 0) &&
354
        (ifa->iface->mtu != 0))
355
      LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
356
                   n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
357

    
358
    if ((rcv_imms == DBDES_IMMS) &&
359
        (n->rid > p->router_id) &&
360
        (plen == ospf_dbdes_hdrlen(p)))
361
    {
362
      /* I'm slave! */
363
      n->dds = rcv_ddseq;
364
      n->ddr = rcv_ddseq;
365
      n->options = rcv_options;
366
      n->myimms &= ~DBDES_MS;
367
      n->imms = rcv_imms;
368
      tm_stop(n->dbdes_timer);
369
      ospf_neigh_sm(n, INM_NEGDONE);
370
      ospf_send_dbdes(p, n);
371
      break;
372
    }
373

    
374
    if (!(rcv_imms & DBDES_I) &&
375
        !(rcv_imms & DBDES_MS) &&
376
        (n->rid < p->router_id) &&
377
        (n->dds == rcv_ddseq))
378
    {
379
      /* I'm master! */
380
      n->options = rcv_options;
381
      n->ddr = rcv_ddseq - 1;        /* It will be set corectly a few lines down */
382
      n->imms = rcv_imms;
383
      ospf_neigh_sm(n, INM_NEGDONE);
384
      /* Continue to the NEIGHBOR_EXCHANGE case */
385
    }
386
    else
387
    {
388
      DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
389
      break;
390
    }
391

    
392
  case NEIGHBOR_EXCHANGE:
393
    if ((rcv_imms == n->imms) &&
394
        (rcv_options == n->options) &&
395
        (rcv_ddseq == n->ddr))
396
      goto duplicate;
397

    
398
    if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
399
      DROP("MS-bit mismatch", rcv_imms);
400

    
401
    if (rcv_imms & DBDES_I)
402
      DROP("I-bit mismatch", rcv_imms);
403

    
404
    if (rcv_options != n->options)
405
      DROP("options mismatch", rcv_options);
406

    
407
    n->ddr = rcv_ddseq;
408
    n->imms = rcv_imms;
409

    
410
    if (n->myimms & DBDES_MS)
411
    {
412
      /* MASTER */
413

    
414
      if (rcv_ddseq != n->dds)
415
        DROP("DD sequence number mismatch", rcv_ddseq);
416

    
417
      n->dds++;
418

    
419
      if (ospf_process_dbdes(p, pkt, n) < 0)
420
        return;
421

    
422
      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
423
      {
424
        tm_stop(n->dbdes_timer);
425
        ospf_neigh_sm(n, INM_EXDONE);
426
        break;
427
      }
428

    
429
      ospf_send_dbdes(p, n);
430
      tm_start(n->dbdes_timer, n->ifa->rxmtint);
431
    }
432
    else
433
    {
434
      /* SLAVE */
435

    
436
      if (rcv_ddseq != (n->dds + 1))
437
        DROP("DD sequence number mismatch", rcv_ddseq);
438

    
439
      n->ddr = rcv_ddseq;
440
      n->dds = rcv_ddseq;
441

    
442
      if (ospf_process_dbdes(p, pkt, n) < 0)
443
        return;
444

    
445
      ospf_send_dbdes(p, n);
446

    
447
      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
448
        ospf_neigh_sm(n, INM_EXDONE);
449
    }
450
    break;
451

    
452
  case NEIGHBOR_LOADING:
453
  case NEIGHBOR_FULL:
454
    if ((rcv_imms == n->imms) &&
455
        (rcv_options == n->options) &&
456
        (rcv_ddseq == n->ddr))
457
      goto duplicate;
458

    
459
    DROP("too late for DD exchange", n->state);
460

    
461
  default:
462
    bug("Undefined interface state");
463
  }
464
  return;
465

    
466
duplicate:
467
  OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
468

    
469
  /* Slave should retransmit DBDES packet */
470
  if (!(n->myimms & DBDES_MS))
471
    ospf_rxmt_dbdes(p, n);
472
  return;
473

    
474
drop:
475
  LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
476
          n->rid, ifa->ifname, err_dsc, err_val);
477

    
478
  ospf_neigh_sm(n, INM_SEQMIS);
479
  return;
480
}