]>
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" |
f173deb3 OD |
46 | #include "link_state.h" |
47 | #include "zclient.h" | |
48 | #include "printfrr.h" | |
718e3744 | 49 | |
50 | #include "ospfd/ospfd.h" | |
51 | #include "ospfd/ospf_interface.h" | |
52 | #include "ospfd/ospf_ism.h" | |
53 | #include "ospfd/ospf_asbr.h" | |
54 | #include "ospfd/ospf_lsa.h" | |
55 | #include "ospfd/ospf_lsdb.h" | |
56 | #include "ospfd/ospf_neighbor.h" | |
57 | #include "ospfd/ospf_nsm.h" | |
58 | #include "ospfd/ospf_flood.h" | |
59 | #include "ospfd/ospf_packet.h" | |
60 | #include "ospfd/ospf_spf.h" | |
61 | #include "ospfd/ospf_dump.h" | |
62 | #include "ospfd/ospf_route.h" | |
63 | #include "ospfd/ospf_ase.h" | |
64 | #include "ospfd/ospf_zebra.h" | |
65 | #include "ospfd/ospf_te.h" | |
f173deb3 OD |
66 | #include "ospfd/ospf_sr.h" |
67 | #include "ospfd/ospf_ri.h" | |
68 | #include "ospfd/ospf_ext.h" | |
16f1b9ee | 69 | #include "ospfd/ospf_vty.h" |
85c9b439 | 70 | #include "ospfd/ospf_errors.h" |
718e3744 | 71 | |
72 | /* | |
73 | * Global variable to manage Opaque-LSA/MPLS-TE on this node. | |
74 | * Note that all parameter values are stored in network byte order. | |
75 | */ | |
16f1b9ee | 76 | struct ospf_mpls_te OspfMplsTE; |
718e3744 | 77 | |
2b64873d | 78 | static const char *const mode2text[] = {"Off", "AS", "Area"}; |
718e3744 | 79 | |
f173deb3 | 80 | |
718e3744 | 81 | /*------------------------------------------------------------------------* |
78dfa0c7 | 82 | * Following are initialize/terminate functions for MPLS-TE handling. |
718e3744 | 83 | *------------------------------------------------------------------------*/ |
84 | ||
d62a17ae | 85 | static int ospf_mpls_te_new_if(struct interface *ifp); |
86 | static int ospf_mpls_te_del_if(struct interface *ifp); | |
87 | static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_status); | |
88 | static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_status); | |
89 | static void ospf_mpls_te_config_write_router(struct vty *vty); | |
3e63092b RW |
90 | static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, |
91 | struct ospf_lsa *lsa); | |
d62a17ae | 92 | static int ospf_mpls_te_lsa_originate_area(void *arg); |
2efd7e2b OD |
93 | static int ospf_mpls_te_lsa_inter_as_as(void *arg); |
94 | static int ospf_mpls_te_lsa_inter_as_area(void *arg); | |
d62a17ae | 95 | static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa); |
f173deb3 OD |
96 | static int ospf_mpls_te_lsa_update(struct ospf_lsa *lsa); |
97 | static int ospf_mpls_te_lsa_delete(struct ospf_lsa *lsa); | |
d62a17ae | 98 | |
99 | static void del_mpls_te_link(void *val); | |
100 | static void ospf_mpls_te_register_vty(void); | |
101 | ||
102 | int ospf_mpls_te_init(void) | |
103 | { | |
104 | int rc; | |
105 | ||
2efd7e2b | 106 | /* Register Opaque AREA LSA Type 1 for Traffic Engineering */ |
d62a17ae | 107 | rc = ospf_register_opaque_functab( |
f173deb3 OD |
108 | OSPF_OPAQUE_AREA_LSA, |
109 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
110 | ospf_mpls_te_new_if, | |
111 | ospf_mpls_te_del_if, | |
112 | ospf_mpls_te_ism_change, | |
113 | ospf_mpls_te_nsm_change, | |
718e3744 | 114 | ospf_mpls_te_config_write_router, |
f173deb3 | 115 | NULL, /* ospf_mpls_te_config_write_if */ |
d62a17ae | 116 | NULL, /* ospf_mpls_te_config_write_debug */ |
117 | ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate_area, | |
f173deb3 OD |
118 | ospf_mpls_te_lsa_refresh, |
119 | ospf_mpls_te_lsa_update, /* ospf_mpls_te_new_lsa_hook */ | |
120 | ospf_mpls_te_lsa_delete /* ospf_mpls_te_del_lsa_hook */); | |
d62a17ae | 121 | if (rc != 0) { |
ade6974d | 122 | flog_warn( |
cf444bcf | 123 | EC_OSPF_OPAQUE_REGISTRATION, |
fd3c7692 OD |
124 | "MPLS-TE (%s): Failed to register Traffic Engineering functions", |
125 | __func__); | |
ead99d5f | 126 | return rc; |
d62a17ae | 127 | } |
718e3744 | 128 | |
2efd7e2b OD |
129 | /* |
130 | * Wee need also to register Opaque LSA Type 6 i.e. Inter-AS RFC5392 for | |
131 | * both AREA and AS at least to have the possibility to call the show() | |
132 | * function when looking to the opaque LSA of the OSPF database. | |
133 | */ | |
134 | rc = ospf_register_opaque_functab(OSPF_OPAQUE_AREA_LSA, | |
135 | OPAQUE_TYPE_INTER_AS_LSA, NULL, | |
136 | NULL, NULL, NULL, NULL, NULL, NULL, | |
137 | ospf_mpls_te_show_info, | |
138 | ospf_mpls_te_lsa_inter_as_area, | |
139 | ospf_mpls_te_lsa_refresh, NULL, NULL); | |
140 | if (rc != 0) { | |
141 | flog_warn( | |
142 | EC_OSPF_OPAQUE_REGISTRATION, | |
143 | "MPLS-TE (%s): Failed to register Inter-AS with Area scope", | |
144 | __func__); | |
ead99d5f | 145 | return rc; |
2efd7e2b | 146 | } |
16f1b9ee | 147 | |
2efd7e2b OD |
148 | rc = ospf_register_opaque_functab(OSPF_OPAQUE_AS_LSA, |
149 | OPAQUE_TYPE_INTER_AS_LSA, NULL, | |
d62a17ae | 150 | NULL, NULL, NULL, NULL, NULL, NULL, |
151 | ospf_mpls_te_show_info, | |
2efd7e2b | 152 | ospf_mpls_te_lsa_inter_as_as, |
d62a17ae | 153 | ospf_mpls_te_lsa_refresh, NULL, NULL); |
d62a17ae | 154 | if (rc != 0) { |
2efd7e2b OD |
155 | flog_warn( |
156 | EC_OSPF_OPAQUE_REGISTRATION, | |
157 | "MPLS-TE (%s): Failed to register Inter-AS with AS scope", | |
158 | __func__); | |
d62a17ae | 159 | return rc; |
160 | } | |
16f1b9ee | 161 | |
6006b807 | 162 | memset(&OspfMplsTE, 0, sizeof(OspfMplsTE)); |
2efd7e2b OD |
163 | OspfMplsTE.enabled = false; |
164 | OspfMplsTE.export = false; | |
165 | OspfMplsTE.inter_as = Off; | |
166 | OspfMplsTE.iflist = list_new(); | |
167 | OspfMplsTE.iflist->del = del_mpls_te_link; | |
bcf4475e | 168 | |
2efd7e2b | 169 | ospf_mpls_te_register_vty(); |
bcf4475e | 170 | |
2efd7e2b | 171 | return rc; |
bcf4475e OD |
172 | } |
173 | ||
d62a17ae | 174 | void ospf_mpls_te_term(void) |
718e3744 | 175 | { |
6a154c88 | 176 | list_delete(&OspfMplsTE.iflist); |
718e3744 | 177 | |
bcf4475e OD |
178 | ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, |
179 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); | |
2efd7e2b OD |
180 | ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, |
181 | OPAQUE_TYPE_INTER_AS_LSA); | |
182 | ospf_delete_opaque_functab(OSPF_OPAQUE_AS_LSA, | |
183 | OPAQUE_TYPE_INTER_AS_LSA); | |
bcf4475e | 184 | |
32ab5cf4 | 185 | OspfMplsTE.enabled = false; |
ead99d5f | 186 | OspfMplsTE.inter_as = Off; |
f173deb3 | 187 | OspfMplsTE.export = false; |
16f1b9ee | 188 | |
d62a17ae | 189 | return; |
718e3744 | 190 | } |
191 | ||
bcf4475e OD |
192 | void ospf_mpls_te_finish(void) |
193 | { | |
bcf4475e OD |
194 | OspfMplsTE.enabled = false; |
195 | OspfMplsTE.inter_as = Off; | |
f173deb3 | 196 | OspfMplsTE.export = false; |
bcf4475e OD |
197 | } |
198 | ||
718e3744 | 199 | /*------------------------------------------------------------------------* |
78dfa0c7 | 200 | * Following are control functions for MPLS-TE parameters management. |
718e3744 | 201 | *------------------------------------------------------------------------*/ |
d62a17ae | 202 | static void del_mpls_te_link(void *val) |
718e3744 | 203 | { |
d62a17ae | 204 | XFREE(MTYPE_OSPF_MPLS_TE, val); |
205 | return; | |
718e3744 | 206 | } |
207 | ||
d7c0a89a | 208 | static uint32_t get_mpls_te_instance_value(void) |
718e3744 | 209 | { |
d7c0a89a | 210 | static uint32_t seqno = 0; |
718e3744 | 211 | |
d62a17ae | 212 | if (seqno < MAX_LEGAL_TE_INSTANCE_NUM) |
213 | seqno += 1; | |
214 | else | |
215 | seqno = 1; /* Avoid zero. */ | |
718e3744 | 216 | |
d62a17ae | 217 | return seqno; |
718e3744 | 218 | } |
219 | ||
d62a17ae | 220 | static struct mpls_te_link *lookup_linkparams_by_ifp(struct interface *ifp) |
718e3744 | 221 | { |
d62a17ae | 222 | struct listnode *node, *nnode; |
223 | struct mpls_te_link *lp; | |
718e3744 | 224 | |
d62a17ae | 225 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) |
226 | if (lp->ifp == ifp) | |
227 | return lp; | |
718e3744 | 228 | |
d62a17ae | 229 | return NULL; |
718e3744 | 230 | } |
231 | ||
d62a17ae | 232 | static struct mpls_te_link *lookup_linkparams_by_instance(struct ospf_lsa *lsa) |
718e3744 | 233 | { |
d62a17ae | 234 | struct listnode *node; |
235 | struct mpls_te_link *lp; | |
236 | unsigned int key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)); | |
718e3744 | 237 | |
d62a17ae | 238 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) |
239 | if (lp->instance == key) | |
240 | return lp; | |
718e3744 | 241 | |
fd3c7692 | 242 | ote_debug("MPLS-TE (%s): Entry not found: key(%x)", __func__, key); |
d62a17ae | 243 | return NULL; |
718e3744 | 244 | } |
245 | ||
996c9314 LB |
246 | static void ospf_mpls_te_foreach_area( |
247 | void (*func)(struct mpls_te_link *lp, enum lsa_opcode sched_opcode), | |
248 | enum lsa_opcode sched_opcode) | |
718e3744 | 249 | { |
d62a17ae | 250 | struct listnode *node, *nnode; |
251 | struct listnode *node2; | |
252 | struct mpls_te_link *lp; | |
253 | struct ospf_area *area; | |
718e3744 | 254 | |
d62a17ae | 255 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { |
256 | /* Skip Inter-AS TEv2 Links */ | |
257 | if (IS_INTER_AS(lp->type)) | |
258 | continue; | |
259 | if ((area = lp->area) == NULL) | |
260 | continue; | |
32ab5cf4 OD |
261 | if (CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE)) |
262 | continue; | |
718e3744 | 263 | |
d62a17ae | 264 | if (func != NULL) |
265 | (*func)(lp, sched_opcode); | |
718e3744 | 266 | |
d62a17ae | 267 | for (node2 = listnextnode(node); node2; |
268 | node2 = listnextnode(node2)) | |
269 | if ((lp = listgetdata(node2)) != NULL) | |
270 | if (lp->area != NULL) | |
271 | if (IPV4_ADDR_SAME(&lp->area->area_id, | |
272 | &area->area_id)) | |
273 | SET_FLAG(lp->flags, | |
274 | LPFLG_LOOKUP_DONE); | |
275 | } | |
718e3744 | 276 | |
d62a17ae | 277 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) |
278 | if (lp->area != NULL) | |
279 | UNSET_FLAG(lp->flags, LPFLG_LOOKUP_DONE); | |
718e3744 | 280 | |
d62a17ae | 281 | return; |
718e3744 | 282 | } |
283 | ||
d62a17ae | 284 | static void set_mpls_te_router_addr(struct in_addr ipv4) |
718e3744 | 285 | { |
d62a17ae | 286 | OspfMplsTE.router_addr.header.type = htons(TE_TLV_ROUTER_ADDR); |
287 | OspfMplsTE.router_addr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
288 | OspfMplsTE.router_addr.value = ipv4; | |
289 | return; | |
718e3744 | 290 | } |
291 | ||
d62a17ae | 292 | static void set_linkparams_link_header(struct mpls_te_link *lp) |
718e3744 | 293 | { |
d7c0a89a | 294 | uint16_t length = 0; |
718e3744 | 295 | |
d62a17ae | 296 | /* TE_LINK_SUBTLV_LINK_TYPE */ |
297 | if (ntohs(lp->link_type.header.type) != 0) | |
298 | length += TLV_SIZE(&lp->link_type.header); | |
718e3744 | 299 | |
d62a17ae | 300 | /* TE_LINK_SUBTLV_LINK_ID */ |
301 | if (ntohs(lp->link_id.header.type) != 0) | |
302 | length += TLV_SIZE(&lp->link_id.header); | |
718e3744 | 303 | |
d62a17ae | 304 | /* TE_LINK_SUBTLV_LCLIF_IPADDR */ |
305 | if (lp->lclif_ipaddr.header.type != 0) | |
306 | length += TLV_SIZE(&lp->lclif_ipaddr.header); | |
718e3744 | 307 | |
d62a17ae | 308 | /* TE_LINK_SUBTLV_RMTIF_IPADDR */ |
309 | if (lp->rmtif_ipaddr.header.type != 0) | |
310 | length += TLV_SIZE(&lp->rmtif_ipaddr.header); | |
718e3744 | 311 | |
d62a17ae | 312 | /* TE_LINK_SUBTLV_TE_METRIC */ |
313 | if (ntohs(lp->te_metric.header.type) != 0) | |
314 | length += TLV_SIZE(&lp->te_metric.header); | |
718e3744 | 315 | |
d62a17ae | 316 | /* TE_LINK_SUBTLV_MAX_BW */ |
317 | if (ntohs(lp->max_bw.header.type) != 0) | |
318 | length += TLV_SIZE(&lp->max_bw.header); | |
718e3744 | 319 | |
d62a17ae | 320 | /* TE_LINK_SUBTLV_MAX_RSV_BW */ |
321 | if (ntohs(lp->max_rsv_bw.header.type) != 0) | |
322 | length += TLV_SIZE(&lp->max_rsv_bw.header); | |
718e3744 | 323 | |
d62a17ae | 324 | /* TE_LINK_SUBTLV_UNRSV_BW */ |
325 | if (ntohs(lp->unrsv_bw.header.type) != 0) | |
326 | length += TLV_SIZE(&lp->unrsv_bw.header); | |
718e3744 | 327 | |
d62a17ae | 328 | /* TE_LINK_SUBTLV_RSC_CLSCLR */ |
329 | if (ntohs(lp->rsc_clsclr.header.type) != 0) | |
330 | length += TLV_SIZE(&lp->rsc_clsclr.header); | |
331 | ||
332 | /* TE_LINK_SUBTLV_LLRI */ | |
333 | if (ntohs(lp->llri.header.type) != 0) | |
334 | length += TLV_SIZE(&lp->llri.header); | |
335 | ||
336 | /* TE_LINK_SUBTLV_RIP */ | |
337 | if (ntohs(lp->rip.header.type) != 0) | |
338 | length += TLV_SIZE(&lp->rip.header); | |
339 | ||
340 | /* TE_LINK_SUBTLV_RAS */ | |
341 | if (ntohs(lp->ras.header.type) != 0) | |
342 | length += TLV_SIZE(&lp->ras.header); | |
343 | ||
344 | /* TE_LINK_SUBTLV_LRRID */ | |
345 | if (ntohs(lp->lrrid.header.type) != 0) | |
346 | length += TLV_SIZE(&lp->lrrid.header); | |
347 | ||
348 | /* TE_LINK_SUBTLV_AV_DELAY */ | |
349 | if (ntohs(lp->av_delay.header.type) != 0) | |
350 | length += TLV_SIZE(&lp->av_delay.header); | |
351 | ||
352 | /* TE_LINK_SUBTLV_MM_DELAY */ | |
353 | if (ntohs(lp->mm_delay.header.type) != 0) | |
354 | length += TLV_SIZE(&lp->mm_delay.header); | |
355 | ||
356 | /* TE_LINK_SUBTLV_DELAY_VAR */ | |
357 | if (ntohs(lp->delay_var.header.type) != 0) | |
358 | length += TLV_SIZE(&lp->delay_var.header); | |
359 | ||
360 | /* TE_LINK_SUBTLV_PKT_LOSS */ | |
361 | if (ntohs(lp->pkt_loss.header.type) != 0) | |
362 | length += TLV_SIZE(&lp->pkt_loss.header); | |
363 | ||
364 | /* TE_LINK_SUBTLV_RES_BW */ | |
365 | if (ntohs(lp->res_bw.header.type) != 0) | |
366 | length += TLV_SIZE(&lp->res_bw.header); | |
367 | ||
368 | /* TE_LINK_SUBTLV_AVA_BW */ | |
369 | if (ntohs(lp->ava_bw.header.type) != 0) | |
370 | length += TLV_SIZE(&lp->ava_bw.header); | |
371 | ||
372 | /* TE_LINK_SUBTLV_USE_BW */ | |
373 | if (ntohs(lp->use_bw.header.type) != 0) | |
374 | length += TLV_SIZE(&lp->use_bw.header); | |
718e3744 | 375 | |
d62a17ae | 376 | lp->link_header.header.type = htons(TE_TLV_LINK); |
377 | lp->link_header.header.length = htons(length); | |
378 | ||
379 | return; | |
718e3744 | 380 | } |
d62a17ae | 381 | |
382 | static void set_linkparams_link_type(struct ospf_interface *oi, | |
383 | struct mpls_te_link *lp) | |
384 | { | |
385 | lp->link_type.header.type = htons(TE_LINK_SUBTLV_LINK_TYPE); | |
386 | lp->link_type.header.length = htons(TE_LINK_SUBTLV_TYPE_SIZE); | |
387 | ||
388 | switch (oi->type) { | |
389 | case OSPF_IFTYPE_POINTOPOINT: | |
390 | lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; | |
391 | break; | |
392 | case OSPF_IFTYPE_BROADCAST: | |
393 | case OSPF_IFTYPE_NBMA: | |
394 | lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; | |
395 | break; | |
396 | default: | |
397 | /* Not supported yet. */ /* XXX */ | |
398 | lp->link_type.header.type = htons(0); | |
399 | break; | |
400 | } | |
401 | return; | |
718e3744 | 402 | } |
d62a17ae | 403 | |
01c9b80a OD |
404 | static void set_linkparams_link_id(struct mpls_te_link *lp, |
405 | struct in_addr link_id) | |
718e3744 | 406 | { |
718e3744 | 407 | |
d62a17ae | 408 | lp->link_id.header.type = htons(TE_LINK_SUBTLV_LINK_ID); |
409 | lp->link_id.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
01c9b80a | 410 | lp->link_id.value = link_id; |
d62a17ae | 411 | return; |
718e3744 | 412 | } |
413 | ||
d62a17ae | 414 | static void set_linkparams_lclif_ipaddr(struct mpls_te_link *lp, |
415 | struct in_addr lclif) | |
16f1b9ee OD |
416 | { |
417 | ||
d62a17ae | 418 | lp->lclif_ipaddr.header.type = htons(TE_LINK_SUBTLV_LCLIF_IPADDR); |
419 | lp->lclif_ipaddr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
420 | lp->lclif_ipaddr.value[0] = lclif; | |
421 | return; | |
16f1b9ee OD |
422 | } |
423 | ||
d62a17ae | 424 | static void set_linkparams_rmtif_ipaddr(struct mpls_te_link *lp, |
425 | struct in_addr rmtif) | |
16f1b9ee OD |
426 | { |
427 | ||
d62a17ae | 428 | lp->rmtif_ipaddr.header.type = htons(TE_LINK_SUBTLV_RMTIF_IPADDR); |
429 | lp->rmtif_ipaddr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
430 | lp->rmtif_ipaddr.value[0] = rmtif; | |
431 | return; | |
16f1b9ee OD |
432 | } |
433 | ||
d62a17ae | 434 | static void set_linkparams_te_metric(struct mpls_te_link *lp, |
d7c0a89a | 435 | uint32_t te_metric) |
718e3744 | 436 | { |
d62a17ae | 437 | lp->te_metric.header.type = htons(TE_LINK_SUBTLV_TE_METRIC); |
438 | lp->te_metric.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
439 | lp->te_metric.value = htonl(te_metric); | |
440 | return; | |
718e3744 | 441 | } |
442 | ||
d62a17ae | 443 | static void set_linkparams_max_bw(struct mpls_te_link *lp, float fp) |
718e3744 | 444 | { |
d62a17ae | 445 | lp->max_bw.header.type = htons(TE_LINK_SUBTLV_MAX_BW); |
446 | lp->max_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
447 | lp->max_bw.value = htonf(fp); | |
448 | return; | |
718e3744 | 449 | } |
450 | ||
d62a17ae | 451 | static void set_linkparams_max_rsv_bw(struct mpls_te_link *lp, float fp) |
718e3744 | 452 | { |
d62a17ae | 453 | lp->max_rsv_bw.header.type = htons(TE_LINK_SUBTLV_MAX_RSV_BW); |
454 | lp->max_rsv_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
455 | lp->max_rsv_bw.value = htonf(fp); | |
456 | return; | |
718e3744 | 457 | } |
458 | ||
d62a17ae | 459 | static void set_linkparams_unrsv_bw(struct mpls_te_link *lp, int priority, |
460 | float fp) | |
718e3744 | 461 | { |
d62a17ae | 462 | /* Note that TLV-length field is the size of array. */ |
463 | lp->unrsv_bw.header.type = htons(TE_LINK_SUBTLV_UNRSV_BW); | |
464 | lp->unrsv_bw.header.length = htons(TE_LINK_SUBTLV_UNRSV_SIZE); | |
465 | lp->unrsv_bw.value[priority] = htonf(fp); | |
466 | return; | |
718e3744 | 467 | } |
468 | ||
d62a17ae | 469 | static void set_linkparams_rsc_clsclr(struct mpls_te_link *lp, |
d7c0a89a | 470 | uint32_t classcolor) |
718e3744 | 471 | { |
d62a17ae | 472 | lp->rsc_clsclr.header.type = htons(TE_LINK_SUBTLV_RSC_CLSCLR); |
473 | lp->rsc_clsclr.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
474 | lp->rsc_clsclr.value = htonl(classcolor); | |
475 | return; | |
718e3744 | 476 | } |
477 | ||
d62a17ae | 478 | static void set_linkparams_inter_as(struct mpls_te_link *lp, |
d7c0a89a | 479 | struct in_addr addr, uint32_t as) |
16f1b9ee OD |
480 | { |
481 | ||
d62a17ae | 482 | /* Set the Remote ASBR IP address and then the associated AS number */ |
483 | lp->rip.header.type = htons(TE_LINK_SUBTLV_RIP); | |
484 | lp->rip.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
485 | lp->rip.value = addr; | |
16f1b9ee | 486 | |
d62a17ae | 487 | lp->ras.header.type = htons(TE_LINK_SUBTLV_RAS); |
488 | lp->ras.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
489 | lp->ras.value = htonl(as); | |
2efd7e2b OD |
490 | |
491 | /* Set Type & Flooding flag accordingly */ | |
492 | lp->type = INTER_AS; | |
493 | if (OspfMplsTE.inter_as == AS) | |
494 | SET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
495 | else | |
496 | UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
16f1b9ee OD |
497 | } |
498 | ||
d62a17ae | 499 | static void unset_linkparams_inter_as(struct mpls_te_link *lp) |
16f1b9ee OD |
500 | { |
501 | ||
d62a17ae | 502 | /* Reset the Remote ASBR IP address and then the associated AS number */ |
503 | lp->rip.header.type = htons(0); | |
504 | lp->rip.header.length = htons(0); | |
505 | lp->rip.value.s_addr = htonl(0); | |
16f1b9ee | 506 | |
d62a17ae | 507 | lp->ras.header.type = htons(0); |
508 | lp->ras.header.length = htons(0); | |
509 | lp->ras.value = htonl(0); | |
2efd7e2b OD |
510 | |
511 | /* Reset Type & Flooding flag accordingly */ | |
512 | lp->type = STD_TE; | |
513 | UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
16f1b9ee OD |
514 | } |
515 | ||
d7c0a89a QY |
516 | void set_linkparams_llri(struct mpls_te_link *lp, uint32_t local, |
517 | uint32_t remote) | |
16f1b9ee OD |
518 | { |
519 | ||
d62a17ae | 520 | lp->llri.header.type = htons(TE_LINK_SUBTLV_LLRI); |
521 | lp->llri.header.length = htons(TE_LINK_SUBTLV_LLRI_SIZE); | |
522 | lp->llri.local = htonl(local); | |
523 | lp->llri.remote = htonl(remote); | |
16f1b9ee OD |
524 | } |
525 | ||
d62a17ae | 526 | void set_linkparams_lrrid(struct mpls_te_link *lp, struct in_addr local, |
527 | struct in_addr remote) | |
16f1b9ee OD |
528 | { |
529 | ||
d62a17ae | 530 | lp->lrrid.header.type = htons(TE_LINK_SUBTLV_LRRID); |
531 | lp->lrrid.header.length = htons(TE_LINK_SUBTLV_LRRID_SIZE); | |
532 | lp->lrrid.local.s_addr = local.s_addr; | |
533 | lp->lrrid.remote.s_addr = remote.s_addr; | |
16f1b9ee OD |
534 | } |
535 | ||
d7c0a89a QY |
536 | static void set_linkparams_av_delay(struct mpls_te_link *lp, uint32_t delay, |
537 | uint8_t anormal) | |
16f1b9ee | 538 | { |
d7c0a89a | 539 | uint32_t tmp; |
d62a17ae | 540 | /* Note that TLV-length field is the size of array. */ |
541 | lp->av_delay.header.type = htons(TE_LINK_SUBTLV_AV_DELAY); | |
542 | lp->av_delay.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
543 | tmp = delay & TE_EXT_MASK; | |
544 | if (anormal) | |
545 | tmp |= TE_EXT_ANORMAL; | |
546 | lp->av_delay.value = htonl(tmp); | |
547 | return; | |
16f1b9ee OD |
548 | } |
549 | ||
d7c0a89a QY |
550 | static void set_linkparams_mm_delay(struct mpls_te_link *lp, uint32_t low, |
551 | uint32_t high, uint8_t anormal) | |
16f1b9ee | 552 | { |
d7c0a89a | 553 | uint32_t tmp; |
d62a17ae | 554 | /* Note that TLV-length field is the size of array. */ |
555 | lp->mm_delay.header.type = htons(TE_LINK_SUBTLV_MM_DELAY); | |
556 | lp->mm_delay.header.length = htons(TE_LINK_SUBTLV_MM_DELAY_SIZE); | |
557 | tmp = low & TE_EXT_MASK; | |
558 | if (anormal) | |
559 | tmp |= TE_EXT_ANORMAL; | |
560 | lp->mm_delay.low = htonl(tmp); | |
561 | lp->mm_delay.high = htonl(high); | |
562 | return; | |
16f1b9ee OD |
563 | } |
564 | ||
d7c0a89a | 565 | static void set_linkparams_delay_var(struct mpls_te_link *lp, uint32_t jitter) |
16f1b9ee | 566 | { |
d62a17ae | 567 | /* Note that TLV-length field is the size of array. */ |
568 | lp->delay_var.header.type = htons(TE_LINK_SUBTLV_DELAY_VAR); | |
569 | lp->delay_var.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
570 | lp->delay_var.value = htonl(jitter & TE_EXT_MASK); | |
571 | return; | |
16f1b9ee OD |
572 | } |
573 | ||
d7c0a89a QY |
574 | static void set_linkparams_pkt_loss(struct mpls_te_link *lp, uint32_t loss, |
575 | uint8_t anormal) | |
16f1b9ee | 576 | { |
d7c0a89a | 577 | uint32_t tmp; |
d62a17ae | 578 | /* Note that TLV-length field is the size of array. */ |
579 | lp->pkt_loss.header.type = htons(TE_LINK_SUBTLV_PKT_LOSS); | |
580 | lp->pkt_loss.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
581 | tmp = loss & TE_EXT_MASK; | |
582 | if (anormal) | |
583 | tmp |= TE_EXT_ANORMAL; | |
584 | lp->pkt_loss.value = htonl(tmp); | |
585 | return; | |
16f1b9ee OD |
586 | } |
587 | ||
d62a17ae | 588 | static void set_linkparams_res_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 589 | { |
d62a17ae | 590 | /* Note that TLV-length field is the size of array. */ |
591 | lp->res_bw.header.type = htons(TE_LINK_SUBTLV_RES_BW); | |
592 | lp->res_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
593 | lp->res_bw.value = htonf(fp); | |
594 | return; | |
16f1b9ee OD |
595 | } |
596 | ||
d62a17ae | 597 | static void set_linkparams_ava_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 598 | { |
d62a17ae | 599 | /* Note that TLV-length field is the size of array. */ |
600 | lp->ava_bw.header.type = htons(TE_LINK_SUBTLV_AVA_BW); | |
601 | lp->ava_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
602 | lp->ava_bw.value = htonf(fp); | |
603 | return; | |
16f1b9ee OD |
604 | } |
605 | ||
d62a17ae | 606 | static void set_linkparams_use_bw(struct mpls_te_link *lp, float fp) |
16f1b9ee | 607 | { |
d62a17ae | 608 | /* Note that TLV-length field is the size of array. */ |
609 | lp->use_bw.header.type = htons(TE_LINK_SUBTLV_USE_BW); | |
610 | lp->use_bw.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); | |
611 | lp->use_bw.value = htonf(fp); | |
612 | return; | |
16f1b9ee OD |
613 | } |
614 | ||
615 | /* Update TE parameters from Interface */ | |
d62a17ae | 616 | static void update_linkparams(struct mpls_te_link *lp) |
617 | { | |
618 | int i; | |
619 | struct interface *ifp; | |
620 | ||
621 | /* Get the Interface structure */ | |
622 | if ((ifp = lp->ifp) == NULL) { | |
fd3c7692 OD |
623 | ote_debug( |
624 | "MPLS-TE (%s): Abort update TE parameters: no interface associated to Link Parameters", | |
625 | __func__); | |
d62a17ae | 626 | return; |
627 | } | |
628 | if (!HAS_LINK_PARAMS(ifp)) { | |
fd3c7692 OD |
629 | ote_debug( |
630 | "MPLS-TE (%s): Abort update TE parameters: no Link Parameters for interface", | |
631 | __func__); | |
d62a17ae | 632 | return; |
633 | } | |
634 | ||
635 | /* RFC3630 metrics */ | |
636 | if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) | |
637 | set_linkparams_rsc_clsclr(lp, ifp->link_params->admin_grp); | |
638 | else | |
639 | TLV_TYPE(lp->rsc_clsclr) = 0; | |
640 | ||
641 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) | |
642 | set_linkparams_max_bw(lp, ifp->link_params->max_bw); | |
643 | else | |
644 | TLV_TYPE(lp->max_bw) = 0; | |
645 | ||
646 | if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) | |
647 | set_linkparams_max_rsv_bw(lp, ifp->link_params->max_rsv_bw); | |
648 | else | |
649 | TLV_TYPE(lp->max_rsv_bw) = 0; | |
650 | ||
651 | if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) | |
652 | for (i = 0; i < MAX_CLASS_TYPE; i++) | |
653 | set_linkparams_unrsv_bw(lp, i, | |
654 | ifp->link_params->unrsv_bw[i]); | |
655 | else | |
656 | TLV_TYPE(lp->unrsv_bw) = 0; | |
657 | ||
658 | if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) | |
659 | set_linkparams_te_metric(lp, ifp->link_params->te_metric); | |
660 | else | |
661 | TLV_TYPE(lp->te_metric) = 0; | |
662 | ||
663 | /* TE metric Extensions */ | |
664 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) | |
665 | set_linkparams_av_delay(lp, ifp->link_params->av_delay, 0); | |
666 | else | |
667 | TLV_TYPE(lp->av_delay) = 0; | |
668 | ||
669 | if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) | |
670 | set_linkparams_mm_delay(lp, ifp->link_params->min_delay, | |
671 | ifp->link_params->max_delay, 0); | |
672 | else | |
673 | TLV_TYPE(lp->mm_delay) = 0; | |
674 | ||
675 | if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) | |
676 | set_linkparams_delay_var(lp, ifp->link_params->delay_var); | |
677 | else | |
678 | TLV_TYPE(lp->delay_var) = 0; | |
679 | ||
680 | if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) | |
681 | set_linkparams_pkt_loss(lp, ifp->link_params->pkt_loss, 0); | |
682 | else | |
683 | TLV_TYPE(lp->pkt_loss) = 0; | |
684 | ||
685 | if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) | |
686 | set_linkparams_res_bw(lp, ifp->link_params->res_bw); | |
687 | else | |
688 | TLV_TYPE(lp->res_bw) = 0; | |
689 | ||
690 | if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) | |
691 | set_linkparams_ava_bw(lp, ifp->link_params->ava_bw); | |
692 | else | |
693 | TLV_TYPE(lp->ava_bw) = 0; | |
694 | ||
695 | if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) | |
696 | set_linkparams_use_bw(lp, ifp->link_params->use_bw); | |
697 | else | |
698 | TLV_TYPE(lp->use_bw) = 0; | |
699 | ||
700 | /* RFC5392 */ | |
701 | if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { | |
702 | /* Flush LSA if it engaged and was previously a STD_TE one */ | |
703 | if (IS_STD_TE(lp->type) | |
704 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
fd3c7692 OD |
705 | ote_debug( |
706 | "MPLS-TE (%s): Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", | |
707 | __func__, ifp->name, lp->flags, lp->type); | |
d62a17ae | 708 | |
709 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
710 | /* Then, switch it to INTER-AS */ | |
2efd7e2b OD |
711 | if (OspfMplsTE.inter_as == AS) { |
712 | lp->type = INTER_AS; | |
713 | SET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
714 | } else { | |
715 | lp->type = INTER_AS; | |
716 | UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
d62a17ae | 717 | lp->area = ospf_area_lookup_by_area_id( |
b5a8894d | 718 | ospf_lookup_by_vrf_id(VRF_DEFAULT), |
d62a17ae | 719 | OspfMplsTE.interas_areaid); |
720 | } | |
721 | } | |
722 | set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, | |
723 | ifp->link_params->rmt_as); | |
724 | } else { | |
fd3c7692 OD |
725 | ote_debug( |
726 | "MPLS-TE (%s): Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", | |
727 | __func__, ifp->name, lp->flags, lp->type); | |
d62a17ae | 728 | |
729 | /* reset inter-as TE params */ | |
730 | /* Flush LSA if it engaged and was previously an INTER_AS one */ | |
731 | if (IS_INTER_AS(lp->type) | |
732 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
733 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
734 | /* Then, switch it to Standard TE */ | |
2efd7e2b OD |
735 | lp->flags = STD_TE; |
736 | UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); | |
d62a17ae | 737 | } |
738 | unset_linkparams_inter_as(lp); | |
739 | } | |
740 | } | |
741 | ||
742 | static void initialize_linkparams(struct mpls_te_link *lp) | |
743 | { | |
744 | struct interface *ifp = lp->ifp; | |
ead99d5f OD |
745 | struct ospf_interface *oi = NULL; |
746 | struct route_node *rn; | |
d62a17ae | 747 | |
f173deb3 OD |
748 | ote_debug("MPLS-TE (%s): Initialize Link Parameters for interface %s", |
749 | __func__, ifp->name); | |
d62a17ae | 750 | |
ead99d5f | 751 | /* Search OSPF Interface parameters for this interface */ |
996c9314 | 752 | for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { |
ead99d5f OD |
753 | |
754 | if ((oi = rn->info) == NULL) | |
755 | continue; | |
756 | ||
757 | if (oi->ifp == ifp) | |
758 | break; | |
759 | } | |
760 | ||
761 | if ((oi == NULL) || (oi->ifp != ifp)) { | |
fd3c7692 OD |
762 | ote_debug( |
763 | "MPLS-TE (%s): Could not find corresponding OSPF Interface for %s", | |
764 | __func__, ifp->name); | |
d62a17ae | 765 | return; |
766 | } | |
767 | ||
768 | /* | |
769 | * Try to set initial values those can be derived from | |
770 | * zebra-interface information. | |
771 | */ | |
772 | set_linkparams_link_type(oi, lp); | |
773 | ||
774 | /* Set local IP addr */ | |
775 | set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); | |
776 | ||
777 | /* Set Remote IP addr if Point to Point Interface */ | |
ead99d5f | 778 | if (oi->type == OSPF_IFTYPE_POINTOPOINT) { |
d62a17ae | 779 | struct prefix *pref = CONNECTED_PREFIX(oi->connected); |
780 | if (pref != NULL) | |
781 | set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); | |
782 | } | |
783 | ||
784 | /* Keep Area information in combination with link parameters. */ | |
785 | lp->area = oi->area; | |
786 | ||
787 | return; | |
788 | } | |
789 | ||
790 | static int is_mandated_params_set(struct mpls_te_link *lp) | |
791 | { | |
792 | int rc = 0; | |
793 | ||
794 | if (ntohs(OspfMplsTE.router_addr.header.type) == 0) { | |
fd3c7692 OD |
795 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
796 | "MPLS-TE (%s): Missing Router Address", __func__); | |
ead99d5f | 797 | return rc; |
d62a17ae | 798 | } |
799 | ||
800 | if (ntohs(lp->link_type.header.type) == 0) { | |
cf444bcf | 801 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
fd3c7692 | 802 | "MPLS-TE (%s): Missing Link Type", __func__); |
ead99d5f | 803 | return rc; |
d62a17ae | 804 | } |
805 | ||
806 | if (!IS_INTER_AS(lp->type) && (ntohs(lp->link_id.header.type) == 0)) { | |
f173deb3 OD |
807 | flog_warn(EC_OSPF_TE_UNEXPECTED, "MPLS-TE (%s) Missing Link ID", |
808 | __func__); | |
ead99d5f | 809 | return rc; |
d62a17ae | 810 | } |
811 | ||
812 | rc = 1; | |
d62a17ae | 813 | return rc; |
718e3744 | 814 | } |
815 | ||
816 | /*------------------------------------------------------------------------* | |
78dfa0c7 | 817 | * Following are callback functions against generic Opaque-LSAs handling. |
718e3744 | 818 | *------------------------------------------------------------------------*/ |
819 | ||
d62a17ae | 820 | static int ospf_mpls_te_new_if(struct interface *ifp) |
718e3744 | 821 | { |
d62a17ae | 822 | struct mpls_te_link *new; |
718e3744 | 823 | |
fd3c7692 OD |
824 | ote_debug("MPLS-TE (%s): Add new %s interface %s to MPLS-TE list", |
825 | __func__, ifp->link_params ? "Active" : "Inactive", | |
826 | ifp->name); | |
16f1b9ee | 827 | |
2c72cf2a DS |
828 | if (lookup_linkparams_by_ifp(ifp) != NULL) |
829 | return 0; | |
718e3744 | 830 | |
d62a17ae | 831 | new = XCALLOC(MTYPE_OSPF_MPLS_TE, sizeof(struct mpls_te_link)); |
718e3744 | 832 | |
d62a17ae | 833 | new->instance = get_mpls_te_instance_value(); |
834 | new->ifp = ifp; | |
835 | /* By default TE-Link is RFC3630 compatible flooding in Area and not | |
836 | * active */ | |
837 | /* This default behavior will be adapted with call to | |
838 | * ospf_mpls_te_update_if() */ | |
2efd7e2b | 839 | new->type = STD_TE; |
d62a17ae | 840 | new->flags = LPFLG_LSA_INACTIVE; |
16f1b9ee | 841 | |
d62a17ae | 842 | /* Initialize Link Parameters from Interface */ |
843 | initialize_linkparams(new); | |
718e3744 | 844 | |
d62a17ae | 845 | /* Set TE Parameters from Interface */ |
846 | update_linkparams(new); | |
718e3744 | 847 | |
d62a17ae | 848 | /* Add Link Parameters structure to the list */ |
849 | listnode_add(OspfMplsTE.iflist, new); | |
718e3744 | 850 | |
fd3c7692 OD |
851 | ote_debug("MPLS-TE (%s): Add new LP context for %s[%d/%d]", __func__, |
852 | ifp->name, new->flags, new->type); | |
16f1b9ee | 853 | |
d62a17ae | 854 | /* Schedule Opaque-LSA refresh. */ /* XXX */ |
2c72cf2a | 855 | return 0; |
718e3744 | 856 | } |
857 | ||
d62a17ae | 858 | static int ospf_mpls_te_del_if(struct interface *ifp) |
718e3744 | 859 | { |
d62a17ae | 860 | struct mpls_te_link *lp; |
861 | int rc = -1; | |
718e3744 | 862 | |
d62a17ae | 863 | if ((lp = lookup_linkparams_by_ifp(ifp)) != NULL) { |
864 | struct list *iflist = OspfMplsTE.iflist; | |
718e3744 | 865 | |
d62a17ae | 866 | /* Dequeue listnode entry from the list. */ |
867 | listnode_delete(iflist, lp); | |
718e3744 | 868 | |
d62a17ae | 869 | XFREE(MTYPE_OSPF_MPLS_TE, lp); |
870 | } | |
718e3744 | 871 | |
d62a17ae | 872 | /* Schedule Opaque-LSA refresh. */ /* XXX */ |
718e3744 | 873 | |
d62a17ae | 874 | rc = 0; |
d62a17ae | 875 | return rc; |
718e3744 | 876 | } |
877 | ||
16f1b9ee OD |
878 | /* Main initialization / update function of the MPLS TE Link context */ |
879 | ||
880 | /* Call when interface TE Link parameters are modified */ | |
d62a17ae | 881 | void ospf_mpls_te_update_if(struct interface *ifp) |
882 | { | |
883 | struct mpls_te_link *lp; | |
884 | ||
fd3c7692 OD |
885 | ote_debug("MPLS-TE (%s): Update LSA parameters for interface %s [%s]", |
886 | __func__, ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); | |
d62a17ae | 887 | |
888 | /* Get Link context from interface */ | |
889 | if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) { | |
ade6974d | 890 | flog_warn( |
cf444bcf | 891 | EC_OSPF_TE_UNEXPECTED, |
fd3c7692 OD |
892 | "MPLS-TE (%s): Did not find Link Parameters context for interface %s", |
893 | __func__, ifp->name); | |
d62a17ae | 894 | return; |
895 | } | |
896 | ||
897 | /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */ | |
898 | if (HAS_LINK_PARAMS(ifp)) { | |
899 | SET_FLAG(lp->flags, LPFLG_LSA_ACTIVE); | |
900 | ||
901 | /* Update TE parameters */ | |
902 | update_linkparams(lp); | |
903 | ||
904 | /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is | |
905 | * enabled */ | |
32ab5cf4 | 906 | if (OspfMplsTE.enabled) |
d62a17ae | 907 | if (lp->area != NULL) { |
32ab5cf4 | 908 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
996c9314 LB |
909 | ospf_mpls_te_lsa_schedule( |
910 | lp, REFRESH_THIS_LSA); | |
32ab5cf4 | 911 | else |
996c9314 LB |
912 | ospf_mpls_te_lsa_schedule( |
913 | lp, REORIGINATE_THIS_LSA); | |
d62a17ae | 914 | } |
915 | } else { | |
916 | /* If MPLS TE is disable on this interface, flush LSA if it is | |
917 | * already engaged */ | |
32ab5cf4 OD |
918 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
919 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
d62a17ae | 920 | else |
921 | /* Reset Activity flag */ | |
922 | lp->flags = LPFLG_LSA_INACTIVE; | |
923 | } | |
924 | ||
925 | return; | |
926 | } | |
927 | ||
01c9b80a OD |
928 | /* |
929 | * Just add interface and set available information. Other information | |
930 | * and flooding of LSA will be done later when adjacency will be up | |
931 | * See ospf_mpls_te_nsm_change() after | |
932 | */ | |
d62a17ae | 933 | static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) |
934 | { | |
01c9b80a | 935 | |
d62a17ae | 936 | struct mpls_te_link *lp; |
937 | ||
01c9b80a OD |
938 | lp = lookup_linkparams_by_ifp(oi->ifp); |
939 | if (lp == NULL) { | |
ade6974d | 940 | flog_warn( |
cf444bcf | 941 | EC_OSPF_TE_UNEXPECTED, |
01c9b80a OD |
942 | "MPLS-TE (%s): Cannot get linkparams from OI(%s)?", |
943 | __func__, IF_NAME(oi)); | |
ead99d5f | 944 | return; |
d62a17ae | 945 | } |
946 | ||
947 | if (oi->area == NULL || oi->area->ospf == NULL) { | |
ade6974d | 948 | flog_warn( |
cf444bcf | 949 | EC_OSPF_TE_UNEXPECTED, |
01c9b80a OD |
950 | "MPLS-TE (%s): Cannot refer to OSPF from OI(%s)?", |
951 | __func__, IF_NAME(oi)); | |
ead99d5f | 952 | return; |
d62a17ae | 953 | } |
01c9b80a | 954 | |
d62a17ae | 955 | /* Keep Area information in combination with linkparams. */ |
956 | lp->area = oi->area; | |
957 | ||
d62a17ae | 958 | switch (oi->state) { |
959 | case ISM_PointToPoint: | |
960 | case ISM_DROther: | |
961 | case ISM_Backup: | |
962 | case ISM_DR: | |
01c9b80a | 963 | /* Set Link type and Local IP addr */ |
d62a17ae | 964 | set_linkparams_link_type(oi, lp); |
d62a17ae | 965 | set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); |
966 | ||
d62a17ae | 967 | break; |
50ec09db OD |
968 | case ISM_Down: |
969 | /* Interface goes Down: Flush LSA if engaged */ | |
970 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
971 | ote_debug( | |
972 | "MPLS-TE (%s): Interface %s goes down: flush LSA", | |
973 | __func__, IF_NAME(oi)); | |
32ab5cf4 | 974 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); |
50ec09db OD |
975 | return; |
976 | } | |
977 | break; | |
978 | default: | |
d62a17ae | 979 | break; |
980 | } | |
718e3744 | 981 | |
fd3c7692 OD |
982 | ote_debug("MPLS-TE (%s): Update Link parameters for interface %s", |
983 | __func__, IF_NAME(oi)); | |
01c9b80a | 984 | |
d62a17ae | 985 | return; |
718e3744 | 986 | } |
987 | ||
01c9b80a OD |
988 | /* |
989 | * Complete TE info and schedule LSA flooding | |
990 | * Link-ID and Remote IP address must be set with neighbor info | |
991 | * which are only valid once NSM state is FULL | |
992 | */ | |
d62a17ae | 993 | static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) |
718e3744 | 994 | { |
01c9b80a OD |
995 | struct ospf_interface *oi = nbr->oi; |
996 | struct mpls_te_link *lp; | |
997 | ||
998 | /* Process Neighbor only when its state is NSM Full */ | |
999 | if (nbr->state != NSM_Full) | |
1000 | return; | |
1001 | ||
1002 | /* Get interface information for Traffic Engineering */ | |
1003 | lp = lookup_linkparams_by_ifp(oi->ifp); | |
1004 | if (lp == NULL) { | |
1005 | flog_warn( | |
1006 | EC_OSPF_TE_UNEXPECTED, | |
1007 | "MPLS-TE (%s): Cannot get linkparams from OI(%s)?", | |
1008 | __func__, IF_NAME(oi)); | |
1009 | return; | |
1010 | } | |
1011 | ||
1012 | if (oi->area == NULL || oi->area->ospf == NULL) { | |
1013 | flog_warn( | |
1014 | EC_OSPF_TE_UNEXPECTED, | |
1015 | "MPLS-TE (%s): Cannot refer to OSPF from OI(%s)?", | |
1016 | __func__, IF_NAME(oi)); | |
1017 | return; | |
1018 | } | |
1019 | ||
50ec09db OD |
1020 | /* Flush TE Opaque LSA if Neighbor State goes Down or Deleted */ |
1021 | if (OspfMplsTE.enabled | |
1022 | && (nbr->state == NSM_Down || nbr->state == NSM_Deleted)) { | |
1023 | if (CHECK_FLAG(lp->flags, EXT_LPFLG_LSA_ENGAGED)) { | |
1024 | ote_debug( | |
1025 | "MPLS-TE (%s): Interface %s goes down: flush LSA", | |
1026 | __func__, IF_NAME(oi)); | |
1027 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
1028 | } | |
1029 | return; | |
1030 | } | |
1031 | ||
01c9b80a OD |
1032 | /* Keep Area information in combination with SR info. */ |
1033 | lp->area = oi->area; | |
1034 | ||
01c9b80a OD |
1035 | /* |
1036 | * The Link ID is identical to the contents of the Link ID field | |
1037 | * in the Router LSA for these link types. | |
1038 | */ | |
1039 | switch (oi->state) { | |
1040 | case ISM_PointToPoint: | |
1041 | /* Set Link ID with neighbor Router ID */ | |
1042 | set_linkparams_link_id(lp, nbr->router_id); | |
1043 | /* Set Remote IP address */ | |
1044 | set_linkparams_rmtif_ipaddr(lp, nbr->address.u.prefix4); | |
1045 | break; | |
1046 | ||
1047 | case ISM_DR: | |
1048 | case ISM_DROther: | |
1049 | case ISM_Backup: | |
1050 | /* Set Link ID with the Designated Router ID */ | |
1051 | set_linkparams_link_id(lp, DR(oi)); | |
1052 | break; | |
1053 | ||
50ec09db OD |
1054 | case ISM_Down: |
1055 | /* State goes Down: Flush LSA if engaged */ | |
f173deb3 OD |
1056 | if (OspfMplsTE.enabled |
1057 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
50ec09db OD |
1058 | ote_debug( |
1059 | "MPLS-TE (%s): Interface %s goes down: flush LSA", | |
1060 | __func__, IF_NAME(oi)); | |
01c9b80a | 1061 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); |
50ec09db | 1062 | } |
01c9b80a | 1063 | return; |
50ec09db OD |
1064 | default: |
1065 | break; | |
01c9b80a OD |
1066 | } |
1067 | ||
fd3c7692 OD |
1068 | ote_debug("MPLS-TE (%s): Add Link-ID %pI4 for interface %s ", __func__, |
1069 | &lp->link_id.value, oi->ifp->name); | |
01c9b80a OD |
1070 | |
1071 | /* Try to Schedule LSA */ | |
1072 | if (OspfMplsTE.enabled) { | |
1073 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) | |
1074 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
1075 | else | |
1076 | ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA); | |
1077 | } | |
d62a17ae | 1078 | return; |
718e3744 | 1079 | } |
1080 | ||
1081 | /*------------------------------------------------------------------------* | |
78dfa0c7 | 1082 | * Following are OSPF protocol processing functions for MPLS-TE LSA. |
718e3744 | 1083 | *------------------------------------------------------------------------*/ |
1084 | ||
ead99d5f | 1085 | static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) |
d62a17ae | 1086 | { |
ead99d5f | 1087 | stream_put(s, tlvh, sizeof(struct tlv_header)); |
d62a17ae | 1088 | return; |
1089 | } | |
1090 | ||
1091 | static void build_router_tlv(struct stream *s) | |
1092 | { | |
ead99d5f | 1093 | struct tlv_header *tlvh = &OspfMplsTE.router_addr.header; |
d62a17ae | 1094 | if (ntohs(tlvh->type) != 0) { |
1095 | build_tlv_header(s, tlvh); | |
5d0df50f | 1096 | stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); |
d62a17ae | 1097 | } |
1098 | return; | |
1099 | } | |
1100 | ||
ead99d5f | 1101 | static void build_link_subtlv(struct stream *s, struct tlv_header *tlvh) |
d62a17ae | 1102 | { |
1103 | ||
1104 | if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) { | |
1105 | build_tlv_header(s, tlvh); | |
5d0df50f | 1106 | stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); |
d62a17ae | 1107 | } |
1108 | return; | |
1109 | } | |
1110 | ||
1111 | static void build_link_tlv(struct stream *s, struct mpls_te_link *lp) | |
1112 | { | |
1113 | set_linkparams_link_header(lp); | |
1114 | build_tlv_header(s, &lp->link_header.header); | |
1115 | ||
1116 | build_link_subtlv(s, &lp->link_type.header); | |
1117 | build_link_subtlv(s, &lp->link_id.header); | |
1118 | build_link_subtlv(s, &lp->lclif_ipaddr.header); | |
1119 | build_link_subtlv(s, &lp->rmtif_ipaddr.header); | |
1120 | build_link_subtlv(s, &lp->te_metric.header); | |
1121 | build_link_subtlv(s, &lp->max_bw.header); | |
1122 | build_link_subtlv(s, &lp->max_rsv_bw.header); | |
1123 | build_link_subtlv(s, &lp->unrsv_bw.header); | |
1124 | build_link_subtlv(s, &lp->rsc_clsclr.header); | |
1125 | build_link_subtlv(s, &lp->lrrid.header); | |
1126 | build_link_subtlv(s, &lp->llri.header); | |
1127 | build_link_subtlv(s, &lp->rip.header); | |
1128 | build_link_subtlv(s, &lp->ras.header); | |
1129 | build_link_subtlv(s, &lp->av_delay.header); | |
1130 | build_link_subtlv(s, &lp->mm_delay.header); | |
1131 | build_link_subtlv(s, &lp->delay_var.header); | |
1132 | build_link_subtlv(s, &lp->pkt_loss.header); | |
1133 | build_link_subtlv(s, &lp->res_bw.header); | |
1134 | build_link_subtlv(s, &lp->ava_bw.header); | |
1135 | build_link_subtlv(s, &lp->use_bw.header); | |
1136 | ||
1137 | return; | |
1138 | } | |
1139 | ||
1140 | static void ospf_mpls_te_lsa_body_set(struct stream *s, struct mpls_te_link *lp) | |
1141 | { | |
1142 | /* | |
2efd7e2b OD |
1143 | * The router address TLV is type 1, and ... It must appear in exactly |
1144 | * one Traffic Engineering LSA originated by a router but not in | |
1145 | * Inter-AS TLV. | |
d62a17ae | 1146 | */ |
2efd7e2b OD |
1147 | if (!IS_INTER_AS(lp->type)) |
1148 | build_router_tlv(s); | |
d62a17ae | 1149 | |
1150 | /* | |
1151 | * Only one Link TLV shall be carried in each LSA, allowing for fine | |
1152 | * granularity changes in topology. | |
1153 | */ | |
1154 | build_link_tlv(s, lp); | |
1155 | return; | |
718e3744 | 1156 | } |
1157 | ||
1158 | /* Create new opaque-LSA. */ | |
b5a8894d CS |
1159 | static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf, |
1160 | struct ospf_area *area, | |
d62a17ae | 1161 | struct mpls_te_link *lp) |
1162 | { | |
1163 | struct stream *s; | |
1164 | struct lsa_header *lsah; | |
1165 | struct ospf_lsa *new = NULL; | |
d7c0a89a | 1166 | uint8_t options, lsa_type = 0; |
d62a17ae | 1167 | struct in_addr lsa_id; |
d7c0a89a QY |
1168 | uint32_t tmp; |
1169 | uint16_t length; | |
d62a17ae | 1170 | |
1171 | /* Create a stream for LSA. */ | |
266469eb | 1172 | s = stream_new(OSPF_MAX_LSA_SIZE); |
d62a17ae | 1173 | lsah = (struct lsa_header *)STREAM_DATA(s); |
1174 | ||
1175 | options = OSPF_OPTION_O; /* Don't forget this :-) */ | |
1176 | ||
1177 | /* Set opaque-LSA header fields depending of the type of RFC */ | |
1178 | if (IS_INTER_AS(lp->type)) { | |
2efd7e2b | 1179 | if (IS_FLOOD_AS(lp->flags)) { |
72c03801 QY |
1180 | /* Enable AS external as we flood Inter-AS with Opaque |
1181 | * Type 11 | |
1182 | */ | |
1183 | options |= OSPF_OPTION_E; | |
1184 | lsa_type = OSPF_OPAQUE_AS_LSA; | |
1185 | } else { | |
d62a17ae | 1186 | options |= LSA_OPTIONS_GET( |
1187 | area); /* Get area default option */ | |
1188 | options |= LSA_OPTIONS_NSSA_GET(area); | |
1189 | lsa_type = OSPF_OPAQUE_AREA_LSA; | |
1190 | } | |
1191 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, lp->instance); | |
1192 | lsa_id.s_addr = htonl(tmp); | |
1193 | ||
0760d3c9 DS |
1194 | if (!ospf) { |
1195 | stream_free(s); | |
b5a8894d | 1196 | return NULL; |
0760d3c9 | 1197 | } |
d62a17ae | 1198 | |
b5a8894d | 1199 | lsa_header_set(s, options, lsa_type, lsa_id, ospf->router_id); |
d62a17ae | 1200 | } else { |
1201 | options |= LSA_OPTIONS_GET(area); /* Get area default option */ | |
1202 | options |= LSA_OPTIONS_NSSA_GET(area); | |
1203 | lsa_type = OSPF_OPAQUE_AREA_LSA; | |
1204 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
1205 | lp->instance); | |
1206 | lsa_id.s_addr = htonl(tmp); | |
1207 | lsa_header_set(s, options, lsa_type, lsa_id, | |
1208 | area->ospf->router_id); | |
1209 | } | |
1210 | ||
fd3c7692 | 1211 | ote_debug( |
50ec09db | 1212 | "MPLS-TE (%s): LSA[Type%d:%pI4]: Create an Opaque-LSA/MPLS-TE instance", |
fd3c7692 | 1213 | __func__, lsa_type, &lsa_id); |
d62a17ae | 1214 | |
1215 | /* Set opaque-LSA body fields. */ | |
1216 | ospf_mpls_te_lsa_body_set(s, lp); | |
1217 | ||
1218 | /* Set length. */ | |
1219 | length = stream_get_endp(s); | |
1220 | lsah->length = htons(length); | |
1221 | ||
1222 | /* Now, create an OSPF LSA instance. */ | |
5b3d4186 | 1223 | new = ospf_lsa_new_and_data(length); |
d62a17ae | 1224 | |
b5a8894d CS |
1225 | new->vrf_id = ospf->vrf_id; |
1226 | if (area && area->ospf) | |
1227 | new->vrf_id = area->ospf->vrf_id; | |
d62a17ae | 1228 | new->area = area; |
1229 | SET_FLAG(new->flags, OSPF_LSA_SELF); | |
1230 | memcpy(new->data, lsah, length); | |
1231 | stream_free(s); | |
718e3744 | 1232 | |
d62a17ae | 1233 | return new; |
1234 | } | |
1235 | ||
1236 | static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, | |
1237 | struct mpls_te_link *lp) | |
1238 | { | |
b5a8894d | 1239 | struct ospf_lsa *new = NULL; |
d62a17ae | 1240 | int rc = -1; |
1241 | ||
1242 | /* Create new Opaque-LSA/MPLS-TE instance. */ | |
b5a8894d CS |
1243 | new = ospf_mpls_te_lsa_new(area->ospf, area, lp); |
1244 | if (new == NULL) { | |
fd3c7692 OD |
1245 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
1246 | "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__); | |
ead99d5f | 1247 | return rc; |
d62a17ae | 1248 | } |
1249 | ||
1250 | /* Install this LSA into LSDB. */ | |
1251 | if (ospf_lsa_install(area->ospf, NULL /*oi*/, new) == NULL) { | |
cf444bcf | 1252 | flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, |
fd3c7692 | 1253 | "MPLS-TE (%s): ospf_lsa_install() ?", __func__); |
d62a17ae | 1254 | ospf_lsa_unlock(&new); |
ead99d5f | 1255 | return rc; |
d62a17ae | 1256 | } |
1257 | ||
1258 | /* Now this link-parameter entry has associated LSA. */ | |
1259 | SET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); | |
1260 | /* Update new LSA origination count. */ | |
1261 | area->ospf->lsa_originate_count++; | |
1262 | ||
1263 | /* Flood new LSA through area. */ | |
1264 | ospf_flood_through_area(area, NULL /*nbr*/, new); | |
1265 | ||
fd3c7692 OD |
1266 | ote_debug( |
1267 | "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE: Area(%pI4), Link(%s)", | |
1268 | __func__, new->data->type, &new->data->id, &area->area_id, | |
1269 | lp->ifp->name); | |
1270 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) | |
d62a17ae | 1271 | ospf_lsa_header_dump(new->data); |
d62a17ae | 1272 | |
1273 | rc = 0; | |
d62a17ae | 1274 | return rc; |
1275 | } | |
1276 | ||
1277 | static int ospf_mpls_te_lsa_originate_area(void *arg) | |
1278 | { | |
1279 | struct ospf_area *area = (struct ospf_area *)arg; | |
1280 | struct listnode *node, *nnode; | |
1281 | struct mpls_te_link *lp; | |
1282 | int rc = -1; | |
1283 | ||
32ab5cf4 | 1284 | if (!OspfMplsTE.enabled) { |
fd3c7692 | 1285 | ote_debug("MPLS-TE (%s): MPLS-TE is disabled now.", __func__); |
d62a17ae | 1286 | rc = 0; /* This is not an error case. */ |
ead99d5f | 1287 | return rc; |
d62a17ae | 1288 | } |
1289 | ||
1290 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
1291 | /* Process only enabled LSA with area scope flooding */ | |
1292 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) | |
2efd7e2b | 1293 | || IS_FLOOD_AS(lp->flags)) |
d62a17ae | 1294 | continue; |
1295 | ||
1296 | if (lp->area == NULL) | |
1297 | continue; | |
1298 | ||
1299 | if (!IPV4_ADDR_SAME(&lp->area->area_id, &area->area_id)) | |
1300 | continue; | |
1301 | ||
32ab5cf4 OD |
1302 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { |
1303 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { | |
1304 | UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); | |
fd3c7692 OD |
1305 | ote_debug( |
1306 | "MPLS-TE (%s): Refresh instead of Originate", | |
1307 | __func__); | |
32ab5cf4 | 1308 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); |
d62a17ae | 1309 | } |
32ab5cf4 OD |
1310 | continue; |
1311 | } | |
1312 | ||
d62a17ae | 1313 | if (!is_mandated_params_set(lp)) { |
fd3c7692 OD |
1314 | ote_debug( |
1315 | "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.", | |
1316 | __func__, lp->ifp ? lp->ifp->name : "?"); | |
d62a17ae | 1317 | continue; |
1318 | } | |
1319 | ||
1320 | /* Ok, let's try to originate an LSA for this area and Link. */ | |
fd3c7692 OD |
1321 | ote_debug( |
1322 | "MPLS-TE (%s): Let's finally reoriginate the LSA %d through the Area %pI4 for Link %s", | |
1323 | __func__, lp->instance, &area->area_id, | |
1324 | lp->ifp ? lp->ifp->name : "?"); | |
d62a17ae | 1325 | if (ospf_mpls_te_lsa_originate1(area, lp) != 0) |
ead99d5f | 1326 | return rc; |
d62a17ae | 1327 | } |
1328 | ||
1329 | rc = 0; | |
d62a17ae | 1330 | return rc; |
1331 | } | |
718e3744 | 1332 | |
d62a17ae | 1333 | static int ospf_mpls_te_lsa_originate2(struct ospf *top, |
1334 | struct mpls_te_link *lp) | |
1335 | { | |
1336 | struct ospf_lsa *new; | |
1337 | int rc = -1; | |
1338 | ||
1339 | /* Create new Opaque-LSA/Inter-AS instance. */ | |
b5a8894d CS |
1340 | new = ospf_mpls_te_lsa_new(top, NULL, lp); |
1341 | if (new == NULL) { | |
fd3c7692 OD |
1342 | flog_warn(EC_OSPF_LSA_UNEXPECTED, |
1343 | "MPLS-TE (%s): ospf_router_info_lsa_new() ?", | |
1344 | __func__); | |
ead99d5f | 1345 | return rc; |
d62a17ae | 1346 | } |
b5a8894d | 1347 | new->vrf_id = top->vrf_id; |
d62a17ae | 1348 | |
1349 | /* Install this LSA into LSDB. */ | |
1350 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
cf444bcf | 1351 | flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, |
fd3c7692 | 1352 | "MPLS-TE (%s): ospf_lsa_install() ?", __func__); |
d62a17ae | 1353 | ospf_lsa_unlock(&new); |
ead99d5f | 1354 | return rc; |
d62a17ae | 1355 | } |
1356 | ||
1357 | /* Now this Router Info parameter entry has associated LSA. */ | |
1358 | SET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); | |
1359 | /* Update new LSA origination count. */ | |
1360 | top->lsa_originate_count++; | |
1361 | ||
1362 | /* Flood new LSA through AS. */ | |
1363 | ospf_flood_through_as(top, NULL /*nbr */, new); | |
1364 | ||
fd3c7692 OD |
1365 | ote_debug( |
1366 | "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE Inter-AS", | |
1367 | __func__, new->data->type, &new->data->id); | |
1368 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) | |
d62a17ae | 1369 | ospf_lsa_header_dump(new->data); |
fd3c7692 | 1370 | |
d62a17ae | 1371 | |
1372 | rc = 0; | |
d62a17ae | 1373 | return rc; |
1374 | } | |
1375 | ||
1376 | static int ospf_mpls_te_lsa_originate_as(void *arg) | |
1377 | { | |
1378 | struct ospf *top; | |
1379 | struct ospf_area *area; | |
1380 | struct listnode *node, *nnode; | |
1381 | struct mpls_te_link *lp; | |
1382 | int rc = -1; | |
1383 | ||
996c9314 | 1384 | if ((!OspfMplsTE.enabled) || (OspfMplsTE.inter_as == Off)) { |
fd3c7692 OD |
1385 | ote_debug("MPLS-TE (%s): Inter-AS is disabled for now", |
1386 | __func__); | |
d62a17ae | 1387 | rc = 0; /* This is not an error case. */ |
ead99d5f | 1388 | return rc; |
d62a17ae | 1389 | } |
1390 | ||
1391 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
1392 | /* Process only enabled INTER_AS Links or Pseudo-Links */ | |
1393 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) | |
2efd7e2b | 1394 | || !CHECK_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS) |
d62a17ae | 1395 | || !IS_INTER_AS(lp->type)) |
1396 | continue; | |
1397 | ||
32ab5cf4 OD |
1398 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { |
1399 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { | |
996c9314 | 1400 | UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); |
32ab5cf4 | 1401 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); |
d62a17ae | 1402 | } |
32ab5cf4 OD |
1403 | continue; |
1404 | } | |
1405 | ||
d62a17ae | 1406 | if (!is_mandated_params_set(lp)) { |
ade6974d | 1407 | flog_warn( |
cf444bcf | 1408 | EC_OSPF_TE_UNEXPECTED, |
fd3c7692 OD |
1409 | "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.", |
1410 | __func__, lp->ifp ? lp->ifp->name : "?"); | |
d62a17ae | 1411 | continue; |
1412 | } | |
1413 | ||
1414 | /* Ok, let's try to originate an LSA for this AS and Link. */ | |
fd3c7692 OD |
1415 | ote_debug( |
1416 | "MPLS-TE (%s): Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", | |
1417 | __func__, lp->instance, | |
2efd7e2b | 1418 | IS_FLOOD_AS(lp->flags) ? "AS" : "Area", |
fd3c7692 | 1419 | lp->ifp ? lp->ifp->name : "Unknown"); |
d62a17ae | 1420 | |
2efd7e2b | 1421 | if (IS_FLOOD_AS(lp->flags)) { |
d62a17ae | 1422 | top = (struct ospf *)arg; |
1423 | ospf_mpls_te_lsa_originate2(top, lp); | |
1424 | } else { | |
1425 | area = (struct ospf_area *)arg; | |
1426 | ospf_mpls_te_lsa_originate1(area, lp); | |
1427 | } | |
1428 | } | |
1429 | ||
1430 | rc = 0; | |
d62a17ae | 1431 | return rc; |
1432 | } | |
1433 | ||
2efd7e2b OD |
1434 | /* |
1435 | * As Inter-AS LSA must be registered with both AREA and AS flooding, and | |
1436 | * because all origination callback functions are call (disregarding the Opaque | |
1437 | * LSA type and Flooding scope) it is necessary to determine which flooding | |
1438 | * scope is associated with the LSA origination as parameter is of type void and | |
1439 | * must be cast to struct *ospf for AS flooding and to struct *ospf_area for | |
1440 | * Area flooding. | |
1441 | */ | |
1442 | static int ospf_mpls_te_lsa_inter_as_as(void *arg) | |
1443 | { | |
1444 | if (OspfMplsTE.inter_as == AS) | |
1445 | return ospf_mpls_te_lsa_originate_as(arg); | |
1446 | else | |
1447 | return 0; | |
1448 | } | |
1449 | ||
1450 | static int ospf_mpls_te_lsa_inter_as_area(void *arg) | |
1451 | { | |
1452 | if (OspfMplsTE.inter_as == Area) | |
1453 | return ospf_mpls_te_lsa_originate_area(arg); | |
1454 | else | |
1455 | return 0; | |
1456 | } | |
1457 | ||
d62a17ae | 1458 | static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) |
1459 | { | |
1460 | struct mpls_te_link *lp; | |
1461 | struct ospf_area *area = lsa->area; | |
1462 | struct ospf *top; | |
1463 | struct ospf_lsa *new = NULL; | |
1464 | ||
32ab5cf4 | 1465 | if (!OspfMplsTE.enabled) { |
d62a17ae | 1466 | /* |
1467 | * This LSA must have flushed before due to MPLS-TE status | |
1468 | * change. | |
1469 | * It seems a slip among routers in the routing domain. | |
1470 | */ | |
fd3c7692 | 1471 | ote_debug("MPLS-TE (%s): MPLS-TE is disabled now", __func__); |
d62a17ae | 1472 | lsa->data->ls_age = |
1473 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
1474 | } | |
1475 | ||
1476 | /* At first, resolve lsa/lp relationship. */ | |
1477 | if ((lp = lookup_linkparams_by_instance(lsa)) == NULL) { | |
cf444bcf | 1478 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
fd3c7692 | 1479 | "MPLS-TE (%s): Invalid parameter?", __func__); |
d62a17ae | 1480 | lsa->data->ls_age = |
1481 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
20a7c80c DS |
1482 | ospf_opaque_lsa_flush_schedule(lsa); |
1483 | return NULL; | |
d62a17ae | 1484 | } |
1485 | ||
1486 | /* Check if lp was not disable in the interval */ | |
1487 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) { | |
fd3c7692 OD |
1488 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
1489 | "MPLS-TE (%s): lp was disabled: Flush it!", __func__); | |
d62a17ae | 1490 | lsa->data->ls_age = |
1491 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
1492 | } | |
1493 | ||
1494 | /* If the lsa's age reached to MaxAge, start flushing procedure. */ | |
1495 | if (IS_LSA_MAXAGE(lsa)) { | |
20a7c80c | 1496 | UNSET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); |
d62a17ae | 1497 | ospf_opaque_lsa_flush_schedule(lsa); |
ead99d5f | 1498 | return NULL; |
d62a17ae | 1499 | } |
b5a8894d | 1500 | top = ospf_lookup_by_vrf_id(lsa->vrf_id); |
d62a17ae | 1501 | /* Create new Opaque-LSA/MPLS-TE instance. */ |
b5a8894d CS |
1502 | new = ospf_mpls_te_lsa_new(top, area, lp); |
1503 | if (new == NULL) { | |
cf444bcf | 1504 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
fd3c7692 | 1505 | "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__); |
ead99d5f | 1506 | return NULL; |
d62a17ae | 1507 | } |
1508 | new->data->ls_seqnum = lsa_seqnum_increment(lsa); | |
1509 | ||
1510 | /* Install this LSA into LSDB. */ | |
1511 | /* Given "lsa" will be freed in the next function. */ | |
1512 | /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use | |
1513 | * ospf_lookup() to get ospf instance */ | |
1514 | if (area) | |
1515 | top = area->ospf; | |
d62a17ae | 1516 | |
1517 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
cf444bcf | 1518 | flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, |
fd3c7692 | 1519 | "MPLS-TE (%s): ospf_lsa_install() ?", __func__); |
d62a17ae | 1520 | ospf_lsa_unlock(&new); |
ead99d5f | 1521 | return NULL; |
d62a17ae | 1522 | } |
1523 | ||
1524 | /* Flood updated LSA through AS or Area depending of the RFC of the link | |
1525 | */ | |
2efd7e2b | 1526 | if (IS_FLOOD_AS(lp->flags)) |
d62a17ae | 1527 | ospf_flood_through_as(top, NULL, new); |
1528 | else | |
1529 | ospf_flood_through_area(area, NULL /*nbr*/, new); | |
1530 | ||
1531 | /* Debug logging. */ | |
fd3c7692 OD |
1532 | ote_debug("MPLS-TE (%s): LSA[Type%d:%pI4]: Refresh Opaque-LSA/MPLS-TE", |
1533 | __func__, new->data->type, &new->data->id); | |
1534 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) | |
d62a17ae | 1535 | ospf_lsa_header_dump(new->data); |
d62a17ae | 1536 | |
d62a17ae | 1537 | return new; |
1538 | } | |
1539 | ||
2a39170c | 1540 | void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) |
d62a17ae | 1541 | { |
1542 | struct ospf_lsa lsa; | |
1543 | struct lsa_header lsah; | |
1544 | struct ospf *top; | |
d7c0a89a | 1545 | uint32_t tmp; |
d62a17ae | 1546 | |
1547 | memset(&lsa, 0, sizeof(lsa)); | |
1548 | memset(&lsah, 0, sizeof(lsah)); | |
b5a8894d | 1549 | top = ospf_lookup_by_vrf_id(VRF_DEFAULT); |
d62a17ae | 1550 | |
1551 | /* Check if the pseudo link is ready to flood */ | |
2efd7e2b | 1552 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) |
d62a17ae | 1553 | return; |
d62a17ae | 1554 | |
f173deb3 OD |
1555 | ote_debug("MPLS-TE (%s): Schedule %s%s%s LSA for interface %s", |
1556 | __func__, | |
fd3c7692 OD |
1557 | opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", |
1558 | opcode == REFRESH_THIS_LSA ? "Refresh" : "", | |
1559 | opcode == FLUSH_THIS_LSA ? "Flush" : "", | |
1560 | lp->ifp ? lp->ifp->name : "-"); | |
1561 | ||
d62a17ae | 1562 | lsa.area = lp->area; |
1563 | lsa.data = &lsah; | |
2efd7e2b | 1564 | if (IS_FLOOD_AS(lp->flags)) { |
d62a17ae | 1565 | lsah.type = OSPF_OPAQUE_AS_LSA; |
1566 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, lp->instance); | |
1567 | lsah.id.s_addr = htonl(tmp); | |
1568 | } else { | |
1569 | lsah.type = OSPF_OPAQUE_AREA_LSA; | |
1570 | if (IS_INTER_AS(lp->type)) { | |
1571 | /* Set the area context if not know */ | |
1572 | if (lp->area == NULL) | |
1573 | lp->area = ospf_area_lookup_by_area_id( | |
1574 | top, OspfMplsTE.interas_areaid); | |
1575 | /* Unable to set the area context. Abort! */ | |
1576 | if (lp->area == NULL) { | |
ade6974d | 1577 | flog_warn( |
cf444bcf | 1578 | EC_OSPF_TE_UNEXPECTED, |
fd3c7692 OD |
1579 | "MPLS-TE (%s): Area context is null. Abort !", |
1580 | __func__); | |
d62a17ae | 1581 | return; |
1582 | } | |
1583 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, | |
1584 | lp->instance); | |
1585 | } else | |
1586 | tmp = SET_OPAQUE_LSID( | |
1587 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, | |
1588 | lp->instance); | |
1589 | lsah.id.s_addr = htonl(tmp); | |
1590 | } | |
1591 | ||
1592 | switch (opcode) { | |
1593 | case REORIGINATE_THIS_LSA: | |
2efd7e2b | 1594 | if (IS_FLOOD_AS(lp->flags)) { |
d62a17ae | 1595 | ospf_opaque_lsa_reoriginate_schedule( |
1596 | (void *)top, OSPF_OPAQUE_AS_LSA, | |
1597 | OPAQUE_TYPE_INTER_AS_LSA); | |
2efd7e2b | 1598 | } else { |
d62a17ae | 1599 | if (IS_INTER_AS(lp->type)) |
1600 | ospf_opaque_lsa_reoriginate_schedule( | |
1601 | (void *)lp->area, OSPF_OPAQUE_AREA_LSA, | |
1602 | OPAQUE_TYPE_INTER_AS_LSA); | |
1603 | else | |
1604 | ospf_opaque_lsa_reoriginate_schedule( | |
1605 | (void *)lp->area, OSPF_OPAQUE_AREA_LSA, | |
1606 | OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); | |
d62a17ae | 1607 | } |
1608 | break; | |
1609 | case REFRESH_THIS_LSA: | |
1610 | ospf_opaque_lsa_refresh_schedule(&lsa); | |
1611 | break; | |
1612 | case FLUSH_THIS_LSA: | |
1613 | /* Reset Activity flag */ | |
1614 | lp->flags = LPFLG_LSA_INACTIVE; | |
1615 | ospf_opaque_lsa_flush_schedule(&lsa); | |
1616 | break; | |
1617 | default: | |
cf444bcf | 1618 | flog_warn(EC_OSPF_TE_UNEXPECTED, |
fd3c7692 | 1619 | "MPLS-TE (%s): Unknown opcode (%u)", __func__, |
d62a17ae | 1620 | opcode); |
1621 | break; | |
1622 | } | |
718e3744 | 1623 | } |
1624 | ||
f173deb3 OD |
1625 | /** |
1626 | * ------------------------------------------------------ | |
78dfa0c7 | 1627 | * Following are Link State Data Base control functions. |
f173deb3 OD |
1628 | * ------------------------------------------------------ |
1629 | */ | |
718e3744 | 1630 | |
f173deb3 OD |
1631 | /** |
1632 | * Get Vertex from TED by the router which advertised the LSA. A new Vertex and | |
1633 | * associated Link State Node are created if Vertex is not found. | |
1634 | * | |
1635 | * @param ted Link State Traffic Engineering Database | |
1636 | * @param lsa OSPF Link State Advertisement | |
1637 | * | |
1638 | * @return Link State Vertex | |
1639 | */ | |
1640 | static struct ls_vertex *get_vertex(struct ls_ted *ted, struct ospf_lsa *lsa) | |
718e3744 | 1641 | { |
f173deb3 OD |
1642 | struct ls_node_id lnid; |
1643 | struct ls_node *lnode; | |
1644 | struct ls_vertex *vertex; | |
718e3744 | 1645 | |
f173deb3 OD |
1646 | /* Sanity Check */ |
1647 | if (!ted || !lsa || !lsa->data || !lsa->area) | |
1648 | return NULL; | |
718e3744 | 1649 | |
f173deb3 OD |
1650 | /* Search if a Link State Vertex already exist */ |
1651 | lnid.origin = OSPFv2; | |
1652 | lnid.id.ip.addr = lsa->data->adv_router; | |
1653 | lnid.id.ip.area_id = lsa->area->area_id; | |
1654 | vertex = ls_find_vertex_by_id(ted, lnid); | |
1655 | ||
1656 | /* Create Node & Vertex in the Link State Date Base if not found */ | |
1657 | if (!vertex) { | |
1658 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; | |
1659 | ||
1660 | lnode = ls_node_new(lnid, inaddr_any, in6addr_any); | |
1661 | snprintfrr(lnode->name, MAX_NAME_LENGTH, "%pI4", | |
1662 | &lnid.id.ip.addr); | |
1663 | vertex = ls_vertex_add(ted, lnode); | |
1664 | } | |
1665 | ||
1666 | if (IS_LSA_SELF(lsa)) | |
1667 | ted->self = vertex; | |
1668 | ||
1669 | return vertex; | |
718e3744 | 1670 | } |
1671 | ||
f173deb3 OD |
1672 | /** |
1673 | * Get Edge from TED by Link State Attribute ID. A new Edge and associated Link | |
1674 | * State Attributes are created if not found. | |
1675 | * | |
1676 | * @param ted Link State Traffic Engineering Database | |
1677 | * @param adv Link State Node ID of router which advertised Edge | |
1678 | * @param link_id Link State Attribute ID | |
1679 | * | |
1680 | * @return Link State Edge | |
1681 | */ | |
1682 | static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_node_id adv, | |
1683 | struct in_addr link_id) | |
718e3744 | 1684 | { |
f173deb3 OD |
1685 | uint64_t key; |
1686 | struct ls_edge *edge; | |
1687 | struct ls_attributes *attr; | |
1688 | ||
1689 | /* Search Edge that corresponds to the Link ID */ | |
1690 | key = ((uint64_t)ntohl(link_id.s_addr)) & 0xffffffff; | |
1691 | edge = ls_find_edge_by_key(ted, key); | |
1692 | ||
1693 | /* Create new one if not exist */ | |
1694 | if (!edge) { | |
1695 | attr = ls_attributes_new(adv, link_id, in6addr_any, 0); | |
1696 | edge = ls_edge_add(ted, attr); | |
1697 | } | |
718e3744 | 1698 | |
f173deb3 | 1699 | return edge; |
718e3744 | 1700 | } |
1701 | ||
f173deb3 OD |
1702 | /** |
1703 | * Export Link State information to consumer daemon through ZAPI Link State | |
1704 | * Opaque Message. | |
1705 | * | |
1706 | * @param type Type of Link State Element i.e. Vertex, Edge or Subnet | |
1707 | * @param link_state Pointer to Link State Vertex, Edge or Subnet | |
1708 | * | |
1709 | * @return 0 if success, -1 otherwise | |
1710 | */ | |
1711 | static int ospf_te_export(uint8_t type, void *link_state) | |
718e3744 | 1712 | { |
f173deb3 OD |
1713 | struct ls_message msg = {}; |
1714 | int rc = 0; | |
718e3744 | 1715 | |
f173deb3 OD |
1716 | if (!OspfMplsTE.export) |
1717 | return rc; | |
1718 | ||
1719 | switch (type) { | |
1720 | case LS_MSG_TYPE_NODE: | |
1721 | ls_vertex2msg(&msg, (struct ls_vertex *)link_state); | |
1722 | rc = ls_send_msg(zclient, &msg, NULL); | |
d62a17ae | 1723 | break; |
f173deb3 OD |
1724 | case LS_MSG_TYPE_ATTRIBUTES: |
1725 | ls_edge2msg(&msg, (struct ls_edge *)link_state); | |
1726 | rc = ls_send_msg(zclient, &msg, NULL); | |
1727 | break; | |
1728 | case LS_MSG_TYPE_PREFIX: | |
1729 | ls_subnet2msg(&msg, (struct ls_subnet *)link_state); | |
1730 | rc = ls_send_msg(zclient, &msg, NULL); | |
d62a17ae | 1731 | break; |
1732 | default: | |
f173deb3 | 1733 | rc = -1; |
d62a17ae | 1734 | break; |
1735 | } | |
718e3744 | 1736 | |
f173deb3 | 1737 | return rc; |
718e3744 | 1738 | } |
1739 | ||
f173deb3 OD |
1740 | /** |
1741 | * Update Link State Edge & Attributes from the given Link State Attributes ID | |
1742 | * and metric. This function is called when parsing Router LSA. | |
1743 | * | |
1744 | * @param ted Link State Traffic Engineering Database | |
1745 | * @param vertex Vertex where the Edge is attached as source | |
1746 | * @param link_data Link State Edge ID | |
1747 | * @param metric Standard metric attached to this Edge | |
1748 | */ | |
1749 | static void ospf_te_update_link(struct ls_ted *ted, struct ls_vertex *vertex, | |
1750 | struct in_addr link_data, uint8_t metric) | |
718e3744 | 1751 | { |
f173deb3 OD |
1752 | struct ls_edge *edge; |
1753 | struct ls_attributes *attr; | |
718e3744 | 1754 | |
f173deb3 OD |
1755 | /* Sanity check */ |
1756 | if (!ted || !vertex || !vertex->node) | |
1757 | return; | |
718e3744 | 1758 | |
f173deb3 OD |
1759 | /* Get Corresponding Edge from Link State Data Base */ |
1760 | edge = get_edge(ted, vertex->node->adv, link_data); | |
1761 | attr = edge->attributes; | |
718e3744 | 1762 | |
f173deb3 OD |
1763 | /* re-attached edge to vertex if needed */ |
1764 | if (!edge->source) | |
1765 | edge->source = vertex; | |
718e3744 | 1766 | |
f173deb3 OD |
1767 | /* Check if it is just an LSA refresh */ |
1768 | if ((CHECK_FLAG(attr->flags, LS_ATTR_METRIC) | |
1769 | && (attr->metric == metric))) { | |
1770 | edge->status = SYNC; | |
1771 | return; | |
1772 | } | |
718e3744 | 1773 | |
f173deb3 OD |
1774 | /* Update metric value */ |
1775 | attr->metric = metric; | |
1776 | SET_FLAG(attr->flags, LS_ATTR_METRIC); | |
1777 | if (edge->status != NEW) | |
1778 | edge->status = UPDATE; | |
718e3744 | 1779 | |
f173deb3 OD |
1780 | ote_debug(" |- %s Edge %pI4 with metric %d", |
1781 | edge->status == NEW ? "Add" : "Update", &attr->standard.local, | |
1782 | attr->metric); | |
1783 | ||
1784 | /* Export Link State Edge */ | |
1785 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
1786 | edge->status = SYNC; | |
718e3744 | 1787 | } |
1788 | ||
f173deb3 OD |
1789 | /** |
1790 | * Update Link State Subnet & Prefix from the given prefix and metric. This | |
1791 | * function is called when parsing Router LSA. | |
1792 | * | |
1793 | * @param ted Link State Traffic Engineering Database | |
1794 | * @param vertex Vertex where the Edge is attached as source | |
1795 | * @param p Prefix associated to the Subnet | |
1796 | * @param metric Standard metric attached to this Edge | |
1797 | */ | |
1798 | static void ospf_te_update_subnet(struct ls_ted *ted, struct ls_vertex *vertex, | |
1799 | struct prefix p, uint8_t metric) | |
718e3744 | 1800 | { |
f173deb3 OD |
1801 | struct ls_subnet *subnet; |
1802 | struct ls_prefix *ls_pref; | |
1803 | ||
1804 | /* Search if there is a Subnet for this prefix */ | |
1805 | subnet = ls_find_subnet(ted, p); | |
1806 | ||
1807 | /* If found a Subnet, check if it is attached to this Vertex */ | |
1808 | if (subnet) { | |
1809 | /* Re-attach the subnet to the vertex if necessary */ | |
1810 | if (subnet->vertex != vertex) { | |
1811 | subnet->vertex = vertex; | |
1812 | listnode_add_sort_nodup(vertex->prefixes, subnet); | |
1813 | } | |
1814 | /* Check if it is a simple refresh */ | |
1815 | ls_pref = subnet->ls_pref; | |
1816 | if ((CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)) | |
1817 | && (ls_pref->metric == metric)) { | |
1818 | subnet->status = SYNC; | |
1819 | return; | |
1820 | } | |
1821 | ls_pref->metric = metric; | |
1822 | SET_FLAG(ls_pref->flags, LS_PREF_METRIC); | |
1823 | subnet->status = UPDATE; | |
1824 | } else { | |
1825 | /* Create new Link State Prefix */ | |
1826 | ls_pref = ls_prefix_new(vertex->node->adv, p); | |
1827 | ls_pref->metric = metric; | |
1828 | SET_FLAG(ls_pref->flags, LS_PREF_METRIC); | |
1829 | /* and add it to the TED */ | |
1830 | subnet = ls_subnet_add(ted, ls_pref); | |
1831 | } | |
718e3744 | 1832 | |
f173deb3 OD |
1833 | ote_debug(" |- %s subnet %pFX with metric %d", |
1834 | subnet->status == NEW ? "Add" : "Update", &subnet->key, | |
1835 | ls_pref->metric); | |
718e3744 | 1836 | |
f173deb3 OD |
1837 | /* Export Link State Subnet */ |
1838 | ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
1839 | subnet->status = SYNC; | |
718e3744 | 1840 | } |
1841 | ||
f173deb3 OD |
1842 | /** |
1843 | * Delete Subnet that correspond to the given IPv4 address and export deletion | |
936fbaef | 1844 | * information before removal. Prefix length is fixed to IPV4_MAX_BITLEN. |
f173deb3 OD |
1845 | * |
1846 | * @param ted Links State Database | |
1847 | * @param addr IPv4 address | |
1848 | */ | |
1849 | static void ospf_te_delete_subnet(struct ls_ted *ted, struct in_addr addr) | |
718e3744 | 1850 | { |
f173deb3 OD |
1851 | struct prefix p; |
1852 | struct ls_subnet *subnet; | |
1853 | ||
1854 | /* Search subnet that correspond to the address/32 as prefix */ | |
1855 | p.family = AF_INET; | |
936fbaef | 1856 | p.prefixlen = IPV4_MAX_BITLEN; |
f173deb3 OD |
1857 | p.u.prefix4 = addr; |
1858 | subnet = ls_find_subnet(ted, p); | |
1859 | ||
1860 | /* Remove subnet if found */ | |
1861 | if (subnet) { | |
1862 | subnet->status = DELETE; | |
1863 | ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
1864 | ls_subnet_del_all(ted, subnet); | |
1865 | } | |
718e3744 | 1866 | } |
1867 | ||
f173deb3 OD |
1868 | /** |
1869 | * Parse Router LSA. This function will create or update corresponding Vertex, | |
1870 | * Edge and Subnet. It also remove Edge and Subnet if they are marked as Orphan | |
1871 | * once Router LSA is parsed. | |
1872 | * | |
1873 | * @param ted Link State Traffic Engineering Database | |
1874 | * @param lsa OSPF Link State Advertisement | |
1875 | * | |
1876 | * @return 0 if success, -1 otherwise | |
1877 | */ | |
1878 | static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) | |
718e3744 | 1879 | { |
f173deb3 OD |
1880 | struct router_lsa *rl; |
1881 | enum ls_node_type type; | |
1882 | struct ls_vertex *vertex; | |
1883 | struct ls_edge *edge; | |
1884 | struct ls_subnet *subnet; | |
1885 | struct listnode *node; | |
8db278b5 | 1886 | int len, links; |
f173deb3 OD |
1887 | |
1888 | /* Sanity Check */ | |
1889 | if (!ted || !lsa || !lsa->data) | |
1890 | return -1; | |
1891 | ||
1892 | ote_debug("MPLS-TE (%s): Parse Router LSA[%pI4] from Router[%pI4]", | |
1893 | __func__, &lsa->data->id, &lsa->data->adv_router); | |
1894 | ||
1895 | /* Get vertex from LSA Advertise Router ID */ | |
1896 | vertex = get_vertex(ted, lsa); | |
1897 | ||
1898 | /* Set Node type information if it has changed */ | |
1899 | rl = (struct router_lsa *)lsa->data; | |
1900 | if (IS_ROUTER_LSA_VIRTUAL(rl)) | |
1901 | type = PSEUDO; | |
1902 | else if (IS_ROUTER_LSA_EXTERNAL(rl)) | |
1903 | type = ASBR; | |
1904 | else if (IS_ROUTER_LSA_BORDER(rl)) | |
1905 | type = ABR; | |
1906 | else | |
1907 | type = STANDARD; | |
1908 | ||
1909 | if (vertex->status == NEW) { | |
1910 | vertex->node->type = type; | |
1911 | SET_FLAG(vertex->node->flags, LS_NODE_TYPE); | |
1912 | } else if (vertex->node->type != type) { | |
1913 | vertex->node->type = type; | |
1914 | vertex->status = UPDATE; | |
1915 | } | |
718e3744 | 1916 | |
f173deb3 OD |
1917 | /* Check if Vertex has been modified */ |
1918 | if (vertex->status != SYNC) { | |
1919 | ote_debug(" |- %s Vertex %pI4", | |
1920 | vertex->status == NEW ? "Add" : "Update", | |
1921 | &vertex->node->router_id); | |
718e3744 | 1922 | |
f173deb3 OD |
1923 | /* Vertex is out of sync: export it */ |
1924 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
1925 | vertex->status = SYNC; | |
1926 | } | |
1927 | ||
1928 | /* Mark outgoing Edge and Subnet as ORPHAN to detect deletion */ | |
1929 | for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) | |
1930 | edge->status = ORPHAN; | |
1931 | ||
1932 | for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) | |
1933 | subnet->status = ORPHAN; | |
1934 | ||
1935 | /* Then, process Link Information */ | |
8db278b5 OD |
1936 | len = lsa->size - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE; |
1937 | links = ntohs(rl->links); | |
1938 | for (int i = 0; i < links && len > 0; len -= 12, i++) { | |
f173deb3 OD |
1939 | struct prefix p; |
1940 | uint32_t metric; | |
1941 | ||
1942 | switch (rl->link[i].type) { | |
1943 | case LSA_LINK_TYPE_POINTOPOINT: | |
1944 | ospf_te_update_link(ted, vertex, rl->link[i].link_data, | |
1945 | ntohs(rl->link[i].metric)); | |
1946 | /* Add corresponding subnet */ | |
1947 | p.family = AF_INET; | |
936fbaef | 1948 | p.prefixlen = IPV4_MAX_BITLEN; |
f173deb3 OD |
1949 | p.u.prefix4 = rl->link[i].link_data; |
1950 | metric = ntohs(rl->link[i].metric); | |
1951 | ospf_te_update_subnet(ted, vertex, p, metric); | |
1952 | break; | |
1953 | case LSA_LINK_TYPE_STUB: | |
1954 | /* Keep only /32 prefix */ | |
1955 | p.prefixlen = ip_masklen(rl->link[i].link_data); | |
936fbaef | 1956 | if (p.prefixlen == IPV4_MAX_BITLEN) { |
f173deb3 OD |
1957 | p.family = AF_INET; |
1958 | p.u.prefix4 = rl->link[i].link_id; | |
1959 | metric = ntohs(rl->link[i].metric); | |
1960 | ospf_te_update_subnet(ted, vertex, p, metric); | |
1961 | } | |
1962 | break; | |
1963 | default: | |
1964 | break; | |
1965 | } | |
1966 | } | |
1967 | /* Clean remaining Orphan Edges or Subnets */ | |
1968 | if (OspfMplsTE.export) | |
1969 | ls_vertex_clean(ted, vertex, zclient); | |
d62a17ae | 1970 | else |
f173deb3 | 1971 | ls_vertex_clean(ted, vertex, NULL); |
718e3744 | 1972 | |
f173deb3 | 1973 | return 0; |
718e3744 | 1974 | } |
1975 | ||
f173deb3 OD |
1976 | /** |
1977 | * Delete Vertex, Edge and Subnet associated to this Router LSA. This function | |
1978 | * is called when the router received such LSA with MAX_AGE (Flush) or when the | |
1979 | * router stop OSPF. | |
1980 | * | |
1981 | * @param ted Link State Traffic Engineering Database | |
1982 | * @param lsa OSPF Link State Advertisement | |
1983 | * | |
1984 | * @return 0 if success, -1 otherwise | |
1985 | */ | |
1986 | static int ospf_te_delete_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) | |
718e3744 | 1987 | { |
f173deb3 OD |
1988 | struct ls_node_id lnid; |
1989 | struct ls_vertex *vertex; | |
718e3744 | 1990 | |
f173deb3 OD |
1991 | /* Sanity Check */ |
1992 | if (!ted || !lsa || !lsa->data) | |
1993 | return -1; | |
718e3744 | 1994 | |
f173deb3 OD |
1995 | /* Search Vertex that corresponds to this LSA */ |
1996 | lnid.origin = OSPFv2; | |
1997 | lnid.id.ip.addr = lsa->data->adv_router; | |
1998 | lnid.id.ip.area_id = lsa->area->area_id; | |
1999 | vertex = ls_find_vertex_by_id(ted, lnid); | |
2000 | if (!vertex) | |
2001 | return -1; | |
718e3744 | 2002 | |
f173deb3 OD |
2003 | ote_debug("MPLS-TE (%s): Delete Vertex %pI4 from Router LSA[%pI4]", |
2004 | __func__, &vertex->node->router_id, &lsa->data->id); | |
718e3744 | 2005 | |
f173deb3 OD |
2006 | /* Export deleted vertex ... */ |
2007 | vertex->status = DELETE; | |
2008 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
16f1b9ee | 2009 | |
f173deb3 OD |
2010 | /* ... and remove Node & Vertex from Link State Date Base */ |
2011 | ls_vertex_del_all(ted, vertex); | |
718e3744 | 2012 | |
f173deb3 | 2013 | return 0; |
718e3744 | 2014 | } |
2015 | ||
f173deb3 OD |
2016 | /** |
2017 | * Create or update Remote Vertex that corresponds to the remote ASBR of the | |
2018 | * foreign network if Edge is associated to an Inter-AS LSA (Type 6). | |
2019 | * | |
2020 | * @param ted Link State Traffic Engineering Database | |
2021 | * @param edge Link State Edge | |
2022 | */ | |
2023 | static void ospf_te_update_remote_asbr(struct ls_ted *ted, struct ls_edge *edge) | |
718e3744 | 2024 | { |
f173deb3 OD |
2025 | struct ls_node_id lnid; |
2026 | struct ls_vertex *vertex; | |
2027 | struct ls_node *lnode; | |
2028 | struct ls_attributes *attr; | |
2029 | struct prefix p; | |
2030 | ||
2031 | /* Sanity Check */ | |
2032 | if (!ted || !edge) | |
2033 | return; | |
718e3744 | 2034 | |
f173deb3 OD |
2035 | /* Search if a Link State Vertex already exist */ |
2036 | attr = edge->attributes; | |
2037 | lnid.origin = OSPFv2; | |
2038 | lnid.id.ip.addr = attr->standard.remote_addr; | |
2039 | lnid.id.ip.area_id = attr->adv.id.ip.area_id; | |
2040 | vertex = ls_find_vertex_by_id(ted, lnid); | |
2041 | ||
2042 | /* Create Node & Vertex in the Link State Date Base if not found */ | |
2043 | if (!vertex) { | |
2044 | const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; | |
2045 | ||
2046 | lnode = ls_node_new(lnid, inaddr_any, in6addr_any); | |
2047 | snprintfrr(lnode->name, MAX_NAME_LENGTH, "%pI4", | |
2048 | &lnid.id.ip.addr); | |
2049 | vertex = ls_vertex_add(ted, lnode); | |
2050 | } | |
16f1b9ee | 2051 | |
f173deb3 OD |
2052 | /* Update Node information */ |
2053 | lnode = vertex->node; | |
2054 | if (CHECK_FLAG(lnode->flags, LS_NODE_TYPE)) { | |
2055 | if (lnode->type != RMT_ASBR) { | |
2056 | lnode->type = RMT_ASBR; | |
2057 | if (vertex->status != NEW) | |
2058 | vertex->status = UPDATE; | |
2059 | } | |
2060 | } else { | |
2061 | lnode->type = RMT_ASBR; | |
2062 | SET_FLAG(lnode->flags, LS_NODE_TYPE); | |
2063 | if (vertex->status != NEW) | |
2064 | vertex->status = UPDATE; | |
2065 | } | |
2066 | if (CHECK_FLAG(lnode->flags, LS_NODE_AS_NUMBER)) { | |
2067 | if (lnode->as_number != attr->standard.remote_as) { | |
2068 | lnode->as_number = attr->standard.remote_as; | |
2069 | if (vertex->status != NEW) | |
2070 | vertex->status = UPDATE; | |
2071 | } | |
2072 | } else { | |
2073 | lnode->as_number = attr->standard.remote_as; | |
2074 | SET_FLAG(lnode->flags, LS_NODE_AS_NUMBER); | |
2075 | if (vertex->status != NEW) | |
2076 | vertex->status = UPDATE; | |
2077 | } | |
16f1b9ee | 2078 | |
f173deb3 OD |
2079 | /* Export Link State Vertex if needed */ |
2080 | if (vertex->status == NEW || vertex->status == UPDATE) { | |
2081 | ote_debug(" |- %s Remote Vertex %pI4 for AS %u", | |
2082 | vertex->status == NEW ? "Add" : "Update", | |
2083 | &lnode->router_id, lnode->as_number); | |
2084 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
2085 | vertex->status = SYNC; | |
2086 | } | |
16f1b9ee | 2087 | |
f173deb3 OD |
2088 | /* Update corresponding Subnets */ |
2089 | p.family = AF_INET; | |
936fbaef | 2090 | p.prefixlen = IPV4_MAX_BITLEN; |
f173deb3 OD |
2091 | p.u.prefix4 = attr->standard.local; |
2092 | ospf_te_update_subnet(ted, edge->source, p, attr->standard.te_metric); | |
2093 | ||
2094 | p.family = AF_INET; | |
936fbaef | 2095 | p.prefixlen = IPV4_MAX_BITLEN; |
f173deb3 OD |
2096 | p.u.prefix4 = attr->standard.remote_addr; |
2097 | ospf_te_update_subnet(ted, vertex, p, attr->standard.te_metric); | |
2098 | ||
2099 | /* Connect Edge to the remote Vertex */ | |
2100 | if (edge->destination == NULL) { | |
2101 | edge->destination = vertex; | |
2102 | listnode_add_sort_nodup(vertex->incoming_edges, edge); | |
2103 | } | |
16f1b9ee | 2104 | |
f173deb3 OD |
2105 | /* Finally set type to ASBR the node that advertised this Edge ... */ |
2106 | vertex = edge->source; | |
2107 | lnode = vertex->node; | |
2108 | if (CHECK_FLAG(lnode->flags, LS_NODE_TYPE)) { | |
2109 | if (lnode->type != ASBR) { | |
2110 | lnode->type = ASBR; | |
2111 | if (vertex->status != NEW) | |
2112 | vertex->status = UPDATE; | |
2113 | } | |
d62a17ae | 2114 | } else { |
f173deb3 OD |
2115 | lnode->type = ASBR; |
2116 | SET_FLAG(lnode->flags, LS_NODE_TYPE); | |
2117 | if (vertex->status != NEW) | |
2118 | vertex->status = UPDATE; | |
d62a17ae | 2119 | } |
16f1b9ee | 2120 | |
f173deb3 OD |
2121 | /* ... and Export it if needed */ |
2122 | if (vertex->status == NEW || vertex->status == UPDATE) { | |
2123 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
2124 | vertex->status = SYNC; | |
2125 | } | |
2126 | } | |
2127 | ||
2128 | /** | |
2129 | * Parse Opaque Traffic Engineering LSA (Type 1) TLVs and create or update the | |
2130 | * corresponding Link State Edge and Attributes. Vertex connections are also | |
2131 | * updated if needed based on the remote IP address of the Edge and existing | |
2132 | * reverse Edge. | |
2133 | * | |
2134 | * @param ted Link State Traffic Engineering Database | |
2135 | * @param lsa OSPF Link State Advertisement | |
2136 | * | |
2137 | * @return 0 if success, -1 otherwise | |
2138 | */ | |
2139 | static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2140 | { | |
2141 | struct ls_edge *edge; | |
2142 | struct ls_vertex *vertex; | |
2143 | struct ls_attributes *old, attr = {}; | |
2144 | struct tlv_header *tlvh; | |
2145 | void *value; | |
2146 | uint16_t len, sum; | |
2147 | uint8_t lsa_id; | |
2148 | ||
2149 | /* Initialize Attribute */ | |
2150 | attr.adv.origin = OSPFv2; | |
2151 | attr.adv.id.ip.addr = lsa->data->adv_router; | |
2152 | if (lsa->data->type != OSPF_OPAQUE_AS_LSA) | |
2153 | attr.adv.id.ip.area_id = lsa->area->area_id; | |
2154 | ||
2155 | /* Initialize TLV browsing */ | |
2156 | tlvh = TLV_HDR_TOP(lsa->data); | |
8db278b5 | 2157 | len = lsa->size - OSPF_LSA_HEADER_SIZE; |
f173deb3 | 2158 | |
8db278b5 OD |
2159 | /* Check if TE Router-ID TLV is present */ |
2160 | if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) { | |
2161 | /* if TE Router-ID is alone, we are done ... */ | |
2162 | if (len == TE_LINK_SUBTLV_DEF_SIZE) | |
2163 | return 0; | |
23508fff | 2164 | |
8db278b5 OD |
2165 | /* ... otherwise, skip it */ |
2166 | len -= TE_LINK_SUBTLV_DEF_SIZE + TLV_HDR_SIZE; | |
f173deb3 | 2167 | tlvh = TLV_HDR_NEXT(tlvh); |
8db278b5 | 2168 | } |
f173deb3 | 2169 | |
8db278b5 | 2170 | /* Check if we have a valid TE Link TLV */ |
f173deb3 OD |
2171 | if ((len == 0) || (ntohs(tlvh->type) != TE_TLV_LINK)) |
2172 | return 0; | |
2173 | ||
e3db39db | 2174 | sum = sizeof(struct tlv_header); |
f173deb3 OD |
2175 | /* Browse sub-TLV and fulfill Link State Attributes */ |
2176 | for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | |
2177 | uint32_t val32, tab32[2]; | |
2178 | float valf, tabf[8]; | |
2179 | struct in_addr addr; | |
2180 | ||
2181 | value = TLV_DATA(tlvh); | |
2182 | switch (ntohs(tlvh->type)) { | |
2183 | case TE_LINK_SUBTLV_LCLIF_IPADDR: | |
2184 | memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2185 | attr.standard.local = addr; | |
2186 | SET_FLAG(attr.flags, LS_ATTR_LOCAL_ADDR); | |
2187 | break; | |
2188 | case TE_LINK_SUBTLV_RMTIF_IPADDR: | |
2189 | memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2190 | attr.standard.remote = addr; | |
2191 | SET_FLAG(attr.flags, LS_ATTR_NEIGH_ADDR); | |
2192 | break; | |
2193 | case TE_LINK_SUBTLV_TE_METRIC: | |
2194 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2195 | attr.standard.te_metric = ntohl(val32); | |
2196 | SET_FLAG(attr.flags, LS_ATTR_TE_METRIC); | |
2197 | break; | |
2198 | case TE_LINK_SUBTLV_MAX_BW: | |
2199 | memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2200 | attr.standard.max_bw = ntohf(valf); | |
2201 | SET_FLAG(attr.flags, LS_ATTR_MAX_BW); | |
2202 | break; | |
2203 | case TE_LINK_SUBTLV_MAX_RSV_BW: | |
2204 | memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2205 | attr.standard.max_rsv_bw = ntohf(valf); | |
2206 | SET_FLAG(attr.flags, LS_ATTR_MAX_RSV_BW); | |
2207 | break; | |
2208 | case TE_LINK_SUBTLV_UNRSV_BW: | |
2209 | memcpy(tabf, value, TE_LINK_SUBTLV_UNRSV_SIZE); | |
2210 | for (int i = 0; i < MAX_CLASS_TYPE; i++) | |
2211 | attr.standard.unrsv_bw[i] = ntohf(tabf[i]); | |
2212 | SET_FLAG(attr.flags, LS_ATTR_UNRSV_BW); | |
2213 | break; | |
2214 | case TE_LINK_SUBTLV_RSC_CLSCLR: | |
2215 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2216 | attr.standard.admin_group = ntohl(val32); | |
2217 | SET_FLAG(attr.flags, LS_ATTR_ADM_GRP); | |
2218 | break; | |
2219 | case TE_LINK_SUBTLV_LLRI: | |
2220 | memcpy(tab32, value, TE_LINK_SUBTLV_LLRI_SIZE); | |
2221 | attr.standard.local_id = ntohl(tab32[0]); | |
2222 | attr.standard.remote_id = ntohl(tab32[1]); | |
2223 | SET_FLAG(attr.flags, LS_ATTR_LOCAL_ID); | |
2224 | SET_FLAG(attr.flags, LS_ATTR_NEIGH_ID); | |
2225 | break; | |
2226 | case TE_LINK_SUBTLV_RIP: | |
2227 | memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2228 | attr.standard.remote_addr = addr; | |
2229 | SET_FLAG(attr.flags, LS_ATTR_REMOTE_ADDR); | |
2230 | break; | |
2231 | case TE_LINK_SUBTLV_RAS: | |
2232 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2233 | attr.standard.remote_as = ntohl(val32); | |
2234 | SET_FLAG(attr.flags, LS_ATTR_REMOTE_AS); | |
2235 | break; | |
2236 | case TE_LINK_SUBTLV_AV_DELAY: | |
2237 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2238 | attr.extended.delay = ntohl(val32); | |
2239 | SET_FLAG(attr.flags, LS_ATTR_DELAY); | |
2240 | break; | |
2241 | case TE_LINK_SUBTLV_MM_DELAY: | |
2242 | memcpy(tab32, value, TE_LINK_SUBTLV_MM_DELAY_SIZE); | |
2243 | attr.extended.min_delay = ntohl(tab32[0]); | |
2244 | attr.extended.max_delay = ntohl(tab32[1]); | |
2245 | SET_FLAG(attr.flags, LS_ATTR_MIN_MAX_DELAY); | |
2246 | break; | |
2247 | case TE_LINK_SUBTLV_DELAY_VAR: | |
2248 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2249 | attr.extended.jitter = ntohl(val32); | |
2250 | SET_FLAG(attr.flags, LS_ATTR_JITTER); | |
2251 | break; | |
2252 | case TE_LINK_SUBTLV_PKT_LOSS: | |
2253 | memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2254 | attr.extended.pkt_loss = ntohl(val32); | |
2255 | SET_FLAG(attr.flags, LS_ATTR_PACKET_LOSS); | |
2256 | break; | |
2257 | case TE_LINK_SUBTLV_RES_BW: | |
2258 | memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2259 | attr.extended.rsv_bw = ntohf(valf); | |
2260 | SET_FLAG(attr.flags, LS_ATTR_RSV_BW); | |
2261 | break; | |
2262 | case TE_LINK_SUBTLV_AVA_BW: | |
2263 | memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2264 | attr.extended.ava_bw = ntohf(valf); | |
2265 | SET_FLAG(attr.flags, LS_ATTR_AVA_BW); | |
2266 | break; | |
2267 | case TE_LINK_SUBTLV_USE_BW: | |
2268 | memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); | |
2269 | attr.extended.used_bw = ntohf(valf); | |
2270 | SET_FLAG(attr.flags, LS_ATTR_USE_BW); | |
2271 | break; | |
2272 | default: | |
2273 | break; | |
2274 | } | |
2275 | sum += TLV_SIZE(tlvh); | |
2276 | } | |
2277 | ||
2278 | /* Get corresponding Edge from Link State Data Base */ | |
2279 | edge = get_edge(ted, attr.adv, attr.standard.local); | |
2280 | old = edge->attributes; | |
2281 | ||
2282 | ote_debug(" |- Process Traffic Engineering LSA %pI4 for Edge %pI4", | |
2283 | &lsa->data->id, &attr.standard.local); | |
2284 | ||
2285 | /* Update standard fields */ | |
2286 | len = sizeof(struct ls_standard); | |
2287 | if ((attr.flags & 0x0FFFF) == (old->flags & 0x0FFFF)) { | |
2288 | if (memcmp(&attr.standard, &old->standard, len) != 0) { | |
2289 | memcpy(&old->standard, &attr.standard, len); | |
2290 | if (edge->status != NEW) | |
2291 | edge->status = UPDATE; | |
2292 | } | |
2293 | } else { | |
2294 | memcpy(&old->standard, &attr.standard, len); | |
2295 | old->flags |= attr.flags & 0x0FFFF; | |
2296 | if (edge->status != NEW) | |
2297 | edge->status = UPDATE; | |
2298 | } | |
2299 | /* Update extended fields */ | |
2300 | len = sizeof(struct ls_extended); | |
2301 | if ((attr.flags & 0x0FF0000) == (old->flags & 0x0FF0000)) { | |
2302 | if (memcmp(&attr.extended, &old->extended, len) != 0) { | |
2303 | memcpy(&old->extended, &attr.extended, len); | |
2304 | if (edge->status != NEW) | |
2305 | edge->status = UPDATE; | |
2306 | } | |
2307 | } else { | |
2308 | memcpy(&old->extended, &attr.extended, len); | |
2309 | old->flags |= attr.flags & 0x0FF0000; | |
2310 | if (edge->status != NEW) | |
2311 | edge->status = UPDATE; | |
2312 | } | |
2313 | ||
2314 | /* If LSA is an Opaque Inter-AS, Add Node and Subnet */ | |
2315 | lsa_id = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); | |
2316 | if (lsa_id == OPAQUE_TYPE_INTER_AS_LSA) | |
2317 | ospf_te_update_remote_asbr(ted, edge); | |
2318 | ||
2319 | /* Update remote Link if remote IP addr is known */ | |
2320 | if (CHECK_FLAG(old->flags, LS_ATTR_NEIGH_ADDR)) { | |
2321 | struct ls_edge *dst; | |
2322 | ||
2323 | dst = ls_find_edge_by_destination(ted, old); | |
2324 | /* Attach remote link if not set */ | |
2325 | if (dst && edge->source && dst->destination == NULL) { | |
2326 | vertex = edge->source; | |
2327 | if (vertex->incoming_edges) | |
2328 | listnode_add_sort_nodup(vertex->incoming_edges, | |
2329 | dst); | |
2330 | dst->destination = vertex; | |
2331 | } | |
2332 | /* and destination vertex to this edge */ | |
2333 | if (dst && dst->source && edge->destination == NULL) { | |
2334 | vertex = dst->source; | |
2335 | if (vertex->incoming_edges) | |
2336 | listnode_add_sort_nodup(vertex->incoming_edges, | |
2337 | edge); | |
2338 | edge->destination = vertex; | |
2339 | } | |
2340 | } | |
2341 | ||
2342 | /* Export Link State Edge if needed */ | |
2343 | if (edge->status == NEW || edge->status == UPDATE) { | |
2344 | ote_debug(" |- %s TE info. for Edge %pI4", | |
2345 | edge->status == NEW ? "Add" : "Update", | |
2346 | &edge->attributes->standard.local); | |
2347 | ||
2348 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2349 | edge->status = SYNC; | |
2350 | } | |
2351 | ||
2352 | return 0; | |
2353 | } | |
2354 | ||
2355 | /** | |
2356 | * Delete Link State Attributes information that correspond to the Opaque | |
2357 | * Traffic Engineering LSA (Type 1) TLVs. Note that the Edge is not removed. | |
2358 | * | |
2359 | * @param ted Link State Traffic Engineering Database | |
2360 | * @param lsa OSPF Link State Advertisement | |
2361 | * | |
2362 | * @return 0 if success, -1 otherwise | |
2363 | */ | |
2364 | static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2365 | { | |
2366 | struct ls_edge *edge; | |
2367 | struct ls_attributes *attr; | |
2368 | struct tlv_header *tlvh; | |
2369 | struct in_addr addr; | |
2370 | uint64_t key = 0; | |
2371 | uint16_t len, sum; | |
2372 | uint8_t lsa_id; | |
2373 | ||
2374 | /* Initialize TLV browsing */ | |
2375 | tlvh = TLV_HDR_TOP(lsa->data); | |
2376 | /* Skip Router TE ID if present */ | |
2377 | if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) | |
2378 | tlvh = TLV_HDR_NEXT(tlvh); | |
2379 | len = TLV_BODY_SIZE(tlvh); | |
e3db39db | 2380 | sum = sizeof(struct tlv_header); |
f173deb3 OD |
2381 | |
2382 | /* Browse sub-TLV to find Link ID */ | |
2383 | for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | |
2384 | if (ntohs(tlvh->type) == TE_LINK_SUBTLV_LCLIF_IPADDR) { | |
2385 | memcpy(&addr, TLV_DATA(tlvh), TE_LINK_SUBTLV_DEF_SIZE); | |
2386 | key = ((uint64_t)ntohl(addr.s_addr)) & 0xffffffff; | |
2387 | break; | |
2388 | } | |
2389 | sum += TLV_SIZE(tlvh); | |
2390 | } | |
2391 | if (key == 0) | |
2392 | return 0; | |
2393 | ||
2394 | /* Search Edge that corresponds to the Link ID */ | |
2395 | edge = ls_find_edge_by_key(ted, key); | |
2396 | if (!edge || !edge->attributes) | |
2397 | return 0; | |
2398 | attr = edge->attributes; | |
2399 | ||
2400 | /* First, remove Remote ASBR and associated Edge & Subnet if any */ | |
2401 | lsa_id = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); | |
2402 | if (lsa_id == OPAQUE_TYPE_INTER_AS_LSA) { | |
2403 | ote_debug(" |- Delete remote ASBR, Edge and Subnet"); | |
2404 | ||
2405 | if (edge->destination) { | |
2406 | edge->destination->status = DELETE; | |
2407 | ospf_te_export(LS_MSG_TYPE_NODE, edge->destination); | |
2408 | ls_vertex_del_all(ted, edge->destination); | |
2409 | } | |
2410 | ||
2411 | ospf_te_delete_subnet(ted, attr->standard.local); | |
2412 | ||
2413 | edge->status = DELETE; | |
2414 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2415 | ls_edge_del_all(ted, edge); | |
2416 | ||
2417 | return 0; | |
2418 | } | |
2419 | ||
2420 | ote_debug(" |- Delete TE info. for Edge %pI4", | |
2421 | &edge->attributes->standard.local); | |
2422 | ||
2423 | /* Remove Link State Attributes TE information */ | |
2424 | memset(&attr->standard, 0, sizeof(struct ls_standard)); | |
2425 | attr->flags &= 0x0FFFF; | |
2426 | memset(&attr->extended, 0, sizeof(struct ls_extended)); | |
2427 | attr->flags &= 0x0FF0000; | |
2428 | ls_attributes_srlg_del(attr); | |
2429 | ||
2430 | /* Export Edge that has been updated */ | |
2431 | if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID) | |
2432 | || CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { | |
2433 | edge->status = UPDATE; | |
2434 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2435 | edge->status = SYNC; | |
2436 | } else { | |
2437 | /* Remove completely the Edge if Segment Routing is not set */ | |
2438 | ospf_te_delete_subnet(ted, attr->standard.local); | |
2439 | edge->status = DELETE; | |
2440 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2441 | ls_edge_del_all(ted, edge); | |
2442 | } | |
2443 | ||
2444 | return 0; | |
2445 | } | |
2446 | ||
2447 | /** | |
2448 | * Parse Opaque Router Information LSA (Type 4) TLVs and update the | |
2449 | * corresponding Link State Vertex with these information (Segment Routing). | |
2450 | * | |
2451 | * @param ted Link State Traffic Engineering Database | |
2452 | * @param lsa OSPF Link State Advertisement | |
2453 | * | |
2454 | * @return 0 if success, -1 otherwise | |
2455 | */ | |
2456 | static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2457 | { | |
2458 | struct ls_vertex *vertex; | |
2459 | struct ls_node *node; | |
2460 | struct lsa_header *lsah = lsa->data; | |
2461 | struct tlv_header *tlvh; | |
2462 | uint16_t len = 0, sum = 0; | |
2463 | ||
2464 | /* Get vertex / Node from LSA Advertised Router ID */ | |
2465 | vertex = get_vertex(ted, lsa); | |
2466 | node = vertex->node; | |
2467 | ||
2468 | ote_debug(" |- Process Router Information LSA %pI4 for Vertex %pI4", | |
2469 | &lsa->data->id, &node->router_id); | |
2470 | ||
2471 | /* Initialize TLV browsing */ | |
8db278b5 OD |
2472 | len = lsa->size - OSPF_LSA_HEADER_SIZE; |
2473 | for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh; | |
2474 | tlvh = TLV_HDR_NEXT(tlvh)) { | |
f173deb3 OD |
2475 | struct ri_sr_tlv_sr_algorithm *algo; |
2476 | struct ri_sr_tlv_sid_label_range *range; | |
2477 | struct ri_sr_tlv_node_msd *msd; | |
2478 | uint32_t size, lower; | |
2479 | ||
2480 | switch (ntohs(tlvh->type)) { | |
2481 | case RI_SR_TLV_SR_ALGORITHM: | |
2482 | algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; | |
2483 | ||
2484 | for (int i = 0; i < ntohs(algo->header.length); i++) { | |
2485 | if (CHECK_FLAG(node->flags, LS_NODE_SR) | |
2486 | && (node->algo[i] == algo->value[i])) | |
2487 | continue; | |
2488 | ||
2489 | node->algo[i] = algo->value[i]; | |
2490 | SET_FLAG(node->flags, LS_NODE_SR); | |
2491 | if (vertex->status != NEW) | |
2492 | vertex->status = UPDATE; | |
2493 | } | |
2494 | ||
2495 | /* Reset other Algorithms */ | |
2496 | for (int i = ntohs(algo->header.length); i < 2; i++) { | |
2497 | if (vertex->status != NEW | |
2498 | && node->algo[i] != SR_ALGORITHM_UNSET) | |
2499 | vertex->status = UPDATE; | |
2500 | node->algo[i] = SR_ALGORITHM_UNSET; | |
2501 | } | |
2502 | ||
2503 | break; | |
2504 | ||
2505 | case RI_SR_TLV_SRGB_LABEL_RANGE: | |
2506 | range = (struct ri_sr_tlv_sid_label_range *)tlvh; | |
2507 | size = GET_RANGE_SIZE(ntohl(range->size)); | |
2508 | lower = GET_LABEL(ntohl(range->lower.value)); | |
2509 | if ((CHECK_FLAG(node->flags, LS_NODE_SR)) | |
2510 | && ((node->srgb.range_size == size) | |
2511 | && (node->srgb.lower_bound == lower))) | |
2512 | break; | |
2513 | ||
2514 | node->srgb.range_size = size; | |
2515 | node->srgb.lower_bound = lower; | |
2516 | SET_FLAG(node->flags, LS_NODE_SR); | |
2517 | if (vertex->status != NEW) | |
2518 | vertex->status = UPDATE; | |
2519 | ||
2520 | break; | |
2521 | ||
2522 | case RI_SR_TLV_SRLB_LABEL_RANGE: | |
2523 | range = (struct ri_sr_tlv_sid_label_range *)tlvh; | |
2524 | size = GET_RANGE_SIZE(ntohl(range->size)); | |
2525 | lower = GET_LABEL(ntohl(range->lower.value)); | |
2526 | if ((CHECK_FLAG(node->flags, LS_NODE_SRLB)) | |
2527 | && ((node->srlb.range_size == size) | |
2528 | && (node->srlb.lower_bound == lower))) | |
2529 | break; | |
2530 | ||
2531 | node->srlb.range_size = size; | |
2532 | node->srlb.lower_bound = lower; | |
2533 | SET_FLAG(node->flags, LS_NODE_SRLB); | |
2534 | if (vertex->status != NEW) | |
2535 | vertex->status = UPDATE; | |
2536 | ||
2537 | break; | |
2538 | ||
2539 | case RI_SR_TLV_NODE_MSD: | |
2540 | msd = (struct ri_sr_tlv_node_msd *)tlvh; | |
2541 | if ((CHECK_FLAG(node->flags, LS_NODE_MSD)) | |
2542 | && (node->msd == msd->value)) | |
2543 | break; | |
2544 | ||
2545 | node->msd = msd->value; | |
2546 | SET_FLAG(node->flags, LS_NODE_MSD); | |
2547 | if (vertex->status != NEW) | |
2548 | vertex->status = UPDATE; | |
2549 | ||
2550 | break; | |
2551 | ||
2552 | default: | |
2553 | break; | |
2554 | } | |
2555 | sum += TLV_SIZE(tlvh); | |
2556 | } | |
2557 | ||
2558 | /* Vertex has been created or updated: export it */ | |
2559 | if (vertex->status == NEW || vertex->status == UPDATE) { | |
2560 | ote_debug(" |- %s SR info - SRGB[%d/%d] for Vertex %pI4", | |
2561 | vertex->status == NEW ? "Add" : "Update", | |
2562 | vertex->node->srgb.lower_bound, | |
2563 | vertex->node->srgb.range_size, | |
2564 | &vertex->node->router_id); | |
2565 | ||
2566 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
2567 | vertex->status = SYNC; | |
2568 | } | |
2569 | ||
2570 | return 0; | |
2571 | } | |
2572 | ||
2573 | /** | |
2574 | * Delete Link State Node information (Segment Routing) that correspond to the | |
2575 | * Opaque Router Information LSA (Type 4) TLVs. Note that the Vertex is not | |
2576 | * removed. | |
2577 | * | |
2578 | * @param ted Link State Traffic Engineering Database | |
2579 | * @param lsa OSPF Link State Advertisement | |
2580 | * | |
2581 | * @return 0 if success, -1 otherwise | |
2582 | */ | |
2583 | static int ospf_te_delete_ri(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2584 | { | |
2585 | struct ls_node_id lnid; | |
2586 | struct ls_vertex *vertex; | |
2587 | struct ls_node *node; | |
2588 | ||
2589 | /* Search if a Link State Vertex already exist */ | |
2590 | lnid.origin = OSPFv2; | |
2591 | lnid.id.ip.addr = lsa->data->adv_router; | |
2592 | lnid.id.ip.area_id = lsa->area->area_id; | |
2593 | vertex = ls_find_vertex_by_id(ted, lnid); | |
2594 | if (!vertex) | |
2595 | return -1; | |
2596 | ||
2597 | /* Remove Segment Routing Information if any */ | |
2598 | node = vertex->node; | |
2599 | UNSET_FLAG(node->flags, LS_NODE_SR); | |
2600 | memset(&node->srgb, 0, sizeof(struct ls_srgb)); | |
2601 | node->algo[0] = SR_ALGORITHM_UNSET; | |
2602 | node->algo[1] = SR_ALGORITHM_UNSET; | |
2603 | UNSET_FLAG(node->flags, LS_NODE_SRLB); | |
2604 | memset(&node->srlb, 0, sizeof(struct ls_srlb)); | |
2605 | UNSET_FLAG(node->flags, LS_NODE_MSD); | |
2606 | node->msd = 0; | |
2607 | vertex->status = UPDATE; | |
2608 | ||
2609 | ote_debug(" |- Delete SR info. for Vertex %pI4", | |
2610 | &vertex->node->router_id); | |
2611 | ||
2612 | /* Vertex has been updated: export it */ | |
2613 | ospf_te_export(LS_MSG_TYPE_NODE, vertex); | |
2614 | vertex->status = SYNC; | |
2615 | ||
2616 | return 0; | |
2617 | } | |
2618 | ||
2619 | /** | |
2620 | * Parse Opaque Extended Prefix LSA (Type 7) TLVs and update the corresponding | |
2621 | * Link State Subnet with these information (Segment Routing ID). | |
2622 | * | |
2623 | * @param ted Link State Traffic Engineering Database | |
2624 | * @param lsa OSPF Link State Advertisement | |
2625 | * | |
2626 | * @return 0 if success, -1 otherwise | |
2627 | */ | |
2628 | static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2629 | { | |
2630 | struct ls_node_id lnid; | |
2631 | struct ls_subnet *subnet; | |
2632 | struct ls_prefix *ls_pref; | |
2633 | struct prefix pref; | |
2634 | struct ext_tlv_prefix *ext; | |
2635 | struct ext_subtlv_prefix_sid *pref_sid; | |
2636 | uint32_t label; | |
2637 | ||
2638 | /* Get corresponding Subnet from Link State Data Base */ | |
2639 | ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); | |
2640 | pref.family = AF_INET; | |
2641 | pref.prefixlen = ext->pref_length; | |
2642 | pref.u.prefix4 = ext->address; | |
2643 | subnet = ls_find_subnet(ted, pref); | |
2644 | ||
2645 | /* Create new Link State Prefix if not found */ | |
2646 | if (!subnet) { | |
2647 | lnid.origin = OSPFv2; | |
2648 | lnid.id.ip.addr = lsa->data->adv_router; | |
2649 | lnid.id.ip.area_id = lsa->area->area_id; | |
2650 | ls_pref = ls_prefix_new(lnid, pref); | |
2651 | /* and add it to the TED */ | |
2652 | subnet = ls_subnet_add(ted, ls_pref); | |
2653 | } | |
2654 | ||
2655 | ote_debug(" |- Process Extended Prefix LSA %pI4 for subnet %pFX", | |
2656 | &lsa->data->id, &pref); | |
2657 | ||
2658 | /* Initialize TLV browsing */ | |
2659 | ls_pref = subnet->ls_pref; | |
2660 | pref_sid = (struct ext_subtlv_prefix_sid *)((char *)(ext) + TLV_HDR_SIZE | |
2661 | + EXT_TLV_PREFIX_SIZE); | |
2662 | label = CHECK_FLAG(pref_sid->flags, EXT_SUBTLV_PREFIX_SID_VFLG) | |
2663 | ? GET_LABEL(ntohl(pref_sid->value)) | |
2664 | : ntohl(pref_sid->value); | |
2665 | ||
2666 | /* Check if it is a simple refresh */ | |
2667 | if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR) | |
2668 | && ls_pref->sr.algo == pref_sid->algorithm | |
2669 | && ls_pref->sr.sid_flag == pref_sid->flags | |
2670 | && ls_pref->sr.sid == label) | |
2671 | return 0; | |
2672 | ||
2673 | /* Fulfill SR information */ | |
2674 | ls_pref->sr.algo = pref_sid->algorithm; | |
2675 | ls_pref->sr.sid_flag = pref_sid->flags; | |
2676 | ls_pref->sr.sid = label; | |
2677 | SET_FLAG(ls_pref->flags, LS_PREF_SR); | |
2678 | if (subnet->status != NEW) | |
2679 | subnet->status = UPDATE; | |
2680 | ||
2681 | /* Export Subnet if needed */ | |
2682 | if (subnet->status == NEW || subnet->status == UPDATE) { | |
2683 | ote_debug(" |- %s SID %d to subnet %pFX", | |
2684 | subnet->status == NEW ? "Add" : "Update", | |
2685 | ls_pref->sr.sid, &ls_pref->pref); | |
2686 | ||
2687 | ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
2688 | subnet->status = SYNC; | |
2689 | } | |
2690 | ||
2691 | return 0; | |
2692 | } | |
2693 | ||
2694 | /** | |
2695 | * Delete Link State Subnet information (Segment Routing ID) that correspond to | |
2696 | * the Opaque Extended Prefix LSA (Type 7) TLVs. Note that the Subnet is not | |
2697 | * removed. | |
2698 | * | |
2699 | * @param ted Link State Traffic Engineering Database | |
2700 | * @param lsa OSPF Link State Advertisement | |
2701 | * | |
2702 | * @return 0 if success, -1 otherwise | |
2703 | */ | |
2704 | static int ospf_te_delete_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2705 | { | |
2706 | struct ls_subnet *subnet; | |
2707 | struct ls_prefix *ls_pref; | |
2708 | struct prefix pref; | |
2709 | struct ext_tlv_prefix *ext; | |
2710 | ||
2711 | /* Get corresponding Subnet from Link State Data Base */ | |
2712 | ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); | |
2713 | pref.family = AF_INET; | |
2714 | pref.prefixlen = ext->pref_length; | |
2715 | pref.u.prefix4 = ext->address; | |
2716 | subnet = ls_find_subnet(ted, pref); | |
2717 | ||
2718 | /* Check if there is a corresponding subnet */ | |
2719 | if (!subnet) | |
2720 | return -1; | |
2721 | ||
2722 | ote_debug(" |- Delete SID %d to subnet %pFX", subnet->ls_pref->sr.sid, | |
2723 | &subnet->ls_pref->pref); | |
2724 | ||
2725 | /* Remove Segment Routing information */ | |
2726 | ls_pref = subnet->ls_pref; | |
2727 | UNSET_FLAG(ls_pref->flags, LS_PREF_SR); | |
2728 | memset(&ls_pref->sr, 0, sizeof(struct ls_sid)); | |
2729 | subnet->status = UPDATE; | |
2730 | ||
2731 | /* Subnet has been updated: export it */ | |
2732 | ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); | |
2733 | subnet->status = SYNC; | |
2734 | ||
2735 | return 0; | |
2736 | } | |
2737 | ||
2738 | /** | |
2739 | * Parse Opaque Extended Link LSA (Type 8) TLVs and update the corresponding | |
2740 | * Link State Edge with these information (Segment Routing Adjacency). | |
2741 | * | |
2742 | * @param ted Link State Traffic Engineering Database | |
2743 | * @param lsa OSPF Link State Advertisement | |
2744 | * | |
2745 | * @return 0 if success, -1 otherwise | |
2746 | */ | |
2747 | static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2748 | { | |
2749 | struct ls_node_id lnid; | |
2750 | struct tlv_header *tlvh; | |
2751 | struct ext_tlv_link *ext; | |
2752 | struct ls_edge *edge; | |
2753 | struct ls_attributes *atr; | |
2754 | uint16_t len = 0, sum = 0, i; | |
2755 | uint32_t label; | |
2756 | ||
2757 | /* Get corresponding Edge from Link State Data Base */ | |
2758 | lnid.origin = OSPFv2; | |
2759 | lnid.id.ip.addr = lsa->data->adv_router; | |
2760 | lnid.id.ip.area_id = lsa->area->area_id; | |
2761 | ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); | |
2762 | edge = get_edge(ted, lnid, ext->link_data); | |
2763 | atr = edge->attributes; | |
2764 | ||
2765 | ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4", | |
2766 | &lsa->data->id, &edge->attributes->standard.local); | |
2767 | ||
2768 | /* Initialize TLV browsing */ | |
23508fff | 2769 | len = TLV_BODY_SIZE(&ext->header) - EXT_TLV_LINK_SIZE; |
f173deb3 OD |
2770 | tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE |
2771 | + EXT_TLV_LINK_SIZE); | |
2772 | for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | |
2773 | struct ext_subtlv_adj_sid *adj; | |
2774 | struct ext_subtlv_lan_adj_sid *ladj; | |
2775 | struct ext_subtlv_rmt_itf_addr *rmt; | |
2776 | ||
2777 | switch (ntohs(tlvh->type)) { | |
2778 | case EXT_SUBTLV_ADJ_SID: | |
2779 | adj = (struct ext_subtlv_adj_sid *)tlvh; | |
2780 | label = CHECK_FLAG(adj->flags, | |
2781 | EXT_SUBTLV_LINK_ADJ_SID_VFLG) | |
2782 | ? GET_LABEL(ntohl(adj->value)) | |
2783 | : ntohl(adj->value); | |
2784 | i = CHECK_FLAG(adj->flags, | |
2785 | EXT_SUBTLV_LINK_ADJ_SID_BFLG) ? 1 : 0; | |
2786 | if (((i && CHECK_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID)) | |
2787 | || (!i && CHECK_FLAG(atr->flags, LS_ATTR_ADJ_SID))) | |
2788 | && atr->adj_sid[i].flags == adj->flags | |
2789 | && atr->adj_sid[i].sid == label | |
2790 | && atr->adj_sid[i].weight == adj->weight) | |
2791 | break; | |
2792 | ||
2793 | atr->adj_sid[i].flags = adj->flags; | |
2794 | atr->adj_sid[i].sid = label; | |
2795 | atr->adj_sid[i].weight = adj->weight; | |
2796 | if (i == 0) | |
2797 | SET_FLAG(atr->flags, LS_ATTR_ADJ_SID); | |
2798 | else | |
2799 | SET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); | |
2800 | if (edge->status != NEW) | |
2801 | edge->status = UPDATE; | |
2802 | ||
2803 | break; | |
2804 | case EXT_SUBTLV_LAN_ADJ_SID: | |
2805 | ladj = (struct ext_subtlv_lan_adj_sid *)tlvh; | |
2806 | label = CHECK_FLAG(ladj->flags, | |
2807 | EXT_SUBTLV_LINK_ADJ_SID_VFLG) | |
2808 | ? GET_LABEL(ntohl(ladj->value)) | |
2809 | : ntohl(ladj->value); | |
2810 | i = CHECK_FLAG(ladj->flags, | |
2811 | EXT_SUBTLV_LINK_ADJ_SID_BFLG) ? 1 : 0; | |
2812 | if (((i && CHECK_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID)) | |
2813 | || (!i && CHECK_FLAG(atr->flags, LS_ATTR_ADJ_SID))) | |
2814 | && atr->adj_sid[i].flags == ladj->flags | |
2815 | && atr->adj_sid[i].sid == label | |
2816 | && atr->adj_sid[i].weight == ladj->weight | |
2817 | && IPV4_ADDR_SAME(&atr->adj_sid[1].neighbor.addr, | |
2818 | &ladj->neighbor_id)) | |
2819 | break; | |
2820 | ||
2821 | atr->adj_sid[i].flags = ladj->flags; | |
2822 | atr->adj_sid[i].sid = label; | |
2823 | atr->adj_sid[i].weight = ladj->weight; | |
2824 | atr->adj_sid[i].neighbor.addr = ladj->neighbor_id; | |
2825 | if (i == 0) | |
2826 | SET_FLAG(atr->flags, LS_ATTR_ADJ_SID); | |
2827 | else | |
2828 | SET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); | |
2829 | if (edge->status != NEW) | |
2830 | edge->status = UPDATE; | |
2831 | ||
2832 | break; | |
2833 | case EXT_SUBTLV_RMT_ITF_ADDR: | |
2834 | rmt = (struct ext_subtlv_rmt_itf_addr *)tlvh; | |
2835 | if (CHECK_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR) | |
2836 | && IPV4_ADDR_SAME(&atr->standard.remote, | |
2837 | &rmt->value)) | |
2838 | break; | |
2839 | ||
2840 | atr->standard.remote = rmt->value; | |
2841 | SET_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR); | |
2842 | if (edge->status != NEW) | |
2843 | edge->status = UPDATE; | |
2844 | ||
2845 | break; | |
2846 | default: | |
2847 | break; | |
2848 | } | |
2849 | sum += TLV_SIZE(tlvh); | |
2850 | } | |
2851 | ||
2852 | /* Export Link State Edge if needed */ | |
2853 | if (edge->status == NEW || edge->status == UPDATE) { | |
2854 | ote_debug(" |- %s Adj-SID %d & %d to edge %pI4", | |
2855 | edge->status == NEW ? "Add" : "Update", | |
2856 | edge->attributes->adj_sid[0].sid, | |
2857 | edge->attributes->adj_sid[1].sid, | |
2858 | &edge->attributes->standard.local); | |
2859 | ||
2860 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2861 | edge->status = SYNC; | |
2862 | } | |
2863 | ||
2864 | return 0; | |
2865 | } | |
2866 | ||
2867 | /** | |
2868 | * Delete Link State Edge information (Segment Routing Adjacency) that | |
2869 | * correspond to the Opaque Extended Link LSA (Type 8) TLVs. Note that the Edge | |
2870 | * is not removed. | |
2871 | * | |
2872 | * @param ted Link State Traffic Engineering Database | |
2873 | * @param lsa OSPF Link State Advertisement | |
2874 | * | |
2875 | * @return 0 if success, -1 otherwise | |
2876 | */ | |
2877 | static int ospf_te_delete_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2878 | { | |
2879 | struct ls_edge *edge; | |
2880 | struct ls_attributes *atr; | |
2881 | struct ext_tlv_link *ext; | |
2882 | uint64_t key; | |
2883 | ||
2884 | /* Search for corresponding Edge from Link State Data Base */ | |
2885 | ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); | |
2886 | key = ((uint64_t)ntohl(ext->link_data.s_addr)) & 0xffffffff; | |
2887 | edge = ls_find_edge_by_key(ted, key); | |
2888 | ||
2889 | /* Check if there is a corresponding Edge */ | |
2890 | if (!edge) | |
2891 | return -1; | |
2892 | ||
2893 | ote_debug(" |- Delete Adj-SID %d to edge %pI4", | |
2894 | edge->attributes->adj_sid[0].sid, | |
2895 | &edge->attributes->standard.local); | |
2896 | ||
2897 | /* Remove Segment Routing information */ | |
2898 | atr = edge->attributes; | |
2899 | UNSET_FLAG(atr->flags, LS_ATTR_ADJ_SID); | |
2900 | UNSET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); | |
2901 | memset(atr->adj_sid, 0, 2 * sizeof(struct ls_sid)); | |
2902 | edge->status = UPDATE; | |
2903 | ||
2904 | /* Edge has been updated: export it */ | |
2905 | ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); | |
2906 | edge->status = SYNC; | |
2907 | ||
2908 | return 0; | |
2909 | } | |
2910 | ||
2911 | /** | |
2912 | * Parse Opaque LSA Type and call corresponding parser. | |
2913 | * | |
2914 | * @param ted Link State Traffic Engineering Database | |
2915 | * @param lsa OSPF Link State Advertisement | |
2916 | * | |
2917 | * @return 0 if success, -1 otherwise | |
2918 | */ | |
2919 | static int ospf_te_parse_opaque_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2920 | { | |
2921 | uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); | |
2922 | int rc = -1; | |
2923 | ||
2924 | ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]", | |
2925 | __func__, &lsa->data->id, &lsa->data->adv_router); | |
2926 | ||
2927 | switch (key) { | |
2928 | case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: | |
2929 | case OPAQUE_TYPE_INTER_AS_LSA: | |
2930 | rc = ospf_te_parse_te(ted, lsa); | |
2931 | break; | |
2932 | case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: | |
2933 | rc = ospf_te_parse_ri(ted, lsa); | |
2934 | break; | |
2935 | case OPAQUE_TYPE_EXTENDED_PREFIX_LSA: | |
2936 | rc = ospf_te_parse_ext_pref(ted, lsa); | |
2937 | break; | |
2938 | case OPAQUE_TYPE_EXTENDED_LINK_LSA: | |
2939 | rc = ospf_te_parse_ext_link(ted, lsa); | |
2940 | break; | |
2941 | default: | |
2942 | break; | |
2943 | } | |
2944 | ||
2945 | return rc; | |
2946 | } | |
2947 | ||
2948 | /** | |
2949 | * Parse Opaque LSA Type and call corresponding deletion function. | |
2950 | * | |
2951 | * @param ted Link State Traffic Engineering Database | |
2952 | * @param lsa OSPF Link State Advertisement | |
2953 | * | |
2954 | * @return 0 if success, -1 otherwise | |
2955 | */ | |
2956 | static int ospf_te_delete_opaque_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) | |
2957 | { | |
2958 | uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); | |
2959 | int rc = -1; | |
2960 | ||
2961 | ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]", | |
2962 | __func__, &lsa->data->id, &lsa->data->adv_router); | |
2963 | ||
2964 | switch (key) { | |
2965 | case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: | |
2966 | case OPAQUE_TYPE_INTER_AS_LSA: | |
2967 | rc = ospf_te_delete_te(ted, lsa); | |
2968 | break; | |
2969 | case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: | |
2970 | rc = ospf_te_delete_ri(ted, lsa); | |
2971 | break; | |
2972 | case OPAQUE_TYPE_EXTENDED_PREFIX_LSA: | |
2973 | rc = ospf_te_delete_ext_pref(ted, lsa); | |
2974 | break; | |
2975 | case OPAQUE_TYPE_EXTENDED_LINK_LSA: | |
2976 | rc = ospf_te_delete_ext_link(ted, lsa); | |
2977 | break; | |
2978 | default: | |
2979 | break; | |
2980 | } | |
2981 | ||
2982 | return rc; | |
2983 | } | |
2984 | ||
2985 | /** | |
2986 | * Update Traffic Engineering Database Elements that correspond to the received | |
2987 | * OSPF LSA. If LSA age is equal to MAX_AGE, call deletion function instead. | |
2988 | * | |
2989 | * @param lsa OSPF Link State Advertisement | |
2990 | * | |
2991 | * @return 0 if success, -1 otherwise | |
2992 | */ | |
2993 | static int ospf_mpls_te_lsa_update(struct ospf_lsa *lsa) | |
2994 | { | |
2995 | ||
2996 | uint8_t rc; | |
2997 | ||
2998 | /* Check that MPLS-TE is active */ | |
2999 | if (!OspfMplsTE.enabled || !OspfMplsTE.ted) | |
3000 | return 0; | |
3001 | ||
3002 | /* Sanity Check */ | |
3003 | if (lsa == NULL) { | |
3004 | flog_warn(EC_OSPF_LSA_NULL, "TE (%s): Abort! LSA is NULL", | |
3005 | __func__); | |
3006 | return -1; | |
3007 | } | |
3008 | ||
3009 | /* If LSA is MAX_AGE, remove corresponding Link State element */ | |
3010 | if (IS_LSA_MAXAGE(lsa)) { | |
3011 | switch (lsa->data->type) { | |
3012 | case OSPF_ROUTER_LSA: | |
3013 | rc = ospf_te_delete_router_lsa(OspfMplsTE.ted, lsa); | |
3014 | break; | |
3015 | case OSPF_OPAQUE_AREA_LSA: | |
3016 | case OSPF_OPAQUE_AS_LSA: | |
3017 | rc = ospf_te_delete_opaque_lsa(OspfMplsTE.ted, lsa); | |
3018 | break; | |
3019 | default: | |
3020 | rc = 0; | |
3021 | break; | |
3022 | } | |
3023 | } else { | |
3024 | /* Parse LSA to Update corresponding Link State element */ | |
3025 | switch (lsa->data->type) { | |
3026 | case OSPF_ROUTER_LSA: | |
3027 | rc = ospf_te_parse_router_lsa(OspfMplsTE.ted, lsa); | |
3028 | break; | |
3029 | case OSPF_OPAQUE_AREA_LSA: | |
3030 | case OSPF_OPAQUE_AS_LSA: | |
3031 | rc = ospf_te_parse_opaque_lsa(OspfMplsTE.ted, lsa); | |
3032 | break; | |
3033 | default: | |
3034 | rc = 0; | |
3035 | break; | |
3036 | } | |
3037 | } | |
3038 | ||
3039 | return rc; | |
3040 | } | |
3041 | ||
3042 | /** | |
3043 | * Delete Traffic Engineering Database element from OSPF LSA. This function | |
3044 | * process only self LSA (i.e. advertised by the router) which reach MAX_AGE | |
3045 | * as LSA deleted by neighbor routers are Flushed (i.e. advertised with | |
3046 | * age == MAX_AGE) and processed by ospf_mpls_te_lsa_update() function. | |
3047 | * | |
3048 | * @param lsa OSPF Link State Advertisement | |
3049 | * | |
3050 | * @return 0 if success, -1 otherwise | |
3051 | */ | |
3052 | static int ospf_mpls_te_lsa_delete(struct ospf_lsa *lsa) | |
3053 | { | |
3054 | ||
3055 | uint8_t rc; | |
3056 | ||
3057 | /* Check that MPLS-TE is active */ | |
3058 | if (!OspfMplsTE.enabled || !OspfMplsTE.ted) | |
3059 | return 0; | |
3060 | ||
3061 | /* Sanity Check */ | |
3062 | if (lsa == NULL) { | |
3063 | flog_warn(EC_OSPF_LSA_NULL, "TE (%s): Abort! LSA is NULL", | |
3064 | __func__); | |
3065 | return -1; | |
3066 | } | |
3067 | ||
3068 | /* | |
3069 | * Process only self LSAs that reach MAX_AGE. Indeed, when the router | |
3070 | * need to update or refresh an LSA, it first removes the old LSA from | |
3071 | * the LSDB and then insert the new one. Thus, to avoid removing | |
3072 | * corresponding Link State element and loosing some parameters | |
3073 | * instead of just updating it, only self LSAs that reach MAX_AGE are | |
3074 | * processed here. Other LSAs are processed by ospf_mpls_te_lsa_update() | |
3075 | * and eventually removed when LSA age is MAX_AGE i.e. LSA is flushed | |
3076 | * by the originator. | |
3077 | */ | |
3078 | if (!IS_LSA_SELF(lsa) || !IS_LSA_MAXAGE(lsa)) | |
3079 | return 0; | |
3080 | ||
3081 | /* Parse Link State information */ | |
3082 | switch (lsa->data->type) { | |
3083 | case OSPF_ROUTER_LSA: | |
3084 | rc = ospf_te_delete_router_lsa(OspfMplsTE.ted, lsa); | |
3085 | break; | |
3086 | case OSPF_OPAQUE_AREA_LSA: | |
3087 | case OSPF_OPAQUE_AS_LSA: | |
3088 | rc = ospf_te_delete_opaque_lsa(OspfMplsTE.ted, lsa); | |
3089 | break; | |
3090 | default: | |
3091 | rc = 0; | |
3092 | break; | |
3093 | } | |
3094 | ||
3095 | return rc; | |
3096 | } | |
3097 | ||
3098 | /** | |
3099 | * Send the whole Link State Traffic Engineering Database to the consumer that | |
3100 | * request it through a ZAPI Link State Synchronous Opaque Message. | |
3101 | * | |
3102 | * @param info ZAPI Opaque message | |
3103 | * | |
3104 | * @return 0 if success, -1 otherwise | |
3105 | */ | |
3106 | int ospf_te_sync_ted(struct zapi_opaque_reg_info dst) | |
3107 | { | |
3108 | int rc = -1; | |
3109 | ||
3110 | /* Check that MPLS-TE and TE distribution are enabled */ | |
3111 | if (!OspfMplsTE.enabled || !OspfMplsTE.export) | |
3112 | return rc; | |
3113 | ||
3114 | rc = ls_sync_ted(OspfMplsTE.ted, zclient, &dst); | |
3115 | ||
3116 | return rc; | |
3117 | } | |
3118 | ||
3119 | /** | |
3120 | * Initialize Traffic Engineering Database from the various OSPF Link State | |
3121 | * Database (LSDB). | |
3122 | * | |
3123 | * @param ted Link State Traffice Engineering Database | |
3124 | * @param ospf OSPF main structure | |
3125 | */ | |
3126 | static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf) | |
3127 | { | |
3128 | struct listnode *node, *nnode; | |
3129 | struct route_node *rn; | |
3130 | struct ospf_area *area; | |
3131 | struct ospf_lsa *lsa; | |
3132 | ||
3133 | /* Iterate over all areas. */ | |
3134 | for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { | |
3135 | if (!area->lsdb) | |
3136 | continue; | |
3137 | ||
3138 | /* Parse all Router LSAs from the area LSDB */ | |
3139 | LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) | |
3140 | ospf_te_parse_router_lsa(ted, lsa); | |
3141 | ||
3142 | /* Parse all Opaque LSAs from the area LSDB */ | |
3143 | LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa) | |
3144 | ospf_te_parse_opaque_lsa(ted, lsa); | |
3145 | } | |
3146 | ||
3147 | /* Parse AS-external opaque LSAs from OSPF LSDB */ | |
3148 | if (ospf->lsdb) { | |
3149 | LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) | |
3150 | ospf_te_parse_opaque_lsa(ted, lsa); | |
3151 | } | |
3152 | ||
3153 | } | |
3154 | ||
3155 | /*------------------------------------------------------------------------* | |
78dfa0c7 | 3156 | * Following are vty session control functions. |
f173deb3 | 3157 | *------------------------------------------------------------------------*/ |
8db278b5 OD |
3158 | #define check_tlv_size(size, msg) \ |
3159 | do { \ | |
3160 | if (ntohs(tlvh->length) > size) { \ | |
3161 | if (vty != NULL) \ | |
3162 | vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \ | |
3163 | msg, ntohs(tlvh->length), size); \ | |
3164 | else \ | |
55370b95 | 3165 | zlog_debug(" Wrong %s TLV size: %d(%d)", \ |
8db278b5 OD |
3166 | msg, ntohs(tlvh->length), size); \ |
3167 | return size + TLV_HDR_SIZE; \ | |
3168 | } \ | |
55370b95 | 3169 | } while (0) |
f173deb3 OD |
3170 | |
3171 | static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) | |
3172 | { | |
3173 | struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh; | |
3174 | ||
8db278b5 OD |
3175 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Router Address"); |
3176 | ||
f173deb3 OD |
3177 | if (vty != NULL) |
3178 | vty_out(vty, " Router-Address: %pI4\n", &top->value); | |
3179 | else | |
3180 | zlog_debug(" Router-Address: %pI4", &top->value); | |
3181 | ||
3182 | return TLV_SIZE(tlvh); | |
3183 | } | |
3184 | ||
8db278b5 OD |
3185 | static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh, |
3186 | size_t buf_size) | |
f173deb3 OD |
3187 | { |
3188 | struct te_tlv_link *top = (struct te_tlv_link *)tlvh; | |
3189 | ||
8db278b5 OD |
3190 | if (TLV_SIZE(tlvh) > buf_size) { |
3191 | if (vty != NULL) | |
3192 | vty_out(vty, | |
3193 | " TLV size %d exceeds buffer size. Abort!", | |
3194 | TLV_SIZE(tlvh)); | |
3195 | else | |
3196 | zlog_debug( | |
3197 | " TLV size %d exceeds buffer size. Abort!", | |
3198 | TLV_SIZE(tlvh)); | |
3199 | return buf_size; | |
3200 | } | |
3201 | ||
f173deb3 OD |
3202 | if (vty != NULL) |
3203 | vty_out(vty, " Link: %u octets of data\n", | |
3204 | ntohs(top->header.length)); | |
3205 | else | |
3206 | zlog_debug(" Link: %u octets of data", | |
3207 | ntohs(top->header.length)); | |
3208 | ||
3209 | return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ | |
3210 | } | |
3211 | ||
3212 | static uint16_t show_vty_link_subtlv_link_type(struct vty *vty, | |
3213 | struct tlv_header *tlvh) | |
3214 | { | |
3215 | struct te_link_subtlv_link_type *top; | |
3216 | const char *cp = "Unknown"; | |
3217 | ||
8db278b5 OD |
3218 | check_tlv_size(TE_LINK_SUBTLV_TYPE_SIZE, "Link Type"); |
3219 | ||
f173deb3 OD |
3220 | top = (struct te_link_subtlv_link_type *)tlvh; |
3221 | switch (top->link_type.value) { | |
3222 | case LINK_TYPE_SUBTLV_VALUE_PTP: | |
3223 | cp = "Point-to-point"; | |
3224 | break; | |
3225 | case LINK_TYPE_SUBTLV_VALUE_MA: | |
3226 | cp = "Multiaccess"; | |
3227 | break; | |
3228 | default: | |
3229 | break; | |
3230 | } | |
3231 | ||
3232 | if (vty != NULL) | |
3233 | vty_out(vty, " Link-Type: %s (%u)\n", cp, | |
3234 | top->link_type.value); | |
3235 | else | |
3236 | zlog_debug(" Link-Type: %s (%u)", cp, top->link_type.value); | |
3237 | ||
3238 | return TLV_SIZE(tlvh); | |
3239 | } | |
3240 | ||
3241 | static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, | |
3242 | struct tlv_header *tlvh) | |
3243 | { | |
3244 | struct te_link_subtlv_link_id *top; | |
3245 | ||
8db278b5 OD |
3246 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link ID"); |
3247 | ||
f173deb3 OD |
3248 | top = (struct te_link_subtlv_link_id *)tlvh; |
3249 | if (vty != NULL) | |
3250 | vty_out(vty, " Link-ID: %pI4\n", &top->value); | |
3251 | else | |
3252 | zlog_debug(" Link-ID: %pI4", &top->value); | |
3253 | ||
3254 | return TLV_SIZE(tlvh); | |
3255 | } | |
3256 | ||
3257 | static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, | |
8db278b5 OD |
3258 | struct tlv_header *tlvh, |
3259 | size_t buf_size) | |
f173deb3 OD |
3260 | { |
3261 | struct te_link_subtlv_lclif_ipaddr *top; | |
3262 | int i, n; | |
3263 | ||
8db278b5 OD |
3264 | if (TLV_SIZE(tlvh) > buf_size) { |
3265 | if (vty != NULL) | |
3266 | vty_out(vty, | |
3267 | " TLV size %d exceeds buffer size. Abort!", | |
3268 | TLV_SIZE(tlvh)); | |
3269 | else | |
3270 | zlog_debug( | |
3271 | " TLV size %d exceeds buffer size. Abort!", | |
3272 | TLV_SIZE(tlvh)); | |
3273 | return buf_size; | |
3274 | } | |
3275 | ||
f173deb3 OD |
3276 | top = (struct te_link_subtlv_lclif_ipaddr *)tlvh; |
3277 | n = ntohs(tlvh->length) / sizeof(top->value[0]); | |
3278 | ||
3279 | if (vty != NULL) | |
3280 | vty_out(vty, " Local Interface IP Address(es): %d\n", n); | |
3281 | else | |
3282 | zlog_debug(" Local Interface IP Address(es): %d", n); | |
3283 | ||
3284 | for (i = 0; i < n; i++) { | |
3285 | if (vty != NULL) | |
3286 | vty_out(vty, " #%d: %pI4\n", i, &top->value[i]); | |
3287 | else | |
3288 | zlog_debug(" #%d: %pI4", i, &top->value[i]); | |
3289 | } | |
3290 | return TLV_SIZE(tlvh); | |
3291 | } | |
3292 | ||
3293 | static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, | |
8db278b5 OD |
3294 | struct tlv_header *tlvh, |
3295 | size_t buf_size) | |
f173deb3 OD |
3296 | { |
3297 | struct te_link_subtlv_rmtif_ipaddr *top; | |
3298 | int i, n; | |
3299 | ||
8db278b5 OD |
3300 | if (TLV_SIZE(tlvh) > buf_size) { |
3301 | if (vty != NULL) | |
3302 | vty_out(vty, | |
3303 | " TLV size %d exceeds buffer size. Abort!", | |
3304 | TLV_SIZE(tlvh)); | |
3305 | else | |
3306 | zlog_debug( | |
3307 | " TLV size %d exceeds buffer size. Abort!", | |
3308 | TLV_SIZE(tlvh)); | |
3309 | return buf_size; | |
3310 | } | |
3311 | ||
f173deb3 OD |
3312 | top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh; |
3313 | n = ntohs(tlvh->length) / sizeof(top->value[0]); | |
3314 | if (vty != NULL) | |
3315 | vty_out(vty, " Remote Interface IP Address(es): %d\n", n); | |
3316 | else | |
3317 | zlog_debug(" Remote Interface IP Address(es): %d", n); | |
3318 | ||
3319 | for (i = 0; i < n; i++) { | |
3320 | if (vty != NULL) | |
3321 | vty_out(vty, " #%d: %pI4\n", i, &top->value[i]); | |
3322 | else | |
3323 | zlog_debug(" #%d: %pI4", i, &top->value[i]); | |
3324 | } | |
3325 | return TLV_SIZE(tlvh); | |
3326 | } | |
3327 | ||
3328 | static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty, | |
3329 | struct tlv_header *tlvh) | |
3330 | { | |
3331 | struct te_link_subtlv_te_metric *top; | |
3332 | ||
8db278b5 OD |
3333 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "TE Metric"); |
3334 | ||
f173deb3 OD |
3335 | top = (struct te_link_subtlv_te_metric *)tlvh; |
3336 | if (vty != NULL) | |
3337 | vty_out(vty, " Traffic Engineering Metric: %u\n", | |
3338 | (uint32_t)ntohl(top->value)); | |
3339 | else | |
3340 | zlog_debug(" Traffic Engineering Metric: %u", | |
3341 | (uint32_t)ntohl(top->value)); | |
3342 | ||
3343 | return TLV_SIZE(tlvh); | |
3344 | } | |
3345 | ||
3346 | static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty, | |
3347 | struct tlv_header *tlvh) | |
3348 | { | |
3349 | struct te_link_subtlv_max_bw *top; | |
3350 | float fval; | |
3351 | ||
8db278b5 OD |
3352 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Bandwidth"); |
3353 | ||
f173deb3 OD |
3354 | top = (struct te_link_subtlv_max_bw *)tlvh; |
3355 | fval = ntohf(top->value); | |
3356 | ||
3357 | if (vty != NULL) | |
3358 | vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", fval); | |
3359 | else | |
3360 | zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval); | |
3361 | ||
3362 | return TLV_SIZE(tlvh); | |
3363 | } | |
3364 | ||
3365 | static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, | |
3366 | struct tlv_header *tlvh) | |
3367 | { | |
3368 | struct te_link_subtlv_max_rsv_bw *top; | |
3369 | float fval; | |
3370 | ||
8db278b5 OD |
3371 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Reservable Bandwidth"); |
3372 | ||
f173deb3 OD |
3373 | top = (struct te_link_subtlv_max_rsv_bw *)tlvh; |
3374 | fval = ntohf(top->value); | |
3375 | ||
3376 | if (vty != NULL) | |
3377 | vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n", | |
3378 | fval); | |
3379 | else | |
3380 | zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)", | |
3381 | fval); | |
3382 | ||
3383 | return TLV_SIZE(tlvh); | |
3384 | } | |
3385 | ||
3386 | static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, | |
3387 | struct tlv_header *tlvh) | |
3388 | { | |
3389 | struct te_link_subtlv_unrsv_bw *top; | |
3390 | float fval1, fval2; | |
3391 | int i; | |
3392 | ||
8db278b5 OD |
3393 | check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE, "Unreserved Bandwidth"); |
3394 | ||
f173deb3 OD |
3395 | top = (struct te_link_subtlv_unrsv_bw *)tlvh; |
3396 | if (vty != NULL) | |
3397 | vty_out(vty, | |
3398 | " Unreserved Bandwidth per Class Type in Byte/s:\n"); | |
3399 | else | |
3400 | zlog_debug( | |
3401 | " Unreserved Bandwidth per Class Type in Byte/s:"); | |
3402 | for (i = 0; i < MAX_CLASS_TYPE; i += 2) { | |
3403 | fval1 = ntohf(top->value[i]); | |
3404 | fval2 = ntohf(top->value[i + 1]); | |
3405 | ||
3406 | if (vty != NULL) | |
3407 | vty_out(vty, | |
3408 | " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", | |
3409 | i, fval1, i + 1, fval2); | |
3410 | else | |
3411 | zlog_debug( | |
3412 | " [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)", | |
3413 | i, fval1, i + 1, fval2); | |
3414 | } | |
3415 | ||
3416 | return TLV_SIZE(tlvh); | |
3417 | } | |
3418 | ||
3419 | static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, | |
3420 | struct tlv_header *tlvh) | |
3421 | { | |
3422 | struct te_link_subtlv_rsc_clsclr *top; | |
3423 | ||
8db278b5 OD |
3424 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Resource class/color"); |
3425 | ||
f173deb3 OD |
3426 | top = (struct te_link_subtlv_rsc_clsclr *)tlvh; |
3427 | if (vty != NULL) | |
3428 | vty_out(vty, " Resource class/color: 0x%x\n", | |
3429 | (uint32_t)ntohl(top->value)); | |
3430 | else | |
3431 | zlog_debug(" Resource Class/Color: 0x%x", | |
3432 | (uint32_t)ntohl(top->value)); | |
3433 | ||
3434 | return TLV_SIZE(tlvh); | |
3435 | } | |
3436 | ||
3437 | static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty, | |
3438 | struct tlv_header *tlvh) | |
3439 | { | |
3440 | struct te_link_subtlv_lrrid *top; | |
3441 | ||
8db278b5 OD |
3442 | check_tlv_size(TE_LINK_SUBTLV_LRRID_SIZE, "Local/Remote Router ID"); |
3443 | ||
f173deb3 OD |
3444 | top = (struct te_link_subtlv_lrrid *)tlvh; |
3445 | ||
3446 | if (vty != NULL) { | |
3447 | vty_out(vty, " Local TE Router ID: %pI4\n", | |
3448 | &top->local); | |
3449 | vty_out(vty, " Remote TE Router ID: %pI4\n", | |
3450 | &top->remote); | |
3451 | } else { | |
3452 | zlog_debug(" Local TE Router ID: %pI4", | |
3453 | &top->local); | |
3454 | zlog_debug(" Remote TE Router ID: %pI4", | |
3455 | &top->remote); | |
3456 | } | |
3457 | ||
3458 | return TLV_SIZE(tlvh); | |
16f1b9ee OD |
3459 | } |
3460 | ||
d7c0a89a QY |
3461 | static uint16_t show_vty_link_subtlv_llri(struct vty *vty, |
3462 | struct tlv_header *tlvh) | |
16f1b9ee | 3463 | { |
d62a17ae | 3464 | struct te_link_subtlv_llri *top; |
16f1b9ee | 3465 | |
8db278b5 OD |
3466 | check_tlv_size(TE_LINK_SUBTLV_LLRI_SIZE, "Link Local/Remote ID"); |
3467 | ||
d62a17ae | 3468 | top = (struct te_link_subtlv_llri *)tlvh; |
16f1b9ee | 3469 | |
d62a17ae | 3470 | if (vty != NULL) { |
3471 | vty_out(vty, " Link Local ID: %d\n", | |
d7c0a89a | 3472 | (uint32_t)ntohl(top->local)); |
d62a17ae | 3473 | vty_out(vty, " Link Remote ID: %d\n", |
d7c0a89a | 3474 | (uint32_t)ntohl(top->remote)); |
d62a17ae | 3475 | } else { |
3476 | zlog_debug(" Link Local ID: %d", | |
d7c0a89a | 3477 | (uint32_t)ntohl(top->local)); |
d62a17ae | 3478 | zlog_debug(" Link Remote ID: %d", |
d7c0a89a | 3479 | (uint32_t)ntohl(top->remote)); |
d62a17ae | 3480 | } |
16f1b9ee | 3481 | |
d62a17ae | 3482 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3483 | } |
3484 | ||
d7c0a89a QY |
3485 | static uint16_t show_vty_link_subtlv_rip(struct vty *vty, |
3486 | struct tlv_header *tlvh) | |
16f1b9ee | 3487 | { |
d62a17ae | 3488 | struct te_link_subtlv_rip *top; |
16f1b9ee | 3489 | |
8db278b5 OD |
3490 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote ASBR Address"); |
3491 | ||
d62a17ae | 3492 | top = (struct te_link_subtlv_rip *)tlvh; |
16f1b9ee | 3493 | |
d62a17ae | 3494 | if (vty != NULL) |
96b663a3 MS |
3495 | vty_out(vty, " Inter-AS TE Remote ASBR IP address: %pI4\n", |
3496 | &top->value); | |
d62a17ae | 3497 | else |
96b663a3 MS |
3498 | zlog_debug(" Inter-AS TE Remote ASBR IP address: %pI4", |
3499 | &top->value); | |
16f1b9ee | 3500 | |
d62a17ae | 3501 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3502 | } |
3503 | ||
d7c0a89a QY |
3504 | static uint16_t show_vty_link_subtlv_ras(struct vty *vty, |
3505 | struct tlv_header *tlvh) | |
16f1b9ee | 3506 | { |
d62a17ae | 3507 | struct te_link_subtlv_ras *top; |
16f1b9ee | 3508 | |
8db278b5 OD |
3509 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote AS number"); |
3510 | ||
d62a17ae | 3511 | top = (struct te_link_subtlv_ras *)tlvh; |
16f1b9ee | 3512 | |
d62a17ae | 3513 | if (vty != NULL) |
3514 | vty_out(vty, " Inter-AS TE Remote AS number: %u\n", | |
3515 | ntohl(top->value)); | |
3516 | else | |
3517 | zlog_debug(" Inter-AS TE Remote AS number: %u", | |
3518 | ntohl(top->value)); | |
16f1b9ee | 3519 | |
d62a17ae | 3520 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3521 | } |
3522 | ||
d7c0a89a QY |
3523 | static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty, |
3524 | struct tlv_header *tlvh) | |
16f1b9ee | 3525 | { |
d62a17ae | 3526 | struct te_link_subtlv_av_delay *top; |
d7c0a89a QY |
3527 | uint32_t delay; |
3528 | uint32_t anomalous; | |
16f1b9ee | 3529 | |
8db278b5 OD |
3530 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Average Link Delay"); |
3531 | ||
d62a17ae | 3532 | top = (struct te_link_subtlv_av_delay *)tlvh; |
d7c0a89a QY |
3533 | delay = (uint32_t)ntohl(top->value) & TE_EXT_MASK; |
3534 | anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL; | |
16f1b9ee | 3535 | |
d62a17ae | 3536 | if (vty != NULL) |
3537 | vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n", | |
3538 | anomalous ? "Anomalous" : "Normal", delay); | |
3539 | else | |
3540 | zlog_debug(" %s Average Link Delay: %d (micro-sec)", | |
3541 | anomalous ? "Anomalous" : "Normal", delay); | |
16f1b9ee | 3542 | |
d62a17ae | 3543 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3544 | } |
3545 | ||
d7c0a89a QY |
3546 | static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty, |
3547 | struct tlv_header *tlvh) | |
16f1b9ee | 3548 | { |
d62a17ae | 3549 | struct te_link_subtlv_mm_delay *top; |
d7c0a89a QY |
3550 | uint32_t low, high; |
3551 | uint32_t anomalous; | |
16f1b9ee | 3552 | |
8db278b5 OD |
3553 | check_tlv_size(TE_LINK_SUBTLV_MM_DELAY_SIZE, "Min/Max Link Delay"); |
3554 | ||
d62a17ae | 3555 | top = (struct te_link_subtlv_mm_delay *)tlvh; |
d7c0a89a QY |
3556 | low = (uint32_t)ntohl(top->low) & TE_EXT_MASK; |
3557 | anomalous = (uint32_t)ntohl(top->low) & TE_EXT_ANORMAL; | |
3558 | high = (uint32_t)ntohl(top->high); | |
16f1b9ee | 3559 | |
d62a17ae | 3560 | if (vty != NULL) |
3561 | vty_out(vty, " %s Min/Max Link Delay: %d/%d (micro-sec)\n", | |
3562 | anomalous ? "Anomalous" : "Normal", low, high); | |
3563 | else | |
3564 | zlog_debug(" %s Min/Max Link Delay: %d/%d (micro-sec)", | |
3565 | anomalous ? "Anomalous" : "Normal", low, high); | |
16f1b9ee | 3566 | |
d62a17ae | 3567 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3568 | } |
3569 | ||
d7c0a89a QY |
3570 | static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty, |
3571 | struct tlv_header *tlvh) | |
16f1b9ee | 3572 | { |
d62a17ae | 3573 | struct te_link_subtlv_delay_var *top; |
d7c0a89a | 3574 | uint32_t jitter; |
16f1b9ee | 3575 | |
8db278b5 OD |
3576 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Delay Variation"); |
3577 | ||
d62a17ae | 3578 | top = (struct te_link_subtlv_delay_var *)tlvh; |
d7c0a89a | 3579 | jitter = (uint32_t)ntohl(top->value) & TE_EXT_MASK; |
16f1b9ee | 3580 | |
d62a17ae | 3581 | if (vty != NULL) |
3582 | vty_out(vty, " Delay Variation: %d (micro-sec)\n", jitter); | |
3583 | else | |
3584 | zlog_debug(" Delay Variation: %d (micro-sec)", jitter); | |
16f1b9ee | 3585 | |
d62a17ae | 3586 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3587 | } |
3588 | ||
d7c0a89a QY |
3589 | static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, |
3590 | struct tlv_header *tlvh) | |
16f1b9ee | 3591 | { |
d62a17ae | 3592 | struct te_link_subtlv_pkt_loss *top; |
d7c0a89a QY |
3593 | uint32_t loss; |
3594 | uint32_t anomalous; | |
d62a17ae | 3595 | float fval; |
16f1b9ee | 3596 | |
8db278b5 OD |
3597 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Loss"); |
3598 | ||
d62a17ae | 3599 | top = (struct te_link_subtlv_pkt_loss *)tlvh; |
d7c0a89a | 3600 | loss = (uint32_t)ntohl(top->value) & TE_EXT_MASK; |
d62a17ae | 3601 | fval = (float)(loss * LOSS_PRECISION); |
d7c0a89a | 3602 | anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL; |
16f1b9ee | 3603 | |
d62a17ae | 3604 | if (vty != NULL) |
3605 | vty_out(vty, " %s Link Loss: %g (%%)\n", | |
3606 | anomalous ? "Anomalous" : "Normal", fval); | |
3607 | else | |
3608 | zlog_debug(" %s Link Loss: %g (%%)", | |
3609 | anomalous ? "Anomalous" : "Normal", fval); | |
16f1b9ee | 3610 | |
d62a17ae | 3611 | return TLV_SIZE(tlvh); |
16f1b9ee OD |
3612 | } |
3613 | ||
d7c0a89a QY |
3614 | static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty, |
3615 | struct tlv_header *tlvh) | |
16f1b9ee | 3616 | { |
d62a17ae | 3617 | struct te_link_subtlv_res_bw *top; |
3618 | float fval; | |
16f1b9ee | 3619 | |
8db278b5 OD |
3620 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Residual Bandwidth"); |
3621 | ||
d62a17ae | 3622 | top = (struct te_link_subtlv_res_bw *)tlvh; |
3623 | fval = ntohf(top->value); | |
16f1b9ee | 3624 | |
d62a17ae | 3625 | if (vty != NULL) |
3626 | vty_out(vty, | |
3627 | " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", | |
3628 | fval); | |
3629 | else | |
3630 | zlog_debug( | |
3631 | " Unidirectional Residual Bandwidth: %g (Bytes/sec)", | |
3632 | fval); | |
3633 | ||
3634 | return TLV_SIZE(tlvh); | |
3635 | } | |
3636 | ||
d7c0a89a QY |
3637 | static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty, |
3638 | struct tlv_header *tlvh) | |
d62a17ae | 3639 | { |
3640 | struct te_link_subtlv_ava_bw *top; | |
3641 | float fval; | |
3642 | ||
8db278b5 OD |
3643 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Available Bandwidth"); |
3644 | ||
d62a17ae | 3645 | top = (struct te_link_subtlv_ava_bw *)tlvh; |
3646 | fval = ntohf(top->value); | |
3647 | ||
3648 | if (vty != NULL) | |
3649 | vty_out(vty, | |
3650 | " Unidirectional Available Bandwidth: %g (Bytes/sec)\n", | |
3651 | fval); | |
3652 | else | |
3653 | zlog_debug( | |
3654 | " Unidirectional Available Bandwidth: %g (Bytes/sec)", | |
3655 | fval); | |
3656 | ||
3657 | return TLV_SIZE(tlvh); | |
3658 | } | |
3659 | ||
d7c0a89a QY |
3660 | static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, |
3661 | struct tlv_header *tlvh) | |
d62a17ae | 3662 | { |
3663 | struct te_link_subtlv_use_bw *top; | |
3664 | float fval; | |
3665 | ||
8db278b5 OD |
3666 | check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Utilized Bandwidth"); |
3667 | ||
d62a17ae | 3668 | top = (struct te_link_subtlv_use_bw *)tlvh; |
3669 | fval = ntohf(top->value); | |
3670 | ||
3671 | if (vty != NULL) | |
3672 | vty_out(vty, | |
3673 | " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", | |
3674 | fval); | |
3675 | else | |
3676 | zlog_debug( | |
3677 | " Unidirectional Utilized Bandwidth: %g (Bytes/sec)", | |
3678 | fval); | |
3679 | ||
3680 | return TLV_SIZE(tlvh); | |
3681 | } | |
3682 | ||
8db278b5 OD |
3683 | static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, |
3684 | size_t buf_size) | |
d62a17ae | 3685 | { |
8db278b5 OD |
3686 | if (TLV_SIZE(tlvh) > buf_size) { |
3687 | if (vty != NULL) | |
3688 | vty_out(vty, | |
3689 | " TLV size %d exceeds buffer size. Abort!", | |
3690 | TLV_SIZE(tlvh)); | |
3691 | else | |
3692 | zlog_debug( | |
3693 | " TLV size %d exceeds buffer size. Abort!", | |
3694 | TLV_SIZE(tlvh)); | |
3695 | return buf_size; | |
3696 | } | |
3697 | ||
d62a17ae | 3698 | if (vty != NULL) |
3699 | vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", | |
3700 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
3701 | else | |
3702 | zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", | |
3703 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
3704 | ||
3705 | return TLV_SIZE(tlvh); | |
3706 | } | |
3707 | ||
d7c0a89a QY |
3708 | static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, |
3709 | struct tlv_header *tlvh0, | |
3710 | uint16_t subtotal, uint16_t total) | |
d62a17ae | 3711 | { |
9df48e81 | 3712 | struct tlv_header *tlvh; |
d7c0a89a | 3713 | uint16_t sum = subtotal; |
d62a17ae | 3714 | |
8db278b5 | 3715 | for (tlvh = tlvh0; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { |
d62a17ae | 3716 | switch (ntohs(tlvh->type)) { |
3717 | case TE_LINK_SUBTLV_LINK_TYPE: | |
3718 | sum += show_vty_link_subtlv_link_type(vty, tlvh); | |
3719 | break; | |
3720 | case TE_LINK_SUBTLV_LINK_ID: | |
3721 | sum += show_vty_link_subtlv_link_id(vty, tlvh); | |
3722 | break; | |
3723 | case TE_LINK_SUBTLV_LCLIF_IPADDR: | |
8db278b5 OD |
3724 | sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh, |
3725 | total - sum); | |
d62a17ae | 3726 | break; |
3727 | case TE_LINK_SUBTLV_RMTIF_IPADDR: | |
8db278b5 OD |
3728 | sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh, |
3729 | total - sum); | |
d62a17ae | 3730 | break; |
3731 | case TE_LINK_SUBTLV_TE_METRIC: | |
3732 | sum += show_vty_link_subtlv_te_metric(vty, tlvh); | |
3733 | break; | |
3734 | case TE_LINK_SUBTLV_MAX_BW: | |
3735 | sum += show_vty_link_subtlv_max_bw(vty, tlvh); | |
3736 | break; | |
3737 | case TE_LINK_SUBTLV_MAX_RSV_BW: | |
3738 | sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh); | |
3739 | break; | |
3740 | case TE_LINK_SUBTLV_UNRSV_BW: | |
3741 | sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh); | |
3742 | break; | |
3743 | case TE_LINK_SUBTLV_RSC_CLSCLR: | |
3744 | sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh); | |
3745 | break; | |
3746 | case TE_LINK_SUBTLV_LRRID: | |
3747 | sum += show_vty_link_subtlv_lrrid(vty, tlvh); | |
3748 | break; | |
3749 | case TE_LINK_SUBTLV_LLRI: | |
3750 | sum += show_vty_link_subtlv_llri(vty, tlvh); | |
3751 | break; | |
3752 | case TE_LINK_SUBTLV_RIP: | |
3753 | sum += show_vty_link_subtlv_rip(vty, tlvh); | |
3754 | break; | |
3755 | case TE_LINK_SUBTLV_RAS: | |
3756 | sum += show_vty_link_subtlv_ras(vty, tlvh); | |
3757 | break; | |
3758 | case TE_LINK_SUBTLV_AV_DELAY: | |
3759 | sum += show_vty_link_subtlv_av_delay(vty, tlvh); | |
3760 | break; | |
3761 | case TE_LINK_SUBTLV_MM_DELAY: | |
3762 | sum += show_vty_link_subtlv_mm_delay(vty, tlvh); | |
3763 | break; | |
3764 | case TE_LINK_SUBTLV_DELAY_VAR: | |
3765 | sum += show_vty_link_subtlv_delay_var(vty, tlvh); | |
3766 | break; | |
3767 | case TE_LINK_SUBTLV_PKT_LOSS: | |
3768 | sum += show_vty_link_subtlv_pkt_loss(vty, tlvh); | |
3769 | break; | |
3770 | case TE_LINK_SUBTLV_RES_BW: | |
3771 | sum += show_vty_link_subtlv_res_bw(vty, tlvh); | |
3772 | break; | |
3773 | case TE_LINK_SUBTLV_AVA_BW: | |
3774 | sum += show_vty_link_subtlv_ava_bw(vty, tlvh); | |
3775 | break; | |
3776 | case TE_LINK_SUBTLV_USE_BW: | |
3777 | sum += show_vty_link_subtlv_use_bw(vty, tlvh); | |
3778 | break; | |
3779 | default: | |
8db278b5 | 3780 | sum += show_vty_unknown_tlv(vty, tlvh, total - sum); |
d62a17ae | 3781 | break; |
3782 | } | |
3783 | } | |
3784 | return sum; | |
3785 | } | |
3786 | ||
3e63092b RW |
3787 | static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, |
3788 | struct ospf_lsa *lsa) | |
d62a17ae | 3789 | { |
c4efd0f4 | 3790 | struct lsa_header *lsah = lsa->data; |
ead99d5f | 3791 | struct tlv_header *tlvh, *next; |
d7c0a89a QY |
3792 | uint16_t sum, total; |
3793 | uint16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, | |
3794 | uint16_t subtotal, uint16_t total) = NULL; | |
d62a17ae | 3795 | |
3e63092b RW |
3796 | if (json) |
3797 | return; | |
3798 | ||
d62a17ae | 3799 | sum = 0; |
8db278b5 | 3800 | total = lsa->size - OSPF_LSA_HEADER_SIZE; |
d62a17ae | 3801 | |
8db278b5 | 3802 | for (tlvh = TLV_HDR_TOP(lsah); sum < total && tlvh; |
d62a17ae | 3803 | tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { |
3804 | if (subfunc != NULL) { | |
3805 | sum = (*subfunc)(vty, tlvh, sum, total); | |
ead99d5f | 3806 | next = (struct tlv_header *)((char *)tlvh + sum); |
d62a17ae | 3807 | subfunc = NULL; |
3808 | continue; | |
3809 | } | |
3810 | ||
3811 | next = NULL; | |
3812 | switch (ntohs(tlvh->type)) { | |
3813 | case TE_TLV_ROUTER_ADDR: | |
3814 | sum += show_vty_router_addr(vty, tlvh); | |
3815 | break; | |
3816 | case TE_TLV_LINK: | |
8db278b5 | 3817 | sum += show_vty_link_header(vty, tlvh, total - sum); |
d62a17ae | 3818 | subfunc = ospf_mpls_te_show_link_subtlv; |
5d0df50f | 3819 | next = TLV_DATA(tlvh); |
d62a17ae | 3820 | break; |
3821 | default: | |
8db278b5 | 3822 | sum += show_vty_unknown_tlv(vty, tlvh, total - sum); |
d62a17ae | 3823 | break; |
3824 | } | |
3825 | } | |
3826 | return; | |
3827 | } | |
3828 | ||
3829 | static void ospf_mpls_te_config_write_router(struct vty *vty) | |
3830 | { | |
3831 | ||
32ab5cf4 | 3832 | if (OspfMplsTE.enabled) { |
d62a17ae | 3833 | vty_out(vty, " mpls-te on\n"); |
96b663a3 MS |
3834 | vty_out(vty, " mpls-te router-address %pI4\n", |
3835 | &OspfMplsTE.router_addr.value); | |
d62a17ae | 3836 | |
f173deb3 OD |
3837 | if (OspfMplsTE.inter_as == AS) |
3838 | vty_out(vty, " mpls-te inter-as as\n"); | |
3839 | if (OspfMplsTE.inter_as == Area) | |
3840 | vty_out(vty, " mpls-te inter-as area %pI4 \n", | |
3841 | &OspfMplsTE.interas_areaid); | |
3842 | if (OspfMplsTE.export) | |
3843 | vty_out(vty, " mpls-te export\n"); | |
3844 | } | |
d62a17ae | 3845 | return; |
718e3744 | 3846 | } |
3847 | ||
3848 | /*------------------------------------------------------------------------* | |
78dfa0c7 | 3849 | * Following are vty command functions. |
718e3744 | 3850 | *------------------------------------------------------------------------*/ |
3851 | ||
16f1b9ee OD |
3852 | DEFUN (ospf_mpls_te_on, |
3853 | ospf_mpls_te_on_cmd, | |
3854 | "mpls-te on", | |
3855 | MPLS_TE_STR | |
718e3744 | 3856 | "Enable the MPLS-TE functionality\n") |
3857 | { | |
a3d826f0 | 3858 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 3859 | struct listnode *node; |
3860 | struct mpls_te_link *lp; | |
7c8ff89e | 3861 | |
32ab5cf4 | 3862 | if (OspfMplsTE.enabled) |
d62a17ae | 3863 | return CMD_SUCCESS; |
718e3744 | 3864 | |
fd3c7692 | 3865 | ote_debug("MPLS-TE: OFF -> ON"); |
718e3744 | 3866 | |
32ab5cf4 | 3867 | OspfMplsTE.enabled = true; |
718e3744 | 3868 | |
d62a17ae | 3869 | /* Reoriginate RFC3630 & RFC6827 Links */ |
3870 | ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, | |
3871 | REORIGINATE_THIS_LSA); | |
718e3744 | 3872 | |
d62a17ae | 3873 | /* Reoriginate LSA if INTER-AS is always on */ |
ead99d5f | 3874 | if (OspfMplsTE.inter_as != Off) { |
d62a17ae | 3875 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) { |
3876 | if (IS_INTER_AS(lp->type)) { | |
3877 | ospf_mpls_te_lsa_schedule(lp, | |
3878 | REORIGINATE_THIS_LSA); | |
3879 | } | |
3880 | } | |
3881 | } | |
718e3744 | 3882 | |
f173deb3 OD |
3883 | /* Create TED and initialize it */ |
3884 | OspfMplsTE.ted = ls_ted_new(1, "OSPF", 0); | |
3885 | if (!OspfMplsTE.ted) { | |
3886 | vty_out(vty, "Unable to create Link State Data Base\n"); | |
3887 | return CMD_WARNING; | |
3888 | } | |
3889 | ospf_te_init_ted(OspfMplsTE.ted, ospf); | |
3890 | ||
d62a17ae | 3891 | return CMD_SUCCESS; |
718e3744 | 3892 | } |
3893 | ||
16f1b9ee OD |
3894 | DEFUN (no_ospf_mpls_te, |
3895 | no_ospf_mpls_te_cmd, | |
3a2d747c | 3896 | "no mpls-te [on]", |
718e3744 | 3897 | NO_STR |
3a2d747c | 3898 | MPLS_TE_STR |
718e3744 | 3899 | "Disable the MPLS-TE functionality\n") |
3900 | { | |
a3d826f0 | 3901 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 3902 | struct listnode *node, *nnode; |
3903 | struct mpls_te_link *lp; | |
718e3744 | 3904 | |
32ab5cf4 | 3905 | if (!OspfMplsTE.enabled) |
d62a17ae | 3906 | return CMD_SUCCESS; |
718e3744 | 3907 | |
fd3c7692 | 3908 | ote_debug("MPLS-TE: ON -> OFF"); |
718e3744 | 3909 | |
f173deb3 | 3910 | /* Remove TED */ |
aa5ced0a | 3911 | ls_ted_del_all(&OspfMplsTE.ted); |
32ab5cf4 | 3912 | OspfMplsTE.enabled = false; |
718e3744 | 3913 | |
f173deb3 | 3914 | /* Flush all TE Opaque LSAs */ |
d62a17ae | 3915 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) |
32ab5cf4 OD |
3916 | if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) |
3917 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
718e3744 | 3918 | |
d424f8d8 CG |
3919 | /* |
3920 | * This resets the OspfMplsTE.inter_as to its initial state. | |
3921 | * This is to avoid having an inter-as value different from | |
3922 | * Off when mpls-te gets restarted (after being removed) | |
3923 | */ | |
2efd7e2b | 3924 | OspfMplsTE.inter_as = Off; |
d424f8d8 | 3925 | |
d62a17ae | 3926 | return CMD_SUCCESS; |
718e3744 | 3927 | } |
3928 | ||
16f1b9ee OD |
3929 | DEFUN (ospf_mpls_te_router_addr, |
3930 | ospf_mpls_te_router_addr_cmd, | |
718e3744 | 3931 | "mpls-te router-address A.B.C.D", |
16f1b9ee | 3932 | MPLS_TE_STR |
718e3744 | 3933 | "Stable IP address of the advertising router\n" |
3934 | "MPLS-TE router address in IPv4 address format\n") | |
3935 | { | |
a3d826f0 | 3936 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); |
d62a17ae | 3937 | int idx_ipv4 = 2; |
3938 | struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; | |
3939 | struct in_addr value; | |
3940 | ||
3941 | if (!inet_aton(argv[idx_ipv4]->arg, &value)) { | |
3942 | vty_out(vty, "Please specify Router-Addr by A.B.C.D\n"); | |
3943 | return CMD_WARNING; | |
3944 | } | |
3945 | ||
3946 | if (ntohs(ra->header.type) == 0 | |
3947 | || ntohl(ra->value.s_addr) != ntohl(value.s_addr)) { | |
3948 | struct listnode *node, *nnode; | |
3949 | struct mpls_te_link *lp; | |
3950 | int need_to_reoriginate = 0; | |
3951 | ||
3952 | set_mpls_te_router_addr(value); | |
3953 | ||
32ab5cf4 | 3954 | if (!OspfMplsTE.enabled) |
ead99d5f | 3955 | return CMD_SUCCESS; |
d62a17ae | 3956 | |
3957 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
2efd7e2b | 3958 | if ((lp->area == NULL) || IS_FLOOD_AS(lp->flags)) |
d62a17ae | 3959 | continue; |
3960 | ||
3961 | if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { | |
3962 | need_to_reoriginate = 1; | |
3963 | break; | |
3964 | } | |
3965 | } | |
3966 | ||
3967 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { | |
2efd7e2b | 3968 | if ((lp->area == NULL) || IS_FLOOD_AS(lp->flags)) |
d62a17ae | 3969 | continue; |
3970 | ||
3971 | if (need_to_reoriginate) | |
3972 | SET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); | |
3973 | else | |
3974 | ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); | |
3975 | } | |
3976 | ||
3977 | if (need_to_reoriginate) | |
3978 | ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, | |
3979 | REORIGINATE_THIS_LSA); | |
3980 | } | |
ead99d5f | 3981 | |
d62a17ae | 3982 | return CMD_SUCCESS; |
3983 | } | |
3984 | ||
3985 | static int set_inter_as_mode(struct vty *vty, const char *mode_name, | |
3986 | const char *area_id) | |
3987 | { | |
3988 | enum inter_as_mode mode; | |
3989 | struct listnode *node; | |
3990 | struct mpls_te_link *lp; | |
3991 | int format; | |
3992 | ||
32ab5cf4 | 3993 | if (OspfMplsTE.enabled) { |
d62a17ae | 3994 | |
3995 | /* Read and Check inter_as mode */ | |
3996 | if (strcmp(mode_name, "as") == 0) | |
3997 | mode = AS; | |
3998 | else if (strcmp(mode_name, "area") == 0) { | |
3999 | mode = Area; | |
4000 | VTY_GET_OSPF_AREA_ID(OspfMplsTE.interas_areaid, format, | |
4001 | area_id); | |
4002 | } else { | |
4003 | vty_out(vty, | |
4004 | "Unknown mode. Please choose between as or area\n"); | |
4005 | return CMD_WARNING; | |
4006 | } | |
4007 | ||
fd3c7692 OD |
4008 | ote_debug( |
4009 | "MPLS-TE (%s): Inter-AS enable with %s flooding support", | |
4010 | __func__, mode2text[mode]); | |
d62a17ae | 4011 | |
d62a17ae | 4012 | /* Enable mode and re-originate LSA if needed */ |
ead99d5f | 4013 | if ((OspfMplsTE.inter_as == Off) |
d62a17ae | 4014 | && (mode != OspfMplsTE.inter_as)) { |
4015 | OspfMplsTE.inter_as = mode; | |
4016 | /* Re-originate all InterAS-TEv2 LSA */ | |
4017 | for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, | |
4018 | lp)) { | |
4019 | if (IS_INTER_AS(lp->type)) { | |
4020 | if (mode == AS) | |
2efd7e2b OD |
4021 | SET_FLAG(lp->flags, |
4022 | LPFLG_LSA_FLOOD_AS); | |
d62a17ae | 4023 | else |
2efd7e2b OD |
4024 | UNSET_FLAG(lp->flags, |
4025 | LPFLG_LSA_FLOOD_AS); | |
d62a17ae | 4026 | ospf_mpls_te_lsa_schedule( |
4027 | lp, REORIGINATE_THIS_LSA); | |
4028 | } | |
4029 | } | |
4030 | } else { | |
4031 | vty_out(vty, | |
4032 | "Please change Inter-AS support to disable first before going to mode %s\n", | |
4033 | mode2text[mode]); | |
4034 | return CMD_WARNING; | |
4035 | } | |
4036 | } else { | |
4037 | vty_out(vty, "mpls-te has not been turned on\n"); | |
4038 | return CMD_WARNING; | |
4039 | } | |
4040 | return CMD_SUCCESS; | |
718e3744 | 4041 | } |
4042 | ||
718e3744 | 4043 | |
16f1b9ee OD |
4044 | DEFUN (ospf_mpls_te_inter_as_as, |
4045 | ospf_mpls_te_inter_as_cmd, | |
4046 | "mpls-te inter-as as", | |
4047 | MPLS_TE_STR | |
4048 | "Configure MPLS-TE Inter-AS support\n" | |
4049 | "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") | |
4050 | { | |
d62a17ae | 4051 | return set_inter_as_mode(vty, "as", ""); |
718e3744 | 4052 | } |
4053 | ||
16f1b9ee OD |
4054 | DEFUN (ospf_mpls_te_inter_as_area, |
4055 | ospf_mpls_te_inter_as_area_cmd, | |
6147e2c6 | 4056 | "mpls-te inter-as area <A.B.C.D|(0-4294967295)>", |
16f1b9ee OD |
4057 | MPLS_TE_STR |
4058 | "Configure MPLS-TE Inter-AS support\n" | |
4059 | "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" | |
4060 | "OSPF area ID in IP format\n" | |
4061 | "OSPF area ID as decimal value\n") | |
718e3744 | 4062 | { |
d62a17ae | 4063 | int idx_ipv4_number = 3; |
4064 | return set_inter_as_mode(vty, "area", argv[idx_ipv4_number]->arg); | |
718e3744 | 4065 | } |
4066 | ||
16f1b9ee OD |
4067 | DEFUN (no_ospf_mpls_te_inter_as, |
4068 | no_ospf_mpls_te_inter_as_cmd, | |
4069 | "no mpls-te inter-as", | |
4070 | NO_STR | |
4071 | MPLS_TE_STR | |
4072 | "Disable MPLS-TE Inter-AS support\n") | |
718e3744 | 4073 | { |
16f1b9ee | 4074 | |
d62a17ae | 4075 | struct listnode *node, *nnode; |
4076 | struct mpls_te_link *lp; | |
718e3744 | 4077 | |
fd3c7692 | 4078 | ote_debug("MPLS-TE: Inter-AS support OFF"); |
718e3744 | 4079 | |
996c9314 | 4080 | if ((OspfMplsTE.enabled) && (OspfMplsTE.inter_as != Off)) { |
d62a17ae | 4081 | /* Flush all Inter-AS LSA */ |
4082 | for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) | |
4083 | if (IS_INTER_AS(lp->type) | |
4084 | && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) | |
4085 | ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); | |
718e3744 | 4086 | |
e790de41 DT |
4087 | OspfMplsTE.inter_as = Off; |
4088 | } | |
bcf4475e | 4089 | |
d62a17ae | 4090 | return CMD_SUCCESS; |
718e3744 | 4091 | } |
4092 | ||
f173deb3 OD |
4093 | DEFUN (ospf_mpls_te_export, |
4094 | ospf_mpls_te_export_cmd, | |
4095 | "mpls-te export", | |
4096 | MPLS_TE_STR | |
4097 | "Export the MPLS-TE information as Link State\n") | |
4098 | { | |
4099 | ||
4100 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); | |
4101 | ||
4102 | if (OspfMplsTE.enabled) { | |
4103 | if (ls_register(zclient, true) != 0) { | |
4104 | vty_out(vty, "Unable to register Link State\n"); | |
4105 | return CMD_WARNING; | |
4106 | } | |
4107 | OspfMplsTE.export = true; | |
4108 | } else { | |
4109 | vty_out(vty, "mpls-te has not been turned on\n"); | |
4110 | return CMD_WARNING; | |
4111 | } | |
4112 | return CMD_SUCCESS; | |
4113 | } | |
4114 | ||
4115 | ||
4116 | DEFUN (no_ospf_mpls_te_export, | |
4117 | no_ospf_mpls_te_export_cmd, | |
4118 | "no mpls-te export", | |
4119 | NO_STR | |
4120 | MPLS_TE_STR | |
4121 | "Stop export of the MPLS-TE information as Link State\n") | |
4122 | { | |
4123 | ||
4124 | VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); | |
4125 | ||
4126 | if (OspfMplsTE.export) { | |
4127 | if (ls_unregister(zclient, true) != 0) { | |
4128 | vty_out(vty, "Unable to unregister Link State\n"); | |
4129 | return CMD_WARNING; | |
4130 | } | |
4131 | OspfMplsTE.export = false; | |
4132 | } | |
4133 | return CMD_SUCCESS; | |
4134 | } | |
4135 | ||
16f1b9ee OD |
4136 | DEFUN (show_ip_ospf_mpls_te_router, |
4137 | show_ip_ospf_mpls_te_router_cmd, | |
4138 | "show ip ospf mpls-te router", | |
718e3744 | 4139 | SHOW_STR |
16f1b9ee OD |
4140 | IP_STR |
4141 | OSPF_STR | |
718e3744 | 4142 | "MPLS-TE information\n" |
16f1b9ee | 4143 | "MPLS-TE Router parameters\n") |
718e3744 | 4144 | { |
32ab5cf4 | 4145 | if (OspfMplsTE.enabled) { |
d62a17ae | 4146 | vty_out(vty, "--- MPLS-TE router parameters ---\n"); |
4147 | ||
4148 | if (ntohs(OspfMplsTE.router_addr.header.type) != 0) | |
4149 | show_vty_router_addr(vty, | |
4150 | &OspfMplsTE.router_addr.header); | |
0af35d90 | 4151 | else |
f173deb3 OD |
4152 | vty_out(vty, " Router address is not set\n"); |
4153 | vty_out(vty, " Link State distribution is %s\n", | |
4154 | OspfMplsTE.export ? "Active" : "Inactive"); | |
d62a17ae | 4155 | } |
4156 | return CMD_SUCCESS; | |
4157 | } | |
4158 | ||
4159 | static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) | |
4160 | { | |
4161 | struct mpls_te_link *lp; | |
4162 | ||
996c9314 LB |
4163 | if ((OspfMplsTE.enabled) && HAS_LINK_PARAMS(ifp) && !if_is_loopback(ifp) |
4164 | && if_is_up(ifp) | |
d62a17ae | 4165 | && ((lp = lookup_linkparams_by_ifp(ifp)) != NULL)) { |
4166 | /* Continue only if interface is not passive or support Inter-AS | |
4167 | * TEv2 */ | |
4168 | if (!(ospf_oi_count(ifp) > 0)) { | |
4169 | if (IS_INTER_AS(lp->type)) { | |
4170 | vty_out(vty, | |
4171 | "-- Inter-AS TEv2 link parameters for %s --\n", | |
4172 | ifp->name); | |
4173 | } else { | |
4174 | /* MPLS-TE is not activate on this interface */ | |
4175 | /* or this interface is passive and Inter-AS | |
4176 | * TEv2 is not activate */ | |
4177 | vty_out(vty, | |
4178 | " %s: MPLS-TE is disabled on this interface\n", | |
4179 | ifp->name); | |
4180 | return; | |
4181 | } | |
4182 | } else { | |
4183 | vty_out(vty, "-- MPLS-TE link parameters for %s --\n", | |
4184 | ifp->name); | |
4185 | } | |
4186 | ||
4187 | if (TLV_TYPE(lp->link_type) != 0) | |
4188 | show_vty_link_subtlv_link_type(vty, | |
4189 | &lp->link_type.header); | |
4190 | if (TLV_TYPE(lp->link_id) != 0) | |
4191 | show_vty_link_subtlv_link_id(vty, &lp->link_id.header); | |
4192 | if (TLV_TYPE(lp->lclif_ipaddr) != 0) | |
4193 | show_vty_link_subtlv_lclif_ipaddr( | |
8db278b5 OD |
4194 | vty, &lp->lclif_ipaddr.header, |
4195 | lp->lclif_ipaddr.header.length); | |
d62a17ae | 4196 | if (TLV_TYPE(lp->rmtif_ipaddr) != 0) |
4197 | show_vty_link_subtlv_rmtif_ipaddr( | |
8db278b5 OD |
4198 | vty, &lp->rmtif_ipaddr.header, |
4199 | lp->rmtif_ipaddr.header.length); | |
d62a17ae | 4200 | if (TLV_TYPE(lp->rip) != 0) |
4201 | show_vty_link_subtlv_rip(vty, &lp->rip.header); | |
4202 | if (TLV_TYPE(lp->ras) != 0) | |
4203 | show_vty_link_subtlv_ras(vty, &lp->ras.header); | |
4204 | if (TLV_TYPE(lp->te_metric) != 0) | |
4205 | show_vty_link_subtlv_te_metric(vty, | |
4206 | &lp->te_metric.header); | |
4207 | if (TLV_TYPE(lp->max_bw) != 0) | |
4208 | show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header); | |
4209 | if (TLV_TYPE(lp->max_rsv_bw) != 0) | |
4210 | show_vty_link_subtlv_max_rsv_bw(vty, | |
4211 | &lp->max_rsv_bw.header); | |
4212 | if (TLV_TYPE(lp->unrsv_bw) != 0) | |
4213 | show_vty_link_subtlv_unrsv_bw(vty, | |
4214 | &lp->unrsv_bw.header); | |
4215 | if (TLV_TYPE(lp->rsc_clsclr) != 0) | |
4216 | show_vty_link_subtlv_rsc_clsclr(vty, | |
4217 | &lp->rsc_clsclr.header); | |
4218 | if (TLV_TYPE(lp->av_delay) != 0) | |
4219 | show_vty_link_subtlv_av_delay(vty, | |
4220 | &lp->av_delay.header); | |
4221 | if (TLV_TYPE(lp->mm_delay) != 0) | |
4222 | show_vty_link_subtlv_mm_delay(vty, | |
4223 | &lp->mm_delay.header); | |
4224 | if (TLV_TYPE(lp->delay_var) != 0) | |
4225 | show_vty_link_subtlv_delay_var(vty, | |
4226 | &lp->delay_var.header); | |
4227 | if (TLV_TYPE(lp->pkt_loss) != 0) | |
4228 | show_vty_link_subtlv_pkt_loss(vty, | |
4229 | &lp->pkt_loss.header); | |
4230 | if (TLV_TYPE(lp->res_bw) != 0) | |
4231 | show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header); | |
4232 | if (TLV_TYPE(lp->ava_bw) != 0) | |
4233 | show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header); | |
4234 | if (TLV_TYPE(lp->use_bw) != 0) | |
4235 | show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header); | |
4236 | vty_out(vty, "---------------\n\n"); | |
4237 | } else { | |
4238 | vty_out(vty, " %s: MPLS-TE is disabled on this interface\n", | |
4239 | ifp->name); | |
4240 | } | |
4241 | ||
4242 | return; | |
718e3744 | 4243 | } |
4244 | ||
16f1b9ee OD |
4245 | DEFUN (show_ip_ospf_mpls_te_link, |
4246 | show_ip_ospf_mpls_te_link_cmd, | |
b5a8894d | 4247 | "show ip ospf [vrf <NAME|all>] mpls-te interface [INTERFACE]", |
718e3744 | 4248 | SHOW_STR |
16f1b9ee OD |
4249 | IP_STR |
4250 | OSPF_STR | |
b5a8894d CS |
4251 | VRF_CMD_HELP_STR |
4252 | "All VRFs\n" | |
718e3744 | 4253 | "MPLS-TE information\n" |
4254 | "Interface information\n" | |
4255 | "Interface name\n") | |
4256 | { | |
f4e14fdb | 4257 | struct vrf *vrf; |
03ed9f02 PG |
4258 | int idx_interface = 0; |
4259 | struct interface *ifp = NULL; | |
f4e14fdb | 4260 | struct listnode *node; |
b5a8894d | 4261 | char *vrf_name = NULL; |
8da59e56 | 4262 | bool all_vrf = false; |
b5a8894d CS |
4263 | int inst = 0; |
4264 | int idx_vrf = 0; | |
4265 | struct ospf *ospf = NULL; | |
4266 | ||
4267 | if (argv_find(argv, argc, "vrf", &idx_vrf)) { | |
4268 | vrf_name = argv[idx_vrf + 1]->arg; | |
4269 | all_vrf = strmatch(vrf_name, "all"); | |
4270 | } | |
03ed9f02 | 4271 | argv_find(argv, argc, "INTERFACE", &idx_interface); |
b5a8894d CS |
4272 | /* vrf input is provided could be all or specific vrf*/ |
4273 | if (vrf_name) { | |
4274 | if (all_vrf) { | |
f4e14fdb | 4275 | for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { |
b5a8894d CS |
4276 | if (!ospf->oi_running) |
4277 | continue; | |
f4e14fdb | 4278 | vrf = vrf_lookup_by_id(ospf->vrf_id); |
451fda4f | 4279 | FOR_ALL_INTERFACES (vrf, ifp) |
b5a8894d CS |
4280 | show_mpls_te_link_sub(vty, ifp); |
4281 | } | |
4282 | return CMD_SUCCESS; | |
4283 | } | |
996c9314 | 4284 | ospf = ospf_lookup_by_inst_name(inst, vrf_name); |
03ed9f02 PG |
4285 | } else |
4286 | ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); | |
4287 | if (ospf == NULL || !ospf->oi_running) | |
b5a8894d | 4288 | return CMD_SUCCESS; |
03ed9f02 PG |
4289 | |
4290 | vrf = vrf_lookup_by_id(ospf->vrf_id); | |
4291 | if (!vrf) | |
4292 | return CMD_SUCCESS; | |
4293 | if (idx_interface) { | |
4294 | ifp = if_lookup_by_name( | |
4295 | argv[idx_interface]->arg, | |
a36898e7 | 4296 | ospf->vrf_id); |
03ed9f02 PG |
4297 | if (ifp == NULL) { |
4298 | vty_out(vty, "No such interface name in vrf %s\n", | |
4299 | vrf->name); | |
4300 | return CMD_SUCCESS; | |
43b8d1d8 | 4301 | } |
d62a17ae | 4302 | } |
03ed9f02 PG |
4303 | if (!ifp) { |
4304 | FOR_ALL_INTERFACES (vrf, ifp) | |
d62a17ae | 4305 | show_mpls_te_link_sub(vty, ifp); |
03ed9f02 | 4306 | return CMD_SUCCESS; |
d62a17ae | 4307 | } |
4308 | ||
03ed9f02 | 4309 | show_mpls_te_link_sub(vty, ifp); |
d62a17ae | 4310 | return CMD_SUCCESS; |
4311 | } | |
4312 | ||
f173deb3 OD |
4313 | DEFUN (show_ip_ospf_mpls_te_db, |
4314 | show_ip_ospf_mpls_te_db_cmd, | |
4315 | "show ip ospf mpls-te database [<vertex [<self-originate|adv-router A.B.C.D>]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]", | |
4316 | SHOW_STR | |
4317 | IP_STR | |
4318 | OSPF_STR | |
4319 | "MPLS-TE information\n" | |
4320 | "MPLS-TE database\n" | |
4321 | "MPLS-TE Vertex\n" | |
4322 | "Self-originated MPLS-TE router\n" | |
4323 | "Advertised MPLS-TE router\n" | |
4324 | "MPLS-TE router ID (as an IP address)\n" | |
4325 | "MPLS-TE Edge\n" | |
4326 | "MPLS-TE Edge ID (as an IP address)\n" | |
4327 | "MPLS-TE Subnet\n" | |
4328 | "MPLS-TE Subnet ID (as an IP prefix)\n" | |
4329 | "Verbose output\n" | |
4330 | JSON_STR) | |
4331 | { | |
4332 | int idx = 0; | |
4333 | struct in_addr ip_addr; | |
4334 | struct prefix pref; | |
4335 | struct ls_vertex *vertex; | |
4336 | struct ls_edge *edge; | |
4337 | struct ls_subnet *subnet; | |
4338 | uint64_t key; | |
4339 | bool verbose = false; | |
4340 | bool uj = use_json(argc, argv); | |
4341 | json_object *json = NULL; | |
4342 | ||
4343 | if (!OspfMplsTE.enabled || !OspfMplsTE.ted) { | |
4344 | vty_out(vty, "MPLS-TE database is not enabled\n"); | |
4345 | return CMD_WARNING; | |
4346 | } | |
4347 | ||
4348 | if (uj) | |
4349 | json = json_object_new_object(); | |
4350 | ||
4351 | if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "verbose")) | |
4352 | verbose = true; | |
4353 | ||
4354 | idx = 5; | |
4355 | if (argv_find(argv, argc, "vertex", &idx)) { | |
4356 | /* Show Vertex */ | |
4357 | if (argv_find(argv, argc, "self-originate", &idx)) | |
4358 | vertex = OspfMplsTE.ted->self; | |
4359 | else if (argv_find(argv, argc, "adv-router", &idx)) { | |
4360 | if (!inet_aton(argv[idx + 1]->arg, &ip_addr)) { | |
4361 | vty_out(vty, | |
4362 | "Specified Router ID %s is invalid\n", | |
4363 | argv[idx + 1]->arg); | |
4364 | return CMD_WARNING_CONFIG_FAILED; | |
4365 | } | |
4366 | /* Get the Vertex from the Link State Database */ | |
4367 | key = ((uint64_t)ntohl(ip_addr.s_addr)) & 0xffffffff; | |
4368 | vertex = ls_find_vertex_by_key(OspfMplsTE.ted, key); | |
4369 | if (!vertex) { | |
4370 | vty_out(vty, "No vertex found for ID %pI4\n", | |
4371 | &ip_addr); | |
4372 | return CMD_WARNING; | |
4373 | } | |
4374 | } else | |
4375 | vertex = NULL; | |
4376 | ||
4377 | if (vertex) | |
4378 | ls_show_vertex(vertex, vty, json, verbose); | |
4379 | else | |
4380 | ls_show_vertices(OspfMplsTE.ted, vty, json, verbose); | |
4381 | ||
4382 | } else if (argv_find(argv, argc, "edge", &idx)) { | |
4383 | /* Show Edge */ | |
4384 | if (argv_find(argv, argc, "A.B.C.D", &idx)) { | |
4385 | if (!inet_aton(argv[idx]->arg, &ip_addr)) { | |
4386 | vty_out(vty, | |
4387 | "Specified Edge ID %s is invalid\n", | |
4388 | argv[idx]->arg); | |
4389 | return CMD_WARNING_CONFIG_FAILED; | |
4390 | } | |
4391 | /* Get the Edge from the Link State Database */ | |
4392 | key = ((uint64_t)ntohl(ip_addr.s_addr)) & 0xffffffff; | |
4393 | edge = ls_find_edge_by_key(OspfMplsTE.ted, key); | |
4394 | if (!edge) { | |
4395 | vty_out(vty, "No edge found for ID %pI4\n", | |
4396 | &ip_addr); | |
4397 | return CMD_WARNING; | |
4398 | } | |
4399 | } else | |
4400 | edge = NULL; | |
4401 | ||
4402 | if (edge) | |
4403 | ls_show_edge(edge, vty, json, verbose); | |
4404 | else | |
4405 | ls_show_edges(OspfMplsTE.ted, vty, json, verbose); | |
4406 | ||
4407 | } else if (argv_find(argv, argc, "subnet", &idx)) { | |
4408 | /* Show Subnet */ | |
4409 | if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { | |
4410 | if (!str2prefix(argv[idx]->arg, &pref)) { | |
4411 | vty_out(vty, "Invalid prefix format %s\n", | |
4412 | argv[idx]->arg); | |
4413 | return CMD_WARNING_CONFIG_FAILED; | |
4414 | } | |
4415 | /* Get the Subnet from the Link State Database */ | |
4416 | subnet = ls_find_subnet(OspfMplsTE.ted, pref); | |
4417 | if (!subnet) { | |
4418 | vty_out(vty, "No subnet found for ID %pFX\n", | |
4419 | &pref); | |
4420 | return CMD_WARNING; | |
4421 | } | |
4422 | } else | |
4423 | subnet = NULL; | |
4424 | ||
4425 | if (subnet) | |
4426 | ls_show_subnet(subnet, vty, json, verbose); | |
4427 | else | |
4428 | ls_show_subnets(OspfMplsTE.ted, vty, json, verbose); | |
4429 | ||
4430 | } else { | |
4431 | /* Show the complete TED */ | |
4432 | ls_show_ted(OspfMplsTE.ted, vty, json, verbose); | |
4433 | } | |
4434 | ||
c48349e3 | 4435 | if (uj) |
92ef0078 | 4436 | vty_json(vty, json); |
f173deb3 OD |
4437 | return CMD_SUCCESS; |
4438 | } | |
4439 | ||
d62a17ae | 4440 | static void ospf_mpls_te_register_vty(void) |
4441 | { | |
4442 | install_element(VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd); | |
4443 | install_element(VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); | |
f173deb3 | 4444 | install_element(VIEW_NODE, &show_ip_ospf_mpls_te_db_cmd); |
d62a17ae | 4445 | |
4446 | install_element(OSPF_NODE, &ospf_mpls_te_on_cmd); | |
4447 | install_element(OSPF_NODE, &no_ospf_mpls_te_cmd); | |
4448 | install_element(OSPF_NODE, &ospf_mpls_te_router_addr_cmd); | |
4449 | install_element(OSPF_NODE, &ospf_mpls_te_inter_as_cmd); | |
4450 | install_element(OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); | |
4451 | install_element(OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); | |
f173deb3 OD |
4452 | install_element(OSPF_NODE, &ospf_mpls_te_export_cmd); |
4453 | install_element(OSPF_NODE, &no_ospf_mpls_te_export_cmd); | |
d62a17ae | 4454 | |
4455 | return; | |
718e3744 | 4456 | } |