]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_asbr.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / ospfd / ospf_asbr.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
718e3744 2/*
3 * OSPF AS Boundary Router functions.
4 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
718e3744 5 */
6
7#include <zebra.h>
8
9#include "thread.h"
10#include "memory.h"
11#include "linklist.h"
12#include "prefix.h"
13#include "if.h"
14#include "table.h"
15#include "vty.h"
16#include "filter.h"
17#include "log.h"
18
19#include "ospfd/ospfd.h"
20#include "ospfd/ospf_interface.h"
21#include "ospfd/ospf_asbr.h"
22#include "ospfd/ospf_lsa.h"
23#include "ospfd/ospf_lsdb.h"
24#include "ospfd/ospf_neighbor.h"
25#include "ospfd/ospf_spf.h"
26#include "ospfd/ospf_flood.h"
27#include "ospfd/ospf_route.h"
28#include "ospfd/ospf_zebra.h"
29#include "ospfd/ospf_dump.h"
63f0e941 30#include "ospfd/ospf_errors.h"
6b0655a2 31
718e3744 32/* Remove external route. */
d62a17ae 33void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p)
718e3744 34{
d62a17ae 35 struct route_node *rn;
36 struct ospf_route * or ;
37
38 rn = route_node_lookup(ospf->old_external_route, (struct prefix *)p);
39 if (rn)
40 if ((or = rn->info)) {
ae32e1c2 41 zlog_info("Route[%pFX]: external path deleted", p);
d62a17ae 42
43 /* Remove route from zebra. */
44 if (or->type == OSPF_DESTINATION_NETWORK)
996c9314
LB
45 ospf_zebra_delete(
46 ospf, (struct prefix_ipv4 *)&rn->p, or);
d62a17ae 47
48 ospf_route_free(or);
49 rn->info = NULL;
50
51 route_unlock_node(rn);
52 route_unlock_node(rn);
53 return;
54 }
55
ae32e1c2 56 zlog_info("Route[%pFX]: no such external path", p);
718e3744 57}
58
718e3744 59/* Add an External info for AS-external-LSA. */
4030e186 60struct external_info *ospf_external_info_new(struct ospf *ospf, uint8_t type,
d7c0a89a 61 unsigned short instance)
718e3744 62{
d62a17ae 63 struct external_info *new;
718e3744 64
9f5dc319 65 new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info));
4030e186 66 new->ospf = ospf;
d62a17ae 67 new->type = type;
68 new->instance = instance;
63f0e941 69 new->to_be_processed = 0;
718e3744 70
d62a17ae 71 ospf_reset_route_map_set_values(&new->route_map_set);
72 return new;
718e3744 73}
74
d62a17ae 75static void ospf_external_info_free(struct external_info *ei)
718e3744 76{
d62a17ae 77 XFREE(MTYPE_OSPF_EXTERNAL_INFO, ei);
718e3744 78}
79
d62a17ae 80void ospf_reset_route_map_set_values(struct route_map_set_values *values)
718e3744 81{
d62a17ae 82 values->metric = -1;
83 values->metric_type = -1;
718e3744 84}
85
d62a17ae 86int ospf_route_map_set_compare(struct route_map_set_values *values1,
87 struct route_map_set_values *values2)
718e3744 88{
d62a17ae 89 return values1->metric == values2->metric
90 && values1->metric_type == values2->metric_type;
718e3744 91}
92
93/* Add an External info for AS-external-LSA. */
996c9314 94struct external_info *
d7c0a89a 95ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance,
996c9314
LB
96 struct prefix_ipv4 p, ifindex_t ifindex,
97 struct in_addr nexthop, route_tag_t tag)
718e3744 98{
d62a17ae 99 struct external_info *new;
100 struct route_node *rn;
101 struct ospf_external *ext;
d62a17ae 102
de1ac5fd 103 ext = ospf_external_lookup(ospf, type, instance);
d62a17ae 104 if (!ext)
de1ac5fd 105 ext = ospf_external_add(ospf, type, instance);
d62a17ae 106
107 rn = route_node_get(EXTERNAL_INFO(ext), (struct prefix *)&p);
108 /* If old info exists, -- discard new one or overwrite with new one? */
5e5181bb
DS
109 if (rn && rn->info) {
110 new = rn->info;
111 if ((new->ifindex == ifindex)
112 && (new->nexthop.s_addr == nexthop.s_addr)
113 && (new->tag == tag)) {
114 route_unlock_node(rn);
115 return NULL; /* NULL => no LSA to refresh */
d62a17ae 116 }
117
5e5181bb
DS
118 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
119 zlog_debug(
674c29dd 120 "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
5e5181bb 121 ospf_redist_string(type), instance,
674c29dd 122 ospf->vrf_id, &p, &nexthop.s_addr);
5e5181bb
DS
123 XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
124 }
125
d62a17ae 126 /* Create new External info instance. */
4030e186 127 new = ospf_external_info_new(ospf, type, instance);
d62a17ae 128 new->p = p;
129 new->ifindex = ifindex;
130 new->nexthop = nexthop;
131 new->tag = tag;
04e94d39 132 new->orig_tag = tag;
63f0e941 133 new->aggr_route = NULL;
d62a17ae 134
135 /* we don't unlock rn from the get() because we're attaching the info */
136 if (rn)
137 rn->info = new;
138
139 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
d62a17ae 140 zlog_debug(
674c29dd
DS
141 "Redistribute[%s][%u]: %pFX external info created, with NH %pI4",
142 ospf_redist_string(type), ospf->vrf_id, &p,
143 &nexthop.s_addr);
d62a17ae 144 }
145 return new;
718e3744 146}
147
d7c0a89a
QY
148void ospf_external_info_delete(struct ospf *ospf, uint8_t type,
149 unsigned short instance, struct prefix_ipv4 p)
718e3744 150{
d62a17ae 151 struct route_node *rn;
152 struct ospf_external *ext;
153
de1ac5fd 154 ext = ospf_external_lookup(ospf, type, instance);
d62a17ae 155 if (!ext)
156 return;
157
158 rn = route_node_lookup(EXTERNAL_INFO(ext), (struct prefix *)&p);
159 if (rn) {
160 ospf_external_info_free(rn->info);
161 rn->info = NULL;
162 route_unlock_node(rn);
163 route_unlock_node(rn);
164 }
718e3744 165}
166
d7c0a89a
QY
167struct external_info *ospf_external_info_lookup(struct ospf *ospf, uint8_t type,
168 unsigned short instance,
d62a17ae 169 struct prefix_ipv4 *p)
718e3744 170{
d62a17ae 171 struct route_node *rn;
172 struct ospf_external *ext;
173
de1ac5fd 174 ext = ospf_external_lookup(ospf, type, instance);
d62a17ae 175 if (!ext)
176 return NULL;
177
178 rn = route_node_lookup(EXTERNAL_INFO(ext), (struct prefix *)p);
179 if (rn) {
180 route_unlock_node(rn);
181 if (rn->info)
182 return rn->info;
183 }
184
185 return NULL;
718e3744 186}
187
d62a17ae 188struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf,
189 struct prefix_ipv4 *p)
718e3744 190{
d62a17ae 191 struct ospf_lsa *lsa;
192 struct as_external_lsa *al;
193 struct in_addr mask, id;
718e3744 194
1461559c 195 /* First search the lsdb with address specific LSID
64f46c22 196 * where all the host bits are set, if there a matched
197 * LSA, return.
198 * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
199 * If no lsa with above LSID, use received address as
200 * LSID and check if any LSA in LSDB.
201 * If LSA found, check if the mask is same b/w the matched
202 * LSA and received prefix, if same then it is the LSA for
203 * this prefix.
204 * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
205 */
718e3744 206
d62a17ae 207 masklen2ip(p->prefixlen, &mask);
64f46c22 208 id.s_addr = p->prefix.s_addr | (~mask.s_addr);
209 lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id,
210 ospf->router_id);
a8c22275 211 if (lsa) {
212 if (p->prefixlen == IPV4_MAX_BITLEN) {
213 al = (struct as_external_lsa *)lsa->data;
214
215 if (mask.s_addr != al->mask.s_addr)
216 return NULL;
217 }
64f46c22 218 return lsa;
a8c22275 219 }
718e3744 220
64f46c22 221 lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
222 p->prefix, ospf->router_id);
223
224 if (lsa) {
225 al = (struct as_external_lsa *)lsa->data;
226 if (mask.s_addr == al->mask.s_addr)
227 return lsa;
d62a17ae 228 }
718e3744 229
64f46c22 230 return NULL;
718e3744 231}
232
6b0655a2 233
718e3744 234/* Update ASBR status. */
d7c0a89a 235void ospf_asbr_status_update(struct ospf *ospf, uint8_t status)
718e3744 236{
868a0861
DS
237 zlog_info("ASBR[%s:Status:%d]: Update",
238 ospf_get_name(ospf), status);
d62a17ae 239
240 /* ASBR on. */
241 if (status) {
242 /* Already ASBR. */
243 if (IS_OSPF_ASBR(ospf)) {
868a0861
DS
244 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
245 ospf_get_name(ospf), status);
d62a17ae 246 return;
247 }
248 SET_FLAG(ospf->flags, OSPF_FLAG_ASBR);
249 } else {
250 /* Already non ASBR. */
251 if (!IS_OSPF_ASBR(ospf)) {
868a0861
DS
252 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
253 ospf_get_name(ospf), status);
d62a17ae 254 return;
255 }
256 UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR);
718e3744 257 }
718e3744 258
d62a17ae 259 /* Transition from/to status ASBR, schedule timer. */
260 ospf_spf_calculate_schedule(ospf, SPF_FLAG_ASBR_STATUS_CHANGE);
261 ospf_router_lsa_update(ospf);
718e3744 262}
263
0f321812
AC
264/* If there's redistribution configured, we need to refresh external
265 * LSAs in order to install Type-7 and flood to all NSSA Areas
266 */
cc9f21da 267static void ospf_asbr_nssa_redist_update_timer(struct thread *thread)
0f321812 268{
1c1c342d 269 struct ospf *ospf = THREAD_ARG(thread);
0f321812
AC
270 int type;
271
1c1c342d
AC
272 ospf->t_asbr_nssa_redist_update = NULL;
273
274 if (IS_DEBUG_OSPF_EVENT)
275 zlog_debug("Running ASBR NSSA redistribution update on timer");
276
0f321812
AC
277 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
278 struct list *red_list;
279 struct listnode *node;
280 struct ospf_redist *red;
281
282 red_list = ospf->redist[type];
283 if (!red_list)
284 continue;
285
286 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
945eec2b 287 ospf_external_lsa_refresh_type(ospf, type,
288 red->instance,
1c1c342d 289 LSA_REFRESH_FORCE);
0f321812
AC
290 }
291
292 ospf_external_lsa_refresh_default(ospf);
1c1c342d
AC
293}
294
295void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf)
296{
297 if (IS_DEBUG_OSPF_EVENT)
298 zlog_debug("Scheduling ASBR NSSA redistribution update");
299
300 thread_add_timer(master, ospf_asbr_nssa_redist_update_timer, ospf,
301 OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY,
302 &ospf->t_asbr_nssa_redist_update);
0f321812
AC
303}
304
d7c0a89a
QY
305void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,
306 unsigned short instance)
718e3744 307{
d62a17ae 308 struct route_node *rn;
309 struct external_info *ei;
310 struct ospf_external *ext;
311
de1ac5fd 312 ext = ospf_external_lookup(ospf, type, instance);
d62a17ae 313 if (!ext)
314 return;
315
316 /* Delete external info for specified type. */
5e5181bb
DS
317 if (!EXTERNAL_INFO(ext))
318 return;
319
320 for (rn = route_top(EXTERNAL_INFO(ext)); rn; rn = route_next(rn)) {
321 ei = rn->info;
322
323 if (!ei)
324 continue;
325
326 struct ospf_external_aggr_rt *aggr;
327
1fe59b44 328 if (is_default_prefix4(&ei->p)
5e5181bb
DS
329 && ospf->default_originate != DEFAULT_ORIGINATE_NONE)
330 continue;
331
332 aggr = ei->aggr_route;
333
334 if (aggr)
335 ospf_unlink_ei_from_aggr(ospf, aggr, ei);
336 else if (ospf_external_info_find_lsa(ospf, &ei->p))
337 ospf_external_lsa_flush(ospf, type, &ei->p,
d62a17ae 338 ei->ifindex /*, ei->nexthop */);
339
5e5181bb
DS
340 ospf_external_info_free(ei);
341 route_unlock_node(rn);
342 rn->info = NULL;
343 }
718e3744 344}
ad7222b7 345
5e5181bb 346
ad7222b7 347/* External Route Aggregator Handlers */
423e71c4 348bool is_valid_summary_addr(struct prefix_ipv4 *p)
349{
350 /* Default prefix validation*/
351 if (p->prefix.s_addr == INADDR_ANY)
352 return false;
353
354 /*Host route shouldn't be configured as summary addres*/
936fbaef 355 if (p->prefixlen == IPV4_MAX_BITLEN)
423e71c4 356 return false;
357
358 return true;
359}
ad7222b7 360void ospf_asbr_external_aggregator_init(struct ospf *instance)
361{
362 instance->rt_aggr_tbl = route_table_init();
363
364 instance->t_external_aggr = NULL;
365
366 instance->aggr_action = 0;
367
368 instance->aggr_delay_interval = OSPF_EXTL_AGGR_DEFAULT_DELAY;
369}
370
371static unsigned int ospf_external_rt_hash_key(const void *data)
372{
373 const struct external_info *ei = data;
374 unsigned int key = 0;
375
376 key = prefix_hash_key(&ei->p);
377 return key;
378}
379
380static bool ospf_external_rt_hash_cmp(const void *d1, const void *d2)
381{
382 const struct external_info *ei1 = d1;
383 const struct external_info *ei2 = d2;
384
385 return prefix_same((struct prefix *)&ei1->p, (struct prefix *)&ei2->p);
386}
387
388static struct ospf_external_aggr_rt *
389ospf_external_aggregator_new(struct prefix_ipv4 *p)
390{
391 struct ospf_external_aggr_rt *aggr;
392
393 aggr = (struct ospf_external_aggr_rt *)XCALLOC(
394 MTYPE_OSPF_EXTERNAL_RT_AGGR,
395 sizeof(struct ospf_external_aggr_rt));
396
397 if (!aggr)
398 return NULL;
399
400 aggr->p.family = p->family;
401 aggr->p.prefix = p->prefix;
402 aggr->p.prefixlen = p->prefixlen;
403 aggr->match_extnl_hash = hash_create(ospf_external_rt_hash_key,
404 ospf_external_rt_hash_cmp,
405 "Ospf external route hash");
406 return aggr;
407}
408
63f0e941 409static void ospf_aggr_handle_external_info(void *data)
410{
411 struct external_info *ei = (struct external_info *)data;
412 struct ospf_external_aggr_rt *aggr = NULL;
fa42b7d8 413 struct ospf *ospf = ei->ospf;
63f0e941 414 struct ospf_lsa *lsa = NULL;
415
416 ei->aggr_route = NULL;
417
418 ei->to_be_processed = true;
419
420 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
421 zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__,
422 &ei->p.prefix, ei->p.prefixlen);
423
63f0e941 424 assert(ospf);
425
426 if (!ospf_redistribute_check(ospf, ei, NULL))
427 return;
428
429 aggr = ospf_external_aggr_match(ospf, &ei->p);
430 if (aggr) {
fddbafcc 431 (void)ospf_originate_summary_lsa(ospf, aggr, ei);
63f0e941 432 return;
433 }
434
435 lsa = ospf_external_info_find_lsa(ospf, &ei->p);
436 if (lsa)
437 ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 1);
438 else
fddbafcc 439 (void)ospf_external_lsa_originate(ospf, ei);
63f0e941 440}
441
ad7222b7 442static void ospf_aggr_unlink_external_info(void *data)
443{
444 struct external_info *ei = (struct external_info *)data;
445
446 ei->aggr_route = NULL;
447
448 ei->to_be_processed = true;
449}
450
451void ospf_external_aggregator_free(struct ospf_external_aggr_rt *aggr)
452{
453 if (OSPF_EXTERNAL_RT_COUNT(aggr))
454 hash_clean(aggr->match_extnl_hash,
455 (void *)ospf_aggr_unlink_external_info);
456
457 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
63f0e941 458 zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
459 __func__, &aggr->p.prefix, aggr->p.prefixlen);
ad7222b7 460 hash_free(aggr->match_extnl_hash);
461 aggr->match_extnl_hash = NULL;
462
463 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr);
464}
63f0e941 465
466static void ospf_external_aggr_add(struct ospf *ospf,
467 struct ospf_external_aggr_rt *aggr)
468{
469 struct route_node *rn;
470
471 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
472 zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
473 __func__, &aggr->p.prefix, aggr->p.prefixlen);
474 rn = route_node_get(ospf->rt_aggr_tbl, (struct prefix *)&aggr->p);
475 if (rn->info)
476 route_unlock_node(rn);
477 else
478 rn->info = aggr;
479}
480
481static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn)
482{
483 struct ospf_external_aggr_rt *aggr = rn->info;
484
485 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
486 zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__,
487 &aggr->p.prefix, aggr->p.prefixlen);
488
489 /* Sent a Max age LSA if it is already originated. */
490 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
491 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
492 zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
493 __func__, &aggr->p.prefix,
494 aggr->p.prefixlen);
495 ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
496 }
497
498 rn->info = NULL;
499 route_unlock_node(rn);
63f0e941 500}
501
502struct ospf_external_aggr_rt *
503ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p)
504{
505 struct route_node *rn;
506 struct ospf_external_aggr_rt *summary_rt = NULL;
507
508 rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
509 if (rn) {
510 summary_rt = rn->info;
511 route_unlock_node(rn);
512 return summary_rt;
513 }
514 return NULL;
515}
516
517struct ospf_external_aggr_rt *ospf_external_aggr_match(struct ospf *ospf,
518 struct prefix_ipv4 *p)
519{
520 struct route_node *node;
521 struct ospf_external_aggr_rt *summary_rt = NULL;
522
523 node = route_node_match(ospf->rt_aggr_tbl, (struct prefix *)p);
524 if (node) {
525
526 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
527 if (node->info) {
528 struct ospf_external_aggr_rt *ag = node->info;
529
530 zlog_debug(
1d5453d6 531 "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d",
63f0e941 532 __func__, &p->prefix, p->prefixlen,
533 &ag->p.prefix, ag->p.prefixlen);
534 }
535
536 summary_rt = node->info;
537 route_unlock_node(node);
538 return summary_rt;
539 }
540 return NULL;
541}
542
543void ospf_unlink_ei_from_aggr(struct ospf *ospf,
544 struct ospf_external_aggr_rt *aggr,
545 struct external_info *ei)
546{
547 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
548 zlog_debug(
549 "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
550 __func__, &ei->p.prefix, ei->p.prefixlen,
551 &aggr->p.prefix, aggr->p.prefixlen,
552 OSPF_EXTERNAL_RT_COUNT(aggr));
553 hash_release(aggr->match_extnl_hash, ei);
554 ei->aggr_route = NULL;
555
556 /* Flush the aggreagte route if matching
557 * external route count becomes zero.
558 */
559 if (!OSPF_EXTERNAL_RT_COUNT(aggr)
560 && CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
561
562 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
563 zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
564 __func__, &aggr->p.prefix,
565 aggr->p.prefixlen);
566
567 /* Flush the aggregate LSA */
568 ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
569
570 /* Unset the Origination flag */
571 UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
572 }
573}
574
575static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt *aggr,
576 struct external_info *ei)
577{
578 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
579 zlog_debug(
580 "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
581 __func__, &ei->p.prefix, ei->p.prefixlen,
582 &aggr->p.prefix, aggr->p.prefixlen);
8e3aae66 583 (void)hash_get(aggr->match_extnl_hash, ei, hash_alloc_intern);
63f0e941 584 ei->aggr_route = aggr;
585}
586
587struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf,
588 struct ospf_external_aggr_rt *aggr,
589 struct external_info *ei)
590{
591 struct ospf_lsa *lsa;
592 struct external_info ei_aggr;
593 struct as_external_lsa *asel;
594 struct ospf_external_aggr_rt *old_aggr;
595 route_tag_t tag = 0;
596
597 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
598 zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
599 __func__, &aggr->p.prefix, aggr->p.prefixlen);
600
601 /* This case to handle when the overlapping aggregator address
602 * is availbe.Best match will be considered.So need to delink
603 * from old aggregator and link to the new aggr.
604 */
605 if (ei->aggr_route) {
606 if (ei->aggr_route != aggr) {
607 old_aggr = ei->aggr_route;
608 ospf_unlink_ei_from_aggr(ospf, old_aggr, ei);
609 }
610 }
611
612 /* Add the external route to hash table */
613 ospf_link_ei_to_aggr(aggr, ei);
614
615 lsa = ospf_external_info_find_lsa(ospf, &aggr->p);
1461559c 616 /* Don't originate external LSA,
63f0e941 617 * If it is configured not to advertise.
618 */
619 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
620 /* If it is already originated as external LSA,
621 * But, it is configured not to advertise then
622 * flush the originated external lsa.
623 */
624 if (lsa)
625 ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
626 UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
627
628 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
629 zlog_debug(
630 "%s: Don't originate the summary address,It is configured to not-advertise.",
631 __func__);
632 return NULL;
633 }
634
635 /* Prepare the extrenal_info for aggregator */
6006b807 636 memset(&ei_aggr, 0, sizeof(ei_aggr));
63f0e941 637 ei_aggr.p = aggr->p;
638 ei_aggr.tag = aggr->tag;
639 ei_aggr.type = 0;
640 ei_aggr.instance = ospf->instance;
641 ei_aggr.route_map_set.metric = -1;
642 ei_aggr.route_map_set.metric_type = -1;
643
644 /* Summary route already originated,
645 * So, Do nothing.
646 */
647 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
648 if (!lsa) {
649 flog_warn(EC_OSPF_LSA_MISSING,
650 "%s: Could not refresh/originate %pI4/%d",
651 __func__, &aggr->p.prefix, aggr->p.prefixlen);
652 return NULL;
653 }
654
655 asel = (struct as_external_lsa *)lsa->data;
656 tag = (unsigned long)ntohl(asel->e[0].route_tag);
657
658 /* If tag modified , then re-originate the route
659 * with modified tag details.
660 */
661 if (tag != ei_aggr.tag) {
662 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
663 zlog_debug(
664 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
665 __func__, tag, ei_aggr.tag,
666 &aggr->p.prefix, aggr->p.prefixlen);
667
668 ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
669 LSA_REFRESH_FORCE, 1);
670 }
671 return lsa;
672 }
673
674 if (lsa && IS_LSA_MAXAGE(lsa)) {
675 /* This is special case.
676 * If a summary route need to be originated but where
677 * summary route already exist in lsdb with maxage, then
678 * it need to be refreshed.
679 */
680 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
681 zlog_debug(
682 "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
a4544597 683 __func__, &aggr->p.prefix, aggr->p.prefixlen);
63f0e941 684
685 ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
686 LSA_REFRESH_FORCE, 1);
687 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
688 return lsa;
689 }
690
691 /* If the external route prefix same as aggregate route
692 * and if external route is already originated as TYPE-5
693 * then it need to be refreshed and originate bit should
694 * be set.
695 */
696 if (lsa && prefix_same((struct prefix *)&ei_aggr.p,
697 (struct prefix *)&ei->p)) {
698 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
699 zlog_debug(
700 "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
a4544597 701 __func__, &aggr->p.prefix, aggr->p.prefixlen);
63f0e941 702 ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
703 LSA_REFRESH_FORCE, 1);
704 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
705 return lsa;
706 }
707
708 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
709 zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__,
710 &aggr->p.prefix, aggr->p.prefixlen);
711
712 /* Originate summary LSA */
713 lsa = ospf_external_lsa_originate(ospf, &ei_aggr);
714 if (lsa) {
715 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
716 zlog_debug("%s: Set the origination bit for aggregator",
717 __func__);
718 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
719 }
720
721 return lsa;
722}
723void ospf_unset_all_aggr_flag(struct ospf *ospf)
724{
725 struct route_node *rn = NULL;
726
727 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
728 zlog_debug("Unset the origination bit for all aggregator");
729
730 for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
731 if (!rn->info)
732 continue;
733
734 struct ospf_external_aggr_rt *aggr = rn->info;
735
736 UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
737 }
738}
739
740static void ospf_delete_all_marked_aggregators(struct ospf *ospf)
741{
742 struct route_node *rn = NULL;
743
744 /* Loop through all the aggregators, Delete all aggregators
745 * which are marked as DELETE. Set action to NONE for remaining
746 * aggregators
747 */
748 for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
749 if (!rn->info)
750 continue;
751
752 struct ospf_external_aggr_rt *aggr = rn->info;
753
754 if (aggr->action != OSPF_ROUTE_AGGR_DEL) {
755 aggr->action = OSPF_ROUTE_AGGR_NONE;
756 continue;
757 }
758 ospf_external_aggr_delete(ospf, rn);
759 ospf_external_aggregator_free(aggr);
760 }
761}
762
763static void ospf_handle_aggregated_exnl_rt(struct ospf *ospf,
764 struct ospf_external_aggr_rt *aggr,
765 struct external_info *ei)
766{
767 struct ospf_lsa *lsa;
768 struct as_external_lsa *al;
769 struct in_addr mask;
770
771 /* Handling the case where the external route prefix
772 * and aggregate prefix is same
1461559c 773 * If same don't flush the originated external LSA.
63f0e941 774 */
775 if (prefix_same((struct prefix *)&aggr->p, (struct prefix *)&ei->p)) {
776 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
777 zlog_debug(
1461559c 778 "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.",
63f0e941 779 __func__, &ei->p.prefix, ei->p.prefixlen);
780 return;
781 }
782
783 lsa = ospf_external_info_find_lsa(ospf, &ei->p);
784 if (lsa) {
785 al = (struct as_external_lsa *)lsa->data;
786 masklen2ip(ei->p.prefixlen, &mask);
787
788 if (mask.s_addr != al->mask.s_addr)
789 return;
790
791 ospf_external_lsa_flush(ospf, ei->type, &ei->p, 0);
792 }
793}
794
795static void ospf_handle_exnl_rt_after_aggr_del(struct ospf *ospf,
796 struct external_info *ei)
797{
798 struct ospf_lsa *lsa;
799
800 /* Process only marked external routes.
801 * These routes were part of a deleted
802 * aggregator.So, originate now.
803 */
804 if (!ei->to_be_processed)
805 return;
806
807 ei->to_be_processed = false;
808
809 lsa = ospf_external_info_find_lsa(ospf, &ei->p);
810
811 if (lsa)
812 ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0);
813 else {
814 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
815 zlog_debug("%s: Originate external route(%pI4/%d)",
816 __func__, &ei->p.prefix, ei->p.prefixlen);
817
818 ospf_external_lsa_originate(ospf, ei);
819 }
820}
821
822static void ospf_handle_external_aggr_add(struct ospf *ospf)
823{
824 struct external_info *ei;
825 struct route_node *rn = NULL;
826 struct route_table *rt = NULL;
827 int type = 0;
828
829 /* Delete all the aggregators which are marked as
830 * OSPF_ROUTE_AGGR_DEL.
831 */
832 ospf_delete_all_marked_aggregators(ospf);
833
834 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
835 struct list *ext_list;
836 struct listnode *node;
837 struct ospf_external *ext;
838 struct ospf_external_aggr_rt *aggr;
839
840 ext_list = ospf->external[type];
841 if (!ext_list)
842 continue;
843
844 for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
845 rt = ext->external_info;
846 if (!rt)
847 continue;
848
849 for (rn = route_top(rt); rn; rn = route_next(rn)) {
850 if (!rn->info)
851 continue;
852
853 ei = rn->info;
1fe59b44 854 if (is_default_prefix4(&ei->p))
63f0e941 855 continue;
856
857 /* Check the AS-external-LSA
858 * should be originated.
859 */
860 if (!ospf_redistribute_check(ospf, ei, NULL))
861 continue;
862
863 aggr = ospf_external_aggr_match(ospf, &ei->p);
864
865 /* If matching aggregator found, Add
866 * the external route reference to the
867 * aggregator and originate the aggr
868 * route if it is advertisable.
869 * flush the external LSA if it is
870 * already originated for this external
871 * prefix.
872 */
873 if (aggr) {
874 ospf_originate_summary_lsa(ospf, aggr,
875 ei);
876
877 /* All aggregated external rts
878 * are handled here.
879 */
880 ospf_handle_aggregated_exnl_rt(
881 ospf, aggr, ei);
882 continue;
883 }
884
885 /* External routes which are only out
886 * of aggregation will be handled here.
887 */
888 ospf_handle_exnl_rt_after_aggr_del(ospf, ei);
889 }
890 }
891 }
892}
893
894static void
895ospf_aggr_handle_advertise_change(struct ospf *ospf,
896 struct ospf_external_aggr_rt *aggr,
897 struct external_info *ei_aggr)
898{
899 struct ospf_lsa *lsa;
900
901 /* Check if advertise option modified. */
902 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
903
904 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
905 zlog_debug(
906 "%s: Don't originate the summary address,It is configured to not-advertise.",
907 __func__);
908
909 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
910
911 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
912 zlog_debug(
913 "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
914 __func__, &aggr->p.prefix,
915 aggr->p.prefixlen);
916
917 ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
918
919 UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
920 }
921 return;
922 }
923
924 if (!CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
925 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
926 zlog_debug("%s: Now it is advatisable", __func__);
927
928 lsa = ospf_external_info_find_lsa(ospf, &ei_aggr->p);
929 if (lsa && IS_LSA_MAXAGE(lsa)) {
930 /* This is special case.
931 * If a summary route need to be originated but where
932 * summary route already exist in lsdb with maxage, then
933 * it need to be refreshed.
934 */
935 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
936 zlog_debug(
937 "%s: It is already with Maxage, So refresh it (%pI4/%d)",
938 __func__, &aggr->p.prefix,
939 aggr->p.prefixlen);
940
941 ospf_external_lsa_refresh(ospf, lsa, ei_aggr,
942 LSA_REFRESH_FORCE, 1);
943
944 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
945
946 } else {
947
948 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
949 zlog_debug(
950 "%s: Originate Aggregate LSA (%pI4/%d)",
951 __func__, &aggr->p.prefix,
952 aggr->p.prefixlen);
953
954 /* Originate summary LSA */
955 lsa = ospf_external_lsa_originate(ospf, ei_aggr);
956 if (lsa)
957 SET_FLAG(aggr->flags,
958 OSPF_EXTERNAL_AGGRT_ORIGINATED);
959 }
960 }
961}
962
963static void ospf_handle_external_aggr_update(struct ospf *ospf)
964{
965 struct route_node *rn = NULL;
966
967 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1d5453d6 968 zlog_debug("%s: Process modified aggregators.", __func__);
63f0e941 969
970 for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
971 struct ospf_external_aggr_rt *aggr;
972 struct ospf_lsa *lsa = NULL;
973 struct as_external_lsa *asel = NULL;
974 struct external_info ei_aggr;
975 route_tag_t tag = 0;
976
977 if (!rn->info)
978 continue;
979
980 aggr = rn->info;
981
982 if (aggr->action == OSPF_ROUTE_AGGR_DEL) {
983 aggr->action = OSPF_ROUTE_AGGR_NONE;
984 ospf_external_aggr_delete(ospf, rn);
985
986 if (OSPF_EXTERNAL_RT_COUNT(aggr))
987 hash_clean(
988 aggr->match_extnl_hash,
989 (void *)ospf_aggr_handle_external_info);
990
991 hash_free(aggr->match_extnl_hash);
992 XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr);
993
994 } else if (aggr->action == OSPF_ROUTE_AGGR_MODIFY) {
995
996 aggr->action = OSPF_ROUTE_AGGR_NONE;
997
998 /* Prepare the extrenal_info for aggregator */
6006b807 999 memset(&ei_aggr, 0, sizeof(ei_aggr));
63f0e941 1000 ei_aggr.p = aggr->p;
1001 ei_aggr.tag = aggr->tag;
1002 ei_aggr.type = 0;
1003 ei_aggr.instance = ospf->instance;
1004 ei_aggr.route_map_set.metric = -1;
1005 ei_aggr.route_map_set.metric_type = -1;
1006
1007 /* Check if tag modified */
1008 if (CHECK_FLAG(aggr->flags,
1009 OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
1010 lsa = ospf_external_info_find_lsa(ospf,
1011 &ei_aggr.p);
1012 if (!lsa) {
1013 flog_warn(EC_OSPF_LSA_MISSING,
1014 "%s: Could not refresh/originate %pI4/%d",
1015 __func__, &aggr->p.prefix,
1016 aggr->p.prefixlen);
1017 continue;
1018 }
1019
1020 asel = (struct as_external_lsa *)lsa->data;
1021 tag = (unsigned long)ntohl(
1022 asel->e[0].route_tag);
1023
1024 /* If tag modified , then re-originate the
1025 * route with modified tag details.
1026 */
1027 if (tag != ei_aggr.tag) {
1028 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1029 zlog_debug(
1030 "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1031 __func__, tag,
1032 ei_aggr.tag,
1033 &aggr->p.prefix,
1034 aggr->p.prefixlen);
1035
1036 ospf_external_lsa_refresh(
1037 ospf, lsa, &ei_aggr,
1038 LSA_REFRESH_FORCE, 1);
1039 }
1040 }
1041
1042 /* Advertise option modified ?
1043 * If so, handled it here.
1044 */
1045 ospf_aggr_handle_advertise_change(ospf, aggr, &ei_aggr);
1046 }
1047 }
1048}
1049
cc9f21da 1050static void ospf_asbr_external_aggr_process(struct thread *thread)
63f0e941 1051{
1052 struct ospf *ospf = THREAD_ARG(thread);
1053 int operation = 0;
1054
1055 ospf->t_external_aggr = NULL;
1056 operation = ospf->aggr_action;
1057
1058 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1d5453d6 1059 zlog_debug("%s: operation:%d", __func__, operation);
63f0e941 1060
1061 switch (operation) {
1062 case OSPF_ROUTE_AGGR_ADD:
1063 ospf_handle_external_aggr_add(ospf);
1064 break;
1065 case OSPF_ROUTE_AGGR_DEL:
1066 case OSPF_ROUTE_AGGR_MODIFY:
1067 ospf_handle_external_aggr_update(ospf);
1068 break;
1069 default:
1070 break;
1071 }
63f0e941 1072}
1073static void ospf_external_aggr_timer(struct ospf *ospf,
1074 struct ospf_external_aggr_rt *aggr,
1075 enum ospf_aggr_action_t operation)
1076{
1077 aggr->action = operation;
1078
1079 if (ospf->t_external_aggr) {
1080 if (ospf->aggr_action == OSPF_ROUTE_AGGR_ADD) {
1081
1082 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1083 zlog_debug(
1084 "%s: Not required to retsart timer,set is already added.",
1085 __func__);
1086 return;
1087 }
1088
1089 if (operation == OSPF_ROUTE_AGGR_ADD) {
1090 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1091 zlog_debug(
1092 "%s, Restarting Aggregator delay timer.",
1093 __func__);
1094 THREAD_OFF(ospf->t_external_aggr);
1095 }
1096 }
1097
1098 if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
4b939ad2 1099 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
63f0e941 1100 __func__, ospf->aggr_delay_interval);
1101
1102 ospf->aggr_action = operation;
1103 thread_add_timer(master, ospf_asbr_external_aggr_process, ospf,
1104 ospf->aggr_delay_interval, &ospf->t_external_aggr);
1105}
423e71c4 1106
1107int ospf_asbr_external_aggregator_set(struct ospf *ospf, struct prefix_ipv4 *p,
1108 route_tag_t tag)
1109{
1110 struct ospf_external_aggr_rt *aggregator;
1111
1112 aggregator = ospf_extrenal_aggregator_lookup(ospf, p);
1113
1114 if (aggregator) {
1115 if (CHECK_FLAG(aggregator->flags,
1116 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1117 UNSET_FLAG(aggregator->flags,
1118 OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1119 else if (aggregator->tag == tag)
1120 return OSPF_SUCCESS;
1121
1122 aggregator->tag = tag;
1123
1124 ospf_external_aggr_timer(ospf, aggregator,
1125 OSPF_ROUTE_AGGR_MODIFY);
1126 } else {
1127 aggregator = ospf_external_aggregator_new(p);
1128 if (!aggregator)
1129 return OSPF_FAILURE;
1130
1131 aggregator->tag = tag;
1132
1133 ospf_external_aggr_add(ospf, aggregator);
1134 ospf_external_aggr_timer(ospf, aggregator, OSPF_ROUTE_AGGR_ADD);
1135 }
1136
1137 return OSPF_SUCCESS;
1138}
1139
1140int ospf_asbr_external_aggregator_unset(struct ospf *ospf,
1141 struct prefix_ipv4 *p, route_tag_t tag)
1142{
1143 struct route_node *rn;
1144 struct ospf_external_aggr_rt *aggr;
1145
1146 rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
1147 if (!rn)
1148 return OSPF_INVALID;
08df5b3b 1149 route_unlock_node(rn);
423e71c4 1150
1151 aggr = rn->info;
1152
1153 if (tag && (tag != aggr->tag))
1154 return OSPF_INVALID;
1155
1156 if (!OSPF_EXTERNAL_RT_COUNT(aggr)) {
1157 ospf_external_aggr_delete(ospf, rn);
1158 ospf_external_aggregator_free(aggr);
1159 return OSPF_SUCCESS;
1160 }
1161
1162 ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_DEL);
1163
1164 return OSPF_SUCCESS;
1165}
1166
1167int ospf_asbr_external_rt_no_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
1168{
1169 struct ospf_external_aggr_rt *aggr;
1170 route_tag_t tag = 0;
1171
1172 aggr = ospf_extrenal_aggregator_lookup(ospf, p);
1173 if (aggr) {
1174 if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1175 return OSPF_SUCCESS;
1176
1177 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1178
1179 aggr->tag = tag;
1180
1181 if (!OSPF_EXTERNAL_RT_COUNT(aggr))
1182 return OSPF_SUCCESS;
1183
1184 ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_MODIFY);
1185 } else {
1186 aggr = ospf_external_aggregator_new(p);
1187
1188 if (!aggr)
1189 return OSPF_FAILURE;
1190
1191 SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1192 ospf_external_aggr_add(ospf, aggr);
1193 ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_ADD);
1194 }
1195
1196 return OSPF_SUCCESS;
1197}
1198
1199int ospf_asbr_external_rt_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
1200{
1201 struct route_node *rn;
1202 struct ospf_external_aggr_rt *aggr;
1203
1204 rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
1205 if (!rn)
1206 return OSPF_INVALID;
08df5b3b 1207 route_unlock_node(rn);
423e71c4 1208
1209 aggr = rn->info;
1210
1211 if (!CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1212 return OSPF_INVALID;
1213
1214 UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1215
1216 if (!OSPF_EXTERNAL_RT_COUNT(aggr))
1217 return OSPF_SUCCESS;
1218
1219 ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_MODIFY);
1220 return OSPF_SUCCESS;
1221}
1222
4b939ad2 1223int ospf_external_aggregator_timer_set(struct ospf *ospf, uint16_t interval)
423e71c4 1224{
1225 ospf->aggr_delay_interval = interval;
1226 return OSPF_SUCCESS;
1227}