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