summaryrefslogtreecommitdiff
path: root/eigrpd/eigrp_zebra.c
diff options
context:
space:
mode:
Diffstat (limited to 'eigrpd/eigrp_zebra.c')
-rw-r--r--eigrpd/eigrp_zebra.c579
1 files changed, 579 insertions, 0 deletions
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
new file mode 100644
index 0000000000..aef7208987
--- /dev/null
+++ b/eigrpd/eigrp_zebra.c
@@ -0,0 +1,579 @@
+/*
+ * Zebra connect library for EIGRP.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * 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 "nexthop.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+
+static int eigrp_interface_add (int , struct zclient *, zebra_size_t, vrf_id_t);
+static int eigrp_interface_delete (int , struct zclient *,
+ zebra_size_t, vrf_id_t);
+static int eigrp_interface_address_add (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_address_delete (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_state_up (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_state_down (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static struct interface * zebra_interface_if_lookup (struct stream *);
+
+static int eigrp_zebra_read_ipv4 (int , struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+
+/* 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
+eigrp_router_id_update_zebra (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct eigrp *eigrp;
+ struct prefix router_id;
+ zebra_router_id_update_read (zclient->ibuf,&router_id);
+
+ router_id_zebra = router_id.u.prefix4;
+
+ eigrp = eigrp_lookup ();
+
+ if (eigrp != NULL)
+ eigrp_router_id_update (eigrp);
+
+ return 0;
+}
+
+
+void
+eigrp_zebra_init (void)
+{
+ zclient = zclient_new (master);
+
+ zclient_init (zclient, ZEBRA_ROUTE_EIGRP, 0);
+ zclient->router_id_update = eigrp_router_id_update_zebra;
+ zclient->interface_add = eigrp_interface_add;
+ zclient->interface_delete = eigrp_interface_delete;
+ zclient->interface_up = eigrp_interface_state_up;
+ zclient->interface_down = eigrp_interface_state_down;
+ zclient->interface_address_add = eigrp_interface_address_add;
+ zclient->interface_address_delete = eigrp_interface_address_delete;
+ zclient->redistribute_route_ipv4_add = eigrp_zebra_read_ipv4;
+ zclient->redistribute_route_ipv4_del = eigrp_zebra_read_ipv4;
+}
+
+
+/* Zebra route add and delete treatment. */
+static int
+eigrp_zebra_read_ipv4 (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct stream *s;
+ struct zapi_ipv4 api;
+ struct prefix_ipv4 p;
+ struct eigrp *eigrp;
+
+ s = zclient->ibuf;
+
+ /* Type, flags, message. */
+ api.type = stream_getc (s);
+ api.instance = stream_getw (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);
+ stream_get_ipv4 (s);
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+ {
+ api.ifindex_num = stream_getc (s);
+ /* XXX assert(api.ifindex_num == 1); */
+ stream_getl (s); /* ifindex, unused */
+ }
+ 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);
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ return 0;
+
+ if (command == ZEBRA_IPV4_ROUTE_ADD)
+ {
+
+ }
+ else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
+ {
+
+ }
+
+ return 0;
+}
+
+/* Inteface addition message from zebra. */
+static int
+eigrp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
+
+ assert (ifp->info);
+
+ if (!EIGRP_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
+ IF_DEF_PARAMS (ifp)->type = eigrp_default_iftype (ifp);
+ }
+
+ eigrp_if_update (ifp);
+
+ return 0;
+}
+
+static int
+eigrp_interface_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ 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, vrf_id);
+
+ 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_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
+ ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ if (rn->info)
+ eigrp_if_free ((struct eigrp_interface *) rn->info, INTERFACE_DOWN_BY_ZEBRA);
+
+ ifp->ifindex = IFINDEX_INTERNAL;
+ return 0;
+}
+
+static int
+eigrp_interface_address_add (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *c;
+
+ c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
+
+ if (c == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ {
+ char buf[128];
+ prefix2str (c->address, buf, sizeof (buf));
+ zlog_debug ("Zebra: interface %s address add %s", c->ifp->name, buf);
+ }
+
+ eigrp_if_update (c->ifp);
+
+ return 0;
+}
+
+static int
+eigrp_interface_address_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *c;
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ struct route_node *rn;
+ struct prefix p;
+
+ c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
+
+ if (c == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (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);
+ ei = rn->info;
+
+ /* Call interface hook functions to clean up */
+ eigrp_if_free (ei, INTERFACE_DOWN_BY_ZEBRA);
+
+ connected_free (c);
+
+ return 0;
+}
+
+static int
+eigrp_interface_state_up (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ 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_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);
+
+ if (if_tmp.bandwidth != ifp->bandwidth)
+ {
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
+ ifp->name, if_tmp.bandwidth, ifp->bandwidth);
+
+// eigrp_if_recalculate_output_cost (ifp);
+ }
+
+ if (if_tmp.mtu != ifp->mtu)
+ {
+ if (IS_DEBUG_EIGRP (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. */
+ eigrp_if_reset (ifp);
+ }
+ return 0;
+ }
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+ if (IS_DEBUG_EIGRP (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 ((ei = rn->info) == NULL)
+ continue;
+
+ eigrp_if_up (ei);
+ }
+
+ return 0;
+}
+
+static int
+eigrp_interface_state_down (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ struct route_node *node;
+
+ ifp = zebra_interface_state_read (zclient->ibuf, vrf_id);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (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 ((ei = node->info) == NULL)
+ continue;
+ eigrp_if_down (ei);
+ }
+
+ 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));
+}
+
+void
+eigrp_zebra_route_add (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
+{
+ u_char message;
+ u_char flags;
+ int psize;
+ struct stream *s;
+
+ if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ {
+ message = 0;
+ flags = 0;
+
+ /* EIGRP pass nexthop and metric */
+ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (message, ZAPI_MESSAGE_METRIC);
+
+ /* Distance value. */
+// distance = eigrp_distance_apply (p, er);
+// 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, VRF_DEFAULT);
+ stream_putc (s, ZEBRA_ROUTE_EIGRP);
+ 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, 1);
+
+ /* Nexthop, ifindex, distance and metric information. */
+ stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+ stream_put_in_addr (s, &te->adv_router->src);
+ stream_putl (s, te->ei->ifp->ifindex);
+
+ if (IS_DEBUG_EIGRP (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, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
+ }
+
+ stream_putl (s, te->distance);
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ zclient_send_message (zclient);
+ }
+}
+
+void
+eigrp_zebra_route_delete (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
+{
+ u_char message;
+ u_char flags;
+ int psize;
+ struct stream *s;
+
+ if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ {
+ message = 0;
+ flags = 0;
+ /* Make packet. */
+ s = zclient->obuf;
+ stream_reset (s);
+
+ /* Put command, type, flags, message. */
+ zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT);
+ stream_putc (s, ZEBRA_ROUTE_EIGRP);
+ 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, 1);
+
+ /* Nexthop, ifindex, distance and metric information. */
+ stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+ stream_put_in_addr (s, &te->adv_router->src);
+ stream_putl (s, te->ei->ifp->ifindex);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug ("Zebra: Route del %s/%d nexthop %s",
+ inet_ntop (AF_INET, &p->prefix, buf[0], sizeof (buf[0])),
+ p->prefixlen,
+ inet_ntop (AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
+ }
+
+
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+ {
+ stream_putl (s, te->distance);
+ }
+
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ zclient_send_message (zclient);
+ }
+}
+
+vrf_bitmap_t
+eigrp_is_type_redistributed (int type)
+{
+ return (DEFAULT_ROUTE_TYPE (type)) ?
+ zclient->default_information : zclient->redist[AFI_IP][type];
+}
+
+int
+eigrp_redistribute_set (struct eigrp *eigrp, int type, struct eigrp_metrics metric)
+{
+
+ if (eigrp_is_type_redistributed (type))
+ {
+ if (eigrp_metrics_is_same(&metric, &eigrp->dmetric[type]))
+ {
+ eigrp->dmetric[type] = metric;
+ }
+
+ eigrp_external_routes_refresh (eigrp, type);
+
+// if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]",
+// eigrp_redist_string(type),
+// metric_type (eigrp, type), metric_value (eigrp, type));
+ return CMD_SUCCESS;
+ }
+
+ eigrp->dmetric[type] = metric;
+
+ zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP, type, 0, VRF_DEFAULT);
+
+// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]",
+// ospf_redist_string(type),
+// metric_type (ospf, type), metric_value (ospf, type));
+
+ ++eigrp->redistribute;
+
+ return CMD_SUCCESS;
+}
+
+int
+eigrp_redistribute_unset (struct eigrp *eigrp, int type)
+{
+
+ if (eigrp_is_type_redistributed (type))
+ {
+ memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics));
+ zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient,
+ AFI_IP, type, 0, VRF_DEFAULT);
+ --eigrp->redistribute;
+ }
+
+// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]",
+// ospf_redist_string(type),
+// metric_type (ospf, type), metric_value (ospf, type));
+
+ return CMD_SUCCESS;
+}
+