return ret;
}
+extern void zclient_nhg_del(struct zclient *zclient, uint32_t id)
+{
+ struct stream *s = zclient->obuf;
+
+ stream_reset(s);
+ zclient_create_header(s, ZEBRA_NHG_DEL, VRF_DEFAULT);
+
+ stream_putw(s, zclient->redist_default);
+ stream_putl(s, id);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+}
+
+static void zclient_nhg_writer(struct stream *s, uint16_t proto, int cmd,
+ uint32_t id, size_t nhops,
+ struct zapi_nexthop *znh)
+{
+ size_t i;
+
+ stream_reset(s);
+
+ zapi_nexthop_group_sort(znh, nhops);
+
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+ stream_putw(s, proto);
+ stream_putl(s, id);
+ stream_putw(s, nhops);
+ for (i = 0; i < nhops; i++) {
+ zapi_nexthop_encode(s, znh, 0, 0);
+ znh++;
+ }
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+}
+
+extern void zclient_nhg_add(struct zclient *zclient, uint32_t id,
+ size_t nhops, struct zapi_nexthop *znh)
+{
+ struct stream *s = zclient->obuf;
+
+ zclient_nhg_writer(s, zclient->redist_default, ZEBRA_NHG_ADD, id, nhops,
+ znh);
+}
+
int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
{
struct zapi_nexthop *api_nh;
/*
* 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;
return 0;
}
+bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
+ enum zapi_nhg_notify_owner *note)
+{
+ uint16_t read_id;
+
+ STREAM_GETL(s, read_id);
+ STREAM_GET(note, s, sizeof(*note));
+
+ *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)
(*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,
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,
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);
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,
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);
uint32_t *unique,
enum zapi_ipset_notify_owner *note);
+extern void zclient_nhg_add(struct zclient *zclient,
+ uint32_t id, size_t nhops,
+ struct zapi_nexthop *znh);
+extern void zclient_nhg_del(struct zclient *zclient, uint32_t id);
+
#define ZEBRA_IPSET_NAME_SIZE 32
bool zapi_ipset_entry_notify_decode(struct stream *s,
return zserv_send_message(client, s);
}
+static int nhg_notify(uint16_t type, uint16_t instance, uint16_t id,
+ enum zapi_nhg_notify_owner note)
+{
+ struct zserv *client;
+ struct stream *s;
+
+ client = zserv_find_client(type, instance);
+ if (!client) {
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ zlog_debug("Not Notifying Owner: %u(%u) about %u(%d)",
+ type, instance, id, note);
+ }
+ return 0;
+ }
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_NHG_NOTIFY_OWNER, VRF_DEFAULT);
+
+ stream_putw(s, id);
+ stream_put(s, ¬e, sizeof(note));
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zserv_send_message(client, s);
+}
+
/*
* Common utility send route notification, called from a path using a
* route_entry and from a path using a dataplane context.
/*
* Create a new nexthop based on a zapi nexthop.
*/
-static struct nexthop *nexthop_from_zapi(struct route_entry *re,
- const struct zapi_nexthop *api_nh,
- const struct zapi_route *api)
+static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh,
+ uint32_t flags, struct prefix *p,
+ uint16_t backup_nexthop_num)
{
struct nexthop *nexthop = NULL;
struct ipaddr vtep_ip;
/* Special handling for IPv4 routes sourced from EVPN:
* the nexthop and associated MAC need to be installed.
*/
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
memset(&vtep_ip, 0, sizeof(struct ipaddr));
vtep_ip.ipa_type = IPADDR_V4;
memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4),
sizeof(struct in_addr));
zebra_vxlan_evpn_vrf_route_add(
api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api->prefix);
+ &vtep_ip, p);
}
break;
case NEXTHOP_TYPE_IPV6:
/* Special handling for IPv6 routes sourced from EVPN:
* the nexthop and associated MAC need to be installed.
*/
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
memset(&vtep_ip, 0, sizeof(struct ipaddr));
vtep_ip.ipa_type = IPADDR_V6;
memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
sizeof(struct in6_addr));
zebra_vxlan_evpn_vrf_route_add(
api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api->prefix);
+ &vtep_ip, p);
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
for (i = 0; i < api_nh->backup_num; i++) {
/* Validate backup index */
- if (api_nh->backup_idx[i] < api->backup_nexthop_num) {
+ if (api_nh->backup_idx[i] < backup_nexthop_num) {
nexthop->backup_idx[i] = api_nh->backup_idx[i];
} else {
if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
return nexthop;
}
-static bool zapi_read_nexthops(struct zserv *client, struct zapi_route *api,
- struct route_entry *re,
+static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
+ struct zapi_nexthop *nhops, uint32_t flags,
+ uint32_t message, uint16_t nexthop_num,
+ uint16_t backup_nh_num,
struct nexthop_group **png,
struct nhg_backup_info **pbnhg)
{
struct nexthop_group *ng = NULL;
struct nhg_backup_info *bnhg = NULL;
- uint16_t nexthop_num, i;;
- struct zapi_nexthop *nhops;
+ uint16_t i;
struct nexthop *last_nh = NULL;
assert(!(png && pbnhg));
- if (png) {
+ if (png)
*png = ng = nexthop_group_new();
- nexthop_num = api->nexthop_num;
- nhops = api->nexthops;
- }
- if (pbnhg && api->backup_nexthop_num > 0) {
+ if (pbnhg && backup_nh_num > 0) {
if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: adding %d backup nexthops",
- __func__, api->backup_nexthop_num);
+ zlog_debug("%s: adding %d backup nexthops", __func__,
+ backup_nh_num);
- nexthop_num = api->backup_nexthop_num;
*pbnhg = bnhg = zebra_nhg_backup_alloc();
- nhops = api->backup_nexthops;
}
/*
struct zapi_nexthop *api_nh = &nhops[i];
/* Convert zapi nexthop */
- nexthop = nexthop_from_zapi(re, api_nh, api);
+ nexthop = nexthop_from_zapi(api_nh, flags, p, backup_nh_num);
if (!nexthop) {
flog_warn(
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
nexthop->backup_num = 0;
}
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRTE)) {
+ if (CHECK_FLAG(message, ZAPI_MESSAGE_SRTE)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE);
nexthop->srte_color = api_nh->srte_color;
}
return true;
}
+static void zread_nhg_del(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s = msg;
+ uint32_t id;
+ uint16_t proto;
+
+ STREAM_GETW(s, proto);
+ STREAM_GETL(s, id);
+
+ /*
+ * Delete the received nhg id
+ * id is incremented to make compiler happy right now
+ * it should be removed in future code work.
+ */
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED);
+
+ return;
+
+stream_failure:
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop group deletion failed", __func__);
+ return;
+}
+
+static void zread_nhg_reader(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ uint32_t id;
+ size_t nhops, i;
+ struct zapi_nexthop zapi_nexthops[MULTIPATH_NUM];
+ struct nexthop_group *nhg = NULL;
+ struct prefix p;
+ uint16_t proto;
+
+ memset(&p, 0, sizeof(p));
+
+ s = msg;
+
+ STREAM_GETW(s, proto);
+ STREAM_GETL(s, id);
+ STREAM_GETW(s, nhops);
+
+ if (zserv_nexthop_num_warn(__func__, &p, nhops))
+ return;
+
+ for (i = 0; i < nhops; i++) {
+ struct zapi_nexthop *znh = &zapi_nexthops[i];
+
+ if (zapi_nexthop_decode(s, znh, 0, 0) != 0) {
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop creation failed",
+ __func__);
+ return;
+ }
+ }
+
+ if (!zapi_read_nexthops(client, &p, zapi_nexthops, 0, 0, nhops, 0, &nhg,
+ NULL)) {
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop Group Creation failed",
+ __func__);
+ return;
+ }
+ /*
+ * Install the nhg
+ */
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED);
+
+ return;
+
+stream_failure:
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop Group creation failed with some sort of stream read failure",
+ __func__);
+ return;
+}
+
static void zread_route_add(ZAPI_HANDLER_ARGS)
{
struct stream *s;
zebra_route_string(client->proto), &api.prefix);
}
- if (!zapi_read_nexthops(client, &api, re, &ng, NULL) ||
- !zapi_read_nexthops(client, &api, re, NULL, &bnhg)) {
+ if (!zapi_read_nexthops(client, &api.prefix, api.nexthops, api.flags,
+ api.message, api.nexthop_num,
+ api.backup_nexthop_num, &ng, NULL)
+ || !zapi_read_nexthops(client, &api.prefix, api.backup_nexthops,
+ api.flags, api.message,
+ api.backup_nexthop_num,
+ api.backup_nexthop_num, NULL, &bnhg)) {
XFREE(MTYPE_RE, re);
return;
}
[ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
[ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities,
- [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover};
+ [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,
+ [ZEBRA_NHG_ADD] = zread_nhg_reader,
+ [ZEBRA_NHG_DEL] = zread_nhg_del,
+};
/*
* Process a batch of zapi messages.