1 /*
2  * Copyright (C) 2003 Yasuhiro Ohara
3  *
4  * This file is part of GNU Zebra.
5  *
6  * GNU Zebra is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2, or (at your option) any
9  * later version.
10  *
11  * GNU Zebra is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; see the file COPYING; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <zebra.h>
22 
23 #include "log.h"
24 #include "memory.h"
25 #include "linklist.h"
26 #include "thread.h"
27 #include "vty.h"
28 #include "command.h"
29 #include "if.h"
30 #include "prefix.h"
31 #include "table.h"
32 #include "plist.h"
33 #include "filter.h"
34 
35 #include "ospf6_proto.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_lsdb.h"
38 #include "ospf6_route.h"
39 #include "ospf6_spf.h"
40 #include "ospf6_top.h"
41 #include "ospf6_area.h"
42 #include "ospf6_interface.h"
43 #include "ospf6_intra.h"
44 #include "ospf6_abr.h"
45 #include "ospf6_asbr.h"
46 #include "ospf6d.h"
47 
48 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name")
49 
ospf6_area_cmp(void * va,void * vb)50 int ospf6_area_cmp(void *va, void *vb)
51 {
52 	struct ospf6_area *oa = (struct ospf6_area *)va;
53 	struct ospf6_area *ob = (struct ospf6_area *)vb;
54 	return (ntohl(oa->area_id) < ntohl(ob->area_id) ? -1 : 1);
55 }
56 
57 /* schedule routing table recalculation */
ospf6_area_lsdb_hook_add(struct ospf6_lsa * lsa)58 static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
59 {
60 	switch (ntohs(lsa->header->type)) {
61 	case OSPF6_LSTYPE_ROUTER:
62 	case OSPF6_LSTYPE_NETWORK:
63 		if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) {
64 			zlog_debug("%s Examin LSA %s", __func__, lsa->name);
65 			zlog_debug(" Schedule SPF Calculation for %s",
66 				   OSPF6_AREA(lsa->lsdb->data)->name);
67 		}
68 		ospf6_spf_schedule(
69 			OSPF6_PROCESS(OSPF6_AREA(lsa->lsdb->data)->ospf6),
70 			ospf6_lsadd_to_spf_reason(lsa));
71 		break;
72 
73 	case OSPF6_LSTYPE_INTRA_PREFIX:
74 		ospf6_intra_prefix_lsa_add(lsa);
75 		break;
76 
77 	case OSPF6_LSTYPE_INTER_PREFIX:
78 	case OSPF6_LSTYPE_INTER_ROUTER:
79 		ospf6_abr_examin_summary(lsa,
80 					 (struct ospf6_area *)lsa->lsdb->data);
81 		break;
82 
83 	default:
84 		break;
85 	}
86 }
87 
ospf6_area_lsdb_hook_remove(struct ospf6_lsa * lsa)88 static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
89 {
90 	switch (ntohs(lsa->header->type)) {
91 	case OSPF6_LSTYPE_ROUTER:
92 	case OSPF6_LSTYPE_NETWORK:
93 		if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) {
94 			zlog_debug("LSA disappearing: %s", lsa->name);
95 			zlog_debug("Schedule SPF Calculation for %s",
96 				   OSPF6_AREA(lsa->lsdb->data)->name);
97 		}
98 		ospf6_spf_schedule(
99 			OSPF6_PROCESS(OSPF6_AREA(lsa->lsdb->data)->ospf6),
100 			ospf6_lsremove_to_spf_reason(lsa));
101 		break;
102 
103 	case OSPF6_LSTYPE_INTRA_PREFIX:
104 		ospf6_intra_prefix_lsa_remove(lsa);
105 		break;
106 
107 	case OSPF6_LSTYPE_INTER_PREFIX:
108 	case OSPF6_LSTYPE_INTER_ROUTER:
109 		ospf6_abr_examin_summary(lsa,
110 					 (struct ospf6_area *)lsa->lsdb->data);
111 		break;
112 
113 	default:
114 		break;
115 	}
116 }
117 
ospf6_area_route_hook_add(struct ospf6_route * route)118 static void ospf6_area_route_hook_add(struct ospf6_route *route)
119 {
120 	struct ospf6_route *copy;
121 
122 	copy = ospf6_route_copy(route);
123 	ospf6_route_add(copy, ospf6->route_table);
124 }
125 
ospf6_area_route_hook_remove(struct ospf6_route * route)126 static void ospf6_area_route_hook_remove(struct ospf6_route *route)
127 {
128 	struct ospf6_route *copy;
129 
130 	copy = ospf6_route_lookup_identical(route, ospf6->route_table);
131 	if (copy)
132 		ospf6_route_remove(copy, ospf6->route_table);
133 }
134 
ospf6_area_stub_update(struct ospf6_area * area)135 static void ospf6_area_stub_update(struct ospf6_area *area)
136 {
137 
138 	if (IS_AREA_STUB(area)) {
139 		if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
140 			zlog_debug("Stubbing out area for if %s", area->name);
141 		OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
142 	} else if (IS_AREA_ENABLED(area)) {
143 		if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
144 			zlog_debug("Normal area for if %s", area->name);
145 		OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
146 		ospf6_asbr_send_externals_to_area(area);
147 	}
148 
149 	OSPF6_ROUTER_LSA_SCHEDULE(area);
150 }
151 
ospf6_area_stub_set(struct ospf6 * ospf6,struct ospf6_area * area)152 static int ospf6_area_stub_set(struct ospf6 *ospf6, struct ospf6_area *area)
153 {
154 	if (!IS_AREA_STUB(area)) {
155 		SET_FLAG(area->flag, OSPF6_AREA_STUB);
156 		ospf6_area_stub_update(area);
157 	}
158 
159 	return 1;
160 }
161 
ospf6_area_stub_unset(struct ospf6 * ospf6,struct ospf6_area * area)162 static void ospf6_area_stub_unset(struct ospf6 *ospf6, struct ospf6_area *area)
163 {
164 	if (IS_AREA_STUB(area)) {
165 		UNSET_FLAG(area->flag, OSPF6_AREA_STUB);
166 		ospf6_area_stub_update(area);
167 	}
168 }
169 
ospf6_area_no_summary_set(struct ospf6 * ospf6,struct ospf6_area * area)170 static void ospf6_area_no_summary_set(struct ospf6 *ospf6,
171 				      struct ospf6_area *area)
172 {
173 	if (area) {
174 		if (!area->no_summary) {
175 			area->no_summary = 1;
176 			ospf6_abr_range_reset_cost(ospf6);
177 			ospf6_abr_prefix_resummarize(ospf6);
178 		}
179 	}
180 }
181 
ospf6_area_no_summary_unset(struct ospf6 * ospf6,struct ospf6_area * area)182 static void ospf6_area_no_summary_unset(struct ospf6 *ospf6,
183 					struct ospf6_area *area)
184 {
185 	if (area) {
186 		if (area->no_summary) {
187 			area->no_summary = 0;
188 			ospf6_abr_range_reset_cost(ospf6);
189 			ospf6_abr_prefix_resummarize(ospf6);
190 		}
191 	}
192 }
193 
194 /**
195  * Make new area structure.
196  *
197  * @param area_id - ospf6 area ID
198  * @param o - ospf6 instance
199  * @param df - display format for area ID
200  */
ospf6_area_create(uint32_t area_id,struct ospf6 * o,int df)201 struct ospf6_area *ospf6_area_create(uint32_t area_id, struct ospf6 *o, int df)
202 {
203 	struct ospf6_area *oa;
204 
205 	oa = XCALLOC(MTYPE_OSPF6_AREA, sizeof(struct ospf6_area));
206 
207 	switch (df) {
208 	case OSPF6_AREA_FMT_DECIMAL:
209 		snprintf(oa->name, sizeof(oa->name), "%u", ntohl(area_id));
210 		break;
211 	default:
212 	case OSPF6_AREA_FMT_DOTTEDQUAD:
213 		inet_ntop(AF_INET, &area_id, oa->name, sizeof(oa->name));
214 		break;
215 	}
216 
217 	oa->area_id = area_id;
218 	oa->if_list = list_new();
219 
220 	oa->lsdb = ospf6_lsdb_create(oa);
221 	oa->lsdb->hook_add = ospf6_area_lsdb_hook_add;
222 	oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
223 	oa->lsdb_self = ospf6_lsdb_create(oa);
224 	oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa);
225 
226 	oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS);
227 	oa->spf_table->scope = oa;
228 	oa->route_table = OSPF6_ROUTE_TABLE_CREATE(AREA, ROUTES);
229 	oa->route_table->scope = oa;
230 	oa->route_table->hook_add = ospf6_area_route_hook_add;
231 	oa->route_table->hook_remove = ospf6_area_route_hook_remove;
232 
233 	oa->range_table = OSPF6_ROUTE_TABLE_CREATE(AREA, PREFIX_RANGES);
234 	oa->range_table->scope = oa;
235 	bf_init(oa->range_table->idspace, 32);
236 	oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE(AREA, SUMMARY_PREFIXES);
237 	oa->summary_prefix->scope = oa;
238 	oa->summary_router = OSPF6_ROUTE_TABLE_CREATE(AREA, SUMMARY_ROUTERS);
239 	oa->summary_router->scope = oa;
240 	oa->router_lsa_size_limit = 1024 + 256;
241 
242 	/* set default options */
243 	if (CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER)) {
244 		OSPF6_OPT_CLEAR(oa->options, OSPF6_OPT_V6);
245 		OSPF6_OPT_CLEAR(oa->options, OSPF6_OPT_R);
246 	} else {
247 		OSPF6_OPT_SET(oa->options, OSPF6_OPT_V6);
248 		OSPF6_OPT_SET(oa->options, OSPF6_OPT_R);
249 	}
250 
251 	OSPF6_OPT_SET(oa->options, OSPF6_OPT_E);
252 
253 	SET_FLAG(oa->flag, OSPF6_AREA_ACTIVE);
254 	SET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
255 
256 	oa->ospf6 = o;
257 	listnode_add_sort(o->area_list, oa);
258 
259 	if (area_id == OSPF_AREA_BACKBONE) {
260 		o->backbone = oa;
261 	}
262 
263 	return oa;
264 }
265 
ospf6_area_delete(struct ospf6_area * oa)266 void ospf6_area_delete(struct ospf6_area *oa)
267 {
268 	struct listnode *n;
269 	struct ospf6_interface *oi;
270 
271 	/* The ospf6_interface structs store configuration
272 	 * information which should not be lost/reset when
273 	 * deleting an area.
274 	 * So just detach the interface from the area and
275 	 * keep it around. */
276 	for (ALL_LIST_ELEMENTS_RO(oa->if_list, n, oi))
277 		oi->area = NULL;
278 
279 	list_delete(&oa->if_list);
280 
281 	ospf6_lsdb_delete(oa->lsdb);
282 	ospf6_lsdb_delete(oa->lsdb_self);
283 	ospf6_lsdb_delete(oa->temp_router_lsa_lsdb);
284 
285 	ospf6_spf_table_finish(oa->spf_table);
286 	ospf6_route_table_delete(oa->spf_table);
287 	ospf6_route_table_delete(oa->route_table);
288 
289 	ospf6_route_table_delete(oa->range_table);
290 	ospf6_route_table_delete(oa->summary_prefix);
291 	ospf6_route_table_delete(oa->summary_router);
292 
293 	listnode_delete(oa->ospf6->area_list, oa);
294 	oa->ospf6 = NULL;
295 
296 	/* free area */
297 	XFREE(MTYPE_OSPF6_AREA, oa);
298 }
299 
ospf6_area_lookup(uint32_t area_id,struct ospf6 * ospf6)300 struct ospf6_area *ospf6_area_lookup(uint32_t area_id, struct ospf6 *ospf6)
301 {
302 	struct ospf6_area *oa;
303 	struct listnode *n;
304 
305 	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa))
306 		if (oa->area_id == area_id)
307 			return oa;
308 
309 	return (struct ospf6_area *)NULL;
310 }
311 
ospf6_area_enable(struct ospf6_area * oa)312 void ospf6_area_enable(struct ospf6_area *oa)
313 {
314 	struct listnode *node, *nnode;
315 	struct ospf6_interface *oi;
316 
317 	SET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
318 
319 	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi))
320 		ospf6_interface_enable(oi);
321 	ospf6_abr_enable_area(oa);
322 }
323 
ospf6_area_disable(struct ospf6_area * oa)324 void ospf6_area_disable(struct ospf6_area *oa)
325 {
326 	struct listnode *node, *nnode;
327 	struct ospf6_interface *oi;
328 
329 	UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
330 
331 	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi))
332 		ospf6_interface_disable(oi);
333 
334 	ospf6_abr_disable_area(oa);
335 	ospf6_lsdb_remove_all(oa->lsdb);
336 	ospf6_lsdb_remove_all(oa->lsdb_self);
337 
338 	ospf6_spf_table_finish(oa->spf_table);
339 	ospf6_route_remove_all(oa->route_table);
340 
341 	THREAD_OFF(oa->thread_router_lsa);
342 	THREAD_OFF(oa->thread_intra_prefix_lsa);
343 }
344 
345 
ospf6_area_show(struct vty * vty,struct ospf6_area * oa)346 void ospf6_area_show(struct vty *vty, struct ospf6_area *oa)
347 {
348 	struct listnode *i;
349 	struct ospf6_interface *oi;
350 	unsigned long result;
351 
352 	if (!IS_AREA_STUB(oa))
353 		vty_out(vty, " Area %s\n", oa->name);
354 	else {
355 		if (oa->no_summary) {
356 			vty_out(vty, " Area %s[Stub, No Summary]\n", oa->name);
357 		} else {
358 			vty_out(vty, " Area %s[Stub]\n", oa->name);
359 		}
360 	}
361 	vty_out(vty, "     Number of Area scoped LSAs is %u\n",
362 		oa->lsdb->count);
363 
364 	vty_out(vty, "     Interface attached to this area:");
365 	for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi))
366 		vty_out(vty, " %s", oi->interface->name);
367 	vty_out(vty, "\n");
368 
369 	if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec) {
370 		result = monotime_since(&oa->ts_spf, NULL);
371 		if (result / TIMER_SECOND_MICRO > 0) {
372 			vty_out(vty, "SPF last executed %ld.%lds ago\n",
373 				result / TIMER_SECOND_MICRO,
374 				result % TIMER_SECOND_MICRO);
375 		} else {
376 			vty_out(vty, "SPF last executed %ldus ago\n", result);
377 		}
378 	} else
379 		vty_out(vty, "SPF has not been run\n");
380 }
381 
382 DEFUN (area_range,
383        area_range_cmd,
384        "area <A.B.C.D|(0-4294967295)> range X:X::X:X/M [<advertise|not-advertise|cost (0-16777215)>]",
385        "OSPF6 area parameters\n"
386        "OSPF6 area ID in IP address format\n"
387        "OSPF6 area ID as a decimal value\n"
388        "Configured address range\n"
389        "Specify IPv6 prefix\n"
390        "Advertise\n"
391        "Do not advertise\n"
392        "User specified metric for this range\n"
393        "Advertised metric for this range\n")
394 {
395 	int idx_ipv4 = 1;
396 	int idx_ipv6_prefixlen = 3;
397 	int idx_type = 4;
398 	int ret;
399 	struct ospf6_area *oa;
400 	struct prefix prefix;
401 	struct ospf6_route *range;
402 	uint32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
403 
404 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa);
405 
406 	ret = str2prefix(argv[idx_ipv6_prefixlen]->arg, &prefix);
407 	if (ret != 1 || prefix.family != AF_INET6) {
408 		vty_out(vty, "Malformed argument: %s\n",
409 			argv[idx_ipv6_prefixlen]->arg);
410 		return CMD_SUCCESS;
411 	}
412 
413 	range = ospf6_route_lookup(&prefix, oa->range_table);
414 	if (range == NULL) {
415 		range = ospf6_route_create();
416 		range->type = OSPF6_DEST_TYPE_RANGE;
417 		range->prefix = prefix;
418 		range->path.area_id = oa->area_id;
419 		range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
420 	}
421 
422 	if (argc > idx_type) {
423 		if (strmatch(argv[idx_type]->text, "not-advertise")) {
424 			SET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
425 		} else if (strmatch(argv[idx_type]->text, "advertise")) {
426 			UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
427 			cost = range->path.u.cost_config;
428 		} else {
429 			cost = strtoul(argv[5]->arg, NULL, 10);
430 			UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
431 		}
432 	}
433 
434 	range->path.u.cost_config = cost;
435 
436 	zlog_debug("%s: for prefix %s, flag = %x", __func__,
437 		   argv[idx_ipv6_prefixlen]->arg, range->flag);
438 	if (range->rnode == NULL) {
439 		ospf6_route_add(range, oa->range_table);
440 	}
441 
442 	if (ospf6_is_router_abr(ospf6)) {
443 		/* Redo summaries if required */
444 		ospf6_abr_prefix_resummarize(ospf6);
445 	}
446 
447 	return CMD_SUCCESS;
448 }
449 
450 DEFUN (no_area_range,
451        no_area_range_cmd,
452        "no area <A.B.C.D|(0-4294967295)> range X:X::X:X/M [<advertise|not-advertise|cost (0-16777215)>]",
453        NO_STR
454        "OSPF6 area parameters\n"
455        "OSPF6 area ID in IP address format\n"
456        "OSPF6 area ID as a decimal value\n"
457        "Configured address range\n"
458        "Specify IPv6 prefix\n"
459        "Advertise\n"
460        "Do not advertise\n"
461        "User specified metric for this range\n"
462        "Advertised metric for this range\n")
463 {
464 	int idx_ipv4 = 2;
465 	int idx_ipv6 = 4;
466 	int ret;
467 	struct ospf6_area *oa;
468 	struct prefix prefix;
469 	struct ospf6_route *range, *route;
470 
471 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa);
472 
473 	ret = str2prefix(argv[idx_ipv6]->arg, &prefix);
474 	if (ret != 1 || prefix.family != AF_INET6) {
475 		vty_out(vty, "Malformed argument: %s\n", argv[idx_ipv6]->arg);
476 		return CMD_SUCCESS;
477 	}
478 
479 	range = ospf6_route_lookup(&prefix, oa->range_table);
480 	if (range == NULL) {
481 		vty_out(vty, "Range %s does not exists.\n",
482 			argv[idx_ipv6]->arg);
483 		return CMD_SUCCESS;
484 	}
485 
486 	if (ospf6_is_router_abr(oa->ospf6)) {
487 		/* Blow away the aggregated LSA and route */
488 		SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE);
489 
490 		/* Redo summaries if required */
491 		for (route = ospf6_route_head(ospf6->route_table); route;
492 		     route = ospf6_route_next(route))
493 			ospf6_abr_originate_summary(route);
494 
495 		/* purge the old aggregated summary LSA */
496 		ospf6_abr_originate_summary(range);
497 	}
498 	ospf6_route_remove(range, oa->range_table);
499 
500 	return CMD_SUCCESS;
501 }
502 
ospf6_area_config_write(struct vty * vty)503 void ospf6_area_config_write(struct vty *vty)
504 {
505 	struct listnode *node;
506 	struct ospf6_area *oa;
507 	struct ospf6_route *range;
508 	char buf[PREFIX2STR_BUFFER];
509 
510 	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
511 		for (range = ospf6_route_head(oa->range_table); range;
512 		     range = ospf6_route_next(range)) {
513 			prefix2str(&range->prefix, buf, sizeof(buf));
514 			vty_out(vty, " area %s range %s", oa->name, buf);
515 
516 			if (CHECK_FLAG(range->flag,
517 				       OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
518 				vty_out(vty, " not-advertise");
519 			} else {
520 				// "advertise" is the default so we do not
521 				// display it
522 				if (range->path.u.cost_config
523 				    != OSPF_AREA_RANGE_COST_UNSPEC)
524 					vty_out(vty, " cost %d",
525 						range->path.u.cost_config);
526 			}
527 			vty_out(vty, "\n");
528 		}
529 		if (IS_AREA_STUB(oa)) {
530 			if (oa->no_summary)
531 				vty_out(vty, " area %s stub no-summary\n",
532 					oa->name);
533 			else
534 				vty_out(vty, " area %s stub\n", oa->name);
535 		}
536 		if (PREFIX_NAME_IN(oa))
537 			vty_out(vty, " area %s filter-list prefix %s in\n",
538 				oa->name, PREFIX_NAME_IN(oa));
539 		if (PREFIX_NAME_OUT(oa))
540 			vty_out(vty, " area %s filter-list prefix %s out\n",
541 				oa->name, PREFIX_NAME_OUT(oa));
542 		if (IMPORT_NAME(oa))
543 			vty_out(vty, " area %s import-list %s\n", oa->name,
544 				IMPORT_NAME(oa));
545 		if (EXPORT_NAME(oa))
546 			vty_out(vty, " area %s export-list %s\n", oa->name,
547 				EXPORT_NAME(oa));
548 	}
549 }
550 
551 DEFUN (area_filter_list,
552        area_filter_list_cmd,
553        "area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>",
554        "OSPF6 area parameters\n"
555        "OSPF6 area ID in IP address format\n"
556        "OSPF6 area ID as a decimal value\n"
557        "Filter networks between OSPF6 areas\n"
558        "Filter prefixes between OSPF6 areas\n"
559        "Name of an IPv6 prefix-list\n"
560        "Filter networks sent to this area\n"
561        "Filter networks sent from this area\n")
562 {
563 	char *inout = argv[argc - 1]->text;
564 	char *areaid = argv[1]->arg;
565 	char *plistname = argv[4]->arg;
566 
567 	struct ospf6_area *area;
568 	struct prefix_list *plist;
569 
570 	OSPF6_CMD_AREA_GET(areaid, area);
571 
572 	plist = prefix_list_lookup(AFI_IP6, plistname);
573 	if (strmatch(inout, "in")) {
574 		PREFIX_LIST_IN(area) = plist;
575 		XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
576 		PREFIX_NAME_IN(area) =
577 			XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
578 		ospf6_abr_reimport(area);
579 	} else {
580 		PREFIX_LIST_OUT(area) = plist;
581 		XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
582 		PREFIX_NAME_OUT(area) =
583 			XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
584 		ospf6_abr_enable_area(area);
585 	}
586 
587 	return CMD_SUCCESS;
588 }
589 
590 DEFUN (no_area_filter_list,
591        no_area_filter_list_cmd,
592        "no area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>",
593        NO_STR
594        "OSPF6 area parameters\n"
595        "OSPF6 area ID in IP address format\n"
596        "OSPF6 area ID as a decimal value\n"
597        "Filter networks between OSPF6 areas\n"
598        "Filter prefixes between OSPF6 areas\n"
599        "Name of an IPv6 prefix-list\n"
600        "Filter networks sent to this area\n"
601        "Filter networks sent from this area\n")
602 {
603 	char *inout = argv[argc - 1]->text;
604 	char *areaid = argv[2]->arg;
605 	char *plistname = argv[5]->arg;
606 
607 	struct ospf6_area *area;
608 
609 	OSPF6_CMD_AREA_GET(areaid, area);
610 
611 	if (strmatch(inout, "in")) {
612 		if (PREFIX_NAME_IN(area))
613 			if (!strmatch(PREFIX_NAME_IN(area), plistname))
614 				return CMD_SUCCESS;
615 
616 		PREFIX_LIST_IN(area) = NULL;
617 		XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
618 		ospf6_abr_reimport(area);
619 	} else {
620 		if (PREFIX_NAME_OUT(area))
621 			if (!strmatch(PREFIX_NAME_OUT(area), plistname))
622 				return CMD_SUCCESS;
623 
624 		XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
625 		ospf6_abr_enable_area(area);
626 	}
627 
628 	return CMD_SUCCESS;
629 }
630 
ospf6_area_plist_update(struct prefix_list * plist,int add)631 void ospf6_area_plist_update(struct prefix_list *plist, int add)
632 {
633 	struct ospf6_area *oa;
634 	struct listnode *n;
635 	const char *name = prefix_list_name(plist);
636 
637 	if (!ospf6)
638 		return;
639 
640 	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
641 		if (PREFIX_NAME_IN(oa) && !strcmp(PREFIX_NAME_IN(oa), name))
642 			PREFIX_LIST_IN(oa) = add ? plist : NULL;
643 		if (PREFIX_NAME_OUT(oa) && !strcmp(PREFIX_NAME_OUT(oa), name))
644 			PREFIX_LIST_OUT(oa) = add ? plist : NULL;
645 	}
646 }
647 
648 DEFUN (area_import_list,
649        area_import_list_cmd,
650        "area <A.B.C.D|(0-4294967295)> import-list NAME",
651        "OSPF6 area parameters\n"
652        "OSPF6 area ID in IP address format\n"
653        "OSPF6 area ID as a decimal value\n"
654        "Set the filter for networks from other areas announced to the specified one\n"
655        "Name of the acess-list\n")
656 {
657 	int idx_ipv4 = 1;
658 	int idx_name = 3;
659 	struct ospf6_area *area;
660 	struct access_list *list;
661 
662 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area);
663 
664 	list = access_list_lookup(AFI_IP6, argv[idx_name]->arg);
665 
666 	IMPORT_LIST(area) = list;
667 
668 	if (IMPORT_NAME(area))
669 		free(IMPORT_NAME(area));
670 
671 	IMPORT_NAME(area) = strdup(argv[idx_name]->arg);
672 	ospf6_abr_reimport(area);
673 
674 	return CMD_SUCCESS;
675 }
676 
677 DEFUN (no_area_import_list,
678        no_area_import_list_cmd,
679        "no area <A.B.C.D|(0-4294967295)> import-list NAME",
680        NO_STR
681        "OSPF6 area parameters\n"
682        "OSPF6 area ID in IP address format\n"
683        "OSPF6 area ID as a decimal value\n"
684        "Unset the filter for networks announced to other areas\n"
685        "Name of the access-list\n")
686 {
687 	int idx_ipv4 = 2;
688 	struct ospf6_area *area;
689 
690 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area);
691 
692 	IMPORT_LIST(area) = 0;
693 
694 	if (IMPORT_NAME(area))
695 		free(IMPORT_NAME(area));
696 
697 	IMPORT_NAME(area) = NULL;
698 	ospf6_abr_reimport(area);
699 
700 	return CMD_SUCCESS;
701 }
702 
703 DEFUN (area_export_list,
704        area_export_list_cmd,
705        "area <A.B.C.D|(0-4294967295)> export-list NAME",
706        "OSPF6 area parameters\n"
707        "OSPF6 area ID in IP address format\n"
708        "OSPF6 area ID as a decimal value\n"
709        "Set the filter for networks announced to other areas\n"
710        "Name of the acess-list\n")
711 {
712 	int idx_ipv4 = 1;
713 	int idx_name = 3;
714 	struct ospf6_area *area;
715 	struct access_list *list;
716 
717 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area);
718 
719 	list = access_list_lookup(AFI_IP6, argv[idx_name]->arg);
720 
721 	EXPORT_LIST(area) = list;
722 
723 	if (EXPORT_NAME(area))
724 		free(EXPORT_NAME(area));
725 
726 	EXPORT_NAME(area) = strdup(argv[idx_name]->arg);
727 	ospf6_abr_enable_area(area);
728 
729 	return CMD_SUCCESS;
730 }
731 
732 DEFUN (no_area_export_list,
733        no_area_export_list_cmd,
734        "no area <A.B.C.D|(0-4294967295)> export-list NAME",
735        NO_STR
736        "OSPF6 area parameters\n"
737        "OSPF6 area ID in IP address format\n"
738        "OSPF6 area ID as a decimal value\n"
739        "Unset the filter for networks announced to other areas\n"
740        "Name of the access-list\n")
741 {
742 	int idx_ipv4 = 2;
743 	struct ospf6_area *area;
744 
745 	OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area);
746 
747 	EXPORT_LIST(area) = 0;
748 
749 	if (EXPORT_NAME(area))
750 		free(EXPORT_NAME(area));
751 
752 	EXPORT_NAME(area) = NULL;
753 	ospf6_abr_enable_area(area);
754 
755 	return CMD_SUCCESS;
756 }
757 
758 DEFUN (show_ipv6_ospf6_spf_tree,
759        show_ipv6_ospf6_spf_tree_cmd,
760        "show ipv6 ospf6 spf tree",
761        SHOW_STR
762        IP6_STR
763        OSPF6_STR
764        "Shortest Path First calculation\n"
765        "Show SPF tree\n")
766 {
767 	struct listnode *node;
768 	struct ospf6_area *oa;
769 	struct ospf6_vertex *root;
770 	struct ospf6_route *route;
771 	struct prefix prefix;
772 
773 	OSPF6_CMD_CHECK_RUNNING();
774 
775 	ospf6_linkstate_prefix(ospf6->router_id, htonl(0), &prefix);
776 
777 	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
778 		route = ospf6_route_lookup(&prefix, oa->spf_table);
779 		if (route == NULL) {
780 			vty_out(vty, "LS entry for root not found in area %s\n",
781 				oa->name);
782 			continue;
783 		}
784 		root = (struct ospf6_vertex *)route->route_option;
785 		ospf6_spf_display_subtree(vty, "", 0, root);
786 	}
787 
788 	return CMD_SUCCESS;
789 }
790 
791 DEFUN (show_ipv6_ospf6_area_spf_tree,
792        show_ipv6_ospf6_area_spf_tree_cmd,
793        "show ipv6 ospf6 area A.B.C.D spf tree",
794        SHOW_STR
795        IP6_STR
796        OSPF6_STR
797        OSPF6_AREA_STR
798        OSPF6_AREA_ID_STR
799        "Shortest Path First calculation\n"
800        "Show SPF tree\n")
801 {
802 	int idx_ipv4 = 4;
803 	uint32_t area_id;
804 	struct ospf6_area *oa;
805 	struct ospf6_vertex *root;
806 	struct ospf6_route *route;
807 	struct prefix prefix;
808 
809 	OSPF6_CMD_CHECK_RUNNING();
810 
811 	ospf6_linkstate_prefix(ospf6->router_id, htonl(0), &prefix);
812 
813 	if (inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id) != 1) {
814 		vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
815 		return CMD_SUCCESS;
816 	}
817 	oa = ospf6_area_lookup(area_id, ospf6);
818 	if (oa == NULL) {
819 		vty_out(vty, "No such Area: %s\n", argv[idx_ipv4]->arg);
820 		return CMD_SUCCESS;
821 	}
822 
823 	route = ospf6_route_lookup(&prefix, oa->spf_table);
824 	if (route == NULL) {
825 		vty_out(vty, "LS entry for root not found in area %s\n",
826 			oa->name);
827 		return CMD_SUCCESS;
828 	}
829 	root = (struct ospf6_vertex *)route->route_option;
830 	ospf6_spf_display_subtree(vty, "", 0, root);
831 
832 	return CMD_SUCCESS;
833 }
834 
835 DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
836        show_ipv6_ospf6_simulate_spf_tree_root_cmd,
837        "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D",
838        SHOW_STR
839        IP6_STR
840        OSPF6_STR
841        "Shortest Path First calculation\n"
842        "Show SPF tree\n"
843        "Specify root's router-id to calculate another router's SPF tree\n"
844        "OSPF6 area parameters\n"
845        OSPF6_AREA_ID_STR)
846 {
847 	int idx_ipv4 = 5;
848 	int idx_ipv4_2 = 7;
849 	uint32_t area_id;
850 	struct ospf6_area *oa;
851 	struct ospf6_vertex *root;
852 	struct ospf6_route *route;
853 	struct prefix prefix;
854 	uint32_t router_id;
855 	struct ospf6_route_table *spf_table;
856 	unsigned char tmp_debug_ospf6_spf = 0;
857 
858 	OSPF6_CMD_CHECK_RUNNING();
859 
860 	inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
861 	ospf6_linkstate_prefix(router_id, htonl(0), &prefix);
862 
863 	if (inet_pton(AF_INET, argv[idx_ipv4_2]->arg, &area_id) != 1) {
864 		vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4_2]->arg);
865 		return CMD_SUCCESS;
866 	}
867 	oa = ospf6_area_lookup(area_id, ospf6);
868 	if (oa == NULL) {
869 		vty_out(vty, "No such Area: %s\n", argv[idx_ipv4_2]->arg);
870 		return CMD_SUCCESS;
871 	}
872 
873 	tmp_debug_ospf6_spf = conf_debug_ospf6_spf;
874 	conf_debug_ospf6_spf = 0;
875 
876 	spf_table = OSPF6_ROUTE_TABLE_CREATE(NONE, SPF_RESULTS);
877 	ospf6_spf_calculation(router_id, spf_table, oa);
878 
879 	conf_debug_ospf6_spf = tmp_debug_ospf6_spf;
880 
881 	route = ospf6_route_lookup(&prefix, spf_table);
882 	if (route == NULL) {
883 		ospf6_spf_table_finish(spf_table);
884 		ospf6_route_table_delete(spf_table);
885 		return CMD_SUCCESS;
886 	}
887 	root = (struct ospf6_vertex *)route->route_option;
888 	ospf6_spf_display_subtree(vty, "", 0, root);
889 
890 	ospf6_spf_table_finish(spf_table);
891 	ospf6_route_table_delete(spf_table);
892 
893 	return CMD_SUCCESS;
894 }
895 
896 DEFUN (ospf6_area_stub,
897        ospf6_area_stub_cmd,
898        "area <A.B.C.D|(0-4294967295)> stub",
899        "OSPF6 area parameters\n"
900        "OSPF6 area ID in IP address format\n"
901        "OSPF6 area ID as a decimal value\n"
902        "Configure OSPF6 area as stub\n")
903 {
904 	int idx_ipv4_number = 1;
905 	struct ospf6_area *area;
906 
907 	OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area);
908 
909 	if (!ospf6_area_stub_set(ospf6, area)) {
910 		vty_out(vty,
911 			"First deconfigure all virtual link through this area\n");
912 		return CMD_WARNING_CONFIG_FAILED;
913 	}
914 
915 	ospf6_area_no_summary_unset(ospf6, area);
916 
917 	return CMD_SUCCESS;
918 }
919 
920 DEFUN (ospf6_area_stub_no_summary,
921        ospf6_area_stub_no_summary_cmd,
922        "area <A.B.C.D|(0-4294967295)> stub no-summary",
923        "OSPF6 stub parameters\n"
924        "OSPF6 area ID in IP address format\n"
925        "OSPF6 area ID as a decimal value\n"
926        "Configure OSPF6 area as stub\n"
927        "Do not inject inter-area routes into stub\n")
928 {
929 	int idx_ipv4_number = 1;
930 	struct ospf6_area *area;
931 
932 	OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area);
933 
934 	if (!ospf6_area_stub_set(ospf6, area)) {
935 		vty_out(vty,
936 			"First deconfigure all virtual link through this area\n");
937 		return CMD_WARNING_CONFIG_FAILED;
938 	}
939 
940 	ospf6_area_no_summary_set(ospf6, area);
941 
942 	return CMD_SUCCESS;
943 }
944 
945 DEFUN (no_ospf6_area_stub,
946        no_ospf6_area_stub_cmd,
947        "no area <A.B.C.D|(0-4294967295)> stub",
948        NO_STR
949        "OSPF6 area parameters\n"
950        "OSPF6 area ID in IP address format\n"
951        "OSPF6 area ID as a decimal value\n"
952        "Configure OSPF6 area as stub\n")
953 {
954 	int idx_ipv4_number = 2;
955 	struct ospf6_area *area;
956 
957 	OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area);
958 
959 	ospf6_area_stub_unset(ospf6, area);
960 	ospf6_area_no_summary_unset(ospf6, area);
961 
962 	return CMD_SUCCESS;
963 }
964 
965 DEFUN (no_ospf6_area_stub_no_summary,
966        no_ospf6_area_stub_no_summary_cmd,
967        "no area <A.B.C.D|(0-4294967295)> stub no-summary",
968        NO_STR
969        "OSPF6 area parameters\n"
970        "OSPF6 area ID in IP address format\n"
971        "OSPF6 area ID as a decimal value\n"
972        "Configure OSPF6 area as stub\n"
973        "Do not inject inter-area routes into area\n")
974 {
975 	int idx_ipv4_number = 2;
976 	struct ospf6_area *area;
977 
978 	OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area);
979 
980 	ospf6_area_stub_unset(ospf6, area);
981 	ospf6_area_no_summary_unset(ospf6, area);
982 
983 	return CMD_SUCCESS;
984 }
985 
ospf6_area_init(void)986 void ospf6_area_init(void)
987 {
988 	install_element(VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
989 	install_element(VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
990 	install_element(VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd);
991 
992 	install_element(OSPF6_NODE, &area_range_cmd);
993 	install_element(OSPF6_NODE, &no_area_range_cmd);
994 	install_element(OSPF6_NODE, &ospf6_area_stub_no_summary_cmd);
995 	install_element(OSPF6_NODE, &ospf6_area_stub_cmd);
996 	install_element(OSPF6_NODE, &no_ospf6_area_stub_no_summary_cmd);
997 	install_element(OSPF6_NODE, &no_ospf6_area_stub_cmd);
998 
999 
1000 	install_element(OSPF6_NODE, &area_import_list_cmd);
1001 	install_element(OSPF6_NODE, &no_area_import_list_cmd);
1002 	install_element(OSPF6_NODE, &area_export_list_cmd);
1003 	install_element(OSPF6_NODE, &no_area_export_list_cmd);
1004 
1005 	install_element(OSPF6_NODE, &area_filter_list_cmd);
1006 	install_element(OSPF6_NODE, &no_area_filter_list_cmd);
1007 }
1008 
ospf6_area_interface_delete(struct ospf6_interface * oi)1009 void ospf6_area_interface_delete(struct ospf6_interface *oi)
1010 {
1011 	struct ospf6_area *oa;
1012 	struct listnode *node, *nnode;
1013 
1014 	if (!ospf6)
1015 		return;
1016 	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
1017 		if(listnode_lookup(oa->if_list, oi))
1018 			listnode_delete(oa->if_list, oi);
1019 
1020 }
1021