From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- ospfd/ospf_zebra.c | 1180 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1180 insertions(+) create mode 100644 ospfd/ospf_zebra.c (limited to 'ospfd/ospf_zebra.c') diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c new file mode 100644 index 00000000..1ad31f29 --- /dev/null +++ b/ospfd/ospf_zebra.c @@ -0,0 +1,1180 @@ +/* + * 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 + +#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 "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; + +/* Inteface addition message from zebra. */ +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_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + + if (if_is_broadcast (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + else if (if_is_pointopoint (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; + else if (if_is_loopback (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK; + } + + ospf_if_update (); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +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_info ("Zebra: interface delete %s index %d flags %ld 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); + + for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + ospf_del_if_params (rn->info); + + if_delete (ifp); + + return 0; +} + +struct interface * +zebra_interface_if_lookup (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (!ifp) + return NULL; + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +} + +int +ospf_interface_state_up (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct interface if_tmp; + 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_up (ifp)) + { + /* Temporarily keep ifp values. */ + memcpy (&if_tmp, ifp, sizeof (struct interface)); + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state update.", ifp->name); + + if (if_tmp.bandwidth != ifp->bandwidth) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, if_tmp.bandwidth, ifp->bandwidth); + + ospf_if_recalculate_output_cost (ifp); + } + return 0; + } + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("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; +} + +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_info ("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; +} + +int +ospf_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + { + struct prefix *p; + + p = c->address; + if (p->family == AF_INET) + zlog_info (" connected address %s/%d", + inet_atop (p->u.prefix4), p->prefixlen); + } +#endif + + ospf_if_update (); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (c->ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +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_delete_read (zclient->ibuf); + + if (c == NULL) + return 0; + + ifp = c->ifp; + p = *c->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (ifp), &p); + if (! rn) + 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); + + ospf_if_update(); + + 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; + 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); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type, flags, message. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, ZEBRA_ROUTE_OSPF); + stream_putc (s, flags); + stream_putc (s, message); + + /* 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->path->count); + + /* Nexthop, ifindex, distance and metric information. */ + for (node = listhead (or->path); node; nextnode (node)) + { + path = getdata (node); + + 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->oi) + stream_putl (s, path->oi->ifp->ifindex); + else + stream_putl (s, 0); + } + } + + 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)); + + writen (zclient->sock, s->data, stream_get_endp (s)); + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + { + char *nexthop_str; + + nexthop_str = strdup (inet_ntoa (*nexthop)); + zlog_info ("Zebra: Route add %s/%d nexthop %s metric %d", + inet_ntoa (p->prefix), p->prefixlen, nexthop_str, + metric); + free (nexthop_str); + } +#endif /* 0 */ + } +} + +void +ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = 0; + api.message = 0; + zapi_ipv4_delete (zclient, p, &api); + +#if 0 + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + { + char *nexthop_str; + + nexthop_str = strdup (inet_ntoa (*nexthop)); + zlog_info ("Zebra: Route delete %s/%d nexthop %s", + inet_ntoa (p->prefix), p->prefixlen, nexthop_str); + free (nexthop_str); + } +#endif /* 0 */ + } +} + +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; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_add (zclient, p, &api); + } +} + +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; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_delete (zclient, p, &api); + } +} + +int +ospf_is_type_redistributed (int type) +{ + return (DEFAULT_ROUTE_TYPE (type)) ? + zclient->default_information : zclient->redist[type]; +} + +int +ospf_redistribute_set (int type, int mtype, int mvalue) +{ + int force = 0; + + if (ospf_is_type_redistributed (type)) + { + if (mtype != ospf_top->dmetric[type].type) + { + ospf_top->dmetric[type].type = mtype; + force = LSA_REFRESH_FORCE; + } + if (mvalue != ospf_top->dmetric[type].value) + { + ospf_top->dmetric[type].value = mvalue; + force = LSA_REFRESH_FORCE; + } + + ospf_external_lsa_refresh_type (type, force); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (type), metric_value (type)); + + return CMD_SUCCESS; + } + + ospf_top->dmetric[type].type = mtype; + ospf_top->dmetric[type].value = mvalue; + + zclient_redistribute_set (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Start Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (type), metric_value (type)); + + ospf_asbr_status_update (++ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_unset (int type) +{ + if (type == zclient->redist_default) + return CMD_SUCCESS; + + if (! ospf_is_type_redistributed (type)) + return CMD_SUCCESS; + + zclient_redistribute_unset (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Stop", + LOOKUP (ospf_redistributed_proto, type)); + + ospf_top->dmetric[type].type = -1; + ospf_top->dmetric[type].value = -1; + + /* Remove the routes from OSPF table. */ + ospf_redistribute_withdraw (type); + + ospf_asbr_status_update (--ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_set (int originate, int mtype, int mvalue) +{ + int force = 0; + if (ospf_is_type_redistributed (DEFAULT_ROUTE)) + { + if (mtype != ospf_top->dmetric[DEFAULT_ROUTE].type) + { + ospf_top->dmetric[DEFAULT_ROUTE].type = mtype; + force = 1; + } + if (mvalue != ospf_top->dmetric[DEFAULT_ROUTE].value) + { + force = 1; + ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue; + } + + ospf_external_lsa_refresh_default (); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, DEFAULT_ROUTE), + metric_type (DEFAULT_ROUTE), + metric_value (DEFAULT_ROUTE)); + return CMD_SUCCESS; + } + + ospf_top->default_originate = originate; + ospf_top->dmetric[DEFAULT_ROUTE].type = mtype; + ospf_top->dmetric[DEFAULT_ROUTE].value = mvalue; + + zclient_redistribute_default_set (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", + metric_type (DEFAULT_ROUTE), metric_value (DEFAULT_ROUTE)); + + + if (ospf_top->router_id.s_addr == 0) + ospf_top->external_origin |= (1 << DEFAULT_ROUTE); + else + thread_add_timer (master, ospf_default_originate_timer, + &ospf_top->default_originate, 1); + + ospf_asbr_status_update (++ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_unset () +{ + if (!ospf_is_type_redistributed (DEFAULT_ROUTE)) + return CMD_SUCCESS; + + ospf_top->default_originate = DEFAULT_ORIGINATE_NONE; + ospf_top->dmetric[DEFAULT_ROUTE].type = -1; + ospf_top->dmetric[DEFAULT_ROUTE].value = -1; + + zclient_redistribute_default_unset (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Stop"); + + ospf_asbr_status_update (--ospf_top->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_external_lsa_originate_check (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_top->default_originate == DEFAULT_ORIGINATE_NONE) + { + zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA " + "for default"); + return 0; + } + + return 1; +} + +/* If connected prefix is OSPF enable interface, then do not announce. */ +int +ospf_distribute_check_connected (struct external_info *ei) +{ + struct route_node *rn; + + for (rn = route_top (ospf_top->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + if (prefix_match (&rn->p, (struct prefix *)&ei->p)) + return 0; + + return 1; +} + +/* return 1 if external LSA must be originated, 0 otherwise */ +int +ospf_redistribute_check (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 (ei)) + return 0; + + /* Take care connected route. */ + if (type == ZEBRA_ROUTE_CONNECT && !ospf_distribute_check_connected (ei)) + return 0; + + if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (type)) + /* distirbute-list exists, but access-list may not? */ + if (DISTRIBUTE_LIST (type)) + if (access_list_apply (DISTRIBUTE_LIST (type), p) == FILTER_DENY) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: %s/%d filtered by ditribute-list.", + LOOKUP (ospf_redistributed_proto, 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 (type)) + { + int ret; + + ret = route_map_apply (ROUTEMAP (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_info ("Redistribute[%s]: %s/%d filtered by route-map.", + LOOKUP (ospf_redistributed_proto, 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 (int type, char *name) +{ + if (ROUTEMAP_NAME (type)) + free (ROUTEMAP_NAME (type)); + + ROUTEMAP_NAME (type) = strdup (name); + ROUTEMAP (type) = route_map_lookup_by_name (name); +} + +void +ospf_routemap_unset (int type) +{ + if (ROUTEMAP_NAME (type)) + free (ROUTEMAP_NAME (type)); + + ROUTEMAP_NAME (type) = NULL; + ROUTEMAP (type) = NULL; +} + +/* Zebra route add and delete treatment. */ +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; + + 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)); + + /* 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); + 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); + + if (command == ZEBRA_IPV4_ROUTE_ADD) + { + ei = ospf_external_info_add (api.type, p, ifindex, nexthop); + + if (ospf_top->router_id.s_addr == 0) + /* Set flags to generate AS-external-LSA originate event + for each redistributed protocols later. */ + ospf_top->external_origin |= (1 << api.type); + else + { + if (ei) + { + if (is_prefix_default (&p)) + ospf_external_lsa_refresh_default (); + else + { + struct ospf_lsa *current; + + current = ospf_external_info_find_lsa (&ei->p); + if (!current) + ospf_external_lsa_originate (ei); + else if (IS_LSA_MAXAGE (current)) + ospf_external_lsa_refresh (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_flush (api.type, &p, ifindex, nexthop); + else + ospf_external_lsa_refresh_default (); + } + + return 0; +} + + +int +ospf_distribute_list_out_set (int type, char *name) +{ + /* Lookup access-list for distribute-list. */ + DISTRIBUTE_LIST (type) = access_list_lookup (AFI_IP, name); + + /* Clear previous distribute-name. */ + if (DISTRIBUTE_NAME (type)) + free (DISTRIBUTE_NAME (type)); + + /* Set distribute-name. */ + DISTRIBUTE_NAME (type) = strdup (name); + + /* If access-list have been set, schedule update timer. */ + if (DISTRIBUTE_LIST (type)) + ospf_distribute_list_update (type); + + return CMD_SUCCESS; +} + +int +ospf_distribute_list_out_unset (int type, char *name) +{ + /* Schedule update timer. */ + if (DISTRIBUTE_LIST (type)) + ospf_distribute_list_update (type); + + /* Unset distribute-list. */ + DISTRIBUTE_LIST (type) = NULL; + + /* Clear distribute-name. */ + if (DISTRIBUTE_NAME (type)) + free (DISTRIBUTE_NAME (type)); + + DISTRIBUTE_NAME (type) = NULL; + + return CMD_SUCCESS; +} + +/* distribute-list update timer. */ +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; + u_char type; + + type = (int) THREAD_ARG (thread); + rt = EXTERNAL_INFO (type); + + ospf_top->t_distribute_update = NULL; + + zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!"); + + /* foreach all external info. */ + if (rt) + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + { + if (is_prefix_default (&ei->p)) + ospf_external_lsa_refresh_default (); + else if ((lsa = ospf_external_info_find_lsa (&ei->p))) + ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_IF_CHANGED); + else + ospf_external_lsa_originate (ei); + } + return 0; +} + +#define OSPF_DISTRIBUTE_UPDATE_DELAY 5 + +/* Update distribute-list and set timer to apply access-list. */ +void +ospf_distribute_list_update (int type) +{ + struct route_table *rt; + + zlog_info ("ospf_distribute_list_update(): start"); + + /* External info does not exist. */ + if (!(rt = EXTERNAL_INFO (type))) + return; + + /* If exists previously invoked thread, then cancel it. */ + if (ospf_top->t_distribute_update) + OSPF_TIMER_OFF (ospf_top->t_distribute_update); + + /* Set timer. */ + ospf_top->t_distribute_update = + thread_add_timer (master, ospf_distribute_list_update_timer, + (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); + + zlog_info ("ospf_distribute_list_update(): stop"); +} + +/* If access-list is updated, apply some check. */ +void +ospf_filter_update (struct access_list *access) +{ + int type; + int abr_inv = 0; + struct ospf_area *area; + listnode node; + + /* If OSPF instatnce does not exist, return right now. */ + if (!ospf_top) + return; + + + /* Update distribute-list, and apply filter. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP (type) != NULL) + { + /* if route-map is not NULL it may be using this access list */ + ospf_distribute_list_update (type); + continue; + } + + + if (DISTRIBUTE_NAME (type)) + { + /* Keep old access-list for distribute-list. */ + struct access_list *old = DISTRIBUTE_LIST (type); + + /* Update access-list for distribute-list. */ + DISTRIBUTE_LIST (type) = + access_list_lookup (AFI_IP, DISTRIBUTE_NAME (type)); + + /* No update for this distribute type. */ + if (old == NULL && DISTRIBUTE_LIST (type) == NULL) + continue; + + /* Schedule distribute-list update timer. */ + if (DISTRIBUTE_LIST (type) == NULL || + strcmp (DISTRIBUTE_NAME (type), access->name) == 0) + ospf_distribute_list_update (type); + } + } + + /* Update Area access-list. */ + for (node = listhead (ospf_top->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + { + 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 (OSPF_IS_ABR && abr_inv) + ospf_schedule_abr_task (); +} + + +struct ospf_distance * +ospf_distance_new () +{ + struct ospf_distance *new; + new = XMALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance)); + memset (new, 0, sizeof (struct ospf_distance)); + return new; +} + +void +ospf_distance_free (struct ospf_distance *odistance) +{ + XFREE (MTYPE_OSPF_DISTANCE, odistance); +} + +int +ospf_distance_set (struct vty *vty, char *distance_str, char *ip_str, + 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_top->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, char *distance_str, char *ip_str, + 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); + + rn = route_node_lookup (ospf_top->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 route_node *rn; + struct ospf_distance *odistance; + + for (rn = route_top (ospf_top->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) +{ +#if 0 + struct route_node *rn; + struct ospf_distance *odistance; + struct access_list *alist; + struct prefix_ipv4 q; + + memset (&q, 0, sizeof (struct prefix_ipv4)); + q.family = AF_INET; + /* q.prefix = */ + q.prefixlen = IPV4_MAX_BITLEN; +#endif /* 0 */ + + if (! ospf_top) + return 0; + +#if 0 + rn = route_node_match (ospf_top->distance_table, (struct prefix *) &q); + if (rn) + { + odistance = rn->info; + route_unlock_node (rn); + + if (odistance->access_list) + { + alist = access_list_lookup (AFI_IP, odistance->access_list); + if (alist == NULL) + return 0; + if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) + return 0; + + return odistance->distance; + } + else + return odistance->distance; + } +#endif /* 0 */ + + if (ospf_top->distance_intra) + if (or->path_type == OSPF_PATH_INTRA_AREA) + return ospf_top->distance_intra; + + if (ospf_top->distance_inter) + if (or->path_type == OSPF_PATH_INTER_AREA) + return ospf_top->distance_inter; + + if (ospf_top->distance_external) + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL + || or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + return ospf_top->distance_external; + + if (ospf_top->distance_all) + return ospf_top->distance_all; + + return 0; +} + +void +ospf_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF); + 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); +} -- cgit v1.2.1