Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
492 lines (406 sloc) 11.5 KB
/*
* Zebra connect code.
* Copyright (C) 2018 Cumulus Networks, Inc.
* Donald Sharp
*
* This program 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 of the License, or (at your option)
* any later version.
*
* This program 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 "hash.h"
#include "jhash.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 hash *static_nht_hash;
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 (ifp) {
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);
}
/* Install any static reliant on this interface coming up */
static_install_intf_nh(ifp);
}
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];
if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
return -1;
prefix2str(&p, buf, sizeof(buf));
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);
}
struct static_nht_data {
struct prefix *nh;
vrf_id_t nh_vrf_id;
uint32_t refcount;
uint8_t nh_num;
};
static int static_zebra_nexthop_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct static_nht_data *nhtd, lookup;
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;
memset(&lookup, 0, sizeof(lookup));
lookup.nh = &nhr.prefix;
lookup.nh_vrf_id = vrf_id;
nhtd = hash_lookup(static_nht_hash, &lookup);
if (nhtd) {
nhtd->nh_num = nhr.nexthop_num;
static_nht_update(&nhr.prefix, nhr.nexthop_num, afi,
nhtd->nh_vrf_id);
} else
zlog_err("No nhtd?");
return 1;
}
static void static_zebra_capabilities(struct zclient_capabilities *cap)
{
mpls_enabled = cap->mpls_enabled;
}
static unsigned int static_nht_hash_key(void *data)
{
struct static_nht_data *nhtd = data;
unsigned int key = 0;
key = prefix_hash_key(nhtd->nh);
return jhash_1word(nhtd->nh_vrf_id, key);
}
static bool static_nht_hash_cmp(const void *d1, const void *d2)
{
const struct static_nht_data *nhtd1 = d1;
const struct static_nht_data *nhtd2 = d2;
if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
return false;
return prefix_same(nhtd1->nh, nhtd2->nh);
}
static void *static_nht_hash_alloc(void *data)
{
struct static_nht_data *copy = data;
struct static_nht_data *new;
new = XMALLOC(MTYPE_TMP, sizeof(*new));
new->nh = prefix_new();
prefix_copy(new->nh, copy->nh);
new->refcount = 0;
new->nh_num = 0;
new->nh_vrf_id = copy->nh_vrf_id;
return new;
}
static void static_nht_hash_free(void *data)
{
struct static_nht_data *nhtd = data;
prefix_free(nhtd->nh);
XFREE(MTYPE_TMP, nhtd);
}
void static_zebra_nht_register(struct static_route *si, bool reg)
{
struct static_nht_data *nhtd, lookup;
uint32_t cmd;
struct prefix p;
afi_t afi = AFI_IP;
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_IFNAME:
case STATIC_BLACKHOLE:
return;
case STATIC_IPV4_GATEWAY:
case STATIC_IPV4_GATEWAY_IFNAME:
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = si->addr.ipv4;
afi = AFI_IP;
break;
case STATIC_IPV6_GATEWAY:
case STATIC_IPV6_GATEWAY_IFNAME:
p.family = AF_INET6;
p.prefixlen = IPV6_MAX_BITLEN;
p.u.prefix6 = si->addr.ipv6;
afi = AFI_IP6;
break;
}
memset(&lookup, 0, sizeof(lookup));
lookup.nh = &p;
lookup.nh_vrf_id = si->nh_vrf_id;
si->nh_registered = reg;
if (reg) {
nhtd = hash_get(static_nht_hash, &lookup,
static_nht_hash_alloc);
nhtd->refcount++;
if (nhtd->refcount > 1) {
static_nht_update(nhtd->nh, nhtd->nh_num,
afi, si->nh_vrf_id);
return;
}
} else {
nhtd = hash_lookup(static_nht_hash, &lookup);
if (!nhtd)
return;
nhtd->refcount--;
if (nhtd->refcount >= 1)
return;
hash_release(static_nht_hash, nhtd);
static_nht_hash_free(nhtd);
}
if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
}
extern void static_zebra_route_add(struct route_node *rn,
struct static_route *si_changed,
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.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if (si_changed->distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = si_changed->distance;
}
if (si_changed->tag) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = si_changed->tag;
}
if (si_changed->table_id != 0) {
SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
api.tableid = si_changed->table_id;
}
for (/*loaded above*/; si; si = si->next) {
api_nh = &api.nexthops[nh_num];
if (si->nh_vrf_id == VRF_UNKNOWN)
continue;
if (si->distance != si_changed->distance)
continue;
if (si->table_id != si_changed->table_id)
continue;
api_nh->vrf_id = si->nh_vrf_id;
api_nh->onlink = si->onlink;
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(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;
static_nht_hash = hash_create(static_nht_hash_key,
static_nht_hash_cmp,
"Static Nexthop Tracking hash");
}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.