#include "zebra/zebra_vxlan.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_evpn_mh.h"
DEFINE_MGROUP(ZEBRA, "zebra");
DEFINE_MTYPE(ZEBRA, RE, "Route Entry");
DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination");
DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
-DEFINE_MTYPE_STATIC(ZEBRA, WQ_NHG_WRAPPER, "WQ nhg wrapper");
+DEFINE_MTYPE_STATIC(ZEBRA, WQ_WRAPPER, "WQ wrapper");
/*
* Event, list, and mutex for delivery of dataplane results
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason));
-/* Should we allow non Quagga processes to delete our routes */
+/* Should we allow non FRR processes to delete our routes */
extern int allow_delete;
/* Each route type's string and default distance value. */
uint8_t distance;
uint8_t meta_q_map;
} route_info[ZEBRA_ROUTE_MAX] = {
- [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0},
- [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 6},
- [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 2},
- [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1},
- [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 3},
- [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 4},
- [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 4},
- [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 4},
- [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 4},
- [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 4},
- [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 5},
- [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 6},
- [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 4},
- [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 4},
- [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 6},
- [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 6},
- [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 3},
- [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 6},
- [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 5},
- [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 5},
- [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 5},
- [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 5},
- [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 5},
- [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 4},
- [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 6},
- [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 6},
- [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 6},
- [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 4},
- [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 6},
- [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 6},
+ [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */, 0},
+ [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 7},
+ [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 3},
+ [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 2},
+ [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 4},
+ [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 5},
+ [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 5},
+ [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 5},
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 5},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 5},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 6},
+ [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 7},
+ [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 5},
+ [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 5},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 7},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 7},
+ [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 4},
+ [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 7},
+ [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 6},
+ [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 6},
+ [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 6},
+ [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 6},
+ [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 6},
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 5},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 7},
+ [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 7},
+ [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 7},
+ [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5},
+ [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7},
+ [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7},
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
};
+/* EVPN/VXLAN subqueue is number 1 */
+#define META_QUEUE_EVPN 1
+
/* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update
* from the OS, and an 'nhe' is a nhe update.
*/
#define WQ_NHG_WRAPPER_TYPE_CTX 0x01
#define WQ_NHG_WRAPPER_TYPE_NHG 0x02
+/* Wrapper structs for evpn/vxlan workqueue items. */
+struct wq_evpn_wrapper {
+ int type;
+ bool add_p;
+ vrf_id_t vrf_id;
+ bool esr_rxed;
+ uint8_t df_alg;
+ uint16_t df_pref;
+ esi_t esi;
+ struct ipaddr ip;
+ struct ethaddr mac;
+ struct prefix prefix;
+};
+
+#define WQ_EVPN_WRAPPER_TYPE_VRFROUTE 0x01
+#define WQ_EVPN_WRAPPER_TYPE_REM_ES 0x02
+
/* %pRN is already a printer for route_nodes that just prints the prefix */
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pZN" (struct route_node *)
dplane_ctx_fini(&ctx);
}
+/*
+ * Process a node from the EVPN/VXLAN subqueue.
+ */
+static void process_subq_evpn(struct listnode *lnode)
+{
+ struct wq_evpn_wrapper *w;
+
+ /* In general, the list node points to a wrapper object
+ * holding the info necessary to make some update.
+ */
+ w = listgetdata(lnode);
+ if (!w)
+ return;
+
+ if (w->type == WQ_EVPN_WRAPPER_TYPE_VRFROUTE) {
+ if (w->add_p)
+ zebra_vxlan_evpn_vrf_route_add(w->vrf_id, &w->mac,
+ &w->ip, &w->prefix);
+ else
+ zebra_vxlan_evpn_vrf_route_del(w->vrf_id, &w->ip,
+ &w->prefix);
+ } else if (w->type == WQ_EVPN_WRAPPER_TYPE_REM_ES) {
+ if (w->add_p)
+ zebra_evpn_remote_es_add(&w->esi, w->ip.ipaddr_v4,
+ w->esr_rxed, w->df_alg,
+ w->df_pref);
+ else
+ zebra_evpn_remote_es_del(&w->esi, w->ip.ipaddr_v4);
+ }
+
+ XFREE(MTYPE_WQ_WRAPPER, w);
+}
+
/*
* Process the nexthop-group workqueue subqueue
*/
/* Process incoming nhg update, probably from a proto daemon */
newnhe = zebra_nhg_proto_add(nhe->id, nhe->type,
nhe->zapi_instance,
- nhe->zapi_session,
- &nhe->nhg, 0);
+ nhe->zapi_session, &nhe->nhg, 0);
/* Report error to daemon via ZAPI */
if (newnhe == NULL)
zebra_nhg_free(nhe);
}
- XFREE(MTYPE_WQ_NHG_WRAPPER, w);
+ XFREE(MTYPE_WQ_WRAPPER, w);
}
static void process_subq_route(struct listnode *lnode, uint8_t qindex)
route_unlock_node(rnode);
}
-/* Take a list of route_node structs and return 1, if there was a record
- * picked from it and processed by rib_process(). Don't process more,
- * than one RN record; operate only in the specified sub-queue.
+/*
+ * Examine the specified subqueue; process one entry and return 1 if
+ * there is a node, return 0 otherwise.
*/
static unsigned int process_subq(struct list *subq, uint8_t qindex)
{
if (!lnode)
return 0;
- if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
+ if (qindex == META_QUEUE_EVPN)
+ process_subq_evpn(lnode);
+ else if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
process_subq_nhg(lnode);
else
process_subq_route(lnode, qindex);
return 1;
}
-/* Dispatch the meta queue by picking, processing and unlocking the next RN from
+/* Dispatch the meta queue by picking and processing the next node from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
* data is pointed to the meta queue structure.
*/
if (!ctx)
return -1;
- w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper));
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_nhg_wrapper));
w->type = WQ_NHG_WRAPPER_TYPE_CTX;
w->u.ctx = ctx;
if (!nhe)
return -1;
- w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper));
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_nhg_wrapper));
w->type = WQ_NHG_WRAPPER_TYPE_NHG;
w->u.nhe = nhe;
return 0;
}
+static int rib_meta_queue_evpn_add(struct meta_queue *mq, void *data)
+{
+ listnode_add(mq->subq[META_QUEUE_EVPN], data);
+ mq->size++;
+
+ return 0;
+}
+
static int mq_add_handler(void *data,
int (*mq_add_func)(struct meta_queue *mq, void *data))
{
return mq_add_handler(nhe, rib_meta_queue_nhg_add);
}
+/*
+ * Enqueue evpn route for processing
+ */
+int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
+ const struct ipaddr *vtep_ip,
+ const struct prefix *host_prefix)
+{
+ struct wq_evpn_wrapper *w;
+
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper));
+
+ w->type = WQ_EVPN_WRAPPER_TYPE_VRFROUTE;
+ w->add_p = true;
+ w->vrf_id = vrf_id;
+ w->mac = *rmac;
+ w->ip = *vtep_ip;
+ w->prefix = *host_prefix;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: (%u)%pIA, host prefix %pFX enqueued", __func__,
+ vrf_id, vtep_ip, host_prefix);
+
+ return mq_add_handler(w, rib_meta_queue_evpn_add);
+}
+
+int zebra_rib_queue_evpn_route_del(vrf_id_t vrf_id,
+ const struct ipaddr *vtep_ip,
+ const struct prefix *host_prefix)
+{
+ struct wq_evpn_wrapper *w;
+
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper));
+
+ w->type = WQ_EVPN_WRAPPER_TYPE_VRFROUTE;
+ w->add_p = false;
+ w->vrf_id = vrf_id;
+ w->ip = *vtep_ip;
+ w->prefix = *host_prefix;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: (%u)%pIA, host prefix %pFX enqueued", __func__,
+ vrf_id, vtep_ip, host_prefix);
+
+ return mq_add_handler(w, rib_meta_queue_evpn_add);
+}
+
+/* Enqueue EVPN remote ES for processing */
+int zebra_rib_queue_evpn_rem_es_add(const esi_t *esi,
+ const struct in_addr *vtep_ip,
+ bool esr_rxed, uint8_t df_alg,
+ uint16_t df_pref)
+{
+ struct wq_evpn_wrapper *w;
+ char buf[ESI_STR_LEN];
+
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper));
+
+ w->type = WQ_EVPN_WRAPPER_TYPE_REM_ES;
+ w->add_p = true;
+ w->esi = *esi;
+ w->ip.ipa_type = IPADDR_V4;
+ w->ip.ipaddr_v4 = *vtep_ip;
+ w->esr_rxed = esr_rxed;
+ w->df_alg = df_alg;
+ w->df_pref = df_pref;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: vtep %pI4, esi %s enqueued", __func__, vtep_ip,
+ esi_to_str(esi, buf, sizeof(buf)));
+
+ return mq_add_handler(w, rib_meta_queue_evpn_add);
+}
+
+int zebra_rib_queue_evpn_rem_es_del(const esi_t *esi,
+ const struct in_addr *vtep_ip)
+{
+ struct wq_evpn_wrapper *w;
+ char buf[ESI_STR_LEN];
+
+ w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper));
+
+ w->type = WQ_EVPN_WRAPPER_TYPE_REM_ES;
+ w->add_p = false;
+ w->esi = *esi;
+ w->ip.ipa_type = IPADDR_V4;
+ w->ip.ipaddr_v4 = *vtep_ip;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ if (memcmp(esi, zero_esi, sizeof(esi_t)) != 0)
+ esi_to_str(esi, buf, sizeof(buf));
+ else
+ strlcpy(buf, "-", sizeof(buf));
+
+ zlog_debug("%s: vtep %pI4, esi %s enqueued", __func__, vtep_ip,
+ buf);
+ }
+
+ return mq_add_handler(w, rib_meta_queue_evpn_add);
+}
+
+/* Clean up the EVPN meta-queue list */
+static void evpn_meta_queue_free(struct list *l)
+{
+ struct listnode *node;
+ struct wq_evpn_wrapper *w;
+
+ /* Free the node wrapper object, and the struct it wraps */
+ while ((node = listhead(l)) != NULL) {
+ w = node->data;
+ node->data = NULL;
+
+ XFREE(MTYPE_WQ_WRAPPER, w);
+
+ list_delete_node(l, node);
+ }
+}
+
/* Clean up the nhg meta-queue list */
static void nhg_meta_queue_free(struct list *l)
{
else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG)
zebra_nhg_free(w->u.nhe);
- XFREE(MTYPE_WQ_NHG_WRAPPER, w);
+ XFREE(MTYPE_WQ_WRAPPER, w);
list_delete_node(l, node);
}
/* Some subqueues may need cleanup - nhgs for example */
if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
nhg_meta_queue_free(mq->subq[i]);
+ else if (i == META_QUEUE_EVPN)
+ evpn_meta_queue_free(mq->subq[i]);
list_delete(&mq->subq[i]);
}
* dest is created on-demand by rib_link() and is kept around at least
* as long as there are ribs hanging off it (@see rib_gc_dest()).
*
- * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code):
+ * Refcounting (aka "locking" throughout the Zebra and FRR code):
*
* - route_nodes: refcounted by:
* - dest attached to route_node:
&(tmp_nh->gate.ipv6),
sizeof(struct in6_addr));
}
- zebra_vxlan_evpn_vrf_route_del(re->vrf_id,
+ zebra_rib_queue_evpn_route_del(re->vrf_id,
&vtep_ip, p);
}
}