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