~ubuntu-branches/ubuntu/warty/quagga/warty

« back to all changes in this revision

Viewing changes to isisd/isis_dr.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2004-06-29 09:50:59 UTC
  • Revision ID: james.westby@ubuntu.com-20040629095059-px1m2m108z4qw1mr
Tags: upstream-0.96.5
ImportĀ upstreamĀ versionĀ 0.96.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * IS-IS Rout(e)ing protocol - isis_dr.c
 
3
 *                             IS-IS designated router related routines   
 
4
 *
 
5
 * Copyright (C) 2001,2002   Sampo Saaristo
 
6
 *                           Tampere University of Technology      
 
7
 *                           Institute of Communications Engineering
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify it 
 
10
 * under the terms of the GNU General Public Licenseas published by the Free 
 
11
 * Software Foundation; either version 2 of the License, or (at your option) 
 
12
 * any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,but WITHOUT 
 
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 
16
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
 
17
 * more details.
 
18
 
 
19
 * You should have received a copy of the GNU General Public License along 
 
20
 * with this program; if not, write to the Free Software Foundation, Inc., 
 
21
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
22
 */
 
23
 
 
24
 
 
25
#include <zebra.h>
 
26
#include <net/ethernet.h>
 
27
 
 
28
#include "log.h"
 
29
#include "hash.h"
 
30
#include "thread.h"
 
31
#include "linklist.h"
 
32
#include "vty.h"
 
33
#include "stream.h"
 
34
#include "if.h"
 
35
 
 
36
#include "isisd/dict.h"
 
37
#include "isisd/isis_constants.h"
 
38
#include "isisd/isis_common.h"
 
39
#include "isisd/isis_misc.h"
 
40
#include "isisd/isis_flags.h"
 
41
#include "isisd/isis_circuit.h"
 
42
#include "isisd/isisd.h"
 
43
#include "isisd/isis_adjacency.h"
 
44
#include "isisd/isis_constants.h"
 
45
#include "isisd/isis_pdu.h"
 
46
#include "isisd/isis_tlv.h"
 
47
#include "isisd/isis_lsp.h"
 
48
#include "isisd/isis_dr.h"
 
49
#include "isisd/isis_events.h"
 
50
 
 
51
extern struct isis *isis;
 
52
extern struct thread_master *master;
 
53
 
 
54
char *
 
55
isis_disflag2string (int disflag) {
 
56
 
 
57
  switch (disflag) {
 
58
    case ISIS_IS_NOT_DIS:
 
59
      return "is not DIS";
 
60
    case ISIS_IS_DIS:
 
61
      return "is DIS";
 
62
    case ISIS_WAS_DIS:
 
63
      return "was DIS";
 
64
  default:
 
65
    return "unknown DIS state";
 
66
  }
 
67
  return NULL; /* not reached */
 
68
}
 
69
 
 
70
 
 
71
 
 
72
int
 
73
isis_run_dr_l1 (struct thread *thread)
 
74
{
 
75
  struct isis_circuit *circuit;
 
76
  
 
77
  circuit = THREAD_ARG (thread);
 
78
  assert (circuit);
 
79
 
 
80
  if (circuit->u.bc.run_dr_elect[0])
 
81
    zlog_warn ("isis_run_dr(): run_dr_elect already set for l1");
 
82
  
 
83
  circuit->u.bc.t_run_dr[0] = NULL;
 
84
  circuit->u.bc.run_dr_elect[0] = 1;
 
85
    
 
86
  return ISIS_OK;
 
87
}
 
88
 
 
89
int
 
90
isis_run_dr_l2 (struct thread *thread)
 
91
{
 
92
  struct isis_circuit *circuit;
 
93
  
 
94
  circuit = THREAD_ARG (thread);
 
95
  assert (circuit);
 
96
 
 
97
  if (circuit->u.bc.run_dr_elect[1])
 
98
    zlog_warn ("isis_run_dr(): run_dr_elect already set for l2");
 
99
  
 
100
  
 
101
  circuit->u.bc.t_run_dr[1] = NULL; 
 
102
  circuit->u.bc.run_dr_elect[1] = 1;
 
103
    
 
104
  return ISIS_OK;
 
105
}
 
106
 
 
107
int
 
108
isis_check_dr_change (struct isis_adjacency *adj, int level)
 
