]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
16f1b9ee | 2 | * This is an implementation of RFC3630 |
718e3744 | 3 | * Copyright (C) 2001 KDD R&D Laboratories, Inc. |
4 | * http://www.kddlabs.co.jp/ | |
5 | * | |
16f1b9ee OD |
6 | * Copyright (C) 2012 Orange Labs |
7 | * http://www.orange.com | |
8 | * | |
718e3744 | 9 | * This file is part of GNU Zebra. |
10 | * | |
11 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2, or (at your option) any | |
14 | * later version. | |
896014f4 | 15 | * |
718e3744 | 16 | * GNU Zebra is distributed in the hope that it will be useful, but |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
896014f4 DL |
21 | * You should have received a copy of the GNU General Public License along |
22 | * with this program; see the file COPYING; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
718e3744 | 24 | */ |
25 | ||
16f1b9ee OD |
26 | /* Add support of RFC7471 */ |
27 | /* Add support of RFC5392, RFC6827 */ | |
718e3744 | 28 | |
29 | #include <zebra.h> | |
16f1b9ee | 30 | #include <math.h> |
718e3744 | 31 | |
718e3744 | 32 | #include "linklist.h" |
33 | #include "prefix.h" | |
b2d7c082 | 34 | #include "vrf.h" |
718e3744 | 35 | #include "if.h" |
36 | #include "table.h" | |
37 | #include "memory.h" | |
38 | #include "command.h" | |
39 | #include "vty.h" | |
40 | #include "stream.h" | |
41 | #include "log.h" | |
42 | #include "thread.h" | |
43 | #include "hash.h" | |
d62a17ae | 44 | #include "sockunion.h" /* for inet_aton() */ |
16f1b9ee | 45 | #include "network.h" |
718e3744 | 46 | |
47 | #include "ospfd/ospfd.h" | |
48 | #include "ospfd/ospf_interface.h" | |
49 | #include "ospfd/ospf_ism.h" | |
50 | #include "ospfd/ospf_asbr.h" | |
51 | #include "ospfd/ospf_lsa.h" | |
52 | #include "ospfd/ospf_lsdb.h" | |
53 | #include "ospfd/ospf_neighbor.h" | |
54 | #include "ospfd/ospf_nsm.h" | |
55 | #include "ospfd/ospf_flood.h" | |
56 | #include "ospfd/ospf_packet.h" | |
57 | #include "ospfd/ospf_spf.h" | |
58 | #include "ospfd/ospf_dump.h" | |
59 | #include "ospfd/ospf_route.h" | |
60 | #include "ospfd/ospf_ase.h" | |
61 | #include "ospfd/ospf_zebra.h" | |
62 | #include "ospfd/ospf_te.h" | |
16f1b9ee | 63 | #include "ospfd/ospf_vty.h" |
718e3744 | 64 | |
65 | /* | |
66 | * Global variable to manage Opaque-LSA/MPLS-TE on this node. | |
67 | * Note that all parameter values are stored in network byte order. | |
68 | */ | |
16f1b9ee | 69 | struct ospf_mpls_te OspfMplsTE; |
718e3744 | 70 | |
ead99d5f | 71 | const char *mode2text[] = {"Off", "AS", "Area"}; |
718e3744 | 72 | |
73 | /*------------------------------------------------------------------------* | |
74 | * Followings are initialize/terminate functions for MPLS-TE handling. | |
75 | *------------------------------------------------------------------------*/ | |
76 | ||
d62a17ae | 77 | static int ospf_mpls_te_new_if(struct interface *ifp); |
78 | static int ospf_mpls_te_del_if(struct interface *ifp); | |
79 | static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_status); | |
80 | static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_status); | |
81 | static void ospf_mpls_te_config_write_router(struct vty *vty); | |
82 | static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa); | |
83 | static int ospf_mpls_te_lsa_originate_area(void *arg); | |
84 | static int ospf_mpls_te_lsa_originate_as(void *arg); | |
85 | static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa); | |
86 | ||
87 | static void del_mpls_te_link(void *val); | |
88 | static void ospf_mpls_te_register_vty(void); | |
89 | ||
90 | int ospf_mpls_te_init(void) | |
91 | { | |
92 | int rc; | |
93 | ||
94 | rc = ospf_register_opaque_functab( | |
95 | OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
96 | ospf_mpls_te_new_if, ospf_mpls_te_del_if, | |
97 | ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, | |
718e3744 | 98 | ospf_mpls_te_config_write_router, |
d62a17ae | 99 | NULL, /*ospf_mpls_te_config_write_if */ |
100 | NULL, /* ospf_mpls_te_config_write_debug */ | |
101 | ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate_area, | |
102 | ospf_mpls_te_lsa_refresh, NULL, /* ospf_mpls_te_new_lsa_hook */ | |
718e3744 | 103 | NULL /* ospf_mpls_te_del_lsa_hook */); |
d62a17ae | 104 | if (rc != 0) { |
105 | zlog_warn( | |
106 | "ospf_mpls_te_init: Failed to register Traffic Engineering functions"); | |
ead99d5f | 107 | return rc; |
d62a17ae | 108 | } |
718e3744 | 109 | |
d62a17ae | 110 | memset(&OspfMplsTE, 0, sizeof(struct ospf_mpls_te)); |
32ab5cf4 | 111 | OspfMplsTE.enabled = false; |
ead99d5f | 112 | OspfMplsTE.inter_as = Off; |
d62a17ae | 113 | OspfMplsTE.iflist = list_new(); |
114 | OspfMplsTE.iflist->del = del_mpls_te_link; | |
718e3744 | 115 | |
d62a17ae | 116 | ospf_mpls_te_register_vty(); |
718e3744 | 117 | |
d62a17ae | 118 | return rc; |
718e3744 | 119 | } |
120 | ||
16f1b9ee | 121 | /* Additional register for RFC5392 support */ |
d62a17ae | 122 | static int ospf_mpls_te_register(enum inter_as_mode mode) |
16f1b9ee | 123 | { |
ead99d5f | 124 | int rc = 0; |
d62a17ae | 125 | u_int8_t scope; |
16f1b9ee | 126 | |
ead99d5f OD |
127 | if (OspfMplsTE.inter_as != Off) |
128 | return rc; | |
16f1b9ee | 129 | |
d62a17ae | 130 | if (mode == AS) |
131 | scope = OSPF_OPAQUE_AS_LSA; | |
132 | else | |
133 | scope = OSPF_OPAQUE_AREA_LSA; | |
16f1b9ee | 134 | |
d62a17ae | 135 | rc = ospf_register_opaque_functab(scope, OPAQUE_TYPE_INTER_AS_LSA, NULL, |
136 | NULL, NULL, NULL, NULL, NULL, NULL, | |
137 | ospf_mpls_te_show_info, | |
138 | ospf_mpls_te_lsa_originate_as, | |
139 | ospf_mpls_te_lsa_refresh, NULL, NULL); | |
16f1b9ee | 140 | |
d62a17ae | 141 | if (rc != 0) { |
142 | zlog_warn( | |
143 | "ospf_router_info_init: Failed to register Inter-AS functions"); | |
144 | return rc; | |
145 | } | |
16f1b9ee | 146 | |
ead99d5f | 147 | return rc; |
16f1b9ee OD |
148 | } |
149 | ||
d62a17ae | 150 | static int ospf_mpls_te_unregister() |
16f1b9ee | 151 | { |
d62a17ae | 152 | u_int8_t scope; |
16f1b9ee | 153 | |
ead99d5f | 154 | if (OspfMplsTE.inter_as == Off) |
d62a17ae | 155 | return 0; |
16f1b9ee | 156 | |
d62a17ae | 157 | if (OspfMplsTE.inter_as == AS) |
158 | scope = OSPF_OPAQUE_AS_LSA; | |
159 | else | |
160 | scope = OSPF_OPAQUE_AREA_LSA; | |
16f1b9ee | 161 | |
d62a17ae | 162 | ospf_delete_opaque_functab(scope, OPAQUE_TYPE_INTER_AS_LSA); |
16f1b9ee | 163 | |
d62a17ae | 164 | return 0; |
16f1b9ee OD |
165 | } |
166 | ||
d62a17ae | 167 | void ospf_mpls_te_term(void) |
718e3744 | 168 | { |
d62a17ae | 169 | list_delete(OspfMplsTE.iflist); |
170 | OspfMplsTE.iflist = NULL; | |
718e3744 | 171 | |
d62a17ae | 172 | ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, |
173 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); | |
32ab5cf4 | 174 | OspfMplsTE.enabled = false; |
16f1b9ee | 175 | |
d62a17ae | 176 | ospf_mpls_te_unregister(); |
ead99d5f | 177 | OspfMplsTE.inter_as = Off; |
16f1b9ee | 178 | |
d62a17ae | 179 | return; |
718e3744 | 180 | } |
181 | ||
182 | /*------------------------------------------------------------------------* | |
183 | * Followings are control functions for MPLS-TE parameters management. | |
184 | *------------------------------------------------------------------------*/ | |
185 | ||
d62a17ae | 186 | static void del_mpls_te_link(void *val) |
718e3744 | 187 | { |
d62a17ae | 188 | XFREE(MTYPE_OSPF_MPLS_TE, val); |
189 | return; | |
718e3744 | 190 | } |
191 | ||
ead99d5f | 192 | static u_int32_t get_mpls_te_instance_value(void) |
718e3744 | 193 | { |
d62a17ae | 194 | static u_int32_t seqno = 0; |
718e3744 | 195 | |
d62a17ae | 196 | if (seqno < MAX_LEGAL_TE_INSTANCE_NUM) |
197 | seqno += 1; | |
198 | else | |
199 | seqno = 1; /* Avoid zero. */ | |
718e3744 | 200 | |
d62a17ae | 201 | return seqno; |
718e3744 | 202 | } |
203 | ||
d62a17ae | 204 | static struct mpls_te_link *lookup_linkparams_by_ifp(struct interface *ifp) |
718e3744 | 205 | { |
d62a17ae | 206 | struct listnode *node, *nnode; |
207 | struct mpls_te_link *lp; | |
718e3744 | 208 | |
d62a17ae | 209 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) |
210 | if (lp->ifp == ifp) | |
211 | return lp; | |
718e3744 | 212 | |
d62a17ae | 213 | return NULL; |
718e3744 | 214 | } |
215 | ||
d62a17ae | 216 | static struct mpls_te_link *lookup_linkparams_by_instance(struct ospf_lsa *lsa) |
718e3744 | 217 | { |
d62a17ae | 218 | struct listnode *node; |
219 | struct mpls_te_link *lp; | |
220 | unsigned int key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)); | |
718e3744 | 221 | |
d62a17ae | 222 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) |
223 | if (lp->instance == key) | |
224 | return lp; | |
718e3744 | 225 | |
d62a17ae | 226 | zlog_warn("lookup_linkparams_by_instance: Entry not found: key(%x)", |
227 | key); | |
228 | return NULL; | |
718e3744 | 229 | } |
230 | ||
d62a17ae | 231 | static void ospf_mpls_te_foreach_area(void (*func)(struct mpls_te_link *lp, |
2a39170c OD |
232 | enum lsa_opcode sched_opcode), |
233 | enum lsa_opcode sched_opcode) | |
718e3744 | 234 | { |
d62a17ae | 235 | struct listnode *node, *nnode; |
236 | struct listnode *node2; | |
237 | struct mpls_te_link *lp; | |
238 | struct ospf_area *area; | |
718e3744 | 239 | |
d62a17ae | 240 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { |
241 | /* Skip Inter-AS TEv2 Links */ | |
242 | if (IS_INTER_AS(lp->type)) | |
243 | continue; | |
244 | if ((area = lp->area) == NULL) | |
245 | continue; | |
32ab5cf4 OD |
246 | if (CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE)) |
247 | continue; | |
718e3744 | 248 | |
d62a17ae | 249 | if (func != NULL) |
250 | (*func)(lp, sched_opcode); | |
718e3744 | 251 | |
d62a17ae | 252 | for (node2 = listnextnode(node); node2; |
253 | node2 = listnextnode(node2)) | |
254 | if ((lp = listgetdata(node2)) != NULL) | |
255 | if (lp->area != NULL) | |
256 | if (IPV4_ADDR_SAME(&lp->area->area_id, | |
257 | &area->area_id)) | |
258 | SET_FLAG(lp->flags, | |
259 | LPFLG_LOOKUP_DONE); | |
260 | } | |
718e3744 | 261 | |
d62a17ae | 262 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) |
263 | if (lp->area != NULL) | |
264 | UNSET_FLAG(lp->flags, LPFLG_LOOKUP_DONE); | |
718e3744 | 265 | |
d62a17ae | 266 | return; |
718e3744 | 267 | } |
268 | ||
d62a17ae | 269 | static void set_mpls_te_router_addr(struct in_addr ipv4) |
718e3744 | 270 | { |
d62a17ae | 271 | OspfMplsTE.router_addr.header.type = htons(TE_TLV_ROUTER_ADDR); |
272 | OspfMplsTE.router_addr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
273 | OspfMplsTE.router_addr.value = ipv4; | |
274 | return; | |
718e3744 | 275 | } |
276 | ||
d62a17ae | 277 | static void set_linkparams_link_header(struct mpls_te_link *lp) |
718e3744 | 278 | { |
d62a17ae | 279 | u_int16_t length = 0; |
718e3744 | 280 | |
d62a17ae | 281 | /* TE_LINK_SUBTLV_LINK_TYPE */ |
282 | if (ntohs(lp->link_type.header.type) != 0) | |
283 | length += TLV_SIZE(&lp->link_type.header); | |
718e3744 | 284 | |
d62a17ae | 285 | /* TE_LINK_SUBTLV_LINK_ID */ |
286 | if (ntohs(lp->link_id.header.type) != 0) | |
287 | length += TLV_SIZE(&lp->link_id.header); | |
718e3744 | 288 | |
d62a17ae | 289 | /* TE_LINK_SUBTLV_LCLIF_IPADDR */ |
290 | if (lp->lclif_ipaddr.header.type != 0) | |
291 | length += TLV_SIZE(&lp->lclif_ipaddr.header); | |
718e3744 | 292 | |
d62a17ae | 293 | /* TE_LINK_SUBTLV_RMTIF_IPADDR */ |
294 | if (lp->rmtif_ipaddr.header.type != 0) | |
295 | length += TLV_SIZE(&lp->rmtif_ipaddr.header); | |
718e3744 | 296 | |
d62a17ae | 297 | /* TE_LINK_SUBTLV_TE_METRIC */ |
298 | if (ntohs(lp->te_metric.header.type) != 0) | |
299 | length += TLV_SIZE(&lp->te_metric.header); | |
718e3744 | 300 | |
d62a17ae | 301 | /* TE_LINK_SUBTLV_MAX_BW */ |
302 | if (ntohs(lp->max_bw.header.type) != 0) | |
303 | length += TLV_SIZE(&lp->max_bw.header); | |
718e3744 | 304 | |
d62a17ae | 305 | /* TE_LINK_SUBTLV_MAX_RSV_BW */ |
306 | if (ntohs(lp->max_rsv_bw.header.type) != 0) | |
307 | length += TLV_SIZE(&lp->max_rsv_bw.header); | |
718e3744 | 308 | |
d62a17ae | 309 | /* TE_LINK_SUBTLV_UNRSV_BW */ |
310 | if (ntohs(lp->unrsv_bw.header.type) != 0) | |
311 | length += TLV_SIZE(&lp->unrsv_bw.header); | |
718e3744 | 312 | |
d62a17ae | 313 | /* TE_LINK_SUBTLV_RSC_CLSCLR */ |
314 | if (ntohs(lp->rsc_clsclr.header.type) != 0) | |
315 | length += TLV_SIZE(&lp->rsc_clsclr.header); | |
316 | ||
317 | /* TE_LINK_SUBTLV_LLRI */ | |
318 | if (ntohs(lp->llri.header.type) != 0) | |
319 | length += TLV_SIZE(&lp->llri.header); | |
320 | ||
321 | /* TE_LINK_SUBTLV_RIP */ | |
322 | if (ntohs(lp->rip.header.type) != 0) | |
323 | length += TLV_SIZE(&lp->rip.header); | |
324 | ||
325 | /* TE_LINK_SUBTLV_RAS */ | |
326 | if (ntohs(lp->ras.header.type) != 0) | |
327 | length += TLV_SIZE(&lp->ras.header); | |
328 | ||
329 | /* TE_LINK_SUBTLV_LRRID */ | |
330 | if (ntohs(lp->lrrid.header.type) != 0) | |
331 | length += TLV_SIZE(&lp->lrrid.header); | |
332 | ||
333 | /* TE_LINK_SUBTLV_AV_DELAY */ | |
334 | if (ntohs(lp->av_delay.header.type) != 0) | |
335 | length += TLV_SIZE(&lp->av_delay.header); | |
336 | ||
337 | /* TE_LINK_SUBTLV_MM_DELAY */ | |
338 | if (ntohs(lp->mm_delay.header.type) != 0) | |
339 | length += TLV_SIZE(&lp->mm_delay.header); | |
340 | ||
341 | /* TE_LINK_SUBTLV_DELAY_VAR */ | |
342 | if (ntohs(lp->delay_var.header.type) != 0) | |
343 | length += TLV_SIZE(&lp->delay_var.header); | |
344 | ||
345 | /* TE_LINK_SUBTLV_PKT_LOSS */ | |
346 | if (ntohs(lp->pkt_loss.header.type) != 0) | |
347 | length += TLV_SIZE(&lp->pkt_loss.header); | |
348 | ||
349 | /* TE_LINK_SUBTLV_RES_BW */ | |
350 | if (ntohs(lp->res_bw.header.type) != 0) | |
351 | length += TLV_SIZE(&lp->res_bw.header); | |
352 | ||
353 | /* TE_LINK_SUBTLV_AVA_BW */ | |
354 | if (ntohs(lp->ava_bw.header.type) != 0) | |
355 | length += TLV_SIZE(&lp->ava_bw.header); | |
356 | ||
357 | /* TE_LINK_SUBTLV_USE_BW */ | |
358 | if (ntohs(lp->use_bw.header.type) != 0) | |
359 | length += TLV_SIZE(&lp->use_bw.header); | |
718e3744 | 360 | |
d62a17ae | 361 | lp->link_header.header.type = htons(TE_TLV_LINK); |
362 | lp->link_header.header.length = htons(length); | |
363 | ||
364 | return; | |
718e3744 | 365 | } |
d62a17ae | 366 | |
367 | static void set_linkparams_link_type(struct ospf_interface *oi, | |
368 | struct mpls_te_link *lp) | |
369 | { | |
370 | lp->link_type.header.type = htons(TE_LINK_SUBTLV_LINK_TYPE); | |
371 | lp->link_type.header.length = htons(TE_LINK_SUBTLV_TYPE_SIZE); | |
372 | ||
373 | switch (oi->type) { | |
374 | case OSPF_IFTYPE_POINTOPOINT: | |
375 | lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; | |
376 | break; | |
377 | case OSPF_IFTYPE_BROADCAST: | |
378 | case OSPF_IFTYPE_NBMA: | |
379 | lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; | |
380 | break; | |
381 | default: | |
382 | /* Not supported yet. */ /* XXX */ | |
383 | lp->link_type.header.type = htons(0); | |
384 | break; | |
385 | } | |
386 | return; | |
718e3744 | 387 | } |
d62a17ae | 388 | |
389 | static void set_linkparams_link_id(struct ospf_interface *oi, | |
390 | struct mpls_te_link *lp) | |
718e3744 | 391 | { |
d62a17ae | 392 | struct ospf_neighbor *nbr; |
393 | int done = 0; | |
718e3744 | 394 | |
d62a17ae | 395 | lp->link_id.header.type = htons(TE_LINK_SUBTLV_LINK_ID); |
396 | lp->link_id.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
718e3744 | 397 | |
d62a17ae | 398 | /* |
399 | * The Link ID is identical to the contents of the Link ID field | |
400 | * in the Router LSA for these link types. | |
401 | */ | |
402 | switch (oi->type) { | |
403 | case OSPF_IFTYPE_POINTOPOINT: | |
404 | /* Take the router ID of the neighbor. */ | |
405 | if ((nbr = ospf_nbr_lookup_ptop(oi)) | |
406 | && nbr->state == NSM_Full) { | |
407 | lp->link_id.value = nbr->router_id; | |
408 | done = 1; | |
409 | } | |
410 | break; | |
411 | case OSPF_IFTYPE_BROADCAST: | |
412 | case OSPF_IFTYPE_NBMA: | |
413 | /* Take the interface address of the designated router. */ | |
414 | if ((nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi))) == NULL) | |
415 | break; | |
718e3744 | 416 | |
d62a17ae | 417 | if (nbr->state == NSM_Full |
418 | || (IPV4_ADDR_SAME(&oi->address->u.prefix4, &DR(oi)) | |
419 | && ospf_nbr_count(oi, NSM_Full) > 0)) { | |
420 | lp->link_id.value = DR(oi); | |
421 | done = 1; | |
422 | } | |
423 | break; | |
424 | default: | |
425 | /* Not supported yet. */ /* XXX */ | |
426 | lp->link_id.header.type = htons(0); | |
427 | break; | |
428 | } | |
429 | ||
430 | if (!done) { | |
431 | struct in_addr mask; | |
432 | masklen2ip(oi->address->prefixlen, &mask); | |
433 | lp->link_id.value.s_addr = | |
434 | oi->address->u.prefix4.s_addr & mask.s_addr; | |
435 | } | |
436 | return; | |
718e3744 | 437 | } |
438 | ||
d62a17ae | 439 | static void set_linkparams_lclif_ipaddr(struct mpls_te_link *lp, |
440 | struct in_addr lclif) | |
16f1b9ee OD |
441 | { |
442 | ||
d62a17ae | 443 | lp->lclif_ipaddr.header.type = htons(TE_LINK_SUBTLV_LCLIF_IPADDR); |
444 | lp->lclif_ipaddr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
445 | lp->lclif_ipaddr.value[0] = lclif; | |
446 | return; | |
16f1b9ee OD |
447 | } |
448 | ||
d62a17ae | 449 | static void set_linkparams_rmtif_ipaddr(struct mpls_te_link *lp, |
450 | struct in_addr rmtif) | |
16f1b9ee OD |
451 | { |
452 | ||
d62a17ae | 453 | lp->rmtif_ipaddr.header.type = htons(TE_LINK_SUBTLV_RMTIF_IPADDR); |
454 | lp->rmtif_ipaddr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
455 | lp->rmtif_ipaddr.value[0] = rmtif; | |
456 | return; | |
16f1b9ee OD |
457 | } |
458 | ||
d62a17ae | 459 | static void set_linkparams_te_metric(struct mpls_te_link *lp, |
460 | u_int32_t te_metric) | |
718e3744 | 461 | { |
d62a17ae | 462 | lp->te_metric.header.type = htons(TE_LINK_SUBTLV_TE_METRIC); |
463 | lp->te_metric.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
464 | lp->te_metric.value = htonl(te_metric); | |
465 | return; | |
718e3744 | 466 | } |
467 | ||
d62a17ae | 468 | static void set_linkparams_max_bw(struct mpls_te_link *lp, float fp) |
718e3744 | 469 | { |
d62a17ae | 470 | lp->max_bw.header.type = htons(TE_LINK_SUBTLV_MAX_BW); |
471 | lp->max_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
472 | lp->max_bw.value = htonf(fp); | |
473 | return; | |
718e3744 | 474 | } |
475 | ||
d62a17ae | 476 | static void set_linkparams_max_rsv_bw(struct mpls_te_link *lp, float fp) |
718e3744 | 477 | { |
d62a17ae | 478 | lp->max_rsv_bw.header.type = htons(TE_LINK_SUBTLV_MAX_RSV_BW); |
479 | lp->max_rsv_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
480 | lp->max_rsv_bw.value = htonf(fp); | |
481 | return; | |
718e3744 | 482 | } |
483 | ||
d62a17ae | 484 | static void set_linkparams_unrsv_bw(struct mpls_te_link *lp, int priority, |
485 | float fp) | |
718e3744 | 486 | { |
d62a17ae | 487 | /* Note that TLV-length field is the size of array. */ |
488 | lp->unrsv_bw.header.type = htons(TE_LINK_SUBTLV_UNRSV_BW); | |
489 | lp->unrsv_bw.header.length = htons(TE_LINK_SUBTLV_UNRSV_SIZE); | |
490 | lp->unrsv_bw.value[priority] = htonf(fp); | |
491 | return; | |
718e3744 | 492 | } |
493 | ||
d62a17ae | 494 | static void set_linkparams_rsc_clsclr(struct mpls_te_link *lp, |
495 | u_int32_t classcolor) | |
718e3744 | 496 | { |
d62a17ae | 497 | lp->rsc_clsclr.header.type = htons(TE_LINK_SUBTLV_RSC_CLSCLR); |
498 | lp->rsc_clsclr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
499 | lp->rsc_clsclr.value = htonl(classcolor); | |
500 | return; | |
718e3744 | 501 | } |
502 | ||
d62a17ae | 503 | static void set_linkparams_inter_as(struct mpls_te_link *lp, |
504 | struct in_addr addr, u_int32_t as) | |
16f1b9ee OD |
505 | { |
506 | ||
d62a17ae | 507 | /* Set the Remote ASBR IP address and then the associated AS number */ |
508 | lp->rip.header.type = htons(TE_LINK_SUBTLV_RIP); | |
509 | lp->rip.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
510 | lp->rip.value = addr; | |
16f1b9ee | 511 | |
d62a17ae | 512 | lp->ras.header.type = htons(TE_LINK_SUBTLV_RAS); |
513 | lp->ras.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
514 | lp->ras.value = htonl(as); | |
16f1b9ee OD |
515 | } |
516 | ||
d62a17ae | 517 | static void unset_linkparams_inter_as(struct mpls_te_link *lp) |
16f1b9ee OD |
518 | { |
519 | ||
d62a17ae | 520 | /* Reset the Remote ASBR IP address and then the associated AS number */ |
521 | lp->rip.header.type = htons(0); | |
522 | lp->rip.header.length = htons(0); | |
523 | lp->rip.value.s_addr = htonl(0); | |
16f1b9ee | 524 | |
d62a17ae | 525 | lp->ras.header.type = htons(0); |
526 | lp->ras.header.length = htons(0); | |
527 | lp->ras.value = htonl(0); | |
16f1b9ee OD |
528 | } |
529 | ||
d62a17ae | 530 | void set_linkparams_llri(struct mpls_te_link *lp, u_int32_t local, |
531 | u_int32_t remote) | |
16f1b9ee OD |
532 | { |
533 | ||
d62a17ae | 534 | lp->llri.header.type = htons(TE_LINK_SUBTLV_LLRI); |
535 | lp->llri.header.length = htons(TE_LINK_SUBTLV_LLRI_SIZE); | |
536 | lp->llri.local = htonl(local); | |
537 | lp->llri.remote = htonl(remote); | |
16f1b9ee OD |
538 | } |
539 | ||
d62a17ae | 540 | void set_linkparams_lrrid(struct mpls_te_link *lp, struct in_addr local, |
541 | struct in_addr remote) | |
16f1b9ee OD |
542 | { |
543 | ||
d62a17ae | 544 | lp->lrrid.header.type = htons(TE_LINK_SUBTLV_LRRID); |
545 | lp->lrrid.header.length = htons(TE_LINK_SUBTLV_LRRID_SIZE); | |
546 | lp->lrrid.local.s_addr = local.s_addr; | |
547 | lp->lrrid.remote.s_addr = remote.s_addr; | |
16f1b9ee OD |
548 | } |
549 | ||
d62a17ae | 550 | static void set_linkparams_av_delay(struct mpls_te_link *lp, u_int32_t delay, |
551 | u_char anormal) | |
16f1b9ee | 552 | { |
d62a17ae | 553 | u_int32_t tmp; |
554 | /* Note that TLV-length field is the size of array. */ | |
555 | lp->av_delay.header.type = htons(TE_LINK_SUBTLV_AV_DELAY); | |
556 | lp->av_delay.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
557 | tmp = delay & TE_EXT_MASK; | |
558 | if (anormal) | |
559 | tmp |= TE_EXT_ANORMAL; | |
560 | lp->av_delay.value = htonl(tmp); | |
561 | return; | |
16f1b9ee OD |
562 | } |
563 | ||
d62a17ae | 564 | static void set_linkparams_mm_delay(struct mpls_te_link *lp, u_int32_t low, |
565 | u_int32_t high, u_char anormal) | |
16f1b9ee | 566 | { |
d62a17ae | 567 | u_int32_t tmp; |
568 | /* Note that TLV-length field is the size of array. */ | |
569 | lp->mm_delay.header.type = htons(TE_LINK_SUBTLV_MM_DELAY); | |
570 | lp->mm_delay.header.length = htons(TE_LINK_SUBTLV_MM_DELAY_SIZE); | |
571 | tmp = low & TE_EXT_MASK; | |
572 | if (anormal) | |
573 | tmp |= TE_EXT_ANORMAL; | |
574 | lp->mm_delay.low = htonl(tmp); | |
575 | lp->mm_delay.high = htonl(high); | |
576 | return; | |
16f1b9ee OD |
577 | } |
578 | ||
d62a17ae | 579 | static void set_linkparams_delay_var(struct mpls_te_link *lp, u_int32_t jitter) |
16f1b9ee | 580 | { |
d62a17ae | 581 | /* Note that TLV-length field is the size of array. */ |
582 | lp->delay_var.header.type = htons(TE_LINK_SUBTLV_DELAY_VAR); | |
583 | lp->delay_var.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
584 | lp->delay_var.value = htonl(jitter & TE_EXT_MASK); | |
585 | return; | |
16f1b9ee OD |
586 | } |
587 | ||
d62a17ae | 588 | static void set_linkparams_pkt_loss(struct mpls_te_link *lp, u_int32_t loss, |
589 | u_char anormal) | |
16f1b9ee | 590 | { |
d62a17ae | 591 | u_int32_t tmp; |
592 | /* Note that TLV-length field is the size of array. */ | |
593 | lp->pkt_loss.header.type = htons(TE_LINK_SUBTLV_PKT_LOSS); | |
594 | lp->pkt_loss.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
595 | tmp = loss & TE_EXT_MASK; | |
596 | if (anormal) | |
597 | tmp |= TE_EXT_ANORMAL; | |
598 | lp->pkt_loss.value = htonl(tmp); | |
599 | return; | |
16f1b9ee OD |
600 | } |
601 | ||
d62a17ae | 602 | static void set_linkparams_res_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 603 | { |
d62a17ae | 604 | /* Note that TLV-length field is the size of array. */ |
605 | lp->res_bw.header.type = htons(TE_LINK_SUBTLV_RES_BW); | |
606 | lp->res_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
607 | lp->res_bw.value = htonf(fp); | |
608 | return; | |
16f1b9ee OD |
609 | } |
610 | ||
d62a17ae | 611 | static void set_linkparams_ava_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 612 | { |
d62a17ae | 613 | /* Note that TLV-length field is the size of array. */ |
614 | lp->ava_bw.header.type = htons(TE_LINK_SUBTLV_AVA_BW); | |
615 | lp->ava_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
616 | lp->ava_bw.value = htonf(fp); | |
617 | return; | |
16f1b9ee OD |
618 | } |
619 | ||
d62a17ae | 620 | static void set_linkparams_use_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 621 | { |
d62a17ae | 622 | /* Note that TLV-length field is the size of array. */ |
623 | lp->use_bw.header.type = htons(TE_LINK_SUBTLV_USE_BW); | |
624 | lp->use_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
625 | lp->use_bw.value = htonf(fp); | |
626 | return; | |
16f1b9ee OD |
627 | } |
628 | ||
629 | /* Update TE parameters from Interface */ | |
d62a17ae | 630 | static void update_linkparams(struct mpls_te_link *lp) |
631 | { | |
632 | int i; | |
633 | struct interface *ifp; | |
634 | ||
635 | /* Get the Interface structure */ | |
636 | if ((ifp = lp->ifp) == NULL) { | |
637 | if (IS_DEBUG_OSPF_TE) | |
638 | zlog_debug( | |
639 | "OSPF MPLS-TE: Abort update TE parameters: no interface associated to Link Parameters"); | |
640 | return; | |
641 | } | |
642 | if (!HAS_LINK_PARAMS(ifp)) { | |
643 | if (IS_DEBUG_OSPF_TE) | |
644 | zlog_debug( | |
645 | "OSPF MPLS-TE: Abort update TE parameters: no Link Parameters for interface"); | |
646 | return; | |
647 | } | |
648 | ||
649 | /* RFC3630 metrics */ | |
650 | if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) | |
651 | set_linkparams_rsc_clsclr(lp, ifp->link_params->admin_grp); | |
652 | else | |
653 | TLV_TYPE(lp->rsc_clsclr) = 0; | |
654 | ||
655 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) | |
656 | set_linkparams_max_bw(lp, ifp->link_params->max_bw); | |
657 | else | |
658 | TLV_TYPE(lp->max_bw) = 0; | |
659 | ||
660 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) | |
661 | set_linkparams_max_rsv_bw(lp, ifp->link_params->max_rsv_bw); | |
662 | else | |
663 | TLV_TYPE(lp->max_rsv_bw) = 0; | |
664 | ||
665 | if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) | |
666 | for (i = 0; i < MAX_CLASS_TYPE; i++) | |
667 | set_linkparams_unrsv_bw(lp, i, | |
668 | ifp->link_params->unrsv_bw[i]); | |
669 | else | |
670 | TLV_TYPE(lp->unrsv_bw) = 0; | |
671 | ||
672 | if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) | |
673 | set_linkparams_te_metric(lp, ifp->link_params->te_metric); | |
674 | else | |
675 | TLV_TYPE(lp->te_metric) = 0; | |
676 | ||
677 | /* TE metric Extensions */ | |
678 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) | |
679 | set_linkparams_av_delay(lp, ifp->link_params->av_delay, 0); | |
680 | else | |
681 | TLV_TYPE(lp->av_delay) = 0; | |
682 | ||
683 | if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) | |
684 | set_linkparams_mm_delay(lp, ifp->link_params->min_delay, | |
685 | ifp->link_params->max_delay, 0); | |
686 | else | |
687 | TLV_TYPE(lp->mm_delay) = 0; | |
688 | ||
689 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) | |
690 | set_linkparams_delay_var(lp, ifp->link_params->delay_var); | |
691 | else | |
692 | TLV_TYPE(lp->delay_var) = 0; | |
693 | ||
694 | if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) | |
695 | set_linkparams_pkt_loss(lp, ifp->link_params->pkt_loss, 0); | |
696 | else | |
697 | TLV_TYPE(lp->pkt_loss) = 0; | |
698 | ||
699 | if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) | |
700 | set_linkparams_res_bw(lp, ifp->link_params->res_bw); | |
701 | else | |
702 | TLV_TYPE(lp->res_bw) = 0; | |
703 | ||
704 | if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) | |
705 | set_linkparams_ava_bw(lp, ifp->link_params->ava_bw); | |
706 | else | |
707 | TLV_TYPE(lp->ava_bw) = 0; | |
708 | ||
709 | if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) | |
710 | set_linkparams_use_bw(lp, ifp->link_params->use_bw); | |
711 | else | |
712 | TLV_TYPE(lp->use_bw) = 0; | |
713 | ||
714 | /* RFC5392 */ | |
715 | if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { | |
716 | /* Flush LSA if it engaged and was previously a STD_TE one */ | |
717 | if (IS_STD_TE(lp->type) | |
718 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
719 | if (IS_DEBUG_OSPF_TE) | |
720 | zlog_debug( | |
721 | "OSPF MPLS-TE Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", | |
722 | ifp->name, lp->flags, lp->type); | |
723 | ||
724 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
725 | /* Then, switch it to INTER-AS */ | |
726 | if (OspfMplsTE.inter_as == AS) | |
727 | lp->flags = INTER_AS | FLOOD_AS; | |
728 | else { | |
729 | lp->flags = INTER_AS | FLOOD_AREA; | |
730 | lp->area = ospf_area_lookup_by_area_id( | |
731 | ospf_lookup(), | |
732 | OspfMplsTE.interas_areaid); | |
733 | } | |
734 | } | |
735 | set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, | |
736 | ifp->link_params->rmt_as); | |
737 | } else { | |
738 | if (IS_DEBUG_OSPF_TE) | |
739 | zlog_debug( | |
740 | "OSPF MPLS-TE Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", | |
741 | ifp->name, lp->flags, lp->type); | |
742 | ||
743 | /* reset inter-as TE params */ | |
744 | /* Flush LSA if it engaged and was previously an INTER_AS one */ | |
745 | if (IS_INTER_AS(lp->type) | |
746 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
747 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
748 | /* Then, switch it to Standard TE */ | |
749 | lp->flags = STD_TE | FLOOD_AREA; | |
750 | } | |
751 | unset_linkparams_inter_as(lp); | |
752 | } | |
753 | } | |
754 | ||
755 | static void initialize_linkparams(struct mpls_te_link *lp) | |
756 | { | |
757 | struct interface *ifp = lp->ifp; | |
ead99d5f OD |
758 | struct ospf_interface *oi = NULL; |
759 | struct route_node *rn; | |
d62a17ae | 760 | |
761 | if (IS_DEBUG_OSPF_TE) | |
762 | zlog_debug( | |
763 | "MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", | |
764 | ifp->name); | |
765 | ||
ead99d5f OD |
766 | /* Search OSPF Interface parameters for this interface */ |
767 | for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { | |
768 | ||
769 | if ((oi = rn->info) == NULL) | |
770 | continue; | |
771 | ||
772 | if (oi->ifp == ifp) | |
773 | break; | |
774 | } | |
775 | ||
776 | if ((oi == NULL) || (oi->ifp != ifp)) { | |
d62a17ae | 777 | if (IS_DEBUG_OSPF_TE) |
778 | zlog_warn( | |
779 | "MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", | |
780 | ifp->name); | |
781 | return; | |
782 | } | |
783 | ||
784 | /* | |
785 | * Try to set initial values those can be derived from | |
786 | * zebra-interface information. | |
787 | */ | |
788 | set_linkparams_link_type(oi, lp); | |
789 | ||
790 | /* Set local IP addr */ | |
791 | set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); | |
792 | ||
793 | /* Set Remote IP addr if Point to Point Interface */ | |
ead99d5f | 794 | if (oi->type == OSPF_IFTYPE_POINTOPOINT) { |
d62a17ae | 795 | struct prefix *pref = CONNECTED_PREFIX(oi->connected); |
796 | if (pref != NULL) | |
797 | set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); | |
798 | } | |
799 | ||
800 | /* Keep Area information in combination with link parameters. */ | |
801 | lp->area = oi->area; | |
802 | ||
803 | return; | |
804 | } | |
805 | ||
806 | static int is_mandated_params_set(struct mpls_te_link *lp) | |
807 | { | |
808 | int rc = 0; | |
809 | ||
810 | if (ntohs(OspfMplsTE.router_addr.header.type) == 0) { | |
811 | zlog_warn( | |
812 | "MPLS-TE(is_mandated_params_set) Missing Router Address"); | |
ead99d5f | 813 | return rc; |
d62a17ae | 814 | } |
815 | ||
816 | if (ntohs(lp->link_type.header.type) == 0) { | |
817 | zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link Type"); | |
ead99d5f | 818 | return rc; |
d62a17ae | 819 | } |
820 | ||
821 | if (!IS_INTER_AS(lp->type) && (ntohs(lp->link_id.header.type) == 0)) { | |
822 | zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link ID"); | |
ead99d5f | 823 | return rc; |
d62a17ae | 824 | } |
825 | ||
826 | rc = 1; | |
d62a17ae | 827 | return rc; |
718e3744 | 828 | } |
829 | ||
830 | /*------------------------------------------------------------------------* | |
831 | * Followings are callback functions against generic Opaque-LSAs handling. | |
832 | *------------------------------------------------------------------------*/ | |
833 | ||
d62a17ae | 834 | static int ospf_mpls_te_new_if(struct interface *ifp) |
718e3744 | 835 | { |
d62a17ae | 836 | struct mpls_te_link *new; |
837 | int rc = -1; | |
718e3744 | 838 | |
d62a17ae | 839 | if (IS_DEBUG_OSPF_TE) |
840 | zlog_debug( | |
841 | "MPLS-TE(ospf_mpls_te_new_if) Add new %s interface %s to MPLS-TE list", | |
842 | ifp->link_params ? "Active" : "Inactive", ifp->name); | |
16f1b9ee | 843 | |
d62a17ae | 844 | if (lookup_linkparams_by_ifp(ifp) != NULL) { |
845 | zlog_warn("ospf_mpls_te_new_if: ifp(%p) already in use?", | |
846 | (void *)ifp); | |
847 | rc = 0; /* Do nothing here. */ | |
ead99d5f | 848 | return rc; |
d62a17ae | 849 | } |
718e3744 | 850 | |
d62a17ae | 851 | new = XCALLOC(MTYPE_OSPF_MPLS_TE, sizeof(struct mpls_te_link)); |
852 | if (new == NULL) { | |
853 | zlog_warn("ospf_mpls_te_new_if: XMALLOC: %s", | |
854 | safe_strerror(errno)); | |
ead99d5f | 855 | return rc; |
d62a17ae | 856 | } |
718e3744 | 857 | |
d62a17ae | 858 | new->instance = get_mpls_te_instance_value(); |
859 | new->ifp = ifp; | |
860 | /* By default TE-Link is RFC3630 compatible flooding in Area and not | |
861 | * active */ | |
862 | /* This default behavior will be adapted with call to | |
863 | * ospf_mpls_te_update_if() */ | |
864 | new->type = STD_TE | FLOOD_AREA; | |
865 | new->flags = LPFLG_LSA_INACTIVE; | |
16f1b9ee | 866 | |
d62a17ae | 867 | /* Initialize Link Parameters from Interface */ |
868 | initialize_linkparams(new); | |
718e3744 | 869 | |
d62a17ae | 870 | /* Set TE Parameters from Interface */ |
871 | update_linkparams(new); | |
718e3744 | 872 | |
d62a17ae | 873 | /* Add Link Parameters structure to the list */ |
874 | listnode_add(OspfMplsTE.iflist, new); | |
718e3744 | 875 | |
d62a17ae | 876 | if (IS_DEBUG_OSPF_TE) |
877 | zlog_debug( | |
878 | "OSPF MPLS-TE New IF: Add new LP context for %s[%d/%d]", | |
879 | ifp->name, new->flags, new->type); | |
16f1b9ee | 880 | |
d62a17ae | 881 | /* Schedule Opaque-LSA refresh. */ /* XXX */ |
718e3744 | 882 | |
d62a17ae | 883 | rc = 0; |
d62a17ae | 884 | return rc; |
718e3744 | 885 | } |
886 | ||
d62a17ae | 887 | static int ospf_mpls_te_del_if(struct interface *ifp) |
718e3744 | 888 | { |
d62a17ae | 889 | struct mpls_te_link *lp; |
890 | int rc = -1; | |
718e3744 | 891 | |
d62a17ae | 892 | if ((lp = lookup_linkparams_by_ifp(ifp)) != NULL) { |
893 | struct list *iflist = OspfMplsTE.iflist; | |
718e3744 | 894 | |
d62a17ae | 895 | /* Dequeue listnode entry from the list. */ |
896 | listnode_delete(iflist, lp); | |
718e3744 | 897 | |
d62a17ae | 898 | /* Avoid misjudgement in the next lookup. */ |
899 | if (listcount(iflist) == 0) | |
900 | iflist->head = iflist->tail = NULL; | |
718e3744 | 901 | |
d62a17ae | 902 | XFREE(MTYPE_OSPF_MPLS_TE, lp); |
903 | } | |
718e3744 | 904 | |
d62a17ae | 905 | /* Schedule Opaque-LSA refresh. */ /* XXX */ |
718e3744 | 906 | |
d62a17ae | 907 | rc = 0; |
d62a17ae | 908 | return rc; |
718e3744 | 909 | } |
910 | ||
16f1b9ee OD |
911 | /* Main initialization / update function of the MPLS TE Link context */ |
912 | ||
913 | /* Call when interface TE Link parameters are modified */ | |
d62a17ae | 914 | void ospf_mpls_te_update_if(struct interface *ifp) |
915 | { | |
916 | struct mpls_te_link *lp; | |
917 | ||
918 | if (IS_DEBUG_OSPF_TE) | |
919 | zlog_debug( | |
920 | "OSPF MPLS-TE: Update LSA parameters for interface %s [%s]", | |
921 | ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); | |
922 | ||
923 | /* Get Link context from interface */ | |
924 | if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) { | |
ead99d5f OD |
925 | zlog_warn( |
926 | "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", | |
927 | ifp->name); | |
d62a17ae | 928 | return; |
929 | } | |
930 | ||
931 | /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */ | |
932 | if (HAS_LINK_PARAMS(ifp)) { | |
933 | SET_FLAG(lp->flags, LPFLG_LSA_ACTIVE); | |
934 | ||
935 | /* Update TE parameters */ | |
936 | update_linkparams(lp); | |
937 | ||
938 | /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is | |
939 | * enabled */ | |
32ab5cf4 | 940 | if (OspfMplsTE.enabled) |
d62a17ae | 941 | if (lp->area != NULL) { |
32ab5cf4 OD |
942 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
943 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
944 | else | |
945 | ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA); | |
d62a17ae | 946 | } |
947 | } else { | |
948 | /* If MPLS TE is disable on this interface, flush LSA if it is | |
949 | * already engaged */ | |
32ab5cf4 OD |
950 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
951 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
d62a17ae | 952 | else |
953 | /* Reset Activity flag */ | |
954 | lp->flags = LPFLG_LSA_INACTIVE; | |
955 | } | |
956 | ||
957 | return; | |
958 | } | |
959 | ||
960 | static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) | |
961 | { | |
962 | struct te_link_subtlv_link_type old_type; | |
963 | struct te_link_subtlv_link_id old_id; | |
964 | struct mpls_te_link *lp; | |
965 | ||
966 | if ((lp = lookup_linkparams_by_ifp(oi->ifp)) == NULL) { | |
967 | zlog_warn( | |
968 | "ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", | |
969 | IF_NAME(oi)); | |
ead99d5f | 970 | return; |
d62a17ae | 971 | } |
972 | ||
973 | if (oi->area == NULL || oi->area->ospf == NULL) { | |
974 | zlog_warn( | |
975 | "ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", | |
976 | IF_NAME(oi)); | |
ead99d5f | 977 | return; |
d62a17ae | 978 | } |
718e3744 | 979 | #ifdef notyet |
d62a17ae | 980 | if ((lp->area != NULL |
981 | && !IPV4_ADDR_SAME(&lp->area->area_id, &oi->area->area_id)) | |
982 | || (lp->area != NULL && oi->area == NULL)) { | |
983 | /* How should we consider this case? */ | |
984 | zlog_warn( | |
985 | "MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", | |
986 | IF_NAME(oi), | |
987 | oi->area ? inet_ntoa(oi->area->area_id) : "N/A"); | |
988 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
989 | } | |
718e3744 | 990 | #endif |
d62a17ae | 991 | /* Keep Area information in combination with linkparams. */ |
992 | lp->area = oi->area; | |
993 | ||
994 | /* Keep interface MPLS-TE status */ | |
995 | lp->flags = HAS_LINK_PARAMS(oi->ifp); | |
996 | ||
997 | switch (oi->state) { | |
998 | case ISM_PointToPoint: | |
999 | case ISM_DROther: | |
1000 | case ISM_Backup: | |
1001 | case ISM_DR: | |
1002 | old_type = lp->link_type; | |
1003 | old_id = lp->link_id; | |
1004 | ||
1005 | /* Set Link type, Link ID, Local and Remote IP addr */ | |
1006 | set_linkparams_link_type(oi, lp); | |
1007 | set_linkparams_link_id(oi, lp); | |
1008 | set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); | |
1009 | ||
1010 | if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) { | |
1011 | struct prefix *pref = CONNECTED_PREFIX(oi->connected); | |
1012 | if (pref != NULL) | |
1013 | set_linkparams_rmtif_ipaddr(lp, | |
1014 | pref->u.prefix4); | |
1015 | } | |
1016 | ||
1017 | /* Update TE parameters */ | |
1018 | update_linkparams(lp); | |
1019 | ||
1020 | /* Try to Schedule LSA */ | |
1021 | if ((ntohs(old_type.header.type) | |
1022 | != ntohs(lp->link_type.header.type) | |
1023 | || old_type.link_type.value | |
1024 | != lp->link_type.link_type.value) | |
1025 | || (ntohs(old_id.header.type) | |
1026 | != ntohs(lp->link_id.header.type) | |
1027 | || ntohl(old_id.value.s_addr) | |
1028 | != ntohl(lp->link_id.value.s_addr))) { | |
32ab5cf4 OD |
1029 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
1030 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
1031 | else | |
1032 | ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA); | |
d62a17ae | 1033 | } |
1034 | break; | |
1035 | default: | |
1036 | lp->link_type.header.type = htons(0); | |
1037 | lp->link_id.header.type = htons(0); | |
1038 | ||
32ab5cf4 OD |
1039 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
1040 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
d62a17ae | 1041 | break; |
1042 | } | |
718e3744 | 1043 | |
d62a17ae | 1044 | return; |
718e3744 | 1045 | } |
1046 | ||
d62a17ae | 1047 | static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) |
718e3744 | 1048 | { |
d62a17ae | 1049 | /* Nothing to do here */ |
1050 | return; | |
718e3744 | 1051 | } |
1052 | ||
1053 | /*------------------------------------------------------------------------* | |
1054 | * Followings are OSPF protocol processing functions for MPLS-TE. | |
1055 | *------------------------------------------------------------------------*/ | |
1056 | ||
ead99d5f | 1057 | static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) |
d62a17ae | 1058 | { |
ead99d5f | 1059 | stream_put(s, tlvh, sizeof(struct tlv_header)); |
d62a17ae | 1060 | return; |
1061 | } | |
1062 | ||
1063 | static void build_router_tlv(struct stream *s) | |
1064 | { | |
ead99d5f | 1065 | struct tlv_header *tlvh = &OspfMplsTE.router_addr.header; |
d62a17ae | 1066 | if (ntohs(tlvh->type) != 0) { |
1067 | build_tlv_header(s, tlvh); | |
5d0df50f | 1068 | stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); |
d62a17ae | 1069 | } |
1070 | return; | |
1071 | } | |
1072 | ||
ead99d5f | 1073 | static void build_link_subtlv(struct stream *s, struct tlv_header *tlvh) |
d62a17ae | 1074 | { |
1075 | ||
1076 | if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) { | |
1077 | build_tlv_header(s, tlvh); | |
5d0df50f | 1078 | stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); |
d62a17ae | 1079 | } |
1080 | return; | |
1081 | } | |
1082 | ||
1083 | static void build_link_tlv(struct stream *s, struct mpls_te_link *lp) | |
1084 | { | |
1085 | set_linkparams_link_header(lp); | |
1086 | build_tlv_header(s, &lp->link_header.header); | |
1087 | ||
1088 | build_link_subtlv(s, &lp->link_type.header); | |
1089 | build_link_subtlv(s, &lp->link_id.header); | |
1090 | build_link_subtlv(s, &lp->lclif_ipaddr.header); | |
1091 | build_link_subtlv(s, &lp->rmtif_ipaddr.header); | |
1092 | build_link_subtlv(s, &lp->te_metric.header); | |
1093 | build_link_subtlv(s, &lp->max_bw.header); | |
1094 | build_link_subtlv(s, &lp->max_rsv_bw.header); | |
1095 | build_link_subtlv(s, &lp->unrsv_bw.header); | |
1096 | build_link_subtlv(s, &lp->rsc_clsclr.header); | |
1097 | build_link_subtlv(s, &lp->lrrid.header); | |
1098 | build_link_subtlv(s, &lp->llri.header); | |
1099 | build_link_subtlv(s, &lp->rip.header); | |
1100 | build_link_subtlv(s, &lp->ras.header); | |
1101 | build_link_subtlv(s, &lp->av_delay.header); | |
1102 | build_link_subtlv(s, &lp->mm_delay.header); | |
1103 | build_link_subtlv(s, &lp->delay_var.header); | |
1104 | build_link_subtlv(s, &lp->pkt_loss.header); | |
1105 | build_link_subtlv(s, &lp->res_bw.header); | |
1106 | build_link_subtlv(s, &lp->ava_bw.header); | |
1107 | build_link_subtlv(s, &lp->use_bw.header); | |
1108 | ||
1109 | return; | |
1110 | } | |
1111 | ||
1112 | static void ospf_mpls_te_lsa_body_set(struct stream *s, struct mpls_te_link *lp) | |
1113 | { | |
1114 | /* | |
1115 | * The router address TLV is type 1, and ... | |
1116 | * It must appear in exactly one | |
1117 | * Traffic Engineering LSA originated by a router. | |
1118 | */ | |
1119 | build_router_tlv(s); | |
1120 | ||
1121 | /* | |
1122 | * Only one Link TLV shall be carried in each LSA, allowing for fine | |
1123 | * granularity changes in topology. | |
1124 | */ | |
1125 | build_link_tlv(s, lp); | |
1126 | return; | |
718e3744 | 1127 | } |
1128 | ||
1129 | /* Create new opaque-LSA. */ | |
d62a17ae | 1130 | static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area, |
1131 | struct mpls_te_link *lp) | |
1132 | { | |
1133 | struct stream *s; | |
1134 | struct lsa_header *lsah; | |
1135 | struct ospf_lsa *new = NULL; | |
1136 | u_char options, lsa_type = 0; | |
1137 | struct in_addr lsa_id; | |
1138 | u_int32_t tmp; | |
1139 | u_int16_t length; | |
1140 | ||
1141 | /* Create a stream for LSA. */ | |
1142 | if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) { | |
1143 | zlog_warn("ospf_mpls_te_lsa_new: stream_new() ?"); | |
ead99d5f | 1144 | return NULL; |
d62a17ae | 1145 | } |
1146 | lsah = (struct lsa_header *)STREAM_DATA(s); | |
1147 | ||
1148 | options = OSPF_OPTION_O; /* Don't forget this :-) */ | |
1149 | ||
1150 | /* Set opaque-LSA header fields depending of the type of RFC */ | |
1151 | if (IS_INTER_AS(lp->type)) { | |
1152 | if | |
1153 | IS_FLOOD_AS(lp->type) | |
1154 | { | |
1155 | options |= OSPF_OPTION_E; /* Enable AS external | |
1156 | as we flood | |
1157 | Inter-AS with | |
1158 | Opaque Type 11 */ | |
1159 | lsa_type = OSPF_OPAQUE_AS_LSA; | |
1160 | } | |
1161 | else { | |
1162 | options |= LSA_OPTIONS_GET( | |
1163 | area); /* Get area default option */ | |
1164 | options |= LSA_OPTIONS_NSSA_GET(area); | |
1165 | lsa_type = OSPF_OPAQUE_AREA_LSA; | |
1166 | } | |
1167 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, lp->instance); | |
1168 | lsa_id.s_addr = htonl(tmp); | |
1169 | ||
1170 | struct ospf *top = ospf_lookup(); | |
1171 | ||
1172 | lsa_header_set(s, options, lsa_type, lsa_id, top->router_id); | |
1173 | } else { | |
1174 | options |= LSA_OPTIONS_GET(area); /* Get area default option */ | |
1175 | options |= LSA_OPTIONS_NSSA_GET(area); | |
1176 | lsa_type = OSPF_OPAQUE_AREA_LSA; | |
1177 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
1178 | lp->instance); | |
1179 | lsa_id.s_addr = htonl(tmp); | |
1180 | lsa_header_set(s, options, lsa_type, lsa_id, | |
1181 | area->ospf->router_id); | |
1182 | } | |
1183 | ||
1184 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) | |
1185 | zlog_debug( | |
1186 | "LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", | |
1187 | lsa_type, inet_ntoa(lsa_id)); | |
1188 | ||
1189 | /* Set opaque-LSA body fields. */ | |
1190 | ospf_mpls_te_lsa_body_set(s, lp); | |
1191 | ||
1192 | /* Set length. */ | |
1193 | length = stream_get_endp(s); | |
1194 | lsah->length = htons(length); | |
1195 | ||
1196 | /* Now, create an OSPF LSA instance. */ | |
1197 | if ((new = ospf_lsa_new()) == NULL) { | |
1198 | zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); | |
1199 | stream_free(s); | |
ead99d5f | 1200 | return NULL; |
d62a17ae | 1201 | } |
1202 | if ((new->data = ospf_lsa_data_new(length)) == NULL) { | |
1203 | zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); | |
1204 | ospf_lsa_unlock(&new); | |
1205 | new = NULL; | |
1206 | stream_free(s); | |
ead99d5f | 1207 | return new; |
d62a17ae | 1208 | } |
1209 | ||
1210 | new->area = area; | |
1211 | SET_FLAG(new->flags, OSPF_LSA_SELF); | |
1212 | memcpy(new->data, lsah, length); | |
1213 | stream_free(s); | |
718e3744 | 1214 | |
d62a17ae | 1215 | return new; |
1216 | } | |
1217 | ||
1218 | static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, | |
1219 | struct mpls_te_link *lp) | |
1220 | { | |
1221 | struct ospf_lsa *new; | |
1222 | int rc = -1; | |
1223 | ||
1224 | /* Create new Opaque-LSA/MPLS-TE instance. */ | |
1225 | if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) { | |
1226 | zlog_warn( | |
1227 | "ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); | |
ead99d5f | 1228 | return rc; |
d62a17ae | 1229 | } |
1230 | ||
1231 | /* Install this LSA into LSDB. */ | |
1232 | if (ospf_lsa_install(area->ospf, NULL /*oi*/, new) == NULL) { | |
1233 | zlog_warn("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); | |
1234 | ospf_lsa_unlock(&new); | |
ead99d5f | 1235 | return rc; |
d62a17ae | 1236 | } |
1237 | ||
1238 | /* Now this link-parameter entry has associated LSA. */ | |
1239 | SET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); | |
1240 | /* Update new LSA origination count. */ | |
1241 | area->ospf->lsa_originate_count++; | |
1242 | ||
1243 | /* Flood new LSA through area. */ | |
1244 | ospf_flood_through_area(area, NULL /*nbr*/, new); | |
1245 | ||
1246 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
1247 | char area_id[INET_ADDRSTRLEN]; | |
1248 | strcpy(area_id, inet_ntoa(area->area_id)); | |
1249 | zlog_debug( | |
1250 | "LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", | |
1251 | new->data->type, inet_ntoa(new->data->id), area_id, | |
1252 | lp->ifp->name); | |
1253 | ospf_lsa_header_dump(new->data); | |
1254 | } | |
1255 | ||
1256 | rc = 0; | |
d62a17ae | 1257 | return rc; |
1258 | } | |
1259 | ||
1260 | static int ospf_mpls_te_lsa_originate_area(void *arg) | |
1261 | { | |
1262 | struct ospf_area *area = (struct ospf_area *)arg; | |
1263 | struct listnode *node, *nnode; | |
1264 | struct mpls_te_link *lp; | |
1265 | int rc = -1; | |
1266 | ||
32ab5cf4 | 1267 | if (!OspfMplsTE.enabled) { |
d62a17ae | 1268 | zlog_info( |
1269 | "ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); | |
1270 | rc = 0; /* This is not an error case. */ | |
ead99d5f | 1271 | return rc; |
d62a17ae | 1272 | } |
1273 | ||
1274 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
1275 | /* Process only enabled LSA with area scope flooding */ | |
1276 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) | |
1277 | || IS_FLOOD_AS(lp->type)) | |
1278 | continue; | |
1279 | ||
1280 | if (lp->area == NULL) | |
1281 | continue; | |
1282 | ||
1283 | if (!IPV4_ADDR_SAME(&lp->area->area_id, &area->area_id)) | |
1284 | continue; | |
1285 | ||
32ab5cf4 OD |
1286 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { |
1287 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { | |
1288 | UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); | |
1289 | zlog_warn( | |
1290 | "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); | |
1291 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
d62a17ae | 1292 | } |
32ab5cf4 OD |
1293 | continue; |
1294 | } | |
1295 | ||
d62a17ae | 1296 | if (!is_mandated_params_set(lp)) { |
1297 | zlog_warn( | |
1298 | "ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.", | |
1299 | lp->ifp ? lp->ifp->name : "?"); | |
1300 | continue; | |
1301 | } | |
1302 | ||
1303 | /* Ok, let's try to originate an LSA for this area and Link. */ | |
1304 | if (IS_DEBUG_OSPF_TE) | |
1305 | zlog_debug( | |
1306 | "MPLS-TE(ospf_mpls_te_lsa_originate_area) Let's finally reoriginate the LSA %d through the Area %s for Link %s", | |
1307 | lp->instance, inet_ntoa(area->area_id), | |
1308 | lp->ifp ? lp->ifp->name : "?"); | |
1309 | if (ospf_mpls_te_lsa_originate1(area, lp) != 0) | |
ead99d5f | 1310 | return rc; |
d62a17ae | 1311 | } |
1312 | ||
1313 | rc = 0; | |
d62a17ae | 1314 | return rc; |
1315 | } | |
718e3744 | 1316 | |
d62a17ae | 1317 | static int ospf_mpls_te_lsa_originate2(struct ospf *top, |
1318 | struct mpls_te_link *lp) | |
1319 | { | |
1320 | struct ospf_lsa *new; | |
1321 | int rc = -1; | |
1322 | ||
1323 | /* Create new Opaque-LSA/Inter-AS instance. */ | |
1324 | if ((new = ospf_mpls_te_lsa_new(NULL, lp)) == NULL) { | |
1325 | zlog_warn( | |
1326 | "ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); | |
ead99d5f | 1327 | return rc; |
d62a17ae | 1328 | } |
1329 | ||
1330 | /* Install this LSA into LSDB. */ | |
1331 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
1332 | zlog_warn("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); | |
1333 | ospf_lsa_unlock(&new); | |
ead99d5f | 1334 | return rc; |
d62a17ae | 1335 | } |
1336 | ||
1337 | /* Now this Router Info parameter entry has associated LSA. */ | |
1338 | SET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); | |
1339 | /* Update new LSA origination count. */ | |
1340 | top->lsa_originate_count++; | |
1341 | ||
1342 | /* Flood new LSA through AS. */ | |
1343 | ospf_flood_through_as(top, NULL /*nbr */, new); | |
1344 | ||
1345 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
1346 | zlog_debug( | |
1347 | "LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE Inter-AS", | |
1348 | new->data->type, inet_ntoa(new->data->id)); | |
1349 | ospf_lsa_header_dump(new->data); | |
1350 | } | |
1351 | ||
1352 | rc = 0; | |
d62a17ae | 1353 | return rc; |
1354 | } | |
1355 | ||
1356 | static int ospf_mpls_te_lsa_originate_as(void *arg) | |
1357 | { | |
1358 | struct ospf *top; | |
1359 | struct ospf_area *area; | |
1360 | struct listnode *node, *nnode; | |
1361 | struct mpls_te_link *lp; | |
1362 | int rc = -1; | |
1363 | ||
32ab5cf4 | 1364 | if ((!OspfMplsTE.enabled) |
ead99d5f | 1365 | || (OspfMplsTE.inter_as == Off)) { |
d62a17ae | 1366 | zlog_info( |
1367 | "ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); | |
1368 | rc = 0; /* This is not an error case. */ | |
ead99d5f | 1369 | return rc; |
d62a17ae | 1370 | } |
1371 | ||
1372 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
1373 | /* Process only enabled INTER_AS Links or Pseudo-Links */ | |
1374 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) | |
1375 | || !IS_INTER_AS(lp->type)) | |
1376 | continue; | |
1377 | ||
32ab5cf4 OD |
1378 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { |
1379 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { | |
1380 | UNSET_FLAG(lp->flags,LPFLG_LSA_FORCED_REFRESH); | |
1381 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
d62a17ae | 1382 | } |
32ab5cf4 OD |
1383 | continue; |
1384 | } | |
1385 | ||
d62a17ae | 1386 | if (!is_mandated_params_set(lp)) { |
1387 | zlog_warn( | |
1388 | "ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.", | |
1389 | lp->ifp ? lp->ifp->name : "?"); | |
1390 | continue; | |
1391 | } | |
1392 | ||
1393 | /* Ok, let's try to originate an LSA for this AS and Link. */ | |
1394 | if (IS_DEBUG_OSPF_TE) | |
1395 | zlog_debug( | |
1396 | "MPLS-TE(ospf_mpls_te_lsa_originate_as) Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", | |
1397 | lp->instance, | |
1398 | IS_FLOOD_AS(lp->type) ? "AS" : "Area", | |
1399 | lp->ifp ? lp->ifp->name : "Unknown"); | |
1400 | ||
1401 | if (IS_FLOOD_AS(lp->type)) { | |
1402 | top = (struct ospf *)arg; | |
1403 | ospf_mpls_te_lsa_originate2(top, lp); | |
1404 | } else { | |
1405 | area = (struct ospf_area *)arg; | |
1406 | ospf_mpls_te_lsa_originate1(area, lp); | |
1407 | } | |
1408 | } | |
1409 | ||
1410 | rc = 0; | |
d62a17ae | 1411 | return rc; |
1412 | } | |
1413 | ||
1414 | static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) | |
1415 | { | |
1416 | struct mpls_te_link *lp; | |
1417 | struct ospf_area *area = lsa->area; | |
1418 | struct ospf *top; | |
1419 | struct ospf_lsa *new = NULL; | |
1420 | ||
32ab5cf4 | 1421 | if (!OspfMplsTE.enabled) { |
d62a17ae | 1422 | /* |
1423 | * This LSA must have flushed before due to MPLS-TE status | |
1424 | * change. | |
1425 | * It seems a slip among routers in the routing domain. | |
1426 | */ | |
1427 | zlog_info("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); | |
1428 | lsa->data->ls_age = | |
1429 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
1430 | } | |
1431 | ||
1432 | /* At first, resolve lsa/lp relationship. */ | |
1433 | if ((lp = lookup_linkparams_by_instance(lsa)) == NULL) { | |
1434 | zlog_warn("ospf_mpls_te_lsa_refresh: Invalid parameter?"); | |
1435 | lsa->data->ls_age = | |
1436 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
1437 | } | |
1438 | ||
1439 | /* Check if lp was not disable in the interval */ | |
1440 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) { | |
1441 | zlog_warn( | |
1442 | "ospf_mpls_te_lsa_refresh: lp was disabled: Flush it!"); | |
1443 | lsa->data->ls_age = | |
1444 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
1445 | } | |
1446 | ||
1447 | /* If the lsa's age reached to MaxAge, start flushing procedure. */ | |
1448 | if (IS_LSA_MAXAGE(lsa)) { | |
1449 | if (lp) | |
1450 | UNSET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); | |
1451 | ospf_opaque_lsa_flush_schedule(lsa); | |
ead99d5f | 1452 | return NULL; |
d62a17ae | 1453 | } |
1454 | ||
1455 | /* Create new Opaque-LSA/MPLS-TE instance. */ | |
1456 | if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) { | |
1457 | zlog_warn("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); | |
ead99d5f | 1458 | return NULL; |
d62a17ae | 1459 | } |
1460 | new->data->ls_seqnum = lsa_seqnum_increment(lsa); | |
1461 | ||
1462 | /* Install this LSA into LSDB. */ | |
1463 | /* Given "lsa" will be freed in the next function. */ | |
1464 | /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use | |
1465 | * ospf_lookup() to get ospf instance */ | |
1466 | if (area) | |
1467 | top = area->ospf; | |
1468 | else | |
1469 | top = ospf_lookup(); | |
1470 | ||
1471 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
1472 | zlog_warn("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); | |
1473 | ospf_lsa_unlock(&new); | |
ead99d5f | 1474 | return NULL; |
d62a17ae | 1475 | } |
1476 | ||
1477 | /* Flood updated LSA through AS or Area depending of the RFC of the link | |
1478 | */ | |
1479 | if (IS_FLOOD_AS(lp->type)) | |
1480 | ospf_flood_through_as(top, NULL, new); | |
1481 | else | |
1482 | ospf_flood_through_area(area, NULL /*nbr*/, new); | |
1483 | ||
1484 | /* Debug logging. */ | |
1485 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
1486 | zlog_debug("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE", | |
1487 | new->data->type, inet_ntoa(new->data->id)); | |
1488 | ospf_lsa_header_dump(new->data); | |
1489 | } | |
1490 | ||
d62a17ae | 1491 | return new; |
1492 | } | |
1493 | ||
2a39170c | 1494 | void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) |
d62a17ae | 1495 | { |
1496 | struct ospf_lsa lsa; | |
1497 | struct lsa_header lsah; | |
1498 | struct ospf *top; | |
1499 | u_int32_t tmp; | |
1500 | ||
1501 | memset(&lsa, 0, sizeof(lsa)); | |
1502 | memset(&lsah, 0, sizeof(lsah)); | |
1503 | top = ospf_lookup(); | |
1504 | ||
1505 | /* Check if the pseudo link is ready to flood */ | |
1506 | if (!(CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) | |
1507 | || !(IS_FLOOD_AREA(lp->type) || IS_FLOOD_AS(lp->type))) { | |
1508 | return; | |
1509 | } | |
1510 | ||
1511 | lsa.area = lp->area; | |
1512 | lsa.data = &lsah; | |
1513 | if (IS_FLOOD_AS(lp->type)) { | |
1514 | lsah.type = OSPF_OPAQUE_AS_LSA; | |
1515 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, lp->instance); | |
1516 | lsah.id.s_addr = htonl(tmp); | |
1517 | } else { | |
1518 | lsah.type = OSPF_OPAQUE_AREA_LSA; | |
1519 | if (IS_INTER_AS(lp->type)) { | |
1520 | /* Set the area context if not know */ | |
1521 | if (lp->area == NULL) | |
1522 | lp->area = ospf_area_lookup_by_area_id( | |
1523 | top, OspfMplsTE.interas_areaid); | |
1524 | /* Unable to set the area context. Abort! */ | |
1525 | if (lp->area == NULL) { | |
1526 | zlog_warn( | |
1527 | "MPLS-TE(ospf_mpls_te_lsa_schedule) Area context is null. Abort !"); | |
1528 | return; | |
1529 | } | |
1530 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, | |
1531 | lp->instance); | |
1532 | } else | |
1533 | tmp = SET_OPAQUE_LSID( | |
1534 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
1535 | lp->instance); | |
1536 | lsah.id.s_addr = htonl(tmp); | |
1537 | } | |
1538 | ||
1539 | switch (opcode) { | |
1540 | case REORIGINATE_THIS_LSA: | |
1541 | if (IS_FLOOD_AS(lp->type)) { | |
1542 | ospf_opaque_lsa_reoriginate_schedule( | |
1543 | (void *)top, OSPF_OPAQUE_AS_LSA, | |
1544 | OPAQUE_TYPE_INTER_AS_LSA); | |
1545 | break; | |
1546 | } | |
1547 | ||
1548 | if (IS_FLOOD_AREA(lp->type)) { | |
1549 | if (IS_INTER_AS(lp->type)) | |
1550 | ospf_opaque_lsa_reoriginate_schedule( | |
1551 | (void *)lp->area, OSPF_OPAQUE_AREA_LSA, | |
1552 | OPAQUE_TYPE_INTER_AS_LSA); | |
1553 | else | |
1554 | ospf_opaque_lsa_reoriginate_schedule( | |
1555 | (void *)lp->area, OSPF_OPAQUE_AREA_LSA, | |
1556 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); | |
1557 | break; | |
1558 | } | |
1559 | break; | |
1560 | case REFRESH_THIS_LSA: | |
1561 | ospf_opaque_lsa_refresh_schedule(&lsa); | |
1562 | break; | |
1563 | case FLUSH_THIS_LSA: | |
1564 | /* Reset Activity flag */ | |
1565 | lp->flags = LPFLG_LSA_INACTIVE; | |
1566 | ospf_opaque_lsa_flush_schedule(&lsa); | |
1567 | break; | |
1568 | default: | |
1569 | zlog_warn("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", | |
1570 | opcode); | |
1571 | break; | |
1572 | } | |
1573 | ||
1574 | return; | |
718e3744 | 1575 | } |
1576 | ||
16f1b9ee | 1577 | |
718e3744 | 1578 | /*------------------------------------------------------------------------* |
1579 | * Followings are vty session control functions. | |
1580 | *------------------------------------------------------------------------*/ | |
1581 | ||
d62a17ae | 1582 | static u_int16_t show_vty_router_addr(struct vty *vty, |
ead99d5f | 1583 | struct tlv_header *tlvh) |
718e3744 | 1584 | { |
d62a17ae | 1585 | struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh; |
718e3744 | 1586 | |
d62a17ae | 1587 | if (vty != NULL) |
1588 | vty_out(vty, " Router-Address: %s\n", inet_ntoa(top->value)); | |
1589 | else | |
1590 | zlog_debug(" Router-Address: %s", inet_ntoa(top->value)); | |
718e3744 | 1591 | |
d62a17ae | 1592 | return TLV_SIZE(tlvh); |
718e3744 | 1593 | } |
1594 | ||
d62a17ae | 1595 | static u_int16_t show_vty_link_header(struct vty *vty, |
ead99d5f | 1596 | struct tlv_header *tlvh) |
718e3744 | 1597 | { |
d62a17ae | 1598 | struct te_tlv_link *top = (struct te_tlv_link *)tlvh; |
718e3744 | 1599 | |
d62a17ae | 1600 | if (vty != NULL) |
1601 | vty_out(vty, " Link: %u octets of data\n", | |
1602 | ntohs(top->header.length)); | |
1603 | else | |
1604 | zlog_debug(" Link: %u octets of data", | |
1605 | ntohs(top->header.length)); | |
718e3744 | 1606 | |
d62a17ae | 1607 | return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ |
718e3744 | 1608 | } |
1609 | ||
d62a17ae | 1610 | static u_int16_t show_vty_link_subtlv_link_type(struct vty *vty, |
ead99d5f | 1611 | struct tlv_header *tlvh) |
718e3744 | 1612 | { |
d62a17ae | 1613 | struct te_link_subtlv_link_type *top; |
1614 | const char *cp = "Unknown"; | |
718e3744 | 1615 | |
d62a17ae | 1616 | top = (struct te_link_subtlv_link_type *)tlvh; |
1617 | switch (top->link_type.value) { | |
1618 | case LINK_TYPE_SUBTLV_VALUE_PTP: | |
1619 | cp = "Point-to-point"; | |
1620 | break; | |
1621 | case LINK_TYPE_SUBTLV_VALUE_MA: | |
1622 | cp = "Multiaccess"; | |
1623 | break; | |
1624 | default: | |
1625 | break; | |
1626 | } | |
718e3744 | 1627 | |
d62a17ae | 1628 | if (vty != NULL) |
1629 | vty_out(vty, " Link-Type: %s (%u)\n", cp, | |
1630 | top->link_type.value); | |
1631 | else | |
1632 | zlog_debug(" Link-Type: %s (%u)", cp, top->link_type.value); | |
718e3744 | 1633 | |
d62a17ae | 1634 | return TLV_SIZE(tlvh); |
718e3744 | 1635 | } |
1636 | ||
d62a17ae | 1637 | static u_int16_t show_vty_link_subtlv_link_id(struct vty *vty, |
ead99d5f | 1638 | struct tlv_header *tlvh) |
718e3744 | 1639 | { |
d62a17ae | 1640 | struct te_link_subtlv_link_id *top; |
718e3744 | 1641 | |
d62a17ae | 1642 | top = (struct te_link_subtlv_link_id *)tlvh; |
1643 | if (vty != NULL) | |
1644 | vty_out(vty, " Link-ID: %s\n", inet_ntoa(top->value)); | |
1645 | else | |
1646 | zlog_debug(" Link-ID: %s", inet_ntoa(top->value)); | |
718e3744 | 1647 | |
d62a17ae | 1648 | return TLV_SIZE(tlvh); |
718e3744 | 1649 | } |
1650 | ||
d62a17ae | 1651 | static u_int16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, |
ead99d5f | 1652 | struct tlv_header *tlvh) |
718e3744 | 1653 | { |
d62a17ae | 1654 | struct te_link_subtlv_lclif_ipaddr *top; |
1655 | int i, n; | |
718e3744 | 1656 | |
d62a17ae | 1657 | top = (struct te_link_subtlv_lclif_ipaddr *)tlvh; |
1658 | n = ntohs(tlvh->length) / sizeof(top->value[0]); | |
718e3744 | 1659 | |
d62a17ae | 1660 | if (vty != NULL) |
1661 | vty_out(vty, " Local Interface IP Address(es): %d\n", n); | |
1662 | else | |
1663 | zlog_debug(" Local Interface IP Address(es): %d", n); | |
718e3744 | 1664 | |
d62a17ae | 1665 | for (i = 0; i < n; i++) { |
1666 | if (vty != NULL) | |
1667 | vty_out(vty, " #%d: %s\n", i, | |
1668 | inet_ntoa(top->value[i])); | |
1669 | else | |
1670 | zlog_debug(" #%d: %s", i, | |
1671 | inet_ntoa(top->value[i])); | |
1672 | } | |
1673 | return TLV_SIZE(tlvh); | |
718e3744 | 1674 | } |
1675 | ||
d62a17ae | 1676 | static u_int16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, |
ead99d5f | 1677 | struct tlv_header *tlvh) |
718e3744 | 1678 | { |
d62a17ae | 1679 | struct te_link_subtlv_rmtif_ipaddr *top; |
1680 | int i, n; | |
718e3744 | 1681 | |
d62a17ae | 1682 | top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh; |
1683 | n = ntohs(tlvh->length) / sizeof(top->value[0]); | |
1684 | if (vty != NULL) | |
1685 | vty_out(vty, " Remote Interface IP Address(es): %d\n", n); | |
1686 | else | |
1687 | zlog_debug(" Remote Interface IP Address(es): %d", n); | |
718e3744 | 1688 | |
d62a17ae | 1689 | for (i = 0; i < n; i++) { |
1690 | if (vty != NULL) | |
1691 | vty_out(vty, " #%d: %s\n", i, | |
1692 | inet_ntoa(top->value[i])); | |
1693 | else | |
1694 | zlog_debug(" #%d: %s", i, | |
1695 | inet_ntoa(top->value[i])); | |
1696 | } | |
1697 | return TLV_SIZE(tlvh); | |
718e3744 | 1698 | } |
1699 | ||
d62a17ae | 1700 | static u_int16_t show_vty_link_subtlv_te_metric(struct vty *vty, |
ead99d5f | 1701 | struct tlv_header *tlvh) |
718e3744 | 1702 | { |
d62a17ae | 1703 | struct te_link_subtlv_te_metric *top; |
718e3744 | 1704 | |
d62a17ae | 1705 | top = (struct te_link_subtlv_te_metric *)tlvh; |
1706 | if (vty != NULL) | |
1707 | vty_out(vty, " Traffic Engineering Metric: %u\n", | |
1708 | (u_int32_t)ntohl(top->value)); | |
1709 | else | |
1710 | zlog_debug(" Traffic Engineering Metric: %u", | |
1711 | (u_int32_t)ntohl(top->value)); | |
718e3744 | 1712 | |
d62a17ae | 1713 | return TLV_SIZE(tlvh); |
718e3744 | 1714 | } |
1715 | ||
d62a17ae | 1716 | static u_int16_t show_vty_link_subtlv_max_bw(struct vty *vty, |
ead99d5f | 1717 | struct tlv_header *tlvh) |
718e3744 | 1718 | { |
d62a17ae | 1719 | struct te_link_subtlv_max_bw *top; |
1720 | float fval; | |
718e3744 | 1721 | |
d62a17ae | 1722 | top = (struct te_link_subtlv_max_bw *)tlvh; |
1723 | fval = ntohf(top->value); | |
718e3744 | 1724 | |
d62a17ae | 1725 | if (vty != NULL) |
1726 | vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", fval); | |
1727 | else | |
1728 | zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval); | |
718e3744 | 1729 | |
d62a17ae | 1730 | return TLV_SIZE(tlvh); |
718e3744 | 1731 | } |
1732 | ||
d62a17ae | 1733 | static u_int16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, |
ead99d5f | 1734 | struct tlv_header *tlvh) |
718e3744 | 1735 | { |
d62a17ae | 1736 | struct te_link_subtlv_max_rsv_bw *top; |
1737 | float fval; | |
718e3744 | 1738 | |
d62a17ae | 1739 | top = (struct te_link_subtlv_max_rsv_bw *)tlvh; |
1740 | fval = ntohf(top->value); | |
718e3744 | 1741 | |
d62a17ae | 1742 | if (vty != NULL) |
1743 | vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n", | |
1744 | fval); | |
1745 | else | |
1746 | zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)", | |
1747 | fval); | |
718e3744 | 1748 | |
d62a17ae | 1749 | return TLV_SIZE(tlvh); |
718e3744 | 1750 | } |
1751 | ||
d62a17ae | 1752 | static u_int16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, |
ead99d5f | 1753 | struct tlv_header *tlvh) |
718e3744 | 1754 | { |
d62a17ae | 1755 | struct te_link_subtlv_unrsv_bw *top; |
1756 | float fval1, fval2; | |
1757 | int i; | |
718e3744 | 1758 | |
d62a17ae | 1759 | top = (struct te_link_subtlv_unrsv_bw *)tlvh; |
1760 | if (vty != NULL) | |
1761 | vty_out(vty, | |
1762 | " Unreserved Bandwidth per Class Type in Byte/s:\n"); | |
1763 | else | |
1764 | zlog_debug( | |
1765 | " Unreserved Bandwidth per Class Type in Byte/s:"); | |
1766 | for (i = 0; i < MAX_CLASS_TYPE; i += 2) { | |
1767 | fval1 = ntohf(top->value[i]); | |
1768 | fval2 = ntohf(top->value[i + 1]); | |
16f1b9ee | 1769 | |
d62a17ae | 1770 | if (vty != NULL) |
1771 | vty_out(vty, | |
1772 | " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", | |
1773 | i, fval1, i + 1, fval2); | |
1774 | else | |
1775 | zlog_debug( | |
1776 | " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", | |
1777 | i, fval1, i + 1, fval2); | |
1778 | } | |
718e3744 | 1779 | |
d62a17ae | 1780 | return TLV_SIZE(tlvh); |
718e3744 | 1781 | } |
1782 | ||
d62a17ae | 1783 | static u_int16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, |
ead99d5f | 1784 | struct tlv_header *tlvh) |
718e3744 | 1785 | { |
d62a17ae | 1786 | struct te_link_subtlv_rsc_clsclr *top; |
718e3744 | 1787 | |
d62a17ae | 1788 | top = (struct te_link_subtlv_rsc_clsclr *)tlvh; |
1789 | if (vty != NULL) | |
1790 | vty_out(vty, " Resource class/color: 0x%x\n", | |
1791 | (u_int32_t)ntohl(top->value)); | |
1792 | else | |
1793 | zlog_debug(" Resource Class/Color: 0x%x", | |
1794 | (u_int32_t)ntohl(top->value)); | |
16f1b9ee | 1795 | |
d62a17ae | 1796 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1797 | } |
1798 | ||
d62a17ae | 1799 | static u_int16_t show_vty_link_subtlv_lrrid(struct vty *vty, |
ead99d5f | 1800 | struct tlv_header *tlvh) |
16f1b9ee | 1801 | { |
d62a17ae | 1802 | struct te_link_subtlv_lrrid *top; |
16f1b9ee | 1803 | |
d62a17ae | 1804 | top = (struct te_link_subtlv_lrrid *)tlvh; |
16f1b9ee | 1805 | |
d62a17ae | 1806 | if (vty != NULL) { |
1807 | vty_out(vty, " Local TE Router ID: %s\n", | |
1808 | inet_ntoa(top->local)); | |
1809 | vty_out(vty, " Remote TE Router ID: %s\n", | |
1810 | inet_ntoa(top->remote)); | |
1811 | } else { | |
1812 | zlog_debug(" Local TE Router ID: %s", | |
1813 | inet_ntoa(top->local)); | |
1814 | zlog_debug(" Remote TE Router ID: %s", | |
1815 | inet_ntoa(top->remote)); | |
1816 | } | |
16f1b9ee | 1817 | |
d62a17ae | 1818 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1819 | } |
1820 | ||
d62a17ae | 1821 | static u_int16_t show_vty_link_subtlv_llri(struct vty *vty, |
ead99d5f | 1822 | struct tlv_header *tlvh) |
16f1b9ee | 1823 | { |
d62a17ae | 1824 | struct te_link_subtlv_llri *top; |
16f1b9ee | 1825 | |
d62a17ae | 1826 | top = (struct te_link_subtlv_llri *)tlvh; |
16f1b9ee | 1827 | |
d62a17ae | 1828 | if (vty != NULL) { |
1829 | vty_out(vty, " Link Local ID: %d\n", | |
1830 | (u_int32_t)ntohl(top->local)); | |
1831 | vty_out(vty, " Link Remote ID: %d\n", | |
1832 | (u_int32_t)ntohl(top->remote)); | |
1833 | } else { | |
1834 | zlog_debug(" Link Local ID: %d", | |
1835 | (u_int32_t)ntohl(top->local)); | |
1836 | zlog_debug(" Link Remote ID: %d", | |
1837 | (u_int32_t)ntohl(top->remote)); | |
1838 | } | |
16f1b9ee | 1839 | |
d62a17ae | 1840 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1841 | } |
1842 | ||
d62a17ae | 1843 | static u_int16_t show_vty_link_subtlv_rip(struct vty *vty, |
ead99d5f | 1844 | struct tlv_header *tlvh) |
16f1b9ee | 1845 | { |
d62a17ae | 1846 | struct te_link_subtlv_rip *top; |
16f1b9ee | 1847 | |
d62a17ae | 1848 | top = (struct te_link_subtlv_rip *)tlvh; |
16f1b9ee | 1849 | |
d62a17ae | 1850 | if (vty != NULL) |
1851 | vty_out(vty, " Inter-AS TE Remote ASBR IP address: %s\n", | |
1852 | inet_ntoa(top->value)); | |
1853 | else | |
1854 | zlog_debug(" Inter-AS TE Remote ASBR IP address: %s", | |
1855 | inet_ntoa(top->value)); | |
16f1b9ee | 1856 | |
d62a17ae | 1857 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1858 | } |
1859 | ||
d62a17ae | 1860 | static u_int16_t show_vty_link_subtlv_ras(struct vty *vty, |
ead99d5f | 1861 | struct tlv_header *tlvh) |
16f1b9ee | 1862 | { |
d62a17ae | 1863 | struct te_link_subtlv_ras *top; |
16f1b9ee | 1864 | |
d62a17ae | 1865 | top = (struct te_link_subtlv_ras *)tlvh; |
16f1b9ee | 1866 | |
d62a17ae | 1867 | if (vty != NULL) |
1868 | vty_out(vty, " Inter-AS TE Remote AS number: %u\n", | |
1869 | ntohl(top->value)); | |
1870 | else | |
1871 | zlog_debug(" Inter-AS TE Remote AS number: %u", | |
1872 | ntohl(top->value)); | |
16f1b9ee | 1873 | |
d62a17ae | 1874 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1875 | } |
1876 | ||
d62a17ae | 1877 | static u_int16_t show_vty_link_subtlv_av_delay(struct vty *vty, |
ead99d5f | 1878 | struct tlv_header *tlvh) |
16f1b9ee | 1879 | { |
d62a17ae | 1880 | struct te_link_subtlv_av_delay *top; |
1881 | u_int32_t delay; | |
1882 | u_int32_t anomalous; | |
16f1b9ee | 1883 | |
d62a17ae | 1884 | top = (struct te_link_subtlv_av_delay *)tlvh; |
1885 | delay = (u_int32_t)ntohl(top->value) & TE_EXT_MASK; | |
1886 | anomalous = (u_int32_t)ntohl(top->value) & TE_EXT_ANORMAL; | |
16f1b9ee | 1887 | |
d62a17ae | 1888 | if (vty != NULL) |
1889 | vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n", | |
1890 | anomalous ? "Anomalous" : "Normal", delay); | |
1891 | else | |
1892 | zlog_debug(" %s Average Link Delay: %d (micro-sec)", | |
1893 | anomalous ? "Anomalous" : "Normal", delay); | |
16f1b9ee | 1894 | |
d62a17ae | 1895 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1896 | } |
1897 | ||
d62a17ae | 1898 | static u_int16_t show_vty_link_subtlv_mm_delay(struct vty *vty, |
ead99d5f | 1899 | struct tlv_header *tlvh) |
16f1b9ee | 1900 | { |
d62a17ae | 1901 | struct te_link_subtlv_mm_delay *top; |
1902 | u_int32_t low, high; | |
1903 | u_int32_t anomalous; | |
16f1b9ee | 1904 | |
d62a17ae | 1905 | top = (struct te_link_subtlv_mm_delay *)tlvh; |
1906 | low = (u_int32_t)ntohl(top->low) & TE_EXT_MASK; | |
1907 | anomalous = (u_int32_t)ntohl(top->low) & TE_EXT_ANORMAL; | |
1908 | high = (u_int32_t)ntohl(top->high); | |
16f1b9ee | 1909 | |
d62a17ae | 1910 | if (vty != NULL) |
1911 | vty_out(vty, " %s Min/Max Link Delay: %d/%d (micro-sec)\n", | |
1912 | anomalous ? "Anomalous" : "Normal", low, high); | |
1913 | else | |
1914 | zlog_debug(" %s Min/Max Link Delay: %d/%d (micro-sec)", | |
1915 | anomalous ? "Anomalous" : "Normal", low, high); | |
16f1b9ee | 1916 | |
d62a17ae | 1917 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1918 | } |
1919 | ||
d62a17ae | 1920 | static u_int16_t show_vty_link_subtlv_delay_var(struct vty *vty, |
ead99d5f | 1921 | struct tlv_header *tlvh) |
16f1b9ee | 1922 | { |
d62a17ae | 1923 | struct te_link_subtlv_delay_var *top; |
1924 | u_int32_t jitter; | |
16f1b9ee | 1925 | |
d62a17ae | 1926 | top = (struct te_link_subtlv_delay_var *)tlvh; |
1927 | jitter = (u_int32_t)ntohl(top->value) & TE_EXT_MASK; | |
16f1b9ee | 1928 | |
d62a17ae | 1929 | if (vty != NULL) |
1930 | vty_out(vty, " Delay Variation: %d (micro-sec)\n", jitter); | |
1931 | else | |
1932 | zlog_debug(" Delay Variation: %d (micro-sec)", jitter); | |
16f1b9ee | 1933 | |
d62a17ae | 1934 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1935 | } |
1936 | ||
d62a17ae | 1937 | static u_int16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, |
ead99d5f | 1938 | struct tlv_header *tlvh) |
16f1b9ee | 1939 | { |
d62a17ae | 1940 | struct te_link_subtlv_pkt_loss *top; |
1941 | u_int32_t loss; | |
1942 | u_int32_t anomalous; | |
1943 | float fval; | |
16f1b9ee | 1944 | |
d62a17ae | 1945 | top = (struct te_link_subtlv_pkt_loss *)tlvh; |
1946 | loss = (u_int32_t)ntohl(top->value) & TE_EXT_MASK; | |
1947 | fval = (float)(loss * LOSS_PRECISION); | |
1948 | anomalous = (u_int32_t)ntohl(top->value) & TE_EXT_ANORMAL; | |
16f1b9ee | 1949 | |
d62a17ae | 1950 | if (vty != NULL) |
1951 | vty_out(vty, " %s Link Loss: %g (%%)\n", | |
1952 | anomalous ? "Anomalous" : "Normal", fval); | |
1953 | else | |
1954 | zlog_debug(" %s Link Loss: %g (%%)", | |
1955 | anomalous ? "Anomalous" : "Normal", fval); | |
16f1b9ee | 1956 | |
d62a17ae | 1957 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
1958 | } |
1959 | ||
d62a17ae | 1960 | static u_int16_t show_vty_link_subtlv_res_bw(struct vty *vty, |
ead99d5f | 1961 | struct tlv_header *tlvh) |
16f1b9ee | 1962 | { |
d62a17ae | 1963 | struct te_link_subtlv_res_bw *top; |
1964 | float fval; | |
16f1b9ee | 1965 | |
d62a17ae | 1966 | top = (struct te_link_subtlv_res_bw *)tlvh; |
1967 | fval = ntohf(top->value); | |
16f1b9ee | 1968 | |
d62a17ae | 1969 | if (vty != NULL) |
1970 | vty_out(vty, | |
1971 | " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", | |
1972 | fval); | |
1973 | else | |
1974 | zlog_debug( | |
1975 | " Unidirectional Residual Bandwidth: %g (Bytes/sec)", | |
1976 | fval); | |
1977 | ||
1978 | return TLV_SIZE(tlvh); | |
1979 | } | |
1980 | ||
1981 | static u_int16_t show_vty_link_subtlv_ava_bw(struct vty *vty, | |
ead99d5f | 1982 | struct tlv_header *tlvh) |
d62a17ae | 1983 | { |
1984 | struct te_link_subtlv_ava_bw *top; | |
1985 | float fval; | |
1986 | ||
1987 | top = (struct te_link_subtlv_ava_bw *)tlvh; | |
1988 | fval = ntohf(top->value); | |
1989 | ||
1990 | if (vty != NULL) | |
1991 | vty_out(vty, | |
1992 | " Unidirectional Available Bandwidth: %g (Bytes/sec)\n", | |
1993 | fval); | |
1994 | else | |
1995 | zlog_debug( | |
1996 | " Unidirectional Available Bandwidth: %g (Bytes/sec)", | |
1997 | fval); | |
1998 | ||
1999 | return TLV_SIZE(tlvh); | |
2000 | } | |
2001 | ||
2002 | static u_int16_t show_vty_link_subtlv_use_bw(struct vty *vty, | |
ead99d5f | 2003 | struct tlv_header *tlvh) |
d62a17ae | 2004 | { |
2005 | struct te_link_subtlv_use_bw *top; | |
2006 | float fval; | |
2007 | ||
2008 | top = (struct te_link_subtlv_use_bw *)tlvh; | |
2009 | fval = ntohf(top->value); | |
2010 | ||
2011 | if (vty != NULL) | |
2012 | vty_out(vty, | |
2013 | " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", | |
2014 | fval); | |
2015 | else | |
2016 | zlog_debug( | |
2017 | " Unidirectional Utilized Bandwidth: %g (Bytes/sec)", | |
2018 | fval); | |
2019 | ||
2020 | return TLV_SIZE(tlvh); | |
2021 | } | |
2022 | ||
2023 | static u_int16_t show_vty_unknown_tlv(struct vty *vty, | |
ead99d5f | 2024 | struct tlv_header *tlvh) |
d62a17ae | 2025 | { |
2026 | if (vty != NULL) | |
2027 | vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", | |
2028 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
2029 | else | |
2030 | zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", | |
2031 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
2032 | ||
2033 | return TLV_SIZE(tlvh); | |
2034 | } | |
2035 | ||
2036 | static u_int16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, | |
ead99d5f | 2037 | struct tlv_header *tlvh0, |
d62a17ae | 2038 | u_int16_t subtotal, |
2039 | u_int16_t total) | |
2040 | { | |
ead99d5f | 2041 | struct tlv_header *tlvh, *next; |
d62a17ae | 2042 | u_int16_t sum = subtotal; |
2043 | ||
2044 | for (tlvh = tlvh0; sum < total; | |
2045 | tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { | |
2046 | next = NULL; | |
2047 | switch (ntohs(tlvh->type)) { | |
2048 | case TE_LINK_SUBTLV_LINK_TYPE: | |
2049 | sum += show_vty_link_subtlv_link_type(vty, tlvh); | |
2050 | break; | |
2051 | case TE_LINK_SUBTLV_LINK_ID: | |
2052 | sum += show_vty_link_subtlv_link_id(vty, tlvh); | |
2053 | break; | |
2054 | case TE_LINK_SUBTLV_LCLIF_IPADDR: | |
2055 | sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh); | |
2056 | break; | |
2057 | case TE_LINK_SUBTLV_RMTIF_IPADDR: | |
2058 | sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh); | |
2059 | break; | |
2060 | case TE_LINK_SUBTLV_TE_METRIC: | |
2061 | sum += show_vty_link_subtlv_te_metric(vty, tlvh); | |
2062 | break; | |
2063 | case TE_LINK_SUBTLV_MAX_BW: | |
2064 | sum += show_vty_link_subtlv_max_bw(vty, tlvh); | |
2065 | break; | |
2066 | case TE_LINK_SUBTLV_MAX_RSV_BW: | |
2067 | sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh); | |
2068 | break; | |
2069 | case TE_LINK_SUBTLV_UNRSV_BW: | |
2070 | sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh); | |
2071 | break; | |
2072 | case TE_LINK_SUBTLV_RSC_CLSCLR: | |
2073 | sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh); | |
2074 | break; | |
2075 | case TE_LINK_SUBTLV_LRRID: | |
2076 | sum += show_vty_link_subtlv_lrrid(vty, tlvh); | |
2077 | break; | |
2078 | case TE_LINK_SUBTLV_LLRI: | |
2079 | sum += show_vty_link_subtlv_llri(vty, tlvh); | |
2080 | break; | |
2081 | case TE_LINK_SUBTLV_RIP: | |
2082 | sum += show_vty_link_subtlv_rip(vty, tlvh); | |
2083 | break; | |
2084 | case TE_LINK_SUBTLV_RAS: | |
2085 | sum += show_vty_link_subtlv_ras(vty, tlvh); | |
2086 | break; | |
2087 | case TE_LINK_SUBTLV_AV_DELAY: | |
2088 | sum += show_vty_link_subtlv_av_delay(vty, tlvh); | |
2089 | break; | |
2090 | case TE_LINK_SUBTLV_MM_DELAY: | |
2091 | sum += show_vty_link_subtlv_mm_delay(vty, tlvh); | |
2092 | break; | |
2093 | case TE_LINK_SUBTLV_DELAY_VAR: | |
2094 | sum += show_vty_link_subtlv_delay_var(vty, tlvh); | |
2095 | break; | |
2096 | case TE_LINK_SUBTLV_PKT_LOSS: | |
2097 | sum += show_vty_link_subtlv_pkt_loss(vty, tlvh); | |
2098 | break; | |
2099 | case TE_LINK_SUBTLV_RES_BW: | |
2100 | sum += show_vty_link_subtlv_res_bw(vty, tlvh); | |
2101 | break; | |
2102 | case TE_LINK_SUBTLV_AVA_BW: | |
2103 | sum += show_vty_link_subtlv_ava_bw(vty, tlvh); | |
2104 | break; | |
2105 | case TE_LINK_SUBTLV_USE_BW: | |
2106 | sum += show_vty_link_subtlv_use_bw(vty, tlvh); | |
2107 | break; | |
2108 | default: | |
2109 | sum += show_vty_unknown_tlv(vty, tlvh); | |
2110 | break; | |
2111 | } | |
2112 | } | |
2113 | return sum; | |
2114 | } | |
2115 | ||
2116 | static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) | |
2117 | { | |
2118 | struct lsa_header *lsah = (struct lsa_header *)lsa->data; | |
ead99d5f | 2119 | struct tlv_header *tlvh, *next; |
d62a17ae | 2120 | u_int16_t sum, total; |
ead99d5f | 2121 | u_int16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, |
d62a17ae | 2122 | u_int16_t subtotal, u_int16_t total) = NULL; |
2123 | ||
2124 | sum = 0; | |
2125 | total = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; | |
2126 | ||
2127 | for (tlvh = TLV_HDR_TOP(lsah); sum < total; | |
2128 | tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { | |
2129 | if (subfunc != NULL) { | |
2130 | sum = (*subfunc)(vty, tlvh, sum, total); | |
ead99d5f | 2131 | next = (struct tlv_header *)((char *)tlvh + sum); |
d62a17ae | 2132 | subfunc = NULL; |
2133 | continue; | |
2134 | } | |
2135 | ||
2136 | next = NULL; | |
2137 | switch (ntohs(tlvh->type)) { | |
2138 | case TE_TLV_ROUTER_ADDR: | |
2139 | sum += show_vty_router_addr(vty, tlvh); | |
2140 | break; | |
2141 | case TE_TLV_LINK: | |
2142 | sum += show_vty_link_header(vty, tlvh); | |
2143 | subfunc = ospf_mpls_te_show_link_subtlv; | |
5d0df50f | 2144 | next = TLV_DATA(tlvh); |
d62a17ae | 2145 | break; |
2146 | default: | |
2147 | sum += show_vty_unknown_tlv(vty, tlvh); | |
2148 | break; | |
2149 | } | |
2150 | } | |
2151 | return; | |
2152 | } | |
2153 | ||
2154 | static void ospf_mpls_te_config_write_router(struct vty *vty) | |
2155 | { | |
2156 | ||
32ab5cf4 | 2157 | if (OspfMplsTE.enabled) { |
d62a17ae | 2158 | vty_out(vty, " mpls-te on\n"); |
2159 | vty_out(vty, " mpls-te router-address %s\n", | |
2160 | inet_ntoa(OspfMplsTE.router_addr.value)); | |
2161 | } | |
2162 | ||
2163 | if (OspfMplsTE.inter_as == AS) | |
2164 | vty_out(vty, " mpls-te inter-as as\n"); | |
2165 | if (OspfMplsTE.inter_as == Area) | |
2166 | vty_out(vty, " mpls-te inter-as area %s \n", | |
2167 | inet_ntoa(OspfMplsTE.interas_areaid)); | |
2168 | ||
2169 | return; | |
718e3744 | 2170 | } |
2171 | ||
2172 | /*------------------------------------------------------------------------* | |
2173 | * Followings are vty command functions. | |
2174 | *------------------------------------------------------------------------*/ | |
2175 | ||
16f1b9ee OD |
2176 | DEFUN (ospf_mpls_te_on, |
2177 | ospf_mpls_te_on_cmd, | |
2178 | "mpls-te on", | |
2179 | MPLS_TE_STR | |
718e3744 | 2180 | "Enable the MPLS-TE functionality\n") |
2181 | { | |
a3d826f0 | 2182 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 2183 | struct listnode *node; |
2184 | struct mpls_te_link *lp; | |
7c8ff89e | 2185 | |
32ab5cf4 | 2186 | if (OspfMplsTE.enabled) |
d62a17ae | 2187 | return CMD_SUCCESS; |
718e3744 | 2188 | |
d62a17ae | 2189 | if (IS_DEBUG_OSPF_EVENT) |
2190 | zlog_debug("MPLS-TE: OFF -> ON"); | |
718e3744 | 2191 | |
32ab5cf4 | 2192 | OspfMplsTE.enabled = true; |
718e3744 | 2193 | |
d62a17ae | 2194 | /* Reoriginate RFC3630 & RFC6827 Links */ |
2195 | ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, | |
2196 | REORIGINATE_THIS_LSA); | |
718e3744 | 2197 | |
d62a17ae | 2198 | /* Reoriginate LSA if INTER-AS is always on */ |
ead99d5f | 2199 | if (OspfMplsTE.inter_as != Off) { |
d62a17ae | 2200 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) { |
2201 | if (IS_INTER_AS(lp->type)) { | |
2202 | ospf_mpls_te_lsa_schedule(lp, | |
2203 | REORIGINATE_THIS_LSA); | |
2204 | } | |
2205 | } | |
2206 | } | |
718e3744 | 2207 | |
d62a17ae | 2208 | return CMD_SUCCESS; |
718e3744 | 2209 | } |
2210 | ||
16f1b9ee OD |
2211 | DEFUN (no_ospf_mpls_te, |
2212 | no_ospf_mpls_te_cmd, | |
3a2d747c | 2213 | "no mpls-te [on]", |
718e3744 | 2214 | NO_STR |
3a2d747c | 2215 | MPLS_TE_STR |
718e3744 | 2216 | "Disable the MPLS-TE functionality\n") |
2217 | { | |
a3d826f0 | 2218 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 2219 | struct listnode *node, *nnode; |
2220 | struct mpls_te_link *lp; | |
718e3744 | 2221 | |
32ab5cf4 | 2222 | if (!OspfMplsTE.enabled) |
d62a17ae | 2223 | return CMD_SUCCESS; |
718e3744 | 2224 | |
d62a17ae | 2225 | if (IS_DEBUG_OSPF_EVENT) |
2226 | zlog_debug("MPLS-TE: ON -> OFF"); | |
718e3744 | 2227 | |
32ab5cf4 | 2228 | OspfMplsTE.enabled = false; |
718e3744 | 2229 | |
d62a17ae | 2230 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) |
32ab5cf4 OD |
2231 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
2232 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
718e3744 | 2233 | |
d62a17ae | 2234 | return CMD_SUCCESS; |
718e3744 | 2235 | } |
2236 | ||
813d4307 | 2237 | |
16f1b9ee OD |
2238 | DEFUN (ospf_mpls_te_router_addr, |
2239 | ospf_mpls_te_router_addr_cmd, | |
718e3744 | 2240 | "mpls-te router-address A.B.C.D", |
16f1b9ee | 2241 | MPLS_TE_STR |
718e3744 | 2242 | "Stable IP address of the advertising router\n" |
2243 | "MPLS-TE router address in IPv4 address format\n") | |
2244 | { | |
a3d826f0 | 2245 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 2246 | int idx_ipv4 = 2; |
2247 | struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; | |
2248 | struct in_addr value; | |
2249 | ||
2250 | if (!inet_aton(argv[idx_ipv4]->arg, &value)) { | |
2251 | vty_out(vty, "Please specify Router-Addr by A.B.C.D\n"); | |
2252 | return CMD_WARNING; | |
2253 | } | |
2254 | ||
2255 | if (ntohs(ra->header.type) == 0 | |
2256 | || ntohl(ra->value.s_addr) != ntohl(value.s_addr)) { | |
2257 | struct listnode *node, *nnode; | |
2258 | struct mpls_te_link *lp; | |
2259 | int need_to_reoriginate = 0; | |
2260 | ||
2261 | set_mpls_te_router_addr(value); | |
2262 | ||
32ab5cf4 | 2263 | if (!OspfMplsTE.enabled) |
ead99d5f | 2264 | return CMD_SUCCESS; |
d62a17ae | 2265 | |
2266 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
2267 | if ((lp->area == NULL) || IS_FLOOD_AS(lp->type)) | |
2268 | continue; | |
2269 | ||
2270 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
2271 | need_to_reoriginate = 1; | |
2272 | break; | |
2273 | } | |
2274 | } | |
2275 | ||
2276 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
2277 | if ((lp->area == NULL) || IS_FLOOD_AS(lp->type)) | |
2278 | continue; | |
2279 | ||
2280 | if (need_to_reoriginate) | |
2281 | SET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); | |
2282 | else | |
2283 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
2284 | } | |
2285 | ||
2286 | if (need_to_reoriginate) | |
2287 | ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, | |
2288 | REORIGINATE_THIS_LSA); | |
2289 | } | |
ead99d5f | 2290 | |
d62a17ae | 2291 | return CMD_SUCCESS; |
2292 | } | |
2293 | ||
2294 | static int set_inter_as_mode(struct vty *vty, const char *mode_name, | |
2295 | const char *area_id) | |
2296 | { | |
2297 | enum inter_as_mode mode; | |
2298 | struct listnode *node; | |
2299 | struct mpls_te_link *lp; | |
2300 | int format; | |
2301 | ||
32ab5cf4 | 2302 | if (OspfMplsTE.enabled) { |
d62a17ae | 2303 | |
2304 | /* Read and Check inter_as mode */ | |
2305 | if (strcmp(mode_name, "as") == 0) | |
2306 | mode = AS; | |
2307 | else if (strcmp(mode_name, "area") == 0) { | |
2308 | mode = Area; | |
2309 | VTY_GET_OSPF_AREA_ID(OspfMplsTE.interas_areaid, format, | |
2310 | area_id); | |
2311 | } else { | |
2312 | vty_out(vty, | |
2313 | "Unknown mode. Please choose between as or area\n"); | |
2314 | return CMD_WARNING; | |
2315 | } | |
2316 | ||
2317 | if (IS_DEBUG_OSPF_EVENT) | |
2318 | zlog_debug( | |
2319 | "MPLS-TE: Inter-AS enable with %s flooding support", | |
2320 | mode2text[mode]); | |
2321 | ||
2322 | /* Register new callbacks regarding the flooding scope (AS or | |
2323 | * Area) */ | |
2324 | if (ospf_mpls_te_register(mode) < 0) { | |
2325 | vty_out(vty, | |
2326 | "Internal error: Unable to register Inter-AS functions\n"); | |
2327 | return CMD_WARNING; | |
2328 | } | |
2329 | ||
2330 | /* Enable mode and re-originate LSA if needed */ | |
ead99d5f | 2331 | if ((OspfMplsTE.inter_as == Off) |
d62a17ae | 2332 | && (mode != OspfMplsTE.inter_as)) { |
2333 | OspfMplsTE.inter_as = mode; | |
2334 | /* Re-originate all InterAS-TEv2 LSA */ | |
2335 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, | |
2336 | lp)) { | |
2337 | if (IS_INTER_AS(lp->type)) { | |
2338 | if (mode == AS) | |
2339 | lp->type |= FLOOD_AS; | |
2340 | else | |
2341 | lp->type |= FLOOD_AREA; | |
2342 | ospf_mpls_te_lsa_schedule( | |
2343 | lp, REORIGINATE_THIS_LSA); | |
2344 | } | |
2345 | } | |
2346 | } else { | |
2347 | vty_out(vty, | |
2348 | "Please change Inter-AS support to disable first before going to mode %s\n", | |
2349 | mode2text[mode]); | |
2350 | return CMD_WARNING; | |
2351 | } | |
2352 | } else { | |
2353 | vty_out(vty, "mpls-te has not been turned on\n"); | |
2354 | return CMD_WARNING; | |
2355 | } | |
2356 | return CMD_SUCCESS; | |
718e3744 | 2357 | } |
2358 | ||
718e3744 | 2359 | |
16f1b9ee OD |
2360 | DEFUN (ospf_mpls_te_inter_as_as, |
2361 | ospf_mpls_te_inter_as_cmd, | |
2362 | "mpls-te inter-as as", | |
2363 | MPLS_TE_STR | |
2364 | "Configure MPLS-TE Inter-AS support\n" | |
2365 | "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") | |
2366 | { | |
d62a17ae | 2367 | return set_inter_as_mode(vty, "as", ""); |
718e3744 | 2368 | } |
2369 | ||
16f1b9ee OD |
2370 | DEFUN (ospf_mpls_te_inter_as_area, |
2371 | ospf_mpls_te_inter_as_area_cmd, | |
6147e2c6 | 2372 | "mpls-te inter-as area <A.B.C.D|(0-4294967295)>", |
16f1b9ee OD |
2373 | MPLS_TE_STR |
2374 | "Configure MPLS-TE Inter-AS support\n" | |
2375 | "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" | |
2376 | "OSPF area ID in IP format\n" | |
2377 | "OSPF area ID as decimal value\n") | |
718e3744 | 2378 | { |
d62a17ae | 2379 | int idx_ipv4_number = 3; |
2380 | return set_inter_as_mode(vty, "area", argv[idx_ipv4_number]->arg); | |
718e3744 | 2381 | } |
2382 | ||
16f1b9ee OD |
2383 | DEFUN (no_ospf_mpls_te_inter_as, |
2384 | no_ospf_mpls_te_inter_as_cmd, | |
2385 | "no mpls-te inter-as", | |
2386 | NO_STR | |
2387 | MPLS_TE_STR | |
2388 | "Disable MPLS-TE Inter-AS support\n") | |
718e3744 | 2389 | { |
16f1b9ee | 2390 | |
d62a17ae | 2391 | struct listnode *node, *nnode; |
2392 | struct mpls_te_link *lp; | |
718e3744 | 2393 | |
d62a17ae | 2394 | if (IS_DEBUG_OSPF_EVENT) |
2395 | zlog_debug("MPLS-TE: Inter-AS support OFF"); | |
718e3744 | 2396 | |
32ab5cf4 | 2397 | if ((OspfMplsTE.enabled) |
ead99d5f OD |
2398 | && (OspfMplsTE.inter_as != Off)) { |
2399 | OspfMplsTE.inter_as = Off; | |
d62a17ae | 2400 | /* Flush all Inter-AS LSA */ |
2401 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) | |
2402 | if (IS_INTER_AS(lp->type) | |
2403 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) | |
2404 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
2405 | } | |
718e3744 | 2406 | |
d62a17ae | 2407 | /* Deregister the Callbacks for Inter-AS suport */ |
2408 | ospf_mpls_te_unregister(); | |
718e3744 | 2409 | |
d62a17ae | 2410 | return CMD_SUCCESS; |
718e3744 | 2411 | } |
2412 | ||
16f1b9ee OD |
2413 | DEFUN (show_ip_ospf_mpls_te_router, |
2414 | show_ip_ospf_mpls_te_router_cmd, | |
2415 | "show ip ospf mpls-te router", | |
718e3744 | 2416 | SHOW_STR |
16f1b9ee OD |
2417 | IP_STR |
2418 | OSPF_STR | |
718e3744 | 2419 | "MPLS-TE information\n" |
16f1b9ee | 2420 | "MPLS-TE Router parameters\n") |
718e3744 | 2421 | { |
32ab5cf4 | 2422 | if (OspfMplsTE.enabled) { |
d62a17ae | 2423 | vty_out(vty, "--- MPLS-TE router parameters ---\n"); |
2424 | ||
2425 | if (ntohs(OspfMplsTE.router_addr.header.type) != 0) | |
2426 | show_vty_router_addr(vty, | |
2427 | &OspfMplsTE.router_addr.header); | |
2428 | else if (vty != NULL) | |
2429 | vty_out(vty, " N/A\n"); | |
2430 | } | |
2431 | return CMD_SUCCESS; | |
2432 | } | |
2433 | ||
2434 | static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) | |
2435 | { | |
2436 | struct mpls_te_link *lp; | |
2437 | ||
32ab5cf4 | 2438 | if ((OspfMplsTE.enabled) && HAS_LINK_PARAMS(ifp) |
d62a17ae | 2439 | && !if_is_loopback(ifp) && if_is_up(ifp) |
2440 | && ((lp = lookup_linkparams_by_ifp(ifp)) != NULL)) { | |
2441 | /* Continue only if interface is not passive or support Inter-AS | |
2442 | * TEv2 */ | |
2443 | if (!(ospf_oi_count(ifp) > 0)) { | |
2444 | if (IS_INTER_AS(lp->type)) { | |
2445 | vty_out(vty, | |
2446 | "-- Inter-AS TEv2 link parameters for %s --\n", | |
2447 | ifp->name); | |
2448 | } else { | |
2449 | /* MPLS-TE is not activate on this interface */ | |
2450 | /* or this interface is passive and Inter-AS | |
2451 | * TEv2 is not activate */ | |
2452 | vty_out(vty, | |
2453 | " %s: MPLS-TE is disabled on this interface\n", | |
2454 | ifp->name); | |
2455 | return; | |
2456 | } | |
2457 | } else { | |
2458 | vty_out(vty, "-- MPLS-TE link parameters for %s --\n", | |
2459 | ifp->name); | |
2460 | } | |
2461 | ||
2462 | if (TLV_TYPE(lp->link_type) != 0) | |
2463 | show_vty_link_subtlv_link_type(vty, | |
2464 | &lp->link_type.header); | |
2465 | if (TLV_TYPE(lp->link_id) != 0) | |
2466 | show_vty_link_subtlv_link_id(vty, &lp->link_id.header); | |
2467 | if (TLV_TYPE(lp->lclif_ipaddr) != 0) | |
2468 | show_vty_link_subtlv_lclif_ipaddr( | |
2469 | vty, &lp->lclif_ipaddr.header); | |
2470 | if (TLV_TYPE(lp->rmtif_ipaddr) != 0) | |
2471 | show_vty_link_subtlv_rmtif_ipaddr( | |
2472 | vty, &lp->rmtif_ipaddr.header); | |
2473 | if (TLV_TYPE(lp->rip) != 0) | |
2474 | show_vty_link_subtlv_rip(vty, &lp->rip.header); | |
2475 | if (TLV_TYPE(lp->ras) != 0) | |
2476 | show_vty_link_subtlv_ras(vty, &lp->ras.header); | |
2477 | if (TLV_TYPE(lp->te_metric) != 0) | |
2478 | show_vty_link_subtlv_te_metric(vty, | |
2479 | &lp->te_metric.header); | |
2480 | if (TLV_TYPE(lp->max_bw) != 0) | |
2481 | show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header); | |
2482 | if (TLV_TYPE(lp->max_rsv_bw) != 0) | |
2483 | show_vty_link_subtlv_max_rsv_bw(vty, | |
2484 | &lp->max_rsv_bw.header); | |
2485 | if (TLV_TYPE(lp->unrsv_bw) != 0) | |
2486 | show_vty_link_subtlv_unrsv_bw(vty, | |
2487 | &lp->unrsv_bw.header); | |
2488 | if (TLV_TYPE(lp->rsc_clsclr) != 0) | |
2489 | show_vty_link_subtlv_rsc_clsclr(vty, | |
2490 | &lp->rsc_clsclr.header); | |
2491 | if (TLV_TYPE(lp->av_delay) != 0) | |
2492 | show_vty_link_subtlv_av_delay(vty, | |
2493 | &lp->av_delay.header); | |
2494 | if (TLV_TYPE(lp->mm_delay) != 0) | |
2495 | show_vty_link_subtlv_mm_delay(vty, | |
2496 | &lp->mm_delay.header); | |
2497 | if (TLV_TYPE(lp->delay_var) != 0) | |
2498 | show_vty_link_subtlv_delay_var(vty, | |
2499 | &lp->delay_var.header); | |
2500 | if (TLV_TYPE(lp->pkt_loss) != 0) | |
2501 | show_vty_link_subtlv_pkt_loss(vty, | |
2502 | &lp->pkt_loss.header); | |
2503 | if (TLV_TYPE(lp->res_bw) != 0) | |
2504 | show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header); | |
2505 | if (TLV_TYPE(lp->ava_bw) != 0) | |
2506 | show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header); | |
2507 | if (TLV_TYPE(lp->use_bw) != 0) | |
2508 | show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header); | |
2509 | vty_out(vty, "---------------\n\n"); | |
2510 | } else { | |
2511 | vty_out(vty, " %s: MPLS-TE is disabled on this interface\n", | |
2512 | ifp->name); | |
2513 | } | |
2514 | ||
2515 | return; | |
718e3744 | 2516 | } |
2517 | ||
16f1b9ee OD |
2518 | DEFUN (show_ip_ospf_mpls_te_link, |
2519 | show_ip_ospf_mpls_te_link_cmd, | |
2520 | "show ip ospf mpls-te interface [INTERFACE]", | |
718e3744 | 2521 | SHOW_STR |
16f1b9ee OD |
2522 | IP_STR |
2523 | OSPF_STR | |
718e3744 | 2524 | "MPLS-TE information\n" |
2525 | "Interface information\n" | |
2526 | "Interface name\n") | |
2527 | { | |
d62a17ae | 2528 | int idx_interface = 5; |
2529 | struct interface *ifp; | |
2530 | struct listnode *node, *nnode; | |
2531 | ||
2532 | /* Show All Interfaces. */ | |
2533 | if (argc == 5) { | |
2534 | for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, | |
2535 | ifp)) | |
2536 | show_mpls_te_link_sub(vty, ifp); | |
2537 | } | |
2538 | /* Interface name is specified. */ | |
2539 | else { | |
2540 | if ((ifp = if_lookup_by_name(argv[idx_interface]->arg, | |
2541 | VRF_DEFAULT)) | |
2542 | == NULL) | |
2543 | vty_out(vty, "No such interface name\n"); | |
2544 | else | |
2545 | show_mpls_te_link_sub(vty, ifp); | |
2546 | } | |
2547 | ||
2548 | return CMD_SUCCESS; | |
2549 | } | |
2550 | ||
2551 | static void ospf_mpls_te_register_vty(void) | |
2552 | { | |
2553 | install_element(VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd); | |
2554 | install_element(VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); | |
2555 | ||
2556 | install_element(OSPF_NODE, &ospf_mpls_te_on_cmd); | |
2557 | install_element(OSPF_NODE, &no_ospf_mpls_te_cmd); | |
2558 | install_element(OSPF_NODE, &ospf_mpls_te_router_addr_cmd); | |
2559 | install_element(OSPF_NODE, &ospf_mpls_te_inter_as_cmd); | |
2560 | install_element(OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); | |
2561 | install_element(OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); | |
2562 | ||
2563 | return; | |
718e3744 | 2564 | } |