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