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.07k  | { | 
2981  |  |  | 
2982  | 1.07k  |   uint8_t rc;  | 
2983  |  |  | 
2984  |  |   /* Check that MPLS-TE is active */  | 
2985  | 1.07k  |   if (!OspfMplsTE.enabled || !OspfMplsTE.ted)  | 
2986  | 1.07k  |     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  | }  |