109
{
 
110
  int i;
 
111
 
 
112
  if ( adj->dis_record[level-1].dis != 
 
113
       adj->dis_record[(1*ISIS_LEVELS) + level - 1].dis) 
 
114
    /* was there a DIS state transition ? */ 
 
115
    {
 
116
      adj->dischanges[level-1]++;
 
117
      /* ok rotate the history list through */
 
118
      for (i = DIS_RECORDS - 1; i > 0; i--) 
 
119
        {
 
120
          adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = 
 
121
            adj->dis_record[((i-1) * ISIS_LEVELS) + level - 1].dis;
 
122
          adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change = 
 
123
            adj->dis_record[((i-1) * ISIS_LEVELS) + level - 1].last_dis_change;
 
124
        }
 
125
    }
 
126
  return ISIS_OK;
 
127
}
 
128
 
 
129
int 
 
130
isis_dr_elect (struct isis_circuit *circuit, int level)
 
131
{
 
132
  struct list *adjdb;
 
133
  struct listnode *node;
 
134
  struct isis_adjacency *adj, *adj_dr = NULL;
 
135
  struct list *list = list_new ();
 
136
  u_char own_prio;
 
137
  int biggest_prio = -1;
 
138
  int cmp_res, retval = ISIS_OK;
 
139
  
 
140
  own_prio = circuit->u.bc.priority[level - 1];
 
141
  adjdb = circuit->u.bc.adjdb[level - 1];
 
142
 
 
143
  if (!adjdb) {
 
144
    zlog_warn ("isis_dr_elect() adjdb == NULL");
 
145
    retval = ISIS_WARNING;
 
146
    list_delete (list);
 
147
    goto out;
 
148
  }
 
149
  isis_adj_build_up_list (adjdb, list);
 
150
 
 
151
  /*
 
152
   * Loop the adjacencies and find the one with the biggest priority
 
153
   */
 
154
  for (node = listhead (list); node; nextnode (node)) {
 
155
    adj = getdata (node);
 
156
    /* clear flag for show output */
 
157
    adj->dis_record[level-1].dis = ISIS_IS_NOT_DIS;  
 
158
    adj->dis_record[level-1].last_dis_change = time (NULL);
 
159
 
 
160
    if (adj->prio[level-1] > biggest_prio) {
 
161
      biggest_prio = adj->prio[level-1];
 
162
      adj_dr = adj;
 
163
    } else if (adj->prio[level-1] == biggest_prio) {
 
164
      /*
 
165
       * Comparison of MACs breaks a tie
 
166
       */
 
167
      if (adj_dr) {
 
168
        cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN);
 
169
        if (cmp_res < 0) {
 
170
          adj_dr = adj;
 
171
        }
 
172
        if (cmp_res == 0)
 
173
          zlog_warn ("isis_dr_elect(): multiple adjacencies with same SNPA"); 
 
174
      } else {
 
175
        adj_dr = adj;
 
176
      }
 
177
    }
 
178
  }
 
179
  
 
180
  if (!adj_dr) {
 
181
    /*
 
182
     * Could not find the DR - means we are alone and thus the DR
 
183
     */
 
184
    if ( !circuit->u.bc.is_dr[level - 1]) {
 
185
      list_delete (list);
 
186
      list = NULL;
 
187
      return isis_dr_commence (circuit, level);
 
188
    }
 
189
    goto out;
 
190
  }
 
191
 
 
192
  /*
 
193
   * Now we have the DR adjacency, compare it to self
 
194
   */
 
195
  if (adj_dr->prio[level-1] < own_prio || (adj_dr->prio[level-1] == own_prio &&
 
196
                                  memcmp (adj_dr->snpa, circuit->u.bc.snpa, 
 
197
                                          ETH_ALEN) < 0)) {
 
198
    if (!circuit->u.bc.is_dr[level - 1]) {
 
199
      /*
 
200
       * We are the DR -> commence
 
201
       */
 
202
      list_delete (list);
 
203
      return isis_dr_commence (circuit, level);
 
204
    }
 
205
  } else {
 
206
 
 
207
    /* ok we have found the DIS - lets mark the adjacency */
 
208
    /* set flag for show output */
 
209
    adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS; 
 
210
    adj_dr->dis_record[level - 1].last_dis_change = time(NULL);
 
211
 
 
212
    /* now loop through a second time to check if there has been a DIS change
 
213
     * if yes rotate the history log
 
214
     */
 
215
 
 
216
    for (node = listhead (list); node; nextnode (node)) {
 
217
      adj = getdata (node);
 
218
      isis_check_dr_change(adj, level);
 
219
    }
 
220
 
 
221
    /*
 
222
     * We are not DR - if we were -> resign
 
223
     */
 
224
 
 
225
    if (circuit->u.bc.is_dr[level - 1]) {
 
226
      list_delete (list);
 
227
      return isis_dr_resign (circuit, level);
 
228
    }
 
229
  }
 
230
 out:
 
231
  if (list)
 
232
    list_delete (list);
 
233
  return retval;
 
234
}
 
