2004-05-18 21:14:52 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2003 Yasuhiro Ohara
|
|
|
|
*
|
|
|
|
* This file is part of GNU Zebra.
|
|
|
|
*
|
|
|
|
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with GNU Zebra; see the file COPYING. If not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "vty.h"
|
|
|
|
|
|
|
|
#include "ospf6d.h"
|
|
|
|
#include "ospf6_proto.h"
|
|
|
|
#include "ospf6_lsa.h"
|
|
|
|
#include "ospf6_lsdb.h"
|
|
|
|
#include "ospf6_message.h"
|
|
|
|
#include "ospf6_route.h"
|
|
|
|
#include "ospf6_spf.h"
|
|
|
|
|
|
|
|
#include "ospf6_top.h"
|
|
|
|
#include "ospf6_area.h"
|
|
|
|
#include "ospf6_interface.h"
|
|
|
|
#include "ospf6_neighbor.h"
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
ospf6_get_lsa_scope (u_int16_t type, struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
void *scope = NULL;
|
|
|
|
|
|
|
|
if (from == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch (OSPF6_LSA_SCOPE (type))
|
|
|
|
{
|
|
|
|
case OSPF6_LSA_SCOPE_AS:
|
|
|
|
scope = (from)->ospf6_if->area->ospf6;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_AREA:
|
|
|
|
scope = (from)->ospf6_if->area;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_LINKLOCAL:
|
|
|
|
scope = (from)->ospf6_if;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ospf6_lsdb *
|
|
|
|
ospf6_get_scoped_lsdb (u_int16_t type, void *scope)
|
|
|
|
{
|
|
|
|
struct ospf6_lsdb *lsdb = NULL;
|
|
|
|
|
|
|
|
if (scope == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch (OSPF6_LSA_SCOPE (type))
|
|
|
|
{
|
|
|
|
case OSPF6_LSA_SCOPE_AS:
|
|
|
|
lsdb = ((struct ospf6 *)(scope))->lsdb;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_AREA:
|
|
|
|
lsdb = ((struct ospf6_area *)(scope))->lsdb;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_LINKLOCAL:
|
|
|
|
lsdb = ((struct ospf6_interface *)(scope))->lsdb;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lsdb;
|
|
|
|
}
|
|
|
|
|
2004-05-18 21:28:32 +02:00
|
|
|
void
|
|
|
|
ospf6_decrement_onretrans (struct ospf6_lsa *lsa)
|
|
|
|
{
|
|
|
|
struct ospf6_lsdb *lsdb;
|
|
|
|
struct ospf6_lsa *src;
|
|
|
|
|
|
|
|
lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope);
|
|
|
|
if (lsdb == NULL)
|
|
|
|
{
|
|
|
|
zlog_warn ("Decrement onretrans: no such scope: %s", lsa->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
src = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
|
|
|
|
lsa->header->adv_router, lsdb);
|
|
|
|
if (src && src != lsa)
|
|
|
|
src->onretrans--;
|
|
|
|
|
|
|
|
if (src->onretrans < 0)
|
|
|
|
zlog_warn ("internal error: onretrans");
|
|
|
|
}
|
|
|
|
|
2004-05-18 21:14:52 +02:00
|
|
|
void
|
|
|
|
ospf6_flood_clear (struct ospf6_lsa *lsa)
|
|
|
|
{
|
|
|
|
struct ospf6_neighbor *on;
|
|
|
|
struct ospf6_interface *oi, *ospf6_if = NULL;
|
|
|
|
struct ospf6_area *oa, *area = NULL;
|
|
|
|
struct ospf6 *ospf6 = NULL;
|
|
|
|
u_int16_t scope_type;
|
|
|
|
list scoped_interfaces;
|
|
|
|
struct ospf6_lsa *rxmt;
|
|
|
|
listnode i, j;
|
|
|
|
|
|
|
|
scoped_interfaces = list_new ();
|
|
|
|
scope_type = OSPF6_LSA_SCOPE (lsa->header->type);
|
|
|
|
|
|
|
|
if (scope_type == OSPF6_LSA_SCOPE_LINKLOCAL)
|
|
|
|
{
|
|
|
|
ospf6_if = (struct ospf6_interface *) lsa->scope;
|
|
|
|
area = ospf6_if->area;
|
|
|
|
ospf6 = area->ospf6;
|
|
|
|
}
|
|
|
|
else if (scope_type == OSPF6_LSA_SCOPE_AREA)
|
|
|
|
{
|
|
|
|
area = (struct ospf6_area *) lsa->scope;
|
|
|
|
ospf6 = area->ospf6;
|
|
|
|
}
|
|
|
|
else if (scope_type == OSPF6_LSA_SCOPE_AS)
|
|
|
|
{
|
|
|
|
ospf6 = (struct ospf6 *) lsa->scope;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
zlog_warn ("Can't decide LSA scope, quit ospf6_flood_clear ()");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Collect eligible interfaces */
|
|
|
|
for (i = listhead (ospf6->area_list); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oa = (struct ospf6_area *) getdata (i);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS && oa != area)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = listhead (oa->if_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (j);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS &&
|
|
|
|
scope_type != OSPF6_LSA_SCOPE_AREA && oi != ospf6_if)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
listnode_add (scoped_interfaces, oi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = listhead (scoped_interfaces); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (i);
|
|
|
|
for (j = listhead (oi->neighbor_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
on = (struct ospf6_neighbor *) getdata (j);
|
|
|
|
rxmt = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
|
|
|
|
lsa->header->adv_router, on->retrans_list);
|
|
|
|
if (rxmt && ! ospf6_lsa_compare (rxmt, lsa))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info ("Remove %s from retrans_list of %s",
|
|
|
|
rxmt->name, on->name);
|
2004-05-18 21:28:32 +02:00
|
|
|
ospf6_decrement_onretrans (rxmt);
|
2004-05-18 21:14:52 +02:00
|
|
|
ospf6_lsdb_remove (rxmt, on->retrans_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete (scoped_interfaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RFC2328 section 13.2 Installing LSAs in the database */
|
|
|
|
void
|
|
|
|
ospf6_install_lsa (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
|
|
|
|
{
|
|
|
|
struct ospf6_lsa *old;
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info ("Install LSA: %s", lsa->name);
|
|
|
|
|
|
|
|
/* Remove the old instance from all neighbors' Link state
|
|
|
|
retransmission list (RFC2328 13.2 last paragraph) */
|
|
|
|
old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
|
|
|
|
lsa->header->adv_router, lsdb);
|
|
|
|
if (old)
|
|
|
|
ospf6_flood_clear (old);
|
|
|
|
|
|
|
|
/* actually install */
|
|
|
|
gettimeofday (&lsa->installed, (struct timezone *) NULL);
|
|
|
|
ospf6_lsdb_add (lsa, lsdb);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RFC2328 section 13.3 Next step in the flooding procedure */
|
|
|
|
void
|
|
|
|
ospf6_flood_lsa (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6 *scope_as = NULL;
|
|
|
|
struct ospf6_area *oa, *scope_area = NULL;
|
|
|
|
struct ospf6_interface *oi, *scope_linklocal = NULL;
|
|
|
|
struct ospf6_neighbor *on;
|
|
|
|
list eligible_interfaces;
|
|
|
|
listnode i, j;
|
|
|
|
u_int16_t scope_type;
|
|
|
|
struct ospf6_lsa *req;
|
|
|
|
int retrans_added = 0;
|
|
|
|
|
|
|
|
scope_type = OSPF6_LSA_SCOPE (lsa->header->type);
|
|
|
|
switch (scope_type)
|
|
|
|
{
|
|
|
|
case OSPF6_LSA_SCOPE_AS:
|
|
|
|
scope_as = (struct ospf6 *) lsa->scope;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_AREA:
|
|
|
|
scope_as = ((struct ospf6_area *) lsa->scope)->ospf6;
|
|
|
|
scope_area = (struct ospf6_area *) lsa->scope;
|
|
|
|
break;
|
|
|
|
case OSPF6_LSA_SCOPE_LINKLOCAL:
|
|
|
|
scope_as = ((struct ospf6_interface *) lsa->scope)->area->ospf6;
|
|
|
|
scope_area = ((struct ospf6_interface *) lsa->scope)->area;
|
|
|
|
scope_linklocal = (struct ospf6_interface *) lsa->scope;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND))
|
|
|
|
zlog_info ("Can't decide LSA scope");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND))
|
|
|
|
zlog_info ("Flood %s", lsa->name);
|
|
|
|
|
|
|
|
/* Collect eligible interfaces */
|
|
|
|
eligible_interfaces = list_new ();
|
|
|
|
for (i = listhead (scope_as->area_list); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oa = (struct ospf6_area *) getdata (i);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS &&
|
|
|
|
oa != scope_area)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = listhead (oa->if_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (j);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS &&
|
|
|
|
scope_type != OSPF6_LSA_SCOPE_AREA &&
|
|
|
|
oi != scope_linklocal)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
listnode_add (eligible_interfaces, oi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For each eligible interface: */
|
|
|
|
for (i = listhead (eligible_interfaces); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (i);
|
|
|
|
|
|
|
|
/* (1) For each neighbor */
|
|
|
|
for (j = listhead (oi->neighbor_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
on = (struct ospf6_neighbor *) getdata (j);
|
|
|
|
|
|
|
|
/* (a) if neighbor state < Exchange, examin next */
|
|
|
|
if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* (b) if neighbor not yet Full, check request-list */
|
|
|
|
if (on->state != OSPF6_NEIGHBOR_FULL)
|
|
|
|
{
|
|
|
|
req = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
|
|
|
|
lsa->header->adv_router,
|
|
|
|
on->request_list);
|
|
|
|
if (req)
|
|
|
|
{
|
|
|
|
/* If new LSA less recent, examin next neighbor */
|
|
|
|
if (ospf6_lsa_compare (lsa, req) > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If the same instance, delete from request-list and
|
|
|
|
examin next neighbor */
|
|
|
|
if (ospf6_lsa_compare (lsa, req) == 0)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info ("Remove %s from request-list of %s: "
|
|
|
|
"the same instance", req->name, on->name);
|
|
|
|
ospf6_lsdb_remove (req, on->request_list);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the new LSA is more recent, delete from
|
|
|
|
request-list */
|
|
|
|
if (ospf6_lsa_compare (lsa, req) < 0)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info ("Remove %s from request-list of %s: "
|
|
|
|
"newer instance", req->name, on->name);
|
|
|
|
ospf6_lsdb_remove (req, on->request_list);
|
|
|
|
/* fall through */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (c) If the new LSA was received from this neighbor,
|
|
|
|
examin next neighbor */
|
|
|
|
if (from == on)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* (d) add retrans-list, schedule retransmission */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to retrans-list of %s",
|
|
|
|
lsa->name, on->name);
|
2004-05-18 21:28:32 +02:00
|
|
|
lsa->onretrans++;
|
2004-05-18 21:14:52 +02:00
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list);
|
|
|
|
if (on->thread_send_lsupdate == NULL)
|
|
|
|
on->thread_send_lsupdate =
|
|
|
|
thread_add_event (master, ospf6_lsupdate_send_neighbor,
|
|
|
|
on, on->ospf6_if->rxmt_interval);
|
|
|
|
retrans_added++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) examin next interface if not added to retrans-list */
|
|
|
|
if (retrans_added == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* (3) If the new LSA was received on this interface,
|
|
|
|
and it was from DR or BDR, examin next interface */
|
|
|
|
if (from && from->ospf6_if == oi &&
|
|
|
|
(from->router_id == oi->drouter || from->router_id == oi->bdrouter))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* (4) If the new LSA was received on this interface,
|
|
|
|
and the interface state is BDR, examin next interface */
|
|
|
|
if (from && from->ospf6_if == oi && oi->state == OSPF6_INTERFACE_BDR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* (5) flood the LSA out the interface. */
|
|
|
|
if (if_is_broadcast (oi->interface))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (SEND) || IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsupdate_list of %s",
|
|
|
|
lsa->name, oi->interface->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list);
|
|
|
|
if (oi->thread_send_lsupdate == NULL)
|
|
|
|
oi->thread_send_lsupdate =
|
|
|
|
thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (j = listhead (oi->neighbor_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
on = (struct ospf6_neighbor *) getdata (j);
|
|
|
|
THREAD_OFF (on->thread_send_lsupdate);
|
|
|
|
on->thread_send_lsupdate =
|
|
|
|
thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete (eligible_interfaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */
|
|
|
|
static void
|
|
|
|
ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent,
|
|
|
|
struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
|
|
|
|
assert (from && from->ospf6_if);
|
|
|
|
oi = from->ospf6_if;
|
|
|
|
|
|
|
|
/* LSA has been flood back out receiving interface.
|
|
|
|
No acknowledgement sent. */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" BDR, FloodBack, No acknowledgement.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is more recent than database copy, but was not flooded
|
|
|
|
back out receiving interface. Delayed acknowledgement sent
|
|
|
|
if advertisement received from Designated Router,
|
|
|
|
otherwide do nothing. */
|
|
|
|
if (ismore_recent < 0)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" BDR, Not FloodBack, MoreRecent, ");
|
|
|
|
if (oi->drouter == from->router_id)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" From DR, Delayed acknowledgement.");
|
|
|
|
/* Delayed acknowledgement */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsack_list of %s",
|
|
|
|
lsa->name, oi->interface->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list);
|
|
|
|
if (oi->thread_send_lsack == NULL)
|
|
|
|
oi->thread_send_lsack =
|
|
|
|
thread_add_timer (master, ospf6_lsack_send_interface, oi, 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" Not From DR, No acknowledgement.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is a duplicate, and was treated as an implied acknowledgement.
|
|
|
|
Delayed acknowledgement sent if advertisement received from
|
|
|
|
Designated Router, otherwise do nothing */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) &&
|
|
|
|
CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" BDR, Duplicate, ImpliedAck, ");
|
|
|
|
if (oi->drouter == from->router_id)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" From DR, Delayed acknowledgement.");
|
|
|
|
/* Delayed acknowledgement */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsack_list of %s",
|
|
|
|
lsa->name, oi->interface->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list);
|
|
|
|
if (oi->thread_send_lsack == NULL)
|
|
|
|
oi->thread_send_lsack =
|
|
|
|
thread_add_timer (master, ospf6_lsack_send_interface, oi, 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" Not From DR, No acknowledgement.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is a duplicate, and was not treated as an implied acknowledgement.
|
|
|
|
Direct acknowledgement sent */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) &&
|
|
|
|
! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" BDR, Duplicate, Not ImpliedAck, Direct acknowledgement.");
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsack_list of %s",
|
|
|
|
lsa->name, from->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list);
|
|
|
|
if (from->thread_send_lsack == NULL)
|
|
|
|
from->thread_send_lsack =
|
|
|
|
thread_add_event (master, ospf6_lsack_send_neighbor, from, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA's LS age is equal to Maxage, and there is no current instance
|
|
|
|
of the LSA in the link state database, and none of router's
|
|
|
|
neighbors are in states Exchange or Loading */
|
|
|
|
/* Direct acknowledgement sent, but this case is handled in
|
|
|
|
early of ospf6_receive_lsa () */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ospf6_acknowledge_lsa_allother (struct ospf6_lsa *lsa, int ismore_recent,
|
|
|
|
struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
|
|
|
|
assert (from && from->ospf6_if);
|
|
|
|
oi = from->ospf6_if;
|
|
|
|
|
|
|
|
/* LSA has been flood back out receiving interface.
|
|
|
|
No acknowledgement sent. */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" AllOther, FloodBack, No acknowledgement.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is more recent than database copy, but was not flooded
|
|
|
|
back out receiving interface. Delayed acknowledgement sent. */
|
|
|
|
if (ismore_recent < 0)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" AllOther, Not FloodBack, Delayed acknowledgement.");
|
|
|
|
/* Delayed acknowledgement */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsack_list of %s",
|
|
|
|
lsa->name, oi->interface->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list);
|
|
|
|
if (oi->thread_send_lsack == NULL)
|
|
|
|
oi->thread_send_lsack =
|
|
|
|
thread_add_timer (master, ospf6_lsack_send_interface, oi, 3);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is a duplicate, and was treated as an implied acknowledgement.
|
|
|
|
No acknowledgement sent. */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) &&
|
|
|
|
CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" AllOther, Duplicate, ImpliedAck, No acknowledgement.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA is a duplicate, and was not treated as an implied acknowledgement.
|
|
|
|
Direct acknowledgement sent */
|
|
|
|
if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) &&
|
|
|
|
! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info (" AllOther, Duplicate, Not ImpliedAck, Direct acknowledgement.");
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsack_list of %s",
|
|
|
|
lsa->name, from->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list);
|
|
|
|
if (from->thread_send_lsack == NULL)
|
|
|
|
from->thread_send_lsack =
|
|
|
|
thread_add_event (master, ospf6_lsack_send_neighbor, from, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LSA's LS age is equal to Maxage, and there is no current instance
|
|
|
|
of the LSA in the link state database, and none of router's
|
|
|
|
neighbors are in states Exchange or Loading */
|
|
|
|
/* Direct acknowledgement sent, but this case is handled in
|
|
|
|
early of ospf6_receive_lsa () */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ospf6_acknowledge_lsa (struct ospf6_lsa *lsa, int ismore_recent,
|
|
|
|
struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6_interface *oi;
|
|
|
|
|
|
|
|
assert (from && from->ospf6_if);
|
|
|
|
oi = from->ospf6_if;
|
|
|
|
|
|
|
|
if (oi->state == OSPF6_INTERFACE_BDR)
|
|
|
|
ospf6_acknowledge_lsa_bdrouter (lsa, ismore_recent, from);
|
|
|
|
else
|
|
|
|
ospf6_acknowledge_lsa_allother (lsa, ismore_recent, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RFC2328 section 13 (4):
|
|
|
|
if MaxAge LSA and if we have no instance, and no neighbor
|
|
|
|
is in states Exchange or Loading
|
|
|
|
returns 1 if match this case, else returns 0 */
|
|
|
|
static int
|
|
|
|
ospf6_is_maxage_lsa_drop (struct ospf6_lsa *lsa,
|
|
|
|
struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6_lsdb *lsdb = NULL;
|
|
|
|
struct ospf6_neighbor *on;
|
|
|
|
struct ospf6_interface *oi, *ospf6_if = NULL;
|
|
|
|
struct ospf6_area *oa, *area = NULL;
|
|
|
|
struct ospf6 *ospf6 = NULL;
|
|
|
|
u_int16_t scope_type;
|
|
|
|
list scoped_interfaces;
|
|
|
|
listnode i, j;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
if (! OSPF6_LSA_IS_MAXAGE (lsa))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope);
|
|
|
|
if (lsdb == NULL)
|
|
|
|
{
|
|
|
|
zlog_info ("Can't decide scoped LSDB");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
|
|
|
|
lsa->header->adv_router, lsdb))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
scoped_interfaces = list_new ();
|
|
|
|
scope_type = OSPF6_LSA_SCOPE (lsa->header->type);
|
|
|
|
|
|
|
|
if (scope_type == OSPF6_LSA_SCOPE_LINKLOCAL)
|
|
|
|
{
|
|
|
|
ospf6_if = (struct ospf6_interface *) lsa->scope;
|
|
|
|
area = ospf6_if->area;
|
|
|
|
ospf6 = area->ospf6;
|
|
|
|
}
|
|
|
|
else if (scope_type == OSPF6_LSA_SCOPE_AREA)
|
|
|
|
{
|
|
|
|
area = (struct ospf6_area *) lsa->scope;
|
|
|
|
ospf6 = area->ospf6;
|
|
|
|
}
|
|
|
|
else if (scope_type == OSPF6_LSA_SCOPE_AS)
|
|
|
|
{
|
|
|
|
ospf6 = (struct ospf6 *) lsa->scope;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
zlog_info ("Can't decide LSA scope");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Collect eligible interfaces */
|
|
|
|
for (i = listhead (ospf6->area_list); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oa = (struct ospf6_area *) getdata (i);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS && oa != area)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = listhead (oa->if_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (j);
|
|
|
|
if (scope_type != OSPF6_LSA_SCOPE_AS &&
|
|
|
|
scope_type != OSPF6_LSA_SCOPE_AREA && oi != ospf6_if)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
listnode_add (scoped_interfaces, oi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = listhead (scoped_interfaces); i; nextnode (i))
|
|
|
|
{
|
|
|
|
oi = (struct ospf6_interface *) getdata (i);
|
|
|
|
for (j = listhead (oi->neighbor_list); j; nextnode (j))
|
|
|
|
{
|
|
|
|
on = (struct ospf6_neighbor *) getdata (j);
|
|
|
|
if (on->state == OSPF6_NEIGHBOR_EXCHANGE ||
|
|
|
|
on->state == OSPF6_NEIGHBOR_LOADING)
|
|
|
|
count ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
list_delete (scoped_interfaces);
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RFC2328 section 13 The Flooding Procedure */
|
|
|
|
void
|
|
|
|
ospf6_receive_lsa (struct ospf6_lsa_header *lsa_header,
|
|
|
|
struct ospf6_neighbor *from)
|
|
|
|
{
|
|
|
|
struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
|
|
|
|
int ismore_recent;
|
|
|
|
unsigned short cksum;
|
|
|
|
struct ospf6_lsdb *lsdb = NULL;
|
|
|
|
|
|
|
|
ismore_recent = 1;
|
|
|
|
|
|
|
|
/* make lsa structure for received lsa */
|
|
|
|
new = ospf6_lsa_create (lsa_header);
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
{
|
|
|
|
zlog_info ("LSA Receive from %s", from->name);
|
|
|
|
ospf6_lsa_header_print (new);
|
|
|
|
}
|
|
|
|
|
|
|
|
new->scope = ospf6_get_lsa_scope (new->header->type, from);
|
|
|
|
if (new->scope == NULL)
|
|
|
|
{
|
|
|
|
zlog_warn ("Can't decide LSA scope, ignore");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (1) LSA Checksum */
|
|
|
|
cksum = ntohs (new->header->checksum);
|
|
|
|
if (ntohs (ospf6_lsa_checksum (new->header)) != cksum)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Wrong LSA Checksum");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Ebit Missmatch: AS-External-LSA */
|
|
|
|
if (ntohs (new->header->type) == OSPF6_LSTYPE_AS_EXTERNAL &&
|
|
|
|
ospf6_area_is_stub (from->ospf6_if->area))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("AS-External-LSA in stub area");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) if MaxAge LSA and if we have no instance, and no neighbor
|
|
|
|
is in states Exchange or Loading */
|
|
|
|
if (ospf6_is_maxage_lsa_drop (new, from))
|
|
|
|
{
|
|
|
|
/* log */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Drop MaxAge LSA with Direct acknowledgement.");
|
|
|
|
|
|
|
|
/* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add %s to lsack_list of %s",
|
|
|
|
new->name, from->name);
|
|
|
|
ospf6_lsdb_add (new, from->lsack_list);
|
|
|
|
if (from->thread_send_lsack == NULL)
|
|
|
|
from->thread_send_lsack =
|
|
|
|
thread_add_event (master, ospf6_lsack_send_neighbor, from, 0);
|
|
|
|
|
|
|
|
/* b) Discard */
|
|
|
|
/* "new" LSA will be discarded just after the LSAck sent */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (5) */
|
|
|
|
/* lookup the same database copy in lsdb */
|
|
|
|
lsdb = ospf6_get_scoped_lsdb (new->header->type, new->scope);
|
|
|
|
if (lsdb == NULL)
|
|
|
|
{
|
|
|
|
zlog_warn ("Can't decide scoped LSDB, ignore");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old = ospf6_lsdb_lookup (new->header->type, new->header->id,
|
|
|
|
new->header->adv_router, lsdb);
|
|
|
|
if (old)
|
|
|
|
{
|
|
|
|
ismore_recent = ospf6_lsa_compare (new, old);
|
|
|
|
if (ntohl (new->header->seqnum) == ntohl (old->header->seqnum))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Duplicated LSA");
|
|
|
|
SET_FLAG (new->flag, OSPF6_LSA_DUPLICATE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if no database copy or received is more recent */
|
|
|
|
if (old == NULL || ismore_recent < 0)
|
|
|
|
{
|
|
|
|
/* in case we have no database copy */
|
|
|
|
ismore_recent = -1;
|
|
|
|
|
|
|
|
/* (a) MinLSArrival check */
|
|
|
|
if (old)
|
|
|
|
{
|
|
|
|
struct timeval now, res;
|
|
|
|
gettimeofday (&now, (struct timezone *) NULL);
|
|
|
|
timersub (&now, &old->installed, &res);
|
|
|
|
if (res.tv_sec < MIN_LS_ARRIVAL)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (TIMER))
|
|
|
|
zlog_info ("LSA can't be updated within MinLSArrival");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return; /* examin next lsa */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (b) immediately flood and (c) remove from all retrans-list */
|
|
|
|
ospf6_flood_lsa (new, from);
|
|
|
|
|
|
|
|
/* (d), installing lsdb, which may cause routing
|
|
|
|
table calculation (replacing database copy) */
|
|
|
|
ospf6_install_lsa (new, lsdb);
|
|
|
|
|
|
|
|
/* (e) possibly acknowledge */
|
|
|
|
ospf6_acknowledge_lsa (new, ismore_recent, from);
|
|
|
|
|
|
|
|
/* (f) */
|
|
|
|
/* Self Originated LSA, section 13.4 */
|
|
|
|
if (new->header->adv_router == from->ospf6_if->area->ospf6->router_id
|
|
|
|
&& (! old || ismore_recent < 0))
|
|
|
|
{
|
|
|
|
/* We have to make a new instance of the LSA
|
|
|
|
or have to flush this LSA. */
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("New instance of the self-originated LSA");
|
|
|
|
|
|
|
|
SET_FLAG (new->flag, OSPF6_LSA_REFRESH);
|
|
|
|
ospf6_lsa_re_originate (new);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (6) if there is instance on sending neighbor's request list */
|
|
|
|
if (ospf6_lsdb_lookup (new->header->type, new->header->id,
|
|
|
|
new->header->adv_router, from->request_list))
|
|
|
|
{
|
|
|
|
/* if no database copy, should go above state (5) */
|
|
|
|
assert (old);
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("LSA is not newer and on request-list of sending neighbor");
|
|
|
|
|
|
|
|
/* BadLSReq */
|
|
|
|
thread_add_event (master, bad_lsreq, from, 0);
|
|
|
|
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (7) if neither one is more recent */
|
|
|
|
if (ismore_recent == 0)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("The same instance as database copy");
|
|
|
|
|
|
|
|
/* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack */
|
|
|
|
rem = ospf6_lsdb_lookup (new->header->type, new->header->id,
|
|
|
|
new->header->adv_router, from->retrans_list);
|
|
|
|
if (rem)
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Treat as an Implied acknowledgement");
|
|
|
|
SET_FLAG (new->flag, OSPF6_LSA_IMPLIEDACK);
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info ("Remove %s from retrans_list of %s",
|
|
|
|
rem->name, from->name);
|
2004-05-18 21:28:32 +02:00
|
|
|
ospf6_decrement_onretrans (rem);
|
2004-05-18 21:14:52 +02:00
|
|
|
ospf6_lsdb_remove (rem, from->retrans_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (b) possibly acknowledge */
|
|
|
|
ospf6_acknowledge_lsa (new, ismore_recent, from);
|
|
|
|
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (8) previous database copy is more recent */
|
|
|
|
{
|
|
|
|
assert (old);
|
|
|
|
|
|
|
|
/* If database copy is in 'Seqnumber Wrapping',
|
|
|
|
simply discard the received LSA */
|
|
|
|
if (OSPF6_LSA_IS_MAXAGE (old) &&
|
|
|
|
old->header->seqnum == htonl (MAX_SEQUENCE_NUMBER))
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Database copy is in Seqnumber Wrapping");
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise, Send database copy of this LSA to this neighbor */
|
|
|
|
{
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (RECV))
|
|
|
|
zlog_info ("Database is more recent, send back directly");
|
|
|
|
|
|
|
|
/* XXX, MinLSArrival check !? RFC 2328 13 (8) */
|
|
|
|
|
|
|
|
if (IS_OSPF6_DEBUG_LSA (DATABASE))
|
|
|
|
zlog_info (" Add copy of %s to lsupdate_list of %s",
|
|
|
|
old->name, from->name);
|
|
|
|
ospf6_lsdb_add (ospf6_lsa_copy (old), from->lsupdate_list);
|
|
|
|
if (from->thread_send_lsupdate == NULL)
|
|
|
|
from->thread_send_lsupdate =
|
|
|
|
thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0);
|
|
|
|
ospf6_lsa_delete (new);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|