summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--staticd/static_zebra.c92
-rw-r--r--zebra/kernel_netlink.c12
-rw-r--r--zebra/kernel_netlink.h2
-rw-r--r--zebra/rt_netlink.c64
-rw-r--r--zebra/zapi_msg.c10
-rw-r--r--zebra/zebra_rnh.c22
-rw-r--r--zebra/zebra_rnh.h2
7 files changed, 189 insertions, 15 deletions
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index 56ba70eaf8..a87dc074df 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -34,6 +34,7 @@
#include "log.h"
#include "nexthop.h"
#include "nexthop_group.h"
+#include "hash.h"
#include "static_vrf.h"
#include "static_routes.h"
@@ -43,6 +44,7 @@
/* 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)
{
@@ -176,10 +178,16 @@ static void zebra_connected(struct zclient *zclient)
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
+struct static_nht_data {
+ struct prefix *nh;
+ 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;
@@ -191,6 +199,14 @@ static int static_zebra_nexthop_update(int command, struct zclient *zclient,
if (nhr.prefix.family == AF_INET6)
afi = AFI_IP6;
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.nh = &nhr.prefix;
+
+ nhtd = hash_lookup(static_nht_hash, &lookup);
+ if (nhtd)
+ nhtd->nh_num = nhr.nexthop_num;
+
+
static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
return 1;
}
@@ -200,10 +216,50 @@ 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;
+
+ return prefix_hash_key(nhtd->nh);
+}
+
+static int static_nht_hash_cmp(const void *d1, const void *d2)
+{
+ const struct static_nht_data *nhtd1 = d1;
+ const struct static_nht_data *nhtd2 = d2;
+
+ 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;
+
+ 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;
@@ -224,20 +280,48 @@ void static_zebra_nht_register(struct static_route *si, bool reg)
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;
+
+ 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__);
-
- si->nh_registered = reg;
}
extern void static_zebra_route_add(struct route_node *rn,
@@ -373,4 +457,8 @@ void static_zebra_init(void)
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");
}
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index ef7c26c9df..545b4d9d6d 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -467,6 +467,18 @@ void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta,
}
}
+/**
+ * netlink_parse_rtattr_nested() - Parses a nested route attribute
+ * @tb: Pointer to array for storing rtattr in.
+ * @max: Max number to store.
+ * @rta: Pointer to rtattr to look for nested items in.
+ */
+void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
+ struct rtattr *rta)
+{
+ netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
+}
+
int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
const void *data, unsigned int alen)
{
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 65df15599d..af0cc83f4a 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -28,6 +28,8 @@
extern void netlink_parse_rtattr(struct rtattr **tb, int max,
struct rtattr *rta, int len);
+extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
+ struct rtattr *rta);
extern int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
const void *data, unsigned int alen);
extern int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 6a258e6853..cab3f43b19 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -246,6 +246,33 @@ static vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
return VRF_DEFAULT;
}
+/**
+ * @parse_encap_mpls() - Parses encapsulated mpls attributes
+ * @tb: Pointer to rtattr to look for nested items in.
+ * @labels: Pointer to store labels in.
+ *
+ * Return: Number of mpls labels found.
+ */
+static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
+{
+ struct rtattr *tb_encap[MPLS_IPTUNNEL_MAX + 1] = {0};
+ mpls_lse_t *lses = NULL;
+ int num_labels = 0;
+ uint32_t ttl = 0;
+ uint32_t bos = 0;
+ uint32_t exp = 0;
+ mpls_label_t label = 0;
+
+ netlink_parse_rtattr_nested(tb_encap, MPLS_IPTUNNEL_MAX, tb);
+ lses = (mpls_lse_t *)RTA_DATA(tb_encap[MPLS_IPTUNNEL_DST]);
+ while (!bos && num_labels < MPLS_MAX_LABELS) {
+ mpls_lse_decode(lses[num_labels], &label, &ttl, &exp, &bos);
+ labels[num_labels++] = label;
+ }
+
+ return num_labels;
+}
+
/* Looking up routing table by netlink interface. */
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
@@ -274,6 +301,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
void *src = NULL; /* IPv6 srcdest source prefix */
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
+ /* MPLS labels */
+ mpls_label_t labels[MPLS_MAX_LABELS] = {0};
+ int num_labels = 0;
+
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
@@ -508,6 +539,17 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
nh.vrf_id = nh_vrf_id;
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels =
+ parse_encap_mpls(tb[RTA_ENCAP], labels);
+ }
+
+ if (num_labels)
+ nexthop_add_labels(&nh, ZEBRA_LSP_STATIC,
+ num_labels, labels);
+
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
&src_p, &nh, table, metric, mtu, distance, tag);
} else {
@@ -532,6 +574,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
re->tag = tag;
for (;;) {
+ struct nexthop *nh = NULL;
vrf_id_t nh_vrf_id;
if (len < (int)sizeof(*rtnh)
|| rtnh->rtnh_len > len)
@@ -569,35 +612,46 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (tb[RTA_GATEWAY])
gate = RTA_DATA(
tb[RTA_GATEWAY]);
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(
+ tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels = parse_encap_mpls(
+ tb[RTA_ENCAP], labels);
+ }
}
if (gate) {
if (rtm->rtm_family == AF_INET) {
if (index)
- route_entry_nexthop_ipv4_ifindex_add(
+ nh = route_entry_nexthop_ipv4_ifindex_add(
re, gate,
prefsrc, index,
nh_vrf_id);
else
- route_entry_nexthop_ipv4_add(
+ nh = route_entry_nexthop_ipv4_add(
re, gate,
prefsrc,
nh_vrf_id);
} else if (rtm->rtm_family
== AF_INET6) {
if (index)
- route_entry_nexthop_ipv6_ifindex_add(
+ nh = route_entry_nexthop_ipv6_ifindex_add(
re, gate, index,
nh_vrf_id);
else
- route_entry_nexthop_ipv6_add(
+ nh = route_entry_nexthop_ipv6_add(
re, gate,
nh_vrf_id);
}
} else
- route_entry_nexthop_ifindex_add(
+ nh = route_entry_nexthop_ifindex_add(
re, index, nh_vrf_id);
+ if (nh && num_labels)
+ nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
+ num_labels, labels);
+
if (rtnh->rtnh_len == 0)
break;
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 6990fd95f5..d95f78109c 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1022,6 +1022,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
unsigned short l = 0;
uint8_t flags = 0;
uint16_t type = cmd2type[hdr->command];
+ bool exist;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
@@ -1064,7 +1065,10 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
p.family);
return;
}
- rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type);
+ rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type, &exist);
+ if (!rnh)
+ return;
+
if (type == RNH_NEXTHOP_TYPE) {
if (flags
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
@@ -1084,7 +1088,9 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
/* Anything not AF_INET/INET6 has been filtered out above */
- zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p);
+ if (!exist)
+ zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type,
+ &p);
}
stream_failure:
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 156600c105..0b585af6a0 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -103,7 +103,8 @@ char *rnh_str(struct rnh *rnh, char *buf, int size)
return buf;
}
-struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
+struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
+ bool *exists)
{
struct route_table *table;
struct route_node *rn;
@@ -119,6 +120,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
prefix2str(p, buf, sizeof(buf));
zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
buf, type);
+ exists = false;
return NULL;
}
@@ -136,7 +138,9 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
route_lock_node(rn);
rn->info = rnh;
rnh->node = rn;
- }
+ *exists = false;
+ } else
+ *exists = true;
route_unlock_node(rn);
return (rn->info);
@@ -190,6 +194,14 @@ void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
route_unlock_node(rn);
}
+/*
+ * This code will send to the registering client
+ * the looked up rnh.
+ * For a rnh that was created, there is no data
+ * so it will send an empty nexthop group
+ * If rnh exists then we know it has been evaluated
+ * and as such it will have a resolved rnh.
+ */
void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_type_t type, vrf_id_t vrf_id)
{
@@ -201,8 +213,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
}
if (!listnode_lookup(rnh->client_list, client)) {
listnode_add(rnh->client_list, client);
- send_client(rnh, client, type,
- vrf_id); // Pending: check if its needed
+ send_client(rnh, client, type, vrf_id);
}
}
@@ -247,9 +258,10 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
{
struct prefix nh;
struct rnh *rnh;
+ bool exists;
addr2hostprefix(pw->af, &pw->nexthop, &nh);
- rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
+ rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists);
if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
listnode_add(rnh->zebra_pseudowire_list, pw);
pw->rnh = rnh;
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index 9e09a1bc6f..f4b4b56390 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -68,7 +68,7 @@ static inline int rnh_resolve_via_default(int family)
}
extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
- rnh_type_t type);
+ rnh_type_t type, bool *exists);
extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
rnh_type_t type);
extern void zebra_free_rnh(struct rnh *rnh);