235
 
 
236
int 
 
237
isis_dr_resign (struct isis_circuit *circuit, int level)
 
238
{
 
239
  u_char id[ISIS_SYS_ID_LEN + 2];
 
240
      
 
241
  zlog_info ("isis_dr_resign l%d", level);
 
242
 
 
243
  circuit->u.bc.is_dr[level - 1] = 0;
 
244
  circuit->u.bc.run_dr_elect[level - 1] = 0; 
 
245
  THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[level - 1]);
 
246
  THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
 
247
  
 
248
  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
 
249
  LSP_PSEUDO_ID(id) = circuit->circuit_id;
 
250
  LSP_FRAGMENT(id) = 0;
 
251
  lsp_purge_dr (id, circuit, level);
 
252
 
 
253
  if (level == 1) {
 
254
    memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
 
255
    
 
256
    THREAD_TIMER_OFF(circuit->t_send_csnp[0]);
 
257
    
 
258
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
 
259
        circuit, 2 * circuit->hello_interval[1]);
 
260
    
 
261
    THREAD_TIMER_ON(master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
 
262
        isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER));
 
263
  } else {
 
264
    memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
 
265
 
 
266
    THREAD_TIMER_OFF(circuit->t_send_csnp[1]);
 
267
 
 
268
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
 
269
        circuit, 2 * circuit->hello_interval[1]);
 
270
    
 
271
    THREAD_TIMER_ON(master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
 
272
        isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER));
 
273
  }
 
274
  
 
275
  thread_add_event (master, isis_event_dis_status_change, circuit, 0);
 
276
 
 
277
  return ISIS_OK;
 
278
}
 
279
 
 
280
int 
 
281
isis_dr_commence (struct isis_circuit *circuit, int level)
 
282
{
 
283
  u_char old_dr[ISIS_SYS_ID_LEN + 2];
 
284
  
 
285
  zlog_info ("isis_dr_commence l%d", level);
 
286
 
 
287
  /* Lets keep a pause in DR election */
 
288
  circuit->u.bc.run_dr_elect[level - 1] = 0;
 
289
  if (level == 1) 
 
290
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
 
291
        circuit, 2 * circuit->hello_multiplier[0] * 
 
292
                        circuit->hello_interval[0]); 
 
293
  else 
 
294
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
 
295
        circuit, 2 * circuit->hello_multiplier[1] *
 
296
                        circuit->hello_interval[1]);            
 
297
  circuit->u.bc.is_dr[level - 1] = 1;
 
298
 
 
299
  if (level == 1) {
 
300
    memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
 
301
    LSP_FRAGMENT (old_dr) = 0;
 
302
    if (LSP_PSEUDO_ID(old_dr)) {
 
303
      /* there was a dr elected, purge its LSPs from the db */
 
304
      lsp_purge_dr (old_dr, circuit, level);
 
305
    }
 
306
    memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
 
307
    *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
 
308
    
 
309
    assert (circuit->circuit_id); /* must be non-zero */
 
310
    /*    if (circuit->t_send_l1_psnp)
 
311
          thread_cancel (circuit->t_send_l1_psnp); */
 
312
    lsp_l1_pseudo_generate (circuit);
 
313
 
 
314
    THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[0]); 
 
315
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
 
316
        circuit, 2 * circuit->hello_interval[0]);
 
317
    
 
318
    THREAD_TIMER_ON(master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
 
319
        isis_jitter(circuit->csnp_interval[level-1], CSNP_JITTER));
 
320
    
 
321
  } else {
 
322
    memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
 
323
    LSP_FRAGMENT (old_dr) = 0;
 
324
    if (LSP_PSEUDO_ID(old_dr)) {
 
325
      /* there was a dr elected, purge its LSPs from the db */
 
326
      lsp_purge_dr (old_dr, circuit, level);
 
327
    }
 
328
    memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
 
329
    *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
 
330
    
 
331
    assert (circuit->circuit_id); /* must be non-zero */
 
332
    /*    if (circuit->t_send_l1_psnp)
 
333
          thread_cancel (circuit->t_send_l1_psnp); */
 
334
    lsp_l2_pseudo_generate (circuit);
 
335
 
 
336
    THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[1]);
 
337
    THREAD_TIMER_ON(master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
 
338
        circuit, 2 * circuit->hello_interval[1]);
 
339
        
 
340
    THREAD_TIMER_ON(master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
 
341
        isis_jitter (circuit->csnp_interval[level-1], CSNP_JITTER));
 
342
  } 
 
343
 
 
344
  thread_add_event (master, isis_event_dis_status_change, circuit, 0);
 
345
  
 
346
  return ISIS_OK;
 
347
}
 
348