summaryrefslogtreecommitdiff
path: root/staticd/static_zebra.c
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2018-05-08 07:58:32 -0400
committerDonald Sharp <sharpd@cumulusnetworks.com>2018-07-29 12:37:24 -0400
commit7e24fdf333e8ffe78403788d824eae110c6e65bf (patch)
tree08564ff89be16bb9928acb85ffdd05d7e31a196f /staticd/static_zebra.c
parentf23cbcda591480973f0be795d487c9268cb667ec (diff)
staticd: Start the addition of a staticd
This is the start of separating out the static handling code from zebra -> staticd. This will help simplify the zebra code and isolate static route handling to it's own code base. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Diffstat (limited to 'staticd/static_zebra.c')
-rw-r--r--staticd/static_zebra.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
new file mode 100644
index 0000000000..3f7440dfaf
--- /dev/null
+++ b/staticd/static_zebra.c
@@ -0,0 +1,377 @@
+/*
+ * Zebra connect code.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * FRR 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.
+ *
+ * FRR 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 this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "srcdest_table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+#include "nexthop.h"
+#include "nexthop_group.h"
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_zebra.h"
+#include "static_nht.h"
+#include "static_vty.h"
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient;
+
+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(ifname_tmp, VRF_DEFAULT);
+}
+
+/* Inteface addition message from zebra. */
+static int 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);
+
+ if (!ifp)
+ return 0;
+
+ static_ifindex_update(ifp, true);
+ return 0;
+}
+
+static int interface_delete(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s;
+
+ 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_set_index(ifp, IFINDEX_INTERNAL);
+
+ static_ifindex_update(ifp, false);
+ return 0;
+}
+
+static int interface_address_add(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+ return 0;
+}
+
+static int interface_address_delete(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)
+ return 0;
+
+ connected_free(c);
+ return 0;
+}
+
+static int interface_state_up(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_if_lookup(zclient->ibuf);
+
+ if (if_is_vrf(ifp)) {
+ struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
+
+ static_fixup_vrf_ids(svrf);
+ static_config_install_delayed_routes(svrf);
+ }
+
+ return 0;
+}
+
+static int interface_state_down(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ zebra_interface_state_read(zclient->ibuf, vrf_id);
+
+ return 0;
+}
+
+static int route_notify_owner(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct prefix p;
+ enum zapi_route_notify_owner note;
+ uint32_t table_id;
+ char buf[PREFIX_STRLEN];
+
+ prefix2str(&p, buf, sizeof(buf));
+
+ if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
+ return -1;
+
+ switch (note) {
+ case ZAPI_ROUTE_FAIL_INSTALL:
+ zlog_warn("%s: Route %s failed to install for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ case ZAPI_ROUTE_BETTER_ADMIN_WON:
+ zlog_warn("%s: Route %s over-ridden by better route for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ case ZAPI_ROUTE_INSTALLED:
+ break;
+ case ZAPI_ROUTE_REMOVED:
+ break;
+ case ZAPI_ROUTE_REMOVE_FAIL:
+ zlog_warn("%s: Route %s failure to remove for table: %u",
+ __PRETTY_FUNCTION__, buf, table_id);
+ break;
+ }
+
+ return 0;
+}
+static void zebra_connected(struct zclient *zclient)
+{
+ zclient_send_reg_requests(zclient, VRF_DEFAULT);
+}
+
+
+static int static_zebra_nexthop_update(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct zapi_route nhr;
+ afi_t afi = AFI_IP;
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ zlog_warn("Failure to decode nexthop update message");
+ return 1;
+ }
+
+ if (nhr.prefix.family == AF_INET6)
+ afi = AFI_IP6;
+
+ static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
+ return 1;
+}
+
+static void static_zebra_capabilities(struct zclient_capabilities *cap)
+{
+ mpls_enabled = cap->mpls_enabled;
+}
+
+void static_zebra_nht_register(struct static_route *si, bool reg)
+{
+ uint32_t cmd;
+ struct prefix p;
+
+ cmd = (reg) ?
+ ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
+
+ if (si->nh_registered && reg)
+ return;
+
+ if (!si->nh_registered && !reg)
+ return;
+
+ memset(&p, 0, sizeof(p));
+ switch (si->type) {
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ case STATIC_IFNAME:
+ case STATIC_BLACKHOLE:
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ return;
+ case STATIC_IPV4_GATEWAY:
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = si->addr.ipv4;
+ break;
+ case STATIC_IPV6_GATEWAY:
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_BITLEN;
+ p.u.prefix6 = si->addr.ipv6;
+ break;
+ }
+
+ if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
+ zlog_warn("%s: Failure to send nexthop to zebra",
+ __PRETTY_FUNCTION__);
+
+ si->nh_registered = reg;
+}
+
+extern void static_zebra_route_add(struct route_node *rn, vrf_id_t vrf_id,
+ safi_t safi, bool install)
+{
+ struct static_route *si = rn->info;
+ const struct prefix *p, *src_pp;
+ struct zapi_nexthop *api_nh;
+ struct zapi_route api;
+ uint32_t nh_num = 0;
+
+ p = src_pp = NULL;
+ srcdest_rnode_prefixes(rn, &p, &src_pp);
+
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = vrf_id;
+ api.type = ZEBRA_ROUTE_STATIC;
+ api.safi = safi;
+ memcpy(&api.prefix, p, sizeof(api.prefix));
+
+ if (src_pp) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+ memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
+ }
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+
+ for (/*loaded above*/; si; si = si->next) {
+ api_nh = &api.nexthops[nh_num];
+ if (si->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+
+ /*
+ * If we create a ecmp static route the
+ * last distance and tag entered wins. Why because
+ * this cli choosen sucks
+ */
+ if (si->distance) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = si->distance;
+ }
+ if (si->tag) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = si->tag;
+ }
+
+ api.tableid = si->table_id;
+
+ api_nh->vrf_id = si->nh_vrf_id;
+ switch (si->type) {
+ case STATIC_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->ifindex = si->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
+ break;
+ case STATIC_IPV4_GATEWAY:
+ if (!si->nh_valid)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->ifindex = si->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV6_GATEWAY:
+ if (!si->nh_valid)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV6;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ if (si->ifindex == IFINDEX_INTERNAL)
+ continue;
+ api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ api_nh->ifindex = si->ifindex;
+ api_nh->gate = si->addr;
+ break;
+ case STATIC_BLACKHOLE:
+ api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
+ switch (si->bh_type) {
+ case STATIC_BLACKHOLE_DROP:
+ case STATIC_BLACKHOLE_NULL:
+ api_nh->bh_type = BLACKHOLE_NULL;
+ break;
+ case STATIC_BLACKHOLE_REJECT:
+ api_nh->bh_type = BLACKHOLE_REJECT;
+ }
+ break;
+ }
+
+ if (si->snh_label.num_labels) {
+ int i;
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
+ api_nh->label_num = si->snh_label.num_labels;
+ for (i = 0; i < api_nh->label_num; i++)
+ api_nh->labels[i] = si->snh_label.label[i];
+ }
+ nh_num++;
+ }
+
+ api.nexthop_num = nh_num;
+
+ /*
+ * If we have been given an install but nothing is valid
+ * go ahead and delete the route for double plus fun
+ */
+ if (!nh_num && install)
+ install = false;
+
+ zclient_route_send(install ?
+ ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
+ zclient, &api);
+}
+void static_zebra_init(void)
+{
+ struct zclient_options opt = { .receive_notify = true };
+
+ zclient = zclient_new_notify(master, &opt);
+
+ zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
+ zclient->zebra_capabilities = static_zebra_capabilities;
+ zclient->zebra_connected = zebra_connected;
+ zclient->interface_add = interface_add;
+ zclient->interface_delete = interface_delete;
+ zclient->interface_up = interface_state_up;
+ zclient->interface_down = interface_state_down;
+ zclient->interface_address_add = interface_address_add;
+ zclient->interface_address_delete = interface_address_delete;
+ zclient->route_notify_owner = route_notify_owner;
+ zclient->nexthop_update = static_zebra_nexthop_update;
+}