summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/hash.h3
-rw-r--r--lib/log.c5
-rw-r--r--lib/nexthop_group.c42
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/zclient.c95
-rw-r--r--lib/zclient.h56
6 files changed, 184 insertions, 19 deletions
diff --git a/lib/hash.h b/lib/hash.h
index e7ba3187f5..00953ff3b3 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -236,7 +236,8 @@ extern void *hash_release(struct hash *hash, void *data);
* Iterate over the elements in a hash table.
*
* It is safe to delete items passed to the iteration function from the hash
- * table during iteration. Please note that adding entries to the hash
+ * table during iteration. More than one item cannot be deleted during each
+ * iteration. Please note that adding entries to the hash
* during the walk will cause undefined behavior in that some new entries
* will be walked and some will not. So do not do this.
*
diff --git a/lib/log.c b/lib/log.c
index 4054185019..b629658f75 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -452,7 +452,10 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
DESC_ENTRY(ZEBRA_OPAQUE_REGISTER),
DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER),
- DESC_ENTRY(ZEBRA_NEIGH_DISCOVER)};
+ DESC_ENTRY(ZEBRA_NEIGH_DISCOVER),
+ DESC_ENTRY(ZEBRA_NHG_ADD),
+ DESC_ENTRY(ZEBRA_NHG_DEL),
+ DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 687cac4062..83905abe43 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -41,6 +41,7 @@ struct nexthop_hold {
char *nhvrf_name;
union sockunion *addr;
char *intf;
+ bool onlink;
char *labels;
uint32_t weight;
char *backup_str;
@@ -560,6 +561,10 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
if (ret)
return ret;
+ ret = ((int)nh2->onlink) - ((int)nh1->onlink);
+ if (ret)
+ return ret;
+
return nhgc_cmp_helper(nh1->labels, nh2->labels);
}
@@ -673,8 +678,8 @@ DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
- const char *intf, const char *labels,
- const uint32_t weight,
+ const char *intf, bool onlink,
+ const char *labels, const uint32_t weight,
const char *backup_str)
{
struct nexthop_hold *nh;
@@ -690,6 +695,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
if (labels)
nh->labels = XSTRDUP(MTYPE_TMP, labels);
+ nh->onlink = onlink;
+
nh->weight = weight;
if (backup_str)
@@ -738,9 +745,10 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
*/
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
- const char *intf, const char *name,
- const char *labels, int *lbl_ret,
- uint32_t weight, const char *backup_str)
+ const char *intf, bool onlink,
+ const char *name, const char *labels,
+ int *lbl_ret, uint32_t weight,
+ const char *backup_str)
{
int ret = 0;
struct vrf *vrf;
@@ -764,6 +772,9 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
return false;
}
+ if (onlink)
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_ONLINK);
+
if (addr) {
if (addr->sa.sa_family == AF_INET) {
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
@@ -820,15 +831,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
static bool nexthop_group_parse_nhh(struct nexthop *nhop,
const struct nexthop_hold *nhh)
{
- return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
- nhh->nhvrf_name, nhh->labels, NULL,
- nhh->weight, nhh->backup_str));
+ return (nexthop_group_parse_nexthop(
+ nhop, nhh->addr, nhh->intf, nhh->onlink, nhh->nhvrf_name,
+ nhh->labels, NULL, nhh->weight, nhh->backup_str));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"[no] nexthop\
<\
- <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+ <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf [onlink$onlink]]\
|INTERFACE$intf\
>\
[{ \
@@ -842,6 +853,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
+ "Treat nexthop as directly attached to the interface\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n"
@@ -870,8 +882,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
}
- legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
- &lbl_ret, weight, backup_idx);
+ legal = nexthop_group_parse_nexthop(&nhop, addr, intf, !!onlink,
+ vrf_name, label, &lbl_ret, weight,
+ backup_idx);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -933,8 +946,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
/* Save config always */
- nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
- weight, backup_idx);
+ nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, !!onlink,
+ label, weight, backup_idx);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
@@ -1106,6 +1119,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->intf)
vty_out(vty, " %s", nh->intf);
+ if (nh->onlink)
+ vty_out(vty, " onlink");
+
if (nh->nhvrf_name)
vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
diff --git a/lib/route_types.txt b/lib/route_types.txt
index b549c11cfc..37cc2fb590 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -84,7 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
-ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
+ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group"
ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
diff --git a/lib/zclient.c b/lib/zclient.c
index c5016d22e2..b7d240b4e8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1017,6 +1017,57 @@ done:
return ret;
}
+int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
+{
+ int i;
+
+ if (cmd != ZEBRA_NHG_DEL && cmd != ZEBRA_NHG_ADD) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: Specified zapi NHG command (%d) doesn't exist\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ stream_reset(s);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+ stream_putw(s, api_nhg->proto);
+ stream_putl(s, api_nhg->id);
+
+ if (cmd == ZEBRA_NHG_ADD) {
+ /* Nexthops */
+ zapi_nexthop_group_sort(api_nhg->nexthops,
+ api_nhg->nexthop_num);
+
+ stream_putw(s, api_nhg->nexthop_num);
+
+ for (i = 0; i < api_nhg->nexthop_num; i++)
+ zapi_nexthop_encode(s, &api_nhg->nexthops[i], 0, 0);
+
+ /* Backup nexthops */
+
+ stream_putw(s, api_nhg->backup_nexthop_num);
+
+ for (i = 0; i < api_nhg->backup_nexthop_num; i++)
+ zapi_nexthop_encode(s, &api_nhg->backup_nexthops[i], 0,
+ 0);
+ }
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg)
+{
+ api_nhg->proto = zclient->redist_default;
+
+ if (zapi_nhg_encode(zclient->obuf, cmd, api_nhg))
+ return -1;
+
+ return zclient_send_message(zclient);
+}
+
int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
{
struct zapi_nexthop *api_nh;
@@ -1058,6 +1109,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
stream_write(s, (uint8_t *)&api->src_prefix.prefix, psize);
}
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG))
+ stream_putl(s, api->nhgid);
+
/* Nexthops. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
/* limit the number of nexthops if necessary */
@@ -1171,8 +1225,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
/*
* Decode a single zapi nexthop object
*/
-static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
- uint32_t api_flags, uint32_t api_message)
+int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
+ uint32_t api_flags, uint32_t api_message)
{
int i, ret = -1;
@@ -1328,6 +1382,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
}
}
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG))
+ STREAM_GETL(s, api->nhgid);
+
/* Nexthops. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
STREAM_GETW(s, api->nexthop_num);
@@ -1432,6 +1489,22 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
return 0;
}
+bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
+ enum zapi_nhg_notify_owner *note)
+{
+ uint32_t read_id;
+
+ STREAM_GET(note, s, sizeof(*note));
+ STREAM_GETL(s, read_id);
+
+ *id = read_id;
+
+ return true;
+
+stream_failure:
+ return false;
+}
+
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note)
@@ -1582,6 +1655,9 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
znh->ifindex = nh->ifindex;
znh->gate = nh->gate;
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
+ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+
if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
/* Validate */
@@ -3733,6 +3809,11 @@ static int zclient_read(struct thread *thread)
(*zclient->rule_notify_owner)(command, zclient, length,
vrf_id);
break;
+ case ZEBRA_NHG_NOTIFY_OWNER:
+ if (zclient->nhg_notify_owner)
+ (*zclient->nhg_notify_owner)(command, zclient, length,
+ vrf_id);
+ break;
case ZEBRA_GET_LABEL_CHUNK:
if (zclient->label_chunk)
(*zclient->label_chunk)(command, zclient, length,
@@ -4001,3 +4082,13 @@ int zclient_send_neigh_discovery_req(struct zclient *zclient,
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
}
+
+/*
+ * Get a starting nhg point for a routing protocol
+ */
+uint32_t zclient_get_nhg_start(uint32_t proto)
+{
+ assert(proto < ZEBRA_ROUTE_MAX);
+
+ return ZEBRA_NHG_PROTO_SPACING * proto;
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index 050877f27a..959a101395 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -209,6 +209,9 @@ typedef enum {
ZEBRA_MLAG_CLIENT_REGISTER,
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
+ ZEBRA_NHG_ADD,
+ ZEBRA_NHG_DEL,
+ ZEBRA_NHG_NOTIFY_OWNER,
ZEBRA_ERROR,
ZEBRA_CLIENT_CAPABILITIES,
ZEBRA_OPAQUE_MESSAGE,
@@ -354,6 +357,7 @@ struct zclient {
int (*mlag_process_up)(void);
int (*mlag_process_down)(void);
int (*mlag_handle_msg)(struct stream *msg, int len);
+ int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS);
int (*handle_error)(enum zebra_error_types error);
int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS);
int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
@@ -370,6 +374,7 @@ struct zclient {
#define ZAPI_MESSAGE_SRCPFX 0x20
/* Backup nexthops are present */
#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
+#define ZAPI_MESSAGE_NHG 0x80
/*
* This should only be used by a DAEMON that needs to communicate
@@ -434,6 +439,20 @@ struct zapi_nexthop {
#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */
/*
+ * ZAPI Nexthop Group. For use with protocol creation of nexthop groups.
+ */
+struct zapi_nhg {
+ uint16_t proto;
+ uint32_t id;
+
+ uint16_t nexthop_num;
+ struct zapi_nexthop nexthops[MULTIPATH_NUM];
+
+ uint16_t backup_nexthop_num;
+ struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+};
+
+/*
* Some of these data structures do not map easily to
* a actual data structure size giving different compilers
* and systems. For those data structures we need
@@ -514,6 +533,8 @@ struct zapi_route {
uint16_t backup_nexthop_num;
struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+ uint32_t nhgid;
+
uint8_t distance;
uint32_t metric;
@@ -592,6 +613,13 @@ enum zapi_route_notify_owner {
ZAPI_ROUTE_REMOVE_FAIL,
};
+enum zapi_nhg_notify_owner {
+ ZAPI_NHG_FAIL_INSTALL,
+ ZAPI_NHG_INSTALLED,
+ ZAPI_NHG_REMOVED,
+ ZAPI_NHG_REMOVE_FAIL,
+};
+
enum zapi_rule_notify_owner {
ZAPI_RULE_FAIL_INSTALL,
ZAPI_RULE_INSTALLED,
@@ -671,6 +699,22 @@ struct zclient_options {
extern struct zclient_options zclient_options_default;
+/*
+ * We reserve the top 4 bits for l2-NHG, everything else
+ * is for zebra/proto l3-NHG.
+ *
+ * Each client is going to get it's own nexthop group space
+ * and we'll separate them, we'll figure out where to start based upon
+ * the route_types.h
+ */
+#define ZEBRA_NHG_PROTO_UPPER \
+ ((uint32_t)250000000) /* Bottom 28 bits then rounded down */
+#define ZEBRA_NHG_PROTO_SPACING (ZEBRA_NHG_PROTO_UPPER / ZEBRA_ROUTE_MAX)
+#define ZEBRA_NHG_PROTO_LOWER \
+ (ZEBRA_NHG_PROTO_SPACING * (ZEBRA_ROUTE_CONNECT + 1))
+
+extern uint32_t zclient_get_nhg_start(uint32_t proto);
+
extern struct zclient *zclient_new(struct thread_master *m,
struct zclient_options *opt);
@@ -853,7 +897,11 @@ extern int zclient_send_rnh(struct zclient *zclient, int command,
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
uint32_t api_flags, uint32_t api_message);
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
-extern int zapi_route_decode(struct stream *, struct zapi_route *);
+extern int zapi_route_decode(struct stream *s, struct zapi_route *api);
+extern int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
+ uint32_t api_flags, uint32_t api_message);
+bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
+ enum zapi_nhg_notify_owner *note);
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note);
@@ -864,6 +912,12 @@ bool zapi_ipset_notify_decode(struct stream *s,
uint32_t *unique,
enum zapi_ipset_notify_owner *note);
+
+extern int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
+extern int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
+extern int zclient_nhg_send(struct zclient *zclient, int cmd,
+ struct zapi_nhg *api_nhg);
+
#define ZEBRA_IPSET_NAME_SIZE 32
bool zapi_ipset_entry_notify_decode(struct stream *s,