summaryrefslogtreecommitdiff
path: root/ospfd/ospf_zebra.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /ospfd/ospf_zebra.c
Initial revision
Diffstat (limited to 'ospfd/ospf_zebra.c')
-rw-r--r--ospfd/ospf_zebra.c1180
1 files changed, 1180 insertions, 0 deletions
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 <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 "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);
+}