frr/ospfd/ospf_interface.c
paul 1eb8ef2584 2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
	  and some basic auditing of usage.
	* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
	* HACKING: Add notes about deprecating interfaces and commands.
	* lib/linklist.h: Add usage comments.
	  Rename getdata macro to listgetdata.
	  Rename nextnode to listnextnode and fix its odd behaviour to be
	  less dangerous.
	  Make listgetdata macro assert node is not null, NULL list entries
          should be bug condition.
          ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
          with for loop, Suggested by Jim Carlson of Sun.
          Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
          "safety" of previous macro.
	  LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
	  distinguish from the similarly named functions, and reflect their
	  effect better.
	  Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
	  with the old defines which were modified above,
	  for backwards compatibility - guarded to prevent Quagga using it..
	* lib/linklist.c: fix up for linklist.h changes.
	* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
	  scan of the area list, rather than scanning all areas first for
	  INTER_ROUTER and then again for INTER_NETWORK. According to
	  16.2, the scan should be area specific anyway, and further
	  ospf6d does not seem to implement 16.3 anyway.
2005-04-07 07:30:20 +00:00

1249 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* OSPF Interface functions.
* Copyright (C) 1999, 2000 Toshiaki Takada
*
* 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 "thread.h"
#include "linklist.h"
#include "prefix.h"
#include "if.h"
#include "table.h"
#include "memory.h"
#include "command.h"
#include "stream.h"
#include "log.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_spf.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_ism.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
#include "ospfd/ospf_neighbor.h"
#include "ospfd/ospf_nsm.h"
#include "ospfd/ospf_packet.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_dump.h"
#ifdef HAVE_SNMP
#include "ospfd/ospf_snmp.h"
#endif /* HAVE_SNMP */
int
ospf_if_get_output_cost (struct ospf_interface *oi)
{
/* If all else fails, use default OSPF cost */
u_int32_t cost;
u_int32_t bw, refbw;
bw = oi->ifp->bandwidth ? oi->ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH;
refbw = oi->ospf->ref_bandwidth;
/* A specifed ip ospf cost overrides a calculated one. */
if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), output_cost_cmd) ||
OSPF_IF_PARAM_CONFIGURED (oi->params, output_cost_cmd))
cost = OSPF_IF_PARAM (oi, output_cost_cmd);
/* See if a cost can be calculated from the zebra processes
interface bandwidth field. */
else
{
cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5);
if (cost < 1)
cost = 1;
else if (cost > 65535)
cost = 65535;
}
return cost;
}
void
ospf_if_recalculate_output_cost (struct interface *ifp)
{
u_int32_t newcost;
struct route_node *rn;
for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
{
struct ospf_interface *oi;
if ( (oi = rn->info) == NULL)
continue;
newcost = ospf_if_get_output_cost (oi);
/* Is actual output cost changed? */
if (oi->output_cost != newcost)
{
oi->output_cost = newcost;
ospf_router_lsa_timer_add (oi->area);
}
}
}
/* Simulate down/up on the interface. This is needed, for example, when
the MTU changes. */
void
ospf_if_reset(struct interface *ifp)
{
struct route_node *rn;
for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
{
struct ospf_interface *oi;
if ( (oi = rn->info) == NULL)
continue;
ospf_if_down(oi);
ospf_if_up(oi);
}
}
void
ospf_if_reset_variables (struct ospf_interface *oi)
{
/* Set default values. */
/* don't clear this flag. oi->flag = OSPF_IF_DISABLE; */
if (oi->vl_data)
oi->type = OSPF_IFTYPE_VIRTUALLINK;
else
/* preserve network-type */
if (oi->type != OSPF_IFTYPE_NBMA)
oi->type = OSPF_IFTYPE_BROADCAST;
oi->state = ISM_Down;
oi->crypt_seqnum = 0;
/* This must be short, (less than RxmtInterval)
- RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being
held back for too long - MAG */
oi->v_ls_ack = 1;
}
/* lookup oi for specified prefix/ifp */
struct ospf_interface *
ospf_if_table_lookup (struct interface *ifp, struct prefix *prefix)
{
struct prefix p;
struct route_node *rn;
struct ospf_interface *rninfo;
p = *prefix;
rn = route_node_get (IF_OIFS (ifp), &p);
/* route_node_get implicitely locks */
rninfo = (struct ospf_interface *) rn->info;
route_unlock_node (rn);
return rninfo;
}
void
ospf_add_to_if (struct interface *ifp, struct ospf_interface *oi)
{
struct route_node *rn;
struct prefix p;
p = *oi->address;
p.prefixlen = IPV4_MAX_PREFIXLEN;
rn = route_node_get (IF_OIFS (ifp), &p);
/* rn->info should either be NULL or equal to this oi
* as route_node_get may return an existing node
*/
assert (!rn->info || rn->info == oi);
rn->info = oi;
}
void
ospf_delete_from_if (struct interface *ifp, struct ospf_interface *oi)
{
struct route_node *rn;
struct prefix p;
p = *oi->address;
p.prefixlen = IPV4_MAX_PREFIXLEN;
rn = route_node_lookup (IF_OIFS (oi->ifp), &p);
assert (rn);
assert (rn->info);
rn->info = NULL;
route_unlock_node (rn);
route_unlock_node (rn);
}
struct ospf_interface *
ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p)
{
struct ospf_interface *oi;
if ((oi = ospf_if_table_lookup (ifp, p)) == NULL)
{
oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface));
memset (oi, 0, sizeof (struct ospf_interface));
}
else
return oi;
/* Set zebra interface pointer. */
oi->ifp = ifp;
oi->address = p;
ospf_add_to_if (ifp, oi);
listnode_add (ospf->oiflist, oi);
/* Clear self-originated network-LSA. */
oi->network_lsa_self = NULL;
/* Initialize neighbor list. */
oi->nbrs = route_table_init ();
/* Initialize static neighbor list. */
oi->nbr_nbma = list_new ();
/* Initialize Link State Acknowledgment list. */
oi->ls_ack = list_new ();
oi->ls_ack_direct.ls_ack = list_new ();
/* Set default values. */
ospf_if_reset_variables (oi);
/* Add pseudo neighbor. */
oi->nbr_self = ospf_nbr_new (oi);
oi->nbr_self->state = NSM_TwoWay;
oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority);
oi->nbr_self->options = OSPF_OPTION_E;
oi->ls_upd_queue = route_table_init ();
oi->t_ls_upd_event = NULL;
oi->t_ls_ack_direct = NULL;
oi->crypt_seqnum = time (NULL);
#ifdef HAVE_OPAQUE_LSA
ospf_opaque_type9_lsa_init (oi);
#endif /* HAVE_OPAQUE_LSA */
oi->ospf = ospf;
return oi;
}
/* Restore an interface to its pre UP state
Used from ism_interface_down only */
void
ospf_if_cleanup (struct ospf_interface *oi)
{
struct route_node *rn;
struct listnode *node, *nnode;
struct ospf_neighbor *nbr;
struct ospf_nbr_nbma *nbr_nbma;
struct ospf_lsa *lsa;
/* oi->nbrs and oi->nbr_nbma should be deletete on InterafceDown event */
/* delete all static neighbors attached to this interface */
for (ALL_LIST_ELEMENTS (oi->nbr_nbma, node, nnode, nbr_nbma))
{
OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
if (nbr_nbma->nbr)
{
nbr_nbma->nbr->nbr_nbma = NULL;
nbr_nbma->nbr = NULL;
}
nbr_nbma->oi = NULL;
listnode_delete (oi->nbr_nbma, nbr_nbma);
}
/* send Neighbor event KillNbr to all associated neighbors. */
for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
if ((nbr = rn->info) != NULL)
if (nbr != oi->nbr_self)
OSPF_NSM_EVENT_EXECUTE (nbr, NSM_KillNbr);
/* Cleanup Link State Acknowlegdment list. */
for (ALL_LIST_ELEMENTS (oi->ls_ack, node, nnode, lsa))
ospf_lsa_unlock (lsa);
list_delete_all_node (oi->ls_ack);
oi->crypt_seqnum = 0;
/* Empty link state update queue */
ospf_ls_upd_queue_empty (oi);
/* Handle pseudo neighbor. */
ospf_nbr_delete (oi->nbr_self);
oi->nbr_self = ospf_nbr_new (oi);
oi->nbr_self->state = NSM_TwoWay;
oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority);
switch (oi->area->external_routing)
{
case OSPF_AREA_DEFAULT:
SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
break;
case OSPF_AREA_STUB:
UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
break;
case OSPF_AREA_NSSA:
UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E);
SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP);
break;
}
ospf_lsa_unlock (oi->network_lsa_self);
oi->network_lsa_self = NULL;
OSPF_TIMER_OFF (oi->t_network_lsa_self);
}
void
ospf_if_free (struct ospf_interface *oi)
{
ospf_if_down (oi);
assert (oi->state == ISM_Down);
#ifdef HAVE_OPAQUE_LSA
ospf_opaque_type9_lsa_term (oi);
#endif /* HAVE_OPAQUE_LSA */
/* Free Pseudo Neighbour */
ospf_nbr_delete (oi->nbr_self);
route_table_finish (oi->nbrs);
route_table_finish (oi->ls_upd_queue);
/* Free any lists that should be freed */
list_free (oi->nbr_nbma);
list_free (oi->ls_ack);
list_free (oi->ls_ack_direct.ls_ack);
ospf_delete_from_if (oi->ifp, oi);
listnode_delete (oi->ospf->oiflist, oi);
listnode_delete (oi->area->oiflist, oi);
memset (oi, 0, sizeof (*oi));
XFREE (MTYPE_OSPF_IF, oi);
}
/*
* check if interface with given address is configured and
* return it if yes. special treatment for PtP networks.
*/
struct ospf_interface *
ospf_if_is_configured (struct ospf *ospf, struct in_addr *address)
{
struct listnode *node, *nnode;
struct ospf_interface *oi;
struct prefix_ipv4 addr;
addr.family = AF_INET;
addr.prefix = *address;
addr.prefixlen = IPV4_MAX_PREFIXLEN;
for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
{
if (oi->type == OSPF_IFTYPE_POINTOPOINT)
{
if (CONNECTED_DEST_HOST(oi->connected))
{
/* match only destination addr, since local addr is most likely
* not unique (borrowed from another interface) */
if (IPV4_ADDR_SAME (address,
&oi->connected->destination->u.prefix4))
return oi;
}
else
{
/* special leniency: match if addr is anywhere on PtP subnet */
if (prefix_match(oi->address,(struct prefix *)&addr))
return oi;
}
}
else
{
if (IPV4_ADDR_SAME (address, &oi->address->u.prefix4))
return oi;
}
}
return NULL;
}
int
ospf_if_is_up (struct ospf_interface *oi)
{
return if_is_up (oi->ifp);
}
struct ospf_interface *
ospf_if_exists (struct ospf_interface *oic)
{
struct listnode *node;
struct ospf *ospf;
struct ospf_interface *oi;
ospf = ospf_lookup ();
for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
if (oi == oic)
return oi;
return NULL;
}
struct ospf_interface *
ospf_if_lookup_by_local_addr (struct ospf *ospf,
struct interface *ifp, struct in_addr address)
{
struct listnode *node;
struct ospf_interface *oi;
for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
{
if (ifp && oi->ifp != ifp)
continue;
if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4))
return oi;
}
return NULL;
}
struct ospf_interface *
ospf_if_lookup_by_prefix (struct ospf *ospf, struct prefix_ipv4 *p)
{
struct listnode *node;
struct ospf_interface *oi;
struct prefix ptmp;
/* Check each Interface. */
for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
{
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
{
if ((oi->type == OSPF_IFTYPE_POINTOPOINT) &&
CONNECTED_DEST_HOST(oi->connected))
{
prefix_copy (&ptmp, oi->connected->destination);
ptmp.prefixlen = IPV4_MAX_BITLEN;
}
else
prefix_copy (&ptmp, oi->address);
apply_mask (&ptmp);
if (prefix_same (&ptmp, (struct prefix *) p))
return oi;
}
}
return NULL;
}
/* determine receiving interface by source of packet */
struct ospf_interface *
ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src)
{
struct listnode *node;
struct prefix_ipv4 addr;
struct ospf_interface *oi, *match;
addr.family = AF_INET;
addr.prefix = src;
addr.prefixlen = IPV4_MAX_BITLEN;
match = NULL;
for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
{
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
continue;
if ((oi->type == OSPF_IFTYPE_POINTOPOINT) &&
CONNECTED_DEST_HOST(oi->connected))
{
if (IPV4_ADDR_SAME (&oi->connected->destination->u.prefix4, &src))
return oi;
}
else
{
if (prefix_match (oi->address, (struct prefix *) &addr))
{
if ( (match == NULL) ||
(match->address->prefixlen < oi->address->prefixlen)
)
match = oi;
}
}
}
return match;
}
void
ospf_if_stream_set (struct ospf_interface *oi)
{
/* set output fifo queue. */
if (oi->obuf == NULL)
oi->obuf = ospf_fifo_new ();
}
void
ospf_if_stream_unset (struct ospf_interface *oi)
{
struct ospf *ospf = oi->ospf;
if (oi->obuf)
{
ospf_fifo_free (oi->obuf);
oi->obuf = NULL;
if (oi->on_write_q)
{
listnode_delete (ospf->oi_write_q, oi);
if (list_isempty(ospf->oi_write_q))
OSPF_TIMER_OFF (ospf->t_write);
oi->on_write_q = 0;
}
}
}
struct ospf_if_params *
ospf_new_if_params ()
{
struct ospf_if_params *oip;
oip = XMALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params));
if (!oip)
return NULL;
memset (oip, 0, sizeof (struct ospf_if_params));
UNSET_IF_PARAM (oip, output_cost_cmd);
UNSET_IF_PARAM (oip, transmit_delay);
UNSET_IF_PARAM (oip, retransmit_interval);
UNSET_IF_PARAM (oip, passive_interface);
UNSET_IF_PARAM (oip, v_hello);
UNSET_IF_PARAM (oip, v_wait);
UNSET_IF_PARAM (oip, priority);
UNSET_IF_PARAM (oip, type);
UNSET_IF_PARAM (oip, auth_simple);
UNSET_IF_PARAM (oip, auth_crypt);
UNSET_IF_PARAM (oip, auth_type);
oip->auth_crypt = list_new ();
return oip;
}
void
ospf_del_if_params (struct ospf_if_params *oip)
{
list_delete (oip->auth_crypt);
XFREE (MTYPE_OSPF_IF_PARAMS, oip);
}
void
ospf_free_if_params (struct interface *ifp, struct in_addr addr)
{
struct ospf_if_params *oip;
struct prefix_ipv4 p;
struct route_node *rn;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_PREFIXLEN;
p.prefix = addr;
rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
if (!rn || !rn->info)
return;
oip = rn->info;
route_unlock_node (rn);
if (!OSPF_IF_PARAM_CONFIGURED (oip, output_cost_cmd) &&
!OSPF_IF_PARAM_CONFIGURED (oip, transmit_delay) &&
!OSPF_IF_PARAM_CONFIGURED (oip, retransmit_interval) &&
!OSPF_IF_PARAM_CONFIGURED (oip, passive_interface) &&
!OSPF_IF_PARAM_CONFIGURED (oip, v_hello) &&
!OSPF_IF_PARAM_CONFIGURED (oip, v_wait) &&
!OSPF_IF_PARAM_CONFIGURED (oip, priority) &&
!OSPF_IF_PARAM_CONFIGURED (oip, type) &&
!OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) &&
!OSPF_IF_PARAM_CONFIGURED (oip, auth_type) &&
listcount (oip->auth_crypt) == 0)
{
ospf_del_if_params (oip);
rn->info = NULL;
route_unlock_node (rn);
}
}
struct ospf_if_params *
ospf_lookup_if_params (struct interface *ifp, struct in_addr addr)
{
struct prefix_ipv4 p;
struct route_node *rn;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_PREFIXLEN;
p.prefix = addr;
rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
if (rn)
{
route_unlock_node (rn);
return rn->info;
}
return NULL;
}
struct ospf_if_params *
ospf_get_if_params (struct interface *ifp, struct in_addr addr)
{
struct prefix_ipv4 p;
struct route_node *rn;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_PREFIXLEN;
p.prefix = addr;
rn = route_node_get (IF_OIFS_PARAMS (ifp), (struct prefix*)&p);
if (rn->info == NULL)
rn->info = ospf_new_if_params ();
else
route_unlock_node (rn);
return rn->info;
}
void
ospf_if_update_params (struct interface *ifp, struct in_addr addr)
{
struct route_node *rn;
struct ospf_interface *oi;
for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
{
if ((oi = rn->info) == NULL)
continue;
if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &addr))
oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
}
}
int
ospf_if_new_hook (struct interface *ifp)
{
int rc = 0;
ifp->info = XMALLOC (MTYPE_OSPF_IF_INFO, sizeof (struct ospf_if_info));
memset (ifp->info, 0, sizeof (struct ospf_if_info));
IF_OIFS (ifp) = route_table_init ();
IF_OIFS_PARAMS (ifp) = route_table_init ();
IF_DEF_PARAMS (ifp) = ospf_new_if_params ();
SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay);
IF_DEF_PARAMS (ifp)->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval);
IF_DEF_PARAMS (ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), priority);
IF_DEF_PARAMS (ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface);
IF_DEF_PARAMS (ifp)->passive_interface = OSPF_IF_ACTIVE;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
IF_DEF_PARAMS (ifp)->v_hello = OSPF_HELLO_INTERVAL_DEFAULT;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
IF_DEF_PARAMS (ifp)->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_simple);
memset (IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE);
SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET;
#ifdef HAVE_OPAQUE_LSA
rc = ospf_opaque_new_if (ifp);
#endif /* HAVE_OPAQUE_LSA */
return rc;
}
int
ospf_if_delete_hook (struct interface *ifp)
{
int rc = 0;
struct route_node *rn;
#ifdef HAVE_OPAQUE_LSA
rc = ospf_opaque_del_if (ifp);
#endif /* HAVE_OPAQUE_LSA */
route_table_finish (IF_OIFS (ifp));
for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
if (rn->info)
ospf_del_if_params (rn->info);
route_table_finish (IF_OIFS_PARAMS (ifp));
ospf_del_if_params ((struct ospf_if_params *) IF_DEF_PARAMS (ifp));
XFREE (MTYPE_OSPF_IF_INFO, ifp->info);
ifp->info = NULL;
return rc;
}
int
ospf_if_is_enable (struct ospf_interface *oi)
{
if (!if_is_loopback (oi->ifp))
if (if_is_up (oi->ifp))
return 1;
return 0;
}
void
ospf_if_set_multicast(struct ospf_interface *oi)
{
if ((oi->state > ISM_Loopback) &&
(oi->type != OSPF_IFTYPE_LOOPBACK) &&
(oi->type != OSPF_IFTYPE_VIRTUALLINK) &&
(OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
{
/* The interface should belong to the OSPF-all-routers group. */
if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS) &&
(ospf_if_add_allspfrouters(oi->ospf, oi->address,
oi->ifp->ifindex) >= 0))
/* Set the flag only if the system call to join succeeded. */
SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
}
else
{
/* The interface should NOT belong to the OSPF-all-routers group. */
if (CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS))
{
ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex);
/* Unset the flag regardless of whether the system call to leave
the group succeeded, since it's much safer to assume that
we are not a member. */
UNSET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
}
}
if (((oi->type == OSPF_IFTYPE_BROADCAST) ||
(oi->type == OSPF_IFTYPE_POINTOPOINT)) &&
((oi->state == ISM_DR) || (oi->state == ISM_Backup)) &&
(OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
{
/* The interface should belong to the OSPF-designated-routers group. */
if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS) &&
(ospf_if_add_alldrouters(oi->ospf, oi->address,
oi->ifp->ifindex) >= 0))
/* Set the flag only if the system call to join succeeded. */
SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
}
else
{
/* The interface should NOT belong to the OSPF-designated-routers group */
if (CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS))
{
ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex);
/* Unset the flag regardless of whether the system call to leave
the group succeeded, since it's much safer to assume that
we are not a member. */
UNSET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
}
}
}
int
ospf_if_up (struct ospf_interface *oi)
{
if (oi == NULL)
return 0;
if (oi->type == OSPF_IFTYPE_LOOPBACK)
OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd);
else
{
ospf_if_stream_set (oi);
OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
}
return 1;
}
int
ospf_if_down (struct ospf_interface *oi)
{
if (oi == NULL)
return 0;
OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
/* Shutdown packet reception and sending */
ospf_if_stream_unset (oi);
return 1;
}
/* Virtual Link related functions. */
struct ospf_vl_data *
ospf_vl_data_new (struct ospf_area *area, struct in_addr vl_peer)
{
struct ospf_vl_data *vl_data;
vl_data = XMALLOC (MTYPE_OSPF_VL_DATA, sizeof (struct ospf_vl_data));
memset (vl_data, 0, sizeof (struct ospf_vl_data));
vl_data->vl_peer.s_addr = vl_peer.s_addr;
vl_data->vl_area_id = area->area_id;
vl_data->format = area->format;
return vl_data;
}
void
ospf_vl_data_free (struct ospf_vl_data *vl_data)
{
XFREE (MTYPE_OSPF_VL_DATA, vl_data);
}
u_int vlink_count = 0;
struct ospf_interface *
ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data)
{
struct ospf_interface * voi;
struct interface * vi;
char ifname[INTERFACE_NAMSIZ + 1];
struct ospf_area *area;
struct in_addr area_id;
struct connected *co;
struct prefix_ipv4 *p;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): Start");
if (vlink_count == OSPF_VL_MAX_COUNT)
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): Alarm: "
"cannot create more than OSPF_MAX_VL_COUNT virtual links");
return NULL;
}
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): creating pseudo zebra interface");
snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count);
vi = if_create (ifname, strnlen(ifname, sizeof(ifname)));
co = connected_new ();
co->ifp = vi;
listnode_add (vi->connected, co);
p = prefix_ipv4_new ();
p->family = AF_INET;
p->prefix.s_addr = 0;
p->prefixlen = 0;
co->address = (struct prefix *)p;
voi = ospf_if_new (ospf, vi, co->address);
if (voi == NULL)
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): Alarm: OSPF int structure is not created");
return NULL;
}
voi->connected = co;
voi->vl_data = vl_data;
voi->ifp->mtu = OSPF_VL_MTU;
voi->type = OSPF_IFTYPE_VIRTUALLINK;
vlink_count++;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): Created name: %s", ifname);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): set if->name to %s", vi->name);
area_id.s_addr = 0;
area = ospf_area_get (ospf, area_id, OSPF_AREA_ID_FORMAT_ADDRESS);
voi->area = area;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): set associated area to the backbone");
ospf_area_add_if (voi->area, voi);
ospf_if_stream_set (voi);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_new(): Stop");
return voi;
}
void
ospf_vl_if_delete (struct ospf_vl_data *vl_data)
{
struct interface *ifp = vl_data->vl_oi->ifp;
vl_data->vl_oi->address->u.prefix4.s_addr = 0;
vl_data->vl_oi->address->prefixlen = 0;
ospf_if_free (vl_data->vl_oi);
if_delete (ifp);
vlink_count--;
}
struct ospf_vl_data *
ospf_vl_lookup (struct ospf_area *area, struct in_addr vl_peer)
{
struct ospf_vl_data *vl_data;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO (area->ospf->vlinks, node, vl_data))
if (vl_data->vl_peer.s_addr == vl_peer.s_addr &&
IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
return vl_data;
return NULL;
}
void
ospf_vl_shutdown (struct ospf_vl_data *vl_data)
{
struct ospf_interface *oi;
if ((oi = vl_data->vl_oi) == NULL)
return;
oi->address->u.prefix4.s_addr = 0;
oi->address->prefixlen = 0;
UNSET_FLAG (oi->ifp->flags, IFF_UP);
/* OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceDown); */
OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
}
void
ospf_vl_add (struct ospf *ospf, struct ospf_vl_data *vl_data)
{
listnode_add (ospf->vlinks, vl_data);
#ifdef HAVE_SNMP
ospf_snmp_vl_add (vl_data);
#endif /* HAVE_SNMP */
}
void
ospf_vl_delete (struct ospf *ospf, struct ospf_vl_data *vl_data)
{
ospf_vl_shutdown (vl_data);
ospf_vl_if_delete (vl_data);
#ifdef HAVE_SNMP
ospf_snmp_vl_delete (vl_data);
#endif /* HAVE_SNMP */
listnode_delete (ospf->vlinks, vl_data);
ospf_vl_data_free (vl_data);
}
int
ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v)
{
int changed = 0;
struct ospf_interface *voi;
struct listnode *node;
struct vertex_nexthop *nh;
int i;
struct router_lsa *rl;
voi = vl_data->vl_oi;
if (voi->output_cost != v->distance)
{
voi->output_cost = v->distance;
changed = 1;
}
for (ALL_LIST_ELEMENTS_RO (v->nexthop, node, nh))
{
vl_data->out_oi = (struct ospf_interface *) nh->oi;
if (!IPV4_ADDR_SAME(&voi->address->u.prefix4,
&vl_data->out_oi->address->u.prefix4))
changed = 1;
voi->address->u.prefix4 = vl_data->out_oi->address->u.prefix4;
voi->address->prefixlen = vl_data->out_oi->address->prefixlen;
break; /* We take the first interface. */
}
rl = (struct router_lsa *)v->lsa;
/* use SPF determined backlink index in struct vertex
* for virtual link destination address
*/
if (v->backlink >= 0)
{
if (!IPV4_ADDR_SAME (&vl_data->peer_addr,
&rl->link[v->backlink].link_data))
changed = 1;
vl_data->peer_addr = rl->link[v->backlink].link_data;
}
else
{
/* This is highly odd, there is no backlink index
* there should be due to the ospf_spf_has_link() check
* in SPF. Lets warn and try pick a link anyway.
*/
zlog_warn ("ospf_vl_set_params: No backlink for %s!",
vl_data->vl_oi->ifp->name);
for (i = 0; i < ntohs (rl->links); i++)
{
switch (rl->link[i].type)
{
case LSA_LINK_TYPE_VIRTUALLINK:
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("found back link through VL");
case LSA_LINK_TYPE_TRANSIT:
case LSA_LINK_TYPE_POINTOPOINT:
if (!IPV4_ADDR_SAME (&vl_data->peer_addr,
&rl->link[i].link_data))
changed = 1;
vl_data->peer_addr = rl->link[i].link_data;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_set_params: %s peer address is %s\n",
vl_data->vl_oi->ifp->name,
inet_ntoa(vl_data->peer_addr));
return changed;
}
}
}
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_set_params: %s peer address is %s\n",
vl_data->vl_oi->ifp->name,
inet_ntoa(vl_data->peer_addr));
return changed;
}
void
ospf_vl_up_check (struct ospf_area *area, struct in_addr rid,
struct vertex *v)
{
struct ospf *ospf = area->ospf;
struct listnode *node;
struct ospf_vl_data *vl_data;
struct ospf_interface *oi;
if (IS_DEBUG_OSPF_EVENT)
{
zlog_debug ("ospf_vl_up_check(): Start");
zlog_debug ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid));
zlog_debug ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id));
}
for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
{
if (IS_DEBUG_OSPF_EVENT)
{
zlog_debug ("ospf_vl_up_check(): considering VL, name: %s",
vl_data->vl_oi->ifp->name);
zlog_debug ("ospf_vl_up_check(): VL area: %s, peer ID: %s",
inet_ntoa (vl_data->vl_area_id),
inet_ntoa (vl_data->vl_peer));
}
if (IPV4_ADDR_SAME (&vl_data->vl_peer, &rid) &&
IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
{
oi = vl_data->vl_oi;
SET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_up_check(): this VL matched");
if (oi->state == ISM_Down)
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("ospf_vl_up_check(): VL is down, waking it up");
SET_FLAG (oi->ifp->flags, IFF_UP);
OSPF_ISM_EVENT_EXECUTE(oi,ISM_InterfaceUp);
}
if (ospf_vl_set_params (vl_data, v))
{
if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
zlog_debug ("ospf_vl_up_check: VL cost change,"
" scheduling router lsa refresh");
if(ospf->backbone)
ospf_router_lsa_timer_add (ospf->backbone);
else if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
zlog_debug ("ospf_vl_up_check: VL cost change, no backbone!");
}
}
}
}
void
ospf_vl_unapprove (struct ospf *ospf)
{
struct listnode *node;
struct ospf_vl_data *vl_data;
for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED);
}
void
ospf_vl_shut_unapproved (struct ospf *ospf)
{
struct listnode *node, *nnode;
struct ospf_vl_data *vl_data;
for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data))
if (!CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED))
ospf_vl_shutdown (vl_data);
}
int
ospf_full_virtual_nbrs (struct ospf_area *area)
{
if (IS_DEBUG_OSPF_EVENT)
{
zlog_debug ("counting fully adjacent virtual neighbors in area %s",
inet_ntoa (area->area_id));
zlog_debug ("there are %d of them", area->full_vls);
}
return area->full_vls;
}
int
ospf_vls_in_area (struct ospf_area *area)
{
struct listnode *node;
struct ospf_vl_data *vl_data;
int c = 0;
for (ALL_LIST_ELEMENTS_RO (area->ospf->vlinks, node, vl_data))
if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id))
c++;
return c;
}
struct crypt_key *
ospf_crypt_key_new ()
{
struct crypt_key *ck;
ck = XMALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key));
memset (ck, 0, sizeof (struct crypt_key));
return ck;
}
void
ospf_crypt_key_add (struct list *crypt, struct crypt_key *ck)
{
listnode_add (crypt, ck);
}
struct crypt_key *
ospf_crypt_key_lookup (struct list *auth_crypt, u_char key_id)
{
struct listnode *node;
struct crypt_key *ck;
for (ALL_LIST_ELEMENTS_RO (auth_crypt, node, ck))
if (ck->key_id == key_id)
return ck;
return NULL;
}
int
ospf_crypt_key_delete (struct list *auth_crypt, u_char key_id)
{
struct listnode *node, *nnode;
struct crypt_key *ck;
for (ALL_LIST_ELEMENTS (auth_crypt, node, nnode, ck))
{
if (ck->key_id == key_id)
{
listnode_delete (auth_crypt, ck);
return 1;
}
}
return 0;
}
u_char
ospf_default_iftype(struct interface *ifp)
{
if (if_is_pointopoint (ifp))
return OSPF_IFTYPE_POINTOPOINT;
else if (if_is_loopback (ifp))
return OSPF_IFTYPE_LOOPBACK;
else
return OSPF_IFTYPE_BROADCAST;
}
void
ospf_if_init ()
{
/* Initialize Zebra interface data structure. */
if_init ();
om->iflist = iflist;
if_add_hook (IF_NEW_HOOK, ospf_if_new_hook);
if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook);
}