#include "table.h"
#include "memory.h"
#include "command.h"
-#include "if.h"
#include "log.h"
#include "sockunion.h"
#include "linklist.h"
-#include "thread.h"
#include "prefix.h"
#include "nexthop.h"
#include "mpls.h"
#include "jhash.h"
#include "printfrr.h"
+#include "vrf.h"
+#include "nexthop_group.h"
DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
if (next1->type > next2->type)
return 1;
+ if (next1->weight < next2->weight)
+ return -1;
+
+ if (next1->weight > next2->weight)
+ return 1;
+
switch (next1->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV6:
}
ret = _nexthop_source_cmp(next1, next2);
+ if (ret != 0)
+ goto done;
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return -1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 1;
+
+ if (next1->backup_idx < next2->backup_idx)
+ return -1;
+
+ if (next1->backup_idx > next2->backup_idx)
+ return 1;
+done:
return ret;
}
struct nexthop *nexthop_new(void)
{
- return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
+ struct nexthop *nh;
+
+ nh = XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
+
+ /*
+ * Default the weight to 1 here for all nexthops.
+ * The linux kernel does some weird stuff with adding +1 to
+ * all nexthop weights it gets over netlink.
+ * To handle this, just default everything to 1 right from
+ * from the beginning so we don't have to special case
+ * default weights in the linux netlink code.
+ *
+ * 1 should be a valid on all platforms anyway.
+ */
+ nh->weight = 1;
+
+ return nh;
}
/* Free nexthop. */
return true;
}
+/*
+ * Allocate a new nexthop object and initialize it from various args.
+ */
+struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IFINDEX;
+ nexthop->ifindex = ifindex;
+ nexthop->vrf_id = vrf_id;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IPV4;
+ nexthop->vrf_id = vrf_id;
+ nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nexthop->vrf_id = vrf_id;
+ nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
+ nexthop->ifindex = ifindex;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
+ vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = vrf_id;
+ nexthop->type = NEXTHOP_TYPE_IPV6;
+ nexthop->gate.ipv6 = *ipv6;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
+ ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = vrf_id;
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nexthop->gate.ipv6 = *ipv6;
+ nexthop->ifindex = ifindex;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = VRF_DEFAULT;
+ nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
+ nexthop->bh_type = bh_type;
+
+ return nexthop;
+}
+
/* Update nexthop with label information. */
-void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
- uint8_t num_labels, mpls_label_t *label)
+void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
+ uint8_t num_labels, const mpls_label_t *labels)
{
struct mpls_label_stack *nh_label;
int i;
- nexthop->nh_label_type = type;
+ if (num_labels == 0)
+ return;
+
+ /* Enforce limit on label stack size */
+ if (num_labels > MPLS_MAX_LABELS)
+ num_labels = MPLS_MAX_LABELS;
+
+ nexthop->nh_label_type = ltype;
+
nh_label = XCALLOC(MTYPE_NH_LABEL,
sizeof(struct mpls_label_stack)
+ num_labels * sizeof(mpls_label_t));
nh_label->num_labels = num_labels;
for (i = 0; i < num_labels; i++)
- nh_label->label[i] = *(label + i);
+ nh_label->label[i] = *(labels + i);
nexthop->nh_label = nh_label;
}
/* Free label information of nexthop, if present. */
void nexthop_del_labels(struct nexthop *nexthop)
{
- if (nexthop->nh_label) {
- XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
- nexthop->nh_label_type = ZEBRA_LSP_NONE;
- }
+ XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
+ nexthop->nh_label_type = ZEBRA_LSP_NONE;
}
const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
+ uint32_t val;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- key = jhash_2words(nexthop->ifindex,
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
+ val = 0;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ val = (uint32_t)nexthop->backup_idx;
+
+ key = jhash_3words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val,
key);
return key;
return key;
}
-void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
- struct nexthop *rparent)
+void nexthop_copy_no_recurse(struct nexthop *copy,
+ const struct nexthop *nexthop,
+ struct nexthop *rparent)
{
copy->vrf_id = nexthop->vrf_id;
copy->ifindex = nexthop->ifindex;
copy->type = nexthop->type;
copy->flags = nexthop->flags;
+ copy->weight = nexthop->weight;
+ copy->backup_idx = nexthop->backup_idx;
memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(©->src, &nexthop->src, sizeof(nexthop->src));
memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
&nexthop->nh_label->label[0]);
}
+void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
+ struct nexthop *rparent)
+{
+ nexthop_copy_no_recurse(copy, nexthop, rparent);
+
+ /* Bit of a special case here, we need to handle the case
+ * of a nexthop resolving to agroup. Hence, we need to
+ * use a nexthop_group API.
+ */
+ if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(©->resolved, nexthop->resolved, copy);
+}
+
+struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
+ struct nexthop *rparent)
+{
+ struct nexthop *new = nexthop_new();
+
+ nexthop_copy_no_recurse(new, nexthop, rparent);
+ return new;
+}
+
struct nexthop *nexthop_dup(const struct nexthop *nexthop,
struct nexthop *rparent)
{