mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-30 02:22:45 +00:00

The previous commits modified both zebra and bgpd for additional SAFI field, but not any other routing daemon, which led to zebra daemon crashing with failed assertion.
1285 lines
34 KiB
C
1285 lines
34 KiB
C
/*
|
||
* Zebra connect library for OSPFd
|
||
* Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, 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 "command.h"
|
||
#include "network.h"
|
||
#include "prefix.h"
|
||
#include "routemap.h"
|
||
#include "table.h"
|
||
#include "stream.h"
|
||
#include "memory.h"
|
||
#include "zclient.h"
|
||
#include "filter.h"
|
||
#include "plist.h"
|
||
#include "log.h"
|
||
|
||
#include "ospfd/ospfd.h"
|
||
#include "ospfd/ospf_interface.h"
|
||
#include "ospfd/ospf_ism.h"
|
||
#include "ospfd/ospf_asbr.h"
|
||
#include "ospfd/ospf_asbr.h"
|
||
#include "ospfd/ospf_abr.h"
|
||
#include "ospfd/ospf_lsa.h"
|
||
#include "ospfd/ospf_dump.h"
|
||
#include "ospfd/ospf_route.h"
|
||
#include "ospfd/ospf_zebra.h"
|
||
#ifdef HAVE_SNMP
|
||
#include "ospfd/ospf_snmp.h"
|
||
#endif /* HAVE_SNMP */
|
||
|
||
/* Zebra structure to hold current status. */
|
||
struct zclient *zclient = NULL;
|
||
|
||
/* For registering threads. */
|
||
extern struct thread_master *master;
|
||
struct in_addr router_id_zebra;
|
||
|
||
/* Router-id update message from zebra. */
|
||
static int
|
||
ospf_router_id_update_zebra (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct ospf *ospf;
|
||
struct prefix router_id;
|
||
zebra_router_id_update_read(zclient->ibuf,&router_id);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
{
|
||
char buf[128];
|
||
prefix2str(&router_id, buf, sizeof(buf));
|
||
zlog_debug("Zebra rcvd: router id update %s", buf);
|
||
}
|
||
|
||
router_id_zebra = router_id.u.prefix4;
|
||
|
||
ospf = ospf_lookup ();
|
||
|
||
if (ospf != NULL)
|
||
ospf_router_id_update (ospf);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Inteface addition message from zebra. */
|
||
static int
|
||
ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
|
||
{
|
||
struct interface *ifp;
|
||
|
||
ifp = zebra_interface_add_read (zclient->ibuf);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: interface add %s index %d flags %llx metric %d mtu %d",
|
||
ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
|
||
ifp->metric, ifp->mtu);
|
||
|
||
assert (ifp->info);
|
||
|
||
if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
|
||
{
|
||
SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
|
||
IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp);
|
||
}
|
||
|
||
ospf_if_update (NULL, ifp);
|
||
|
||
#ifdef HAVE_SNMP
|
||
ospf_snmp_if_update (ifp);
|
||
#endif /* HAVE_SNMP */
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
ospf_interface_delete (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct interface *ifp;
|
||
struct stream *s;
|
||
struct route_node *rn;
|
||
|
||
s = zclient->ibuf;
|
||
/* zebra_interface_state_read() updates interface structure in iflist */
|
||
ifp = zebra_interface_state_read (s);
|
||
|
||
if (ifp == NULL)
|
||
return 0;
|
||
|
||
if (if_is_up (ifp))
|
||
zlog_warn ("Zebra: got delete of %s, but interface is still up",
|
||
ifp->name);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug
|
||
("Zebra: interface delete %s index %d flags %lld metric %d mtu %d",
|
||
ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
|
||
|
||
#ifdef HAVE_SNMP
|
||
ospf_snmp_if_delete (ifp);
|
||
#endif /* HAVE_SNMP */
|
||
|
||
for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
|
||
if (rn->info)
|
||
ospf_if_free ((struct ospf_interface *) rn->info);
|
||
|
||
ifp->ifindex = IFINDEX_INTERNAL;
|
||
return 0;
|
||
}
|
||
|
||
static struct interface *
|
||
zebra_interface_if_lookup (struct stream *s)
|
||
{
|
||
char ifname_tmp[INTERFACE_NAMSIZ];
|
||
|
||
/* Read interface name. */
|
||
stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
|
||
|
||
/* And look it up. */
|
||
return if_lookup_by_name_len(ifname_tmp,
|
||
strnlen(ifname_tmp, INTERFACE_NAMSIZ));
|
||
}
|
||
|
||
static int
|
||
ospf_interface_state_up (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct interface *ifp;
|
||
struct ospf_interface *oi;
|
||
struct route_node *rn;
|
||
|
||
ifp = zebra_interface_if_lookup (zclient->ibuf);
|
||
|
||
if (ifp == NULL)
|
||
return 0;
|
||
|
||
/* Interface is already up. */
|
||
if (if_is_operative (ifp))
|
||
{
|
||
/* Temporarily keep ifp values. */
|
||
struct interface if_tmp;
|
||
memcpy (&if_tmp, ifp, sizeof (struct interface));
|
||
|
||
zebra_interface_if_set_value (zclient->ibuf, ifp);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);
|
||
|
||
if (if_tmp.bandwidth != ifp->bandwidth)
|
||
{
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
|
||
ifp->name, if_tmp.bandwidth, ifp->bandwidth);
|
||
|
||
ospf_if_recalculate_output_cost (ifp);
|
||
}
|
||
|
||
if (if_tmp.mtu != ifp->mtu)
|
||
{
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.",
|
||
ifp->name, if_tmp.mtu, ifp->mtu);
|
||
|
||
/* Must reset the interface (simulate down/up) when MTU changes. */
|
||
ospf_if_reset(ifp);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
zebra_interface_if_set_value (zclient->ibuf, ifp);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name);
|
||
|
||
for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
|
||
{
|
||
if ((oi = rn->info) == NULL)
|
||
continue;
|
||
|
||
ospf_if_up (oi);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
ospf_interface_state_down (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct interface *ifp;
|
||
struct ospf_interface *oi;
|
||
struct route_node *node;
|
||
|
||
ifp = zebra_interface_state_read (zclient->ibuf);
|
||
|
||
if (ifp == NULL)
|
||
return 0;
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name);
|
||
|
||
for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node))
|
||
{
|
||
if ((oi = node->info) == NULL)
|
||
continue;
|
||
ospf_if_down (oi);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
ospf_interface_address_add (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct connected *c;
|
||
|
||
c = zebra_interface_address_read (command, zclient->ibuf);
|
||
|
||
if (c == NULL)
|
||
return 0;
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
{
|
||
char buf[128];
|
||
prefix2str(c->address, buf, sizeof(buf));
|
||
zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf);
|
||
}
|
||
|
||
ospf_if_update (NULL, c->ifp);
|
||
|
||
#ifdef HAVE_SNMP
|
||
ospf_snmp_if_update (c->ifp);
|
||
#endif /* HAVE_SNMP */
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
ospf_interface_address_delete (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct connected *c;
|
||
struct interface *ifp;
|
||
struct ospf_interface *oi;
|
||
struct route_node *rn;
|
||
struct prefix p;
|
||
|
||
c = zebra_interface_address_read (command, zclient->ibuf);
|
||
|
||
if (c == NULL)
|
||
return 0;
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
|
||
{
|
||
char buf[128];
|
||
prefix2str(c->address, buf, sizeof(buf));
|
||
zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf);
|
||
}
|
||
|
||
ifp = c->ifp;
|
||
p = *c->address;
|
||
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
||
|
||
rn = route_node_lookup (IF_OIFS (ifp), &p);
|
||
if (!rn)
|
||
{
|
||
connected_free (c);
|
||
return 0;
|
||
}
|
||
|
||
assert (rn->info);
|
||
oi = rn->info;
|
||
|
||
/* Call interface hook functions to clean up */
|
||
ospf_if_free (oi);
|
||
|
||
#ifdef HAVE_SNMP
|
||
ospf_snmp_if_update (c->ifp);
|
||
#endif /* HAVE_SNMP */
|
||
|
||
connected_free (c);
|
||
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
|
||
{
|
||
u_char message;
|
||
u_char distance;
|
||
u_char flags;
|
||
int psize;
|
||
struct stream *s;
|
||
struct ospf_path *path;
|
||
struct listnode *node;
|
||
|
||
if (zclient->redist[ZEBRA_ROUTE_OSPF])
|
||
{
|
||
message = 0;
|
||
flags = 0;
|
||
|
||
/* OSPF pass nexthop and metric */
|
||
SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
|
||
SET_FLAG (message, ZAPI_MESSAGE_METRIC);
|
||
|
||
/* Distance value. */
|
||
distance = ospf_distance_apply (p, or);
|
||
if (distance)
|
||
SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
|
||
|
||
/* Make packet. */
|
||
s = zclient->obuf;
|
||
stream_reset (s);
|
||
|
||
/* Put command, type, flags, message. */
|
||
zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD);
|
||
stream_putc (s, ZEBRA_ROUTE_OSPF);
|
||
stream_putc (s, flags);
|
||
stream_putc (s, message);
|
||
stream_putw (s, SAFI_UNICAST);
|
||
|
||
/* Put prefix information. */
|
||
psize = PSIZE (p->prefixlen);
|
||
stream_putc (s, p->prefixlen);
|
||
stream_write (s, (u_char *) & p->prefix, psize);
|
||
|
||
/* Nexthop count. */
|
||
stream_putc (s, or->paths->count);
|
||
|
||
/* Nexthop, ifindex, distance and metric information. */
|
||
for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
|
||
{
|
||
if (path->nexthop.s_addr != INADDR_ANY)
|
||
{
|
||
stream_putc (s, ZEBRA_NEXTHOP_IPV4);
|
||
stream_put_in_addr (s, &path->nexthop);
|
||
}
|
||
else
|
||
{
|
||
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
|
||
if (path->ifindex)
|
||
stream_putl (s, path->ifindex);
|
||
else
|
||
stream_putl (s, 0);
|
||
}
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
{
|
||
char buf[2][INET_ADDRSTRLEN];
|
||
zlog_debug("Zebra: Route add %s/%d nexthop %s",
|
||
inet_ntop(AF_INET, &p->prefix,
|
||
buf[0], sizeof(buf[0])),
|
||
p->prefixlen,
|
||
inet_ntop(AF_INET, &path->nexthop,
|
||
buf[1], sizeof(buf[1])));
|
||
}
|
||
}
|
||
|
||
if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
|
||
stream_putc (s, distance);
|
||
if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
|
||
{
|
||
if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
|
||
stream_putl (s, or->cost + or->u.ext.type2_cost);
|
||
else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
|
||
stream_putl (s, or->u.ext.type2_cost);
|
||
else
|
||
stream_putl (s, or->cost);
|
||
}
|
||
|
||
stream_putw_at (s, 0, stream_get_endp (s));
|
||
|
||
zclient_send_message(zclient);
|
||
}
|
||
}
|
||
|
||
void
|
||
ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or)
|
||
{
|
||
struct zapi_ipv4 api;
|
||
struct ospf_path *path;
|
||
struct in_addr *nexthop;
|
||
struct listnode *node, *nnode;
|
||
|
||
if (zclient->redist[ZEBRA_ROUTE_OSPF])
|
||
{
|
||
api.type = ZEBRA_ROUTE_OSPF;
|
||
api.flags = 0;
|
||
api.message = 0;
|
||
api.safi = SAFI_UNICAST;
|
||
api.ifindex_num = 0;
|
||
api.nexthop_num = 0;
|
||
|
||
for (ALL_LIST_ELEMENTS (or->paths, node, nnode, path))
|
||
{
|
||
if (path->nexthop.s_addr != INADDR_ANY)
|
||
{
|
||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||
api.nexthop_num = 1;
|
||
nexthop = &path->nexthop;
|
||
api.nexthop = &nexthop;
|
||
}
|
||
else if (if_lookup_by_index(path->ifindex))
|
||
{
|
||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||
api.ifindex_num = 1;
|
||
api.ifindex = &path->ifindex;
|
||
}
|
||
else if ( IS_DEBUG_OSPF(zebra,ZEBRA_REDISTRIBUTE) )
|
||
{
|
||
zlog_debug("Zebra: no ifp %s %d",
|
||
inet_ntoa(p->prefix),
|
||
p->prefixlen);
|
||
}
|
||
|
||
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.nexthop_num)
|
||
{
|
||
char buf[2][INET_ADDRSTRLEN];
|
||
zlog_debug("Zebra: Route delete %s/%d nexthop %s",
|
||
inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])),
|
||
p->prefixlen,
|
||
inet_ntop(AF_INET, *api.nexthop,
|
||
buf[1], sizeof(buf[1])));
|
||
}
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.ifindex_num)
|
||
{
|
||
zlog_debug ("Zebra: Route delete %s/%d ifindex %d",
|
||
inet_ntoa (p->prefix),
|
||
p->prefixlen, *api.ifindex);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
ospf_zebra_add_discard (struct prefix_ipv4 *p)
|
||
{
|
||
struct zapi_ipv4 api;
|
||
|
||
if (zclient->redist[ZEBRA_ROUTE_OSPF])
|
||
{
|
||
api.type = ZEBRA_ROUTE_OSPF;
|
||
api.flags = ZEBRA_FLAG_BLACKHOLE;
|
||
api.message = 0;
|
||
api.safi = SAFI_UNICAST;
|
||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||
api.nexthop_num = 0;
|
||
api.ifindex_num = 0;
|
||
|
||
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Zebra: Route add discard %s/%d",
|
||
inet_ntoa (p->prefix), p->prefixlen);
|
||
}
|
||
}
|
||
|
||
void
|
||
ospf_zebra_delete_discard (struct prefix_ipv4 *p)
|
||
{
|
||
struct zapi_ipv4 api;
|
||
|
||
if (zclient->redist[ZEBRA_ROUTE_OSPF])
|
||
{
|
||
api.type = ZEBRA_ROUTE_OSPF;
|
||
api.flags = ZEBRA_FLAG_BLACKHOLE;
|
||
api.message = 0;
|
||
api.safi = SAFI_UNICAST;
|
||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||
api.nexthop_num = 0;
|
||
api.ifindex_num = 0;
|
||
|
||
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Zebra: Route delete discard %s/%d",
|
||
inet_ntoa (p->prefix), p->prefixlen);
|
||
|
||
}
|
||
}
|
||
|
||
int
|
||
ospf_is_type_redistributed (int type)
|
||
{
|
||
return (DEFAULT_ROUTE_TYPE (type)) ?
|
||
zclient->default_information : zclient->redist[type];
|
||
}
|
||
|
||
int
|
||
ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue)
|
||
{
|
||
int force = 0;
|
||
|
||
if (ospf_is_type_redistributed (type))
|
||
{
|
||
if (mtype != ospf->dmetric[type].type)
|
||
{
|
||
ospf->dmetric[type].type = mtype;
|
||
force = LSA_REFRESH_FORCE;
|
||
}
|
||
if (mvalue != ospf->dmetric[type].value)
|
||
{
|
||
ospf->dmetric[type].value = mvalue;
|
||
force = LSA_REFRESH_FORCE;
|
||
}
|
||
|
||
ospf_external_lsa_refresh_type (ospf, type, force);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]",
|
||
ospf_redist_string(type),
|
||
metric_type (ospf, type), metric_value (ospf, type));
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
ospf->dmetric[type].type = mtype;
|
||
ospf->dmetric[type].value = mvalue;
|
||
|
||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]",
|
||
ospf_redist_string(type),
|
||
metric_type (ospf, type), metric_value (ospf, type));
|
||
|
||
ospf_asbr_status_update (ospf, ++ospf->redistribute);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
int
|
||
ospf_redistribute_unset (struct ospf *ospf, int type)
|
||
{
|
||
if (type == zclient->redist_default)
|
||
return CMD_SUCCESS;
|
||
|
||
if (!ospf_is_type_redistributed (type))
|
||
return CMD_SUCCESS;
|
||
|
||
zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: Stop",
|
||
ospf_redist_string(type));
|
||
|
||
ospf->dmetric[type].type = -1;
|
||
ospf->dmetric[type].value = -1;
|
||
|
||
/* Remove the routes from OSPF table. */
|
||
ospf_redistribute_withdraw (ospf, type);
|
||
|
||
ospf_asbr_status_update (ospf, --ospf->redistribute);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
int
|
||
ospf_redistribute_default_set (struct ospf *ospf, int originate,
|
||
int mtype, int mvalue)
|
||
{
|
||
ospf->default_originate = originate;
|
||
ospf->dmetric[DEFAULT_ROUTE].type = mtype;
|
||
ospf->dmetric[DEFAULT_ROUTE].value = mvalue;
|
||
|
||
if (ospf_is_type_redistributed (DEFAULT_ROUTE))
|
||
{
|
||
/* if ospf->default_originate changes value, is calling
|
||
ospf_external_lsa_refresh_default sufficient to implement
|
||
the change? */
|
||
ospf_external_lsa_refresh_default (ospf);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]",
|
||
ospf_redist_string(DEFAULT_ROUTE),
|
||
metric_type (ospf, DEFAULT_ROUTE),
|
||
metric_value (ospf, DEFAULT_ROUTE));
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]",
|
||
metric_type (ospf, DEFAULT_ROUTE),
|
||
metric_value (ospf, DEFAULT_ROUTE));
|
||
|
||
if (ospf->router_id.s_addr == 0)
|
||
ospf->external_origin |= (1 << DEFAULT_ROUTE);
|
||
else
|
||
thread_add_timer (master, ospf_default_originate_timer, ospf, 1);
|
||
|
||
ospf_asbr_status_update (ospf, ++ospf->redistribute);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
int
|
||
ospf_redistribute_default_unset (struct ospf *ospf)
|
||
{
|
||
if (!ospf_is_type_redistributed (DEFAULT_ROUTE))
|
||
return CMD_SUCCESS;
|
||
|
||
ospf->default_originate = DEFAULT_ORIGINATE_NONE;
|
||
ospf->dmetric[DEFAULT_ROUTE].type = -1;
|
||
ospf->dmetric[DEFAULT_ROUTE].value = -1;
|
||
|
||
zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient);
|
||
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[DEFAULT]: Stop");
|
||
|
||
ospf_asbr_status_update (ospf, --ospf->redistribute);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
static int
|
||
ospf_external_lsa_originate_check (struct ospf *ospf,
|
||
struct external_info *ei)
|
||
{
|
||
/* If prefix is multicast, then do not originate LSA. */
|
||
if (IN_MULTICAST (htonl (ei->p.prefix.s_addr)))
|
||
{
|
||
zlog_info ("LSA[Type5:%s]: Not originate AS-external-LSA, "
|
||
"Prefix belongs multicast", inet_ntoa (ei->p.prefix));
|
||
return 0;
|
||
}
|
||
|
||
/* Take care of default-originate. */
|
||
if (is_prefix_default (&ei->p))
|
||
if (ospf->default_originate == DEFAULT_ORIGINATE_NONE)
|
||
{
|
||
zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-external-LSA "
|
||
"for default");
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* If connected prefix is OSPF enable interface, then do not announce. */
|
||
int
|
||
ospf_distribute_check_connected (struct ospf *ospf, struct external_info *ei)
|
||
{
|
||
struct listnode *node;
|
||
struct ospf_interface *oi;
|
||
|
||
|
||
for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
|
||
if (prefix_match (oi->address, (struct prefix *) &ei->p))
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
/* return 1 if external LSA must be originated, 0 otherwise */
|
||
int
|
||
ospf_redistribute_check (struct ospf *ospf,
|
||
struct external_info *ei, int *changed)
|
||
{
|
||
struct route_map_set_values save_values;
|
||
struct prefix_ipv4 *p = &ei->p;
|
||
u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
|
||
|
||
if (changed)
|
||
*changed = 0;
|
||
|
||
if (!ospf_external_lsa_originate_check (ospf, ei))
|
||
return 0;
|
||
|
||
/* Take care connected route. */
|
||
if (type == ZEBRA_ROUTE_CONNECT &&
|
||
!ospf_distribute_check_connected (ospf, ei))
|
||
return 0;
|
||
|
||
if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (ospf, type))
|
||
/* distirbute-list exists, but access-list may not? */
|
||
if (DISTRIBUTE_LIST (ospf, type))
|
||
if (access_list_apply (DISTRIBUTE_LIST (ospf, type), p) == FILTER_DENY)
|
||
{
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: %s/%d filtered by ditribute-list.",
|
||
ospf_redist_string(type),
|
||
inet_ntoa (p->prefix), p->prefixlen);
|
||
return 0;
|
||
}
|
||
|
||
save_values = ei->route_map_set;
|
||
ospf_reset_route_map_set_values (&ei->route_map_set);
|
||
|
||
/* apply route-map if needed */
|
||
if (ROUTEMAP_NAME (ospf, type))
|
||
{
|
||
int ret;
|
||
|
||
ret = route_map_apply (ROUTEMAP (ospf, type), (struct prefix *) p,
|
||
RMAP_OSPF, ei);
|
||
|
||
if (ret == RMAP_DENYMATCH)
|
||
{
|
||
ei->route_map_set = save_values;
|
||
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
|
||
zlog_debug ("Redistribute[%s]: %s/%d filtered by route-map.",
|
||
ospf_redist_string(type),
|
||
inet_ntoa (p->prefix), p->prefixlen);
|
||
return 0;
|
||
}
|
||
|
||
/* check if 'route-map set' changed something */
|
||
if (changed)
|
||
*changed = !ospf_route_map_set_compare (&ei->route_map_set,
|
||
&save_values);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* OSPF route-map set for redistribution */
|
||
void
|
||
ospf_routemap_set (struct ospf *ospf, int type, const char *name)
|
||
{
|
||
if (ROUTEMAP_NAME (ospf, type))
|
||
free (ROUTEMAP_NAME (ospf, type));
|
||
|
||
ROUTEMAP_NAME (ospf, type) = strdup (name);
|
||
ROUTEMAP (ospf, type) = route_map_lookup_by_name (name);
|
||
}
|
||
|
||
void
|
||
ospf_routemap_unset (struct ospf *ospf, int type)
|
||
{
|
||
if (ROUTEMAP_NAME (ospf, type))
|
||
free (ROUTEMAP_NAME (ospf, type));
|
||
|
||
ROUTEMAP_NAME (ospf, type) = NULL;
|
||
ROUTEMAP (ospf, type) = NULL;
|
||
}
|
||
|
||
/* Zebra route add and delete treatment. */
|
||
static int
|
||
ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
|
||
zebra_size_t length)
|
||
{
|
||
struct stream *s;
|
||
struct zapi_ipv4 api;
|
||
unsigned long ifindex;
|
||
struct in_addr nexthop;
|
||
struct prefix_ipv4 p;
|
||
struct external_info *ei;
|
||
struct ospf *ospf;
|
||
|
||
s = zclient->ibuf;
|
||
ifindex = 0;
|
||
nexthop.s_addr = 0;
|
||
|
||
/* Type, flags, message. */
|
||
api.type = stream_getc (s);
|
||
api.flags = stream_getc (s);
|
||
api.message = stream_getc (s);
|
||
|
||
/* IPv4 prefix. */
|
||
memset (&p, 0, sizeof (struct prefix_ipv4));
|
||
p.family = AF_INET;
|
||
p.prefixlen = stream_getc (s);
|
||
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
|
||
|
||
if (IPV4_NET127(ntohl(p.prefix.s_addr)))
|
||
return 0;
|
||
|
||
/* Nexthop, ifindex, distance, metric. */
|
||
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
|
||
{
|
||
api.nexthop_num = stream_getc (s);
|
||
nexthop.s_addr = stream_get_ipv4 (s);
|
||
}
|
||
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
|
||
{
|
||
api.ifindex_num = stream_getc (s);
|
||
/* XXX assert(api.ifindex_num == 1); */
|
||
ifindex = stream_getl (s);
|
||
}
|
||
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
|
||
api.distance = stream_getc (s);
|
||
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
|
||
api.metric = stream_getl (s);
|
||
|
||
ospf = ospf_lookup ();
|
||
if (ospf == NULL)
|
||
return 0;
|
||
|
||
if (command == ZEBRA_IPV4_ROUTE_ADD)
|
||
{
|
||
/* XXX|HACK|TODO|FIXME:
|
||
* Maybe we should ignore reject/blackhole routes? Testing shows that
|
||
* there is no problems though and this is only way to "summarize"
|
||
* routes in ASBR at the moment. Maybe we need just a better generalised
|
||
* solution for these types?
|
||
*
|
||
* if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE)
|
||
* || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
|
||
* return 0;
|
||
*/
|
||
|
||
ei = ospf_external_info_add (api.type, p, ifindex, nexthop);
|
||
|
||
if (ospf->router_id.s_addr == 0)
|
||
/* Set flags to generate AS-external-LSA originate event
|
||
for each redistributed protocols later. */
|
||
ospf->external_origin |= (1 << api.type);
|
||
else
|
||
{
|
||
if (ei)
|
||
{
|
||
if (is_prefix_default (&p))
|
||
ospf_external_lsa_refresh_default (ospf);
|
||
else
|
||
{
|
||
struct ospf_lsa *current;
|
||
|
||
current = ospf_external_info_find_lsa (ospf, &ei->p);
|
||
if (!current)
|
||
ospf_external_lsa_originate (ospf, ei);
|
||
else if (IS_LSA_MAXAGE (current))
|
||
ospf_external_lsa_refresh (ospf, current,
|
||
ei, LSA_REFRESH_FORCE);
|
||
else
|
||
zlog_warn ("ospf_zebra_read_ipv4() : %s already exists",
|
||
inet_ntoa (p.prefix));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
|
||
{
|
||
ospf_external_info_delete (api.type, p);
|
||
if (is_prefix_default (&p))
|
||
ospf_external_lsa_refresh_default (ospf);
|
||
else
|
||
ospf_external_lsa_flush (ospf, api.type, &p, ifindex /*, nexthop */);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
int
|
||
ospf_distribute_list_out_set (struct ospf *ospf, int type, const char *name)
|
||
{
|
||
/* Lookup access-list for distribute-list. */
|
||
DISTRIBUTE_LIST (ospf, type) = access_list_lookup (AFI_IP, name);
|
||
|
||
/* Clear previous distribute-name. */
|
||
if (DISTRIBUTE_NAME (ospf, type))
|
||
free (DISTRIBUTE_NAME (ospf, type));
|
||
|
||
/* Set distribute-name. */
|
||
DISTRIBUTE_NAME (ospf, type) = strdup (name);
|
||
|
||
/* If access-list have been set, schedule update timer. */
|
||
if (DISTRIBUTE_LIST (ospf, type))
|
||
ospf_distribute_list_update (ospf, type);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
int
|
||
ospf_distribute_list_out_unset (struct ospf *ospf, int type, const char *name)
|
||
{
|
||
/* Schedule update timer. */
|
||
if (DISTRIBUTE_LIST (ospf, type))
|
||
ospf_distribute_list_update (ospf, type);
|
||
|
||
/* Unset distribute-list. */
|
||
DISTRIBUTE_LIST (ospf, type) = NULL;
|
||
|
||
/* Clear distribute-name. */
|
||
if (DISTRIBUTE_NAME (ospf, type))
|
||
free (DISTRIBUTE_NAME (ospf, type));
|
||
|
||
DISTRIBUTE_NAME (ospf, type) = NULL;
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
/* distribute-list update timer. */
|
||
static int
|
||
ospf_distribute_list_update_timer (struct thread *thread)
|
||
{
|
||
struct route_node *rn;
|
||
struct external_info *ei;
|
||
struct route_table *rt;
|
||
struct ospf_lsa *lsa;
|
||
int type, default_refresh = 0;
|
||
struct ospf *ospf;
|
||
|
||
ospf = ospf_lookup ();
|
||
if (ospf == NULL)
|
||
return 0;
|
||
|
||
ospf->t_distribute_update = NULL;
|
||
|
||
zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!");
|
||
|
||
/* foreach all external info. */
|
||
for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
|
||
{
|
||
rt = EXTERNAL_INFO (type);
|
||
if (!rt)
|
||
continue;
|
||
for (rn = route_top (rt); rn; rn = route_next (rn))
|
||
if ((ei = rn->info) != NULL)
|
||
{
|
||
if (is_prefix_default (&ei->p))
|
||
default_refresh = 1;
|
||
else if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p)))
|
||
ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_IF_CHANGED);
|
||
else
|
||
ospf_external_lsa_originate (ospf, ei);
|
||
}
|
||
}
|
||
if (default_refresh)
|
||
ospf_external_lsa_refresh_default (ospf);
|
||
return 0;
|
||
}
|
||
|
||
#define OSPF_DISTRIBUTE_UPDATE_DELAY 5
|
||
|
||
/* Update distribute-list and set timer to apply access-list. */
|
||
void
|
||
ospf_distribute_list_update (struct ospf *ospf, int type)
|
||
{
|
||
struct route_table *rt;
|
||
|
||
/* External info does not exist. */
|
||
if (!(rt = EXTERNAL_INFO (type)))
|
||
return;
|
||
|
||
/* If exists previously invoked thread, then let it continue. */
|
||
if (ospf->t_distribute_update)
|
||
return;
|
||
|
||
/* Set timer. */
|
||
ospf->t_distribute_update =
|
||
thread_add_timer (master, ospf_distribute_list_update_timer,
|
||
(void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY);
|
||
}
|
||
|
||
/* If access-list is updated, apply some check. */
|
||
static void
|
||
ospf_filter_update (struct access_list *access)
|
||
{
|
||
struct ospf *ospf;
|
||
int type;
|
||
int abr_inv = 0;
|
||
struct ospf_area *area;
|
||
struct listnode *node;
|
||
|
||
/* If OSPF instatnce does not exist, return right now. */
|
||
ospf = ospf_lookup ();
|
||
if (ospf == NULL)
|
||
return;
|
||
|
||
/* Update distribute-list, and apply filter. */
|
||
for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
|
||
{
|
||
if (ROUTEMAP (ospf, type) != NULL)
|
||
{
|
||
/* if route-map is not NULL it may be using this access list */
|
||
ospf_distribute_list_update (ospf, type);
|
||
continue;
|
||
}
|
||
|
||
/* There is place for route-map for default-information (ZEBRA_ROUTE_MAX),
|
||
* but no distribute list. */
|
||
if (type == ZEBRA_ROUTE_MAX)
|
||
break;
|
||
|
||
if (DISTRIBUTE_NAME (ospf, type))
|
||
{
|
||
/* Keep old access-list for distribute-list. */
|
||
struct access_list *old = DISTRIBUTE_LIST (ospf, type);
|
||
|
||
/* Update access-list for distribute-list. */
|
||
DISTRIBUTE_LIST (ospf, type) =
|
||
access_list_lookup (AFI_IP, DISTRIBUTE_NAME (ospf, type));
|
||
|
||
/* No update for this distribute type. */
|
||
if (old == NULL && DISTRIBUTE_LIST (ospf, type) == NULL)
|
||
continue;
|
||
|
||
/* Schedule distribute-list update timer. */
|
||
if (DISTRIBUTE_LIST (ospf, type) == NULL ||
|
||
strcmp (DISTRIBUTE_NAME (ospf, type), access->name) == 0)
|
||
ospf_distribute_list_update (ospf, type);
|
||
}
|
||
}
|
||
|
||
/* Update Area access-list. */
|
||
for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
|
||
{
|
||
if (EXPORT_NAME (area))
|
||
{
|
||
EXPORT_LIST (area) = NULL;
|
||
abr_inv++;
|
||
}
|
||
|
||
if (IMPORT_NAME (area))
|
||
{
|
||
IMPORT_LIST (area) = NULL;
|
||
abr_inv++;
|
||
}
|
||
}
|
||
|
||
/* Schedule ABR tasks -- this will be changed -- takada. */
|
||
if (IS_OSPF_ABR (ospf) && abr_inv)
|
||
ospf_schedule_abr_task (ospf);
|
||
}
|
||
|
||
/* If prefix-list is updated, do some updates. */
|
||
void
|
||
ospf_prefix_list_update (struct prefix_list *plist)
|
||
{
|
||
struct ospf *ospf;
|
||
int type;
|
||
int abr_inv = 0;
|
||
struct ospf_area *area;
|
||
struct listnode *node;
|
||
|
||
/* If OSPF instatnce does not exist, return right now. */
|
||
ospf = ospf_lookup ();
|
||
if (ospf == NULL)
|
||
return;
|
||
|
||
/* Update all route-maps which are used as redistribution filters.
|
||
* They might use prefix-list.
|
||
*/
|
||
for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
|
||
{
|
||
if (ROUTEMAP (ospf, type) != NULL)
|
||
{
|
||
/* If route-map is not NULL it may be using this prefix list */
|
||
ospf_distribute_list_update (ospf, type);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
/* Update area filter-lists. */
|
||
for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
|
||
{
|
||
/* Update filter-list in. */
|
||
if (PREFIX_NAME_IN (area))
|
||
if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0)
|
||
{
|
||
PREFIX_LIST_IN (area) =
|
||
prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area));
|
||
abr_inv++;
|
||
}
|
||
|
||
/* Update filter-list out. */
|
||
if (PREFIX_NAME_OUT (area))
|
||
if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0)
|
||
{
|
||
PREFIX_LIST_IN (area) =
|
||
prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area));
|
||
abr_inv++;
|
||
}
|
||
}
|
||
|
||
/* Schedule ABR task. */
|
||
if (IS_OSPF_ABR (ospf) && abr_inv)
|
||
ospf_schedule_abr_task (ospf);
|
||
}
|
||
|
||
static struct ospf_distance *
|
||
ospf_distance_new (void)
|
||
{
|
||
return XCALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance));
|
||
}
|
||
|
||
static void
|
||
ospf_distance_free (struct ospf_distance *odistance)
|
||
{
|
||
XFREE (MTYPE_OSPF_DISTANCE, odistance);
|
||
}
|
||
|
||
int
|
||
ospf_distance_set (struct vty *vty, struct ospf *ospf,
|
||
const char *distance_str,
|
||
const char *ip_str,
|
||
const char *access_list_str)
|
||
{
|
||
int ret;
|
||
struct prefix_ipv4 p;
|
||
u_char distance;
|
||
struct route_node *rn;
|
||
struct ospf_distance *odistance;
|
||
|
||
ret = str2prefix_ipv4 (ip_str, &p);
|
||
if (ret == 0)
|
||
{
|
||
vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
|
||
return CMD_WARNING;
|
||
}
|
||
|
||
distance = atoi (distance_str);
|
||
|
||
/* Get OSPF distance node. */
|
||
rn = route_node_get (ospf->distance_table, (struct prefix *) &p);
|
||
if (rn->info)
|
||
{
|
||
odistance = rn->info;
|
||
route_unlock_node (rn);
|
||
}
|
||
else
|
||
{
|
||
odistance = ospf_distance_new ();
|
||
rn->info = odistance;
|
||
}
|
||
|
||
/* Set distance value. */
|
||
odistance->distance = distance;
|
||
|
||
/* Reset access-list configuration. */
|
||
if (odistance->access_list)
|
||
{
|
||
free (odistance->access_list);
|
||
odistance->access_list = NULL;
|
||
}
|
||
if (access_list_str)
|
||
odistance->access_list = strdup (access_list_str);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
int
|
||
ospf_distance_unset (struct vty *vty, struct ospf *ospf,
|
||
const char *distance_str,
|
||
const char *ip_str, char
|
||
const *access_list_str)
|
||
{
|
||
int ret;
|
||
struct prefix_ipv4 p;
|
||
u_char distance;
|
||
struct route_node *rn;
|
||
struct ospf_distance *odistance;
|
||
|
||
ret = str2prefix_ipv4 (ip_str, &p);
|
||
if (ret == 0)
|
||
{
|
||
vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
|
||
return CMD_WARNING;
|
||
}
|
||
|
||
distance = atoi (distance_str);
|
||
|
||
rn = route_node_lookup (ospf->distance_table, (struct prefix *) &p);
|
||
if (!rn)
|
||
{
|
||
vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
|
||
return CMD_WARNING;
|
||
}
|
||
|
||
odistance = rn->info;
|
||
|
||
if (odistance->access_list)
|
||
free (odistance->access_list);
|
||
ospf_distance_free (odistance);
|
||
|
||
rn->info = NULL;
|
||
route_unlock_node (rn);
|
||
route_unlock_node (rn);
|
||
|
||
return CMD_SUCCESS;
|
||
}
|
||
|
||
void
|
||
ospf_distance_reset (struct ospf *ospf)
|
||
{
|
||
struct route_node *rn;
|
||
struct ospf_distance *odistance;
|
||
|
||
for (rn = route_top (ospf->distance_table); rn; rn = route_next (rn))
|
||
if ((odistance = rn->info) != NULL)
|
||
{
|
||
if (odistance->access_list)
|
||
free (odistance->access_list);
|
||
ospf_distance_free (odistance);
|
||
rn->info = NULL;
|
||
route_unlock_node (rn);
|
||
}
|
||
}
|
||
|
||
u_char
|
||
ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or)
|
||
{
|
||
struct ospf *ospf;
|
||
|
||
ospf = ospf_lookup ();
|
||
if (ospf == NULL)
|
||
return 0;
|
||
|
||
if (ospf->distance_intra)
|
||
if (or->path_type == OSPF_PATH_INTRA_AREA)
|
||
return ospf->distance_intra;
|
||
|
||
if (ospf->distance_inter)
|
||
if (or->path_type == OSPF_PATH_INTER_AREA)
|
||
return ospf->distance_inter;
|
||
|
||
if (ospf->distance_external)
|
||
if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL
|
||
|| or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
|
||
return ospf->distance_external;
|
||
|
||
if (ospf->distance_all)
|
||
return ospf->distance_all;
|
||
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
ospf_zebra_init ()
|
||
{
|
||
/* Allocate zebra structure. */
|
||
zclient = zclient_new ();
|
||
zclient_init (zclient, ZEBRA_ROUTE_OSPF);
|
||
zclient->router_id_update = ospf_router_id_update_zebra;
|
||
zclient->interface_add = ospf_interface_add;
|
||
zclient->interface_delete = ospf_interface_delete;
|
||
zclient->interface_up = ospf_interface_state_up;
|
||
zclient->interface_down = ospf_interface_state_down;
|
||
zclient->interface_address_add = ospf_interface_address_add;
|
||
zclient->interface_address_delete = ospf_interface_address_delete;
|
||
zclient->ipv4_route_add = ospf_zebra_read_ipv4;
|
||
zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
|
||
|
||
access_list_add_hook (ospf_filter_update);
|
||
access_list_delete_hook (ospf_filter_update);
|
||
prefix_list_add_hook (ospf_prefix_list_update);
|
||
prefix_list_delete_hook (ospf_prefix_list_update);
|
||
}
|