diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
commit | e2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch) | |
tree | f0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /bgpd/rfapi/bgp_rfapi_cfg.c | |
parent | Initial commit. (diff) | |
download | frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip |
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bgpd/rfapi/bgp_rfapi_cfg.c')
-rw-r--r-- | bgpd/rfapi/bgp_rfapi_cfg.c | 4627 |
1 files changed, 4627 insertions, 0 deletions
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c new file mode 100644 index 0000000..5b6961d --- /dev/null +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -0,0 +1,4627 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * Copyright 2009-2016, LabN Consulting, L.L.C. + * + */ +#include "lib/zebra.h" + +#include "lib/command.h" +#include "lib/prefix.h" +#include "lib/memory.h" +#include "lib/linklist.h" +#include "lib/agg_table.h" +#include "lib/plist.h" +#include "lib/routemap.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h" + +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/rfapi/rfapi.h" +#include "bgpd/rfapi/bgp_rfapi_cfg.h" +#include "bgpd/rfapi/rfapi_backend.h" +#include "bgpd/rfapi/rfapi_import.h" +#include "bgpd/rfapi/rfapi_private.h" +#include "bgpd/rfapi/rfapi_monitor.h" +#include "bgpd/rfapi/vnc_zebra.h" +#include "bgpd/rfapi/vnc_export_bgp.h" +#include "bgpd/rfapi/vnc_export_bgp_p.h" +#include "bgpd/rfapi/rfapi_vty.h" +#include "bgpd/rfapi/vnc_import_bgp.h" +#include "bgpd/rfapi/vnc_debug.h" + +#ifdef ENABLE_BGP_VNC + +#undef BGP_VNC_DEBUG_MATCH_GROUP + + +DEFINE_MGROUP(RFAPI, "rfapi"); +DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic"); +DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor"); +DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap"); +DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop"); +DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option"); +DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option"); +DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw"); +DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName"); +DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data"); +DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info"); +DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address"); +DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag"); +DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra"); +DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info"); +DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr"); +DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue"); +DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route"); +DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option"); +DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet"); + +DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg); +DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg); +/*********************************************************************** + * RFAPI Support + ***********************************************************************/ + + +/* + * compaitibility to old quagga_time call + * time_t value in terms of stabilised absolute time. + * replacement for POSIX time() + */ +time_t rfapi_time(time_t *t) +{ + time_t clock = monotime(NULL); + if (t) + *t = clock; + return clock; +} + +void nve_group_to_nve_list(struct rfapi_nve_group_cfg *rfg, struct list **nves, + uint8_t family) /* AF_INET, AF_INET6 */ +{ + struct listnode *hln; + struct rfapi_descriptor *rfd; + + /* + * loop over nves in this grp, add to list + */ + for (ALL_LIST_ELEMENTS_RO(rfg->nves, hln, rfd)) { + if (rfd->vn_addr.addr_family == family) { + if (!*nves) + *nves = list_new(); + listnode_add(*nves, rfd); + } + } +} + + +struct rfapi_nve_group_cfg *bgp_rfapi_cfg_match_group(struct rfapi_cfg *hc, + struct prefix *vn, + struct prefix *un) +{ + struct rfapi_nve_group_cfg *rfg_vn = NULL; + struct rfapi_nve_group_cfg *rfg_un = NULL; + + struct agg_table *rt_vn; + struct agg_table *rt_un; + struct agg_node *rn_vn; + struct agg_node *rn_un; + + struct rfapi_nve_group_cfg *rfg; + struct listnode *node, *nnode; + + switch (vn->family) { + case AF_INET: + rt_vn = hc->nve_groups_vn[AFI_IP]; + break; + case AF_INET6: + rt_vn = hc->nve_groups_vn[AFI_IP6]; + break; + default: + return NULL; + } + + switch (un->family) { + case AF_INET: + rt_un = hc->nve_groups_un[AFI_IP]; + break; + case AF_INET6: + rt_un = hc->nve_groups_un[AFI_IP6]; + break; + default: + return NULL; + } + + rn_vn = agg_node_match(rt_vn, vn); /* NB locks node */ + if (rn_vn) { + rfg_vn = rn_vn->info; + agg_unlock_node(rn_vn); + } + + rn_un = agg_node_match(rt_un, un); /* NB locks node */ + if (rn_un) { + rfg_un = rn_un->info; + agg_unlock_node(rn_un); + } + +#ifdef BGP_VNC_DEBUG_MATCH_GROUP + { + vnc_zlog_debug_verbose("%s: vn prefix: %pFX", __func__, vn); + vnc_zlog_debug_verbose("%s: un prefix: %pFX", __func__, un); + vnc_zlog_debug_verbose( + "%s: rn_vn=%p, rn_un=%p, rfg_vn=%p, rfg_un=%p", + __func__, rn_vn, rn_un, rfg_vn, rfg_un); + } +#endif + + + if (rfg_un == rfg_vn) /* same group */ + return rfg_un; + if (!rfg_un) /* un doesn't match, return vn-matched grp */ + return rfg_vn; + if (!rfg_vn) /* vn doesn't match, return un-matched grp */ + return rfg_un; + + /* + * Two different nve groups match: the group configured earlier wins. + * For now, just walk the sequential list and pick the first one. + * If this approach is too slow, then store serial numbers in the + * nve group structures as they are defined and just compare + * serial numbers. + */ + for (ALL_LIST_ELEMENTS(hc->nve_groups_sequential, node, nnode, rfg)) { + if ((rfg == rfg_un) || (rfg == rfg_vn)) { + return rfg; + } + } + vnc_zlog_debug_verbose( + "%s: shouldn't happen, returning NULL when un and vn match", + __func__); + return NULL; /* shouldn't happen */ +} + +/*------------------------------------------ + * rfapi_get_rfp_start_val + * + * Returns value passed to rfapi on rfp_start + * + * input: + * void * bgp structure + * + * returns: + * void * + *------------------------------------------*/ +void *rfapi_get_rfp_start_val(void *bgpv) +{ + struct bgp *bgp = bgpv; + if (bgp == NULL || bgp->rfapi == NULL) + return NULL; + return bgp->rfapi->rfp; +} + +/*------------------------------------------ + * bgp_rfapi_is_vnc_configured + * + * Returns if VNC is configured + * + * input: + * bgp NULL (=use default instance) + * + * output: + * + * return value: If VNC is configured for the bgpd instance + * 0 Success + * EPERM Not Default instance (VNC operations not allowed) + * ENXIO VNC not configured + --------------------------------------------*/ +int bgp_rfapi_is_vnc_configured(struct bgp *bgp) +{ + if (bgp == NULL) + bgp = bgp_get_default(); + + if (bgp && bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) + return EPERM; + + if (bgp && bgp->rfapi_cfg) + return 0; + return ENXIO; +} + +/*********************************************************************** + * VNC Configuration/CLI + ***********************************************************************/ +#define VNC_VTY_CONFIG_CHECK(bgp) \ + { \ + switch (bgp_rfapi_is_vnc_configured(bgp)) { \ + case EPERM: \ + vty_out(vty, \ + "VNC operations only permitted on default BGP instance.\n"); \ + return CMD_WARNING_CONFIG_FAILED; \ + break; \ + case ENXIO: \ + vty_out(vty, "VNC not configured.\n"); \ + return CMD_WARNING_CONFIG_FAILED; \ + break; \ + default: \ + break; \ + } \ + } + +DEFUN (vnc_advertise_un_method, + vnc_advertise_un_method_cmd, + "vnc advertise-un-method encap-attr", + VNC_CONFIG_STR + "Method of advertising UN addresses\n" + "Via Tunnel Encap attribute (in VPN SAFI)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VNC_VTY_CONFIG_CHECK(bgp); + + if (!strncmp(argv[2]->arg, "encap-safi", 7)) { + bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP; + } else { + bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP; + } + + return CMD_SUCCESS; +} + +/*------------------------------------------------------------------------- + * RFG defaults + *-----------------------------------------------------------------------*/ + + +DEFUN_NOSH (vnc_defaults, + vnc_defaults_cmd, + "vnc defaults", VNC_CONFIG_STR "Configure default NVE group\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VNC_VTY_CONFIG_CHECK(bgp); + if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { + vty_out(vty, "Malformed community-list value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + vty->node = BGP_VNC_DEFAULTS_NODE; + return CMD_SUCCESS; +} + +static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv, + struct ecommunity **list) +{ + struct ecommunity *ecom = NULL; + struct ecommunity *ecomadd; + + for (; argc; --argc, ++argv) { + + ecomadd = ecommunity_str2com(argv[0]->arg, + ECOMMUNITY_ROUTE_TARGET, 0); + if (!ecomadd) { + vty_out(vty, "Malformed community-list value\n"); + if (ecom) + ecommunity_free(&ecom); + return CMD_WARNING_CONFIG_FAILED; + } + + if (ecom) { + ecommunity_merge(ecom, ecomadd); + ecommunity_free(&ecomadd); + } else { + ecom = ecomadd; + } + } + + if (*list) { + ecommunity_free(&*list); + } + *list = ecom; + + return CMD_SUCCESS; +} + +DEFUN (vnc_defaults_rt_import, + vnc_defaults_rt_import_cmd, + "rt import RTLIST...", + "Specify default route targets\n" + "Import filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return set_ecom_list(vty, argc - 2, argv + 2, + &bgp->rfapi_cfg->default_rt_import_list); +} + +DEFUN (vnc_defaults_rt_export, + vnc_defaults_rt_export_cmd, + "rt export RTLIST...", + "Configure default route targets\n" + "Export filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return set_ecom_list(vty, argc - 2, argv + 2, + &bgp->rfapi_cfg->default_rt_export_list); +} + +DEFUN (vnc_defaults_rt_both, + vnc_defaults_rt_both_cmd, + "rt both RTLIST...", + "Configure default route targets\n" + "Export+import filters\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int rc; + + rc = set_ecom_list(vty, argc - 2, argv + 2, + &bgp->rfapi_cfg->default_rt_import_list); + if (rc != CMD_SUCCESS) + return rc; + return set_ecom_list(vty, argc - 2, argv + 2, + &bgp->rfapi_cfg->default_rt_export_list); +} + +DEFUN (vnc_defaults_rd, + vnc_defaults_rd_cmd, + "rd ASN:NN_OR_IP-ADDRESS:NN", + "Specify default route distinguisher\n" + "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:vn:<number> )\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int ret; + struct prefix_rd prd; + + if (!strncmp(argv[1]->arg, "auto:vn:", 8)) { + /* + * use AF_UNIX to designate automatically-assigned RD + * auto:vn:nn where nn is a 2-octet quantity + */ + char *end = NULL; + uint32_t value32 = strtoul(argv[1]->arg + 8, &end, 10); + uint16_t value = value32 & 0xffff; + + if (!argv[1]->arg[8] || *end) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (value32 > 0xffff) { + vty_out(vty, "%% Malformed rd (must be less than %u\n", + 0x0ffff); + return CMD_WARNING_CONFIG_FAILED; + } + + memset(&prd, 0, sizeof(prd)); + prd.family = AF_UNIX; + prd.prefixlen = 64; + prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff; + prd.val[1] = RD_TYPE_IP & 0x0ff; + prd.val[6] = (value >> 8) & 0x0ff; + prd.val[7] = value & 0x0ff; + + } else { + + /* TODO: save RD format */ + ret = str2prefix_rd(argv[1]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + bgp->rfapi_cfg->default_rd = prd; + return CMD_SUCCESS; +} + +DEFUN (vnc_defaults_l2rd, + vnc_defaults_l2rd_cmd, + "l2rd <(1-255)|auto-vn>", + "Specify default Local Nve ID value to use in RD for L2 routes\n" + "Fixed value 1-255\n" + "use the low-order octet of the NVE's VN address\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + uint8_t value = 0; + + if (strmatch(argv[1]->text, "auto-vn")) { + value = 0; + } else { + char *end = NULL; + unsigned long value_l = strtoul(argv[1]->arg, &end, 10); + + value = value_l & 0xff; + if (!argv[1]->arg[0] || *end) { + vty_out(vty, "%% Malformed l2 nve ID \"%s\"\n", + argv[1]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + if ((value_l < 1) || (value_l > 0xff)) { + vty_out(vty, + "%% Malformed l2 nve id (must be greater than 0 and less than %u\n", + 0x100); + return CMD_WARNING_CONFIG_FAILED; + } + } + bgp->rfapi_cfg->flags |= BGP_VNC_CONFIG_L2RD; + bgp->rfapi_cfg->default_l2rd = value; + + return CMD_SUCCESS; +} + +DEFUN (vnc_defaults_no_l2rd, + vnc_defaults_no_l2rd_cmd, + "no l2rd", + NO_STR + "Specify default Local Nve ID value to use in RD for L2 routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + bgp->rfapi_cfg->default_l2rd = 0; + bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_L2RD; + + return CMD_SUCCESS; +} + +DEFUN (vnc_defaults_responselifetime, + vnc_defaults_responselifetime_cmd, + "response-lifetime <LIFETIME|infinite>", + "Specify default response lifetime\n" + "Response lifetime in seconds\n" "Infinite response lifetime\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + uint32_t rspint; + struct rfapi *h = NULL; + struct listnode *hdnode; + struct rfapi_descriptor *rfd; + + h = bgp->rfapi; + if (!h) + return CMD_WARNING_CONFIG_FAILED; + + if (strmatch(argv[1]->text, "infinite")) { + rspint = RFAPI_INFINITE_LIFETIME; + } else { + rspint = strtoul(argv[1]->arg, NULL, 10); + if (rspint > INT32_MAX) + rspint = INT32_MAX; /* is really an int, not an unsigned + int */ + } + + bgp->rfapi_cfg->default_response_lifetime = rspint; + + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, hdnode, rfd)) + if (rfd->rfg + && !(rfd->rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME)) + rfd->response_lifetime = rfd->rfg->response_lifetime = + rspint; + + return CMD_SUCCESS; +} + +struct rfapi_nve_group_cfg * +bgp_rfapi_cfg_match_byname(struct bgp *bgp, const char *name, + rfapi_group_cfg_type_t type) /* _MAX = any */ +{ + struct rfapi_nve_group_cfg *rfg; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->nve_groups_sequential, node, + nnode, rfg)) { + if ((type == RFAPI_GROUP_CFG_MAX || type == rfg->type) + && !strcmp(rfg->name, name)) + return rfg; + } + return NULL; +} + +static struct rfapi_nve_group_cfg * +rfapi_group_new(struct bgp *bgp, rfapi_group_cfg_type_t type, const char *name) +{ + struct rfapi_nve_group_cfg *rfg; + + rfg = XCALLOC(MTYPE_RFAPI_GROUP_CFG, + sizeof(struct rfapi_nve_group_cfg)); + rfg->type = type; + rfg->name = strdup(name); + /* add to tail of list */ + listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg); + rfg->label = MPLS_LABEL_NONE; + + QOBJ_REG(rfg, rfapi_nve_group_cfg); + + return rfg; +} + +static struct rfapi_l2_group_cfg *rfapi_l2_group_lookup_byname(struct bgp *bgp, + const char *name) +{ + struct rfapi_l2_group_cfg *rfg; + struct listnode *node, *nnode; + + if (bgp->rfapi_cfg->l2_groups == NULL) /* not the best place for this */ + bgp->rfapi_cfg->l2_groups = list_new(); + + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->l2_groups, node, nnode, rfg)) { + if (!strcmp(rfg->name, name)) + return rfg; + } + return NULL; +} + +static struct rfapi_l2_group_cfg *rfapi_l2_group_new(void) +{ + struct rfapi_l2_group_cfg *rfg; + + rfg = XCALLOC(MTYPE_RFAPI_L2_CFG, sizeof(struct rfapi_l2_group_cfg)); + QOBJ_REG(rfg, rfapi_l2_group_cfg); + + return rfg; +} + +static void rfapi_l2_group_del(struct rfapi_l2_group_cfg *rfg) +{ + QOBJ_UNREG(rfg); + XFREE(MTYPE_RFAPI_L2_CFG, rfg); +} + +static int rfapi_str2route_type(const char *l3str, const char *pstr, afi_t *afi, + int *type) +{ + if (!l3str || !pstr) + return EINVAL; + + if (!strcmp(l3str, "ipv4")) { + *afi = AFI_IP; + } else { + if (!strcmp(l3str, "ipv6")) + *afi = AFI_IP6; + else + return ENOENT; + } + + if (!strcmp(pstr, "connected")) + *type = ZEBRA_ROUTE_CONNECT; + if (!strcmp(pstr, "kernel")) + *type = ZEBRA_ROUTE_KERNEL; + if (!strcmp(pstr, "static")) + *type = ZEBRA_ROUTE_STATIC; + if (!strcmp(pstr, "bgp")) + *type = ZEBRA_ROUTE_BGP; + if (!strcmp(pstr, "bgp-direct")) + *type = ZEBRA_ROUTE_BGP_DIRECT; + if (!strcmp(pstr, "bgp-direct-to-nve-groups")) + *type = ZEBRA_ROUTE_BGP_DIRECT_EXT; + + if (!strcmp(pstr, "rip")) { + if (*afi == AFI_IP) + *type = ZEBRA_ROUTE_RIP; + else + *type = ZEBRA_ROUTE_RIPNG; + } + + if (!strcmp(pstr, "ripng")) { + if (*afi == AFI_IP) + return EAFNOSUPPORT; + *type = ZEBRA_ROUTE_RIPNG; + } + + if (!strcmp(pstr, "ospf")) { + if (*afi == AFI_IP) + *type = ZEBRA_ROUTE_OSPF; + else + *type = ZEBRA_ROUTE_OSPF6; + } + + if (!strcmp(pstr, "ospf6")) { + if (*afi == AFI_IP) + return EAFNOSUPPORT; + *type = ZEBRA_ROUTE_OSPF6; + } + + return 0; +} + +/*------------------------------------------------------------------------- + * redistribute + *-----------------------------------------------------------------------*/ + +#define VNC_REDIST_ENABLE(bgp, afi, type) \ + do { \ + switch (type) { \ + case ZEBRA_ROUTE_BGP_DIRECT: \ + vnc_import_bgp_redist_enable((bgp), (afi)); \ + break; \ + case ZEBRA_ROUTE_BGP_DIRECT_EXT: \ + vnc_import_bgp_exterior_redist_enable((bgp), (afi)); \ + break; \ + default: \ + if ((type) < ZEBRA_ROUTE_MAX) \ + vnc_redistribute_set((bgp), (afi), (type)); \ + break; \ + } \ + } while (0) + +#define VNC_REDIST_DISABLE(bgp, afi, type) \ + do { \ + switch (type) { \ + case ZEBRA_ROUTE_BGP_DIRECT: \ + vnc_import_bgp_redist_disable((bgp), (afi)); \ + break; \ + case ZEBRA_ROUTE_BGP_DIRECT_EXT: \ + vnc_import_bgp_exterior_redist_disable((bgp), (afi)); \ + break; \ + default: \ + if ((type) < ZEBRA_ROUTE_MAX) \ + vnc_redistribute_unset((bgp), (afi), (type)); \ + break; \ + } \ + } while (0) + +static uint8_t redist_was_enabled[AFI_MAX][ZEBRA_ROUTE_MAX]; + +static void vnc_redistribute_prechange(struct bgp *bgp) +{ + afi_t afi; + int type; + + vnc_zlog_debug_verbose("%s: entry", __func__); + memset(redist_was_enabled, 0, sizeof(redist_was_enabled)); + + /* + * Look to see if we have any redistribution enabled. If so, flush + * the corresponding routes and turn off redistribution temporarily. + * We need to do it because the RD's used for the redistributed + * routes depend on the nve group. + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + for (type = 0; type < ZEBRA_ROUTE_MAX; ++type) { + if (bgp->rfapi_cfg->redist[afi][type]) { + redist_was_enabled[afi][type] = 1; + VNC_REDIST_DISABLE(bgp, afi, type); + } + } + } + vnc_zlog_debug_verbose("%s: return", __func__); +} + +static void vnc_redistribute_postchange(struct bgp *bgp) +{ + afi_t afi; + int type; + + vnc_zlog_debug_verbose("%s: entry", __func__); + /* + * If we turned off redistribution above, turn it back on. Doing so + * will tell zebra to resend the routes to us + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + for (type = 0; type < ZEBRA_ROUTE_MAX; ++type) { + if (redist_was_enabled[afi][type]) { + VNC_REDIST_ENABLE(bgp, afi, type); + } + } + } + vnc_zlog_debug_verbose("%s: return", __func__); +} + +DEFUN (vnc_redistribute_rh_roo_localadmin, + vnc_redistribute_rh_roo_localadmin_cmd, + "vnc redistribute resolve-nve roo-ec-local-admin (0-65535)", + VNC_CONFIG_STR + "Redistribute routes into VNC\n" + "Resolve-NVE mode\n" + "Route Origin Extended Community Local Admin Field\n" "Field value\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + uint32_t localadmin; + char *endptr; + + VNC_VTY_CONFIG_CHECK(bgp); + + localadmin = strtoul(argv[4]->arg, &endptr, 0); + if (!argv[4]->arg[0] || *endptr) { + vty_out(vty, "%% Malformed value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (localadmin > 0xffff) { + vty_out(vty, "%% Value out of range (0-%d)\n", 0xffff); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->resolve_nve_roo_local_admin == localadmin) + return CMD_SUCCESS; + + if ((bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) + == BGP_VNC_CONFIG_EXPORT_BGP_MODE_CE) { + + vnc_export_bgp_prechange(bgp); + } + vnc_redistribute_prechange(bgp); + + bgp->rfapi_cfg->resolve_nve_roo_local_admin = localadmin; + + if ((bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) + == BGP_VNC_CONFIG_EXPORT_BGP_MODE_CE) { + + vnc_export_bgp_postchange(bgp); + } + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + + +DEFUN (vnc_redistribute_mode, + vnc_redistribute_mode_cmd, + "vnc redistribute mode <nve-group|plain|resolve-nve>", + VNC_CONFIG_STR + "Redistribute routes into VNC\n" + "Redistribution mode\n" + "Based on redistribute nve-group\n" + "Unmodified\n" "Resolve each nexthop to connected NVEs\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vnc_redist_mode_t newmode; + + VNC_VTY_CONFIG_CHECK(bgp); + + switch (argv[3]->arg[0]) { + case 'n': + newmode = VNC_REDIST_MODE_RFG; + break; + + case 'p': + newmode = VNC_REDIST_MODE_PLAIN; + break; + + case 'r': + newmode = VNC_REDIST_MODE_RESOLVE_NVE; + break; + + default: + vty_out(vty, "unknown redistribute mode\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (newmode != bgp->rfapi_cfg->redist_mode) { + vnc_redistribute_prechange(bgp); + bgp->rfapi_cfg->redist_mode = newmode; + vnc_redistribute_postchange(bgp); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_redistribute_protocol, + vnc_redistribute_protocol_cmd, + "vnc redistribute <ipv4|ipv6> <bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static>", + VNC_CONFIG_STR + "Redistribute routes into VNC\n" + "IPv4 routes\n" + "IPv6 routes\n" + "From BGP\n" + "From BGP without Zebra\n" + "From BGP without Zebra, only to configured NVE groups\n" + "Connected interfaces\n" + "From kernel routes\n" + "From Open Shortest Path First (OSPF)\n" + "From Routing Information Protocol (RIP)\n" "From Static routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int type = ZEBRA_ROUTE_MAX; /* init to bogus value */ + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + if (rfapi_str2route_type(argv[2]->arg, argv[3]->arg, &afi, &type)) { + vty_out(vty, "%% Invalid route type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (type == ZEBRA_ROUTE_BGP_DIRECT_EXT) { + if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { + VNC_REDIST_DISABLE(bgp, afi, + type); /* disabled view implicitly */ + free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); + bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; + } + bgp->rfapi_cfg->redist_bgp_exterior_view = bgp; + } + + VNC_REDIST_ENABLE(bgp, afi, type); + + return CMD_SUCCESS; +} + +DEFUN (vnc_no_redistribute_protocol, + vnc_no_redistribute_protocol_cmd, + "no vnc redistribute <ipv4|ipv6> <bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static>", + NO_STR + VNC_CONFIG_STR + "Redistribute from other protocol\n" + "IPv4 routes\n" + "IPv6 routes\n" + "From BGP\n" + "From BGP without Zebra\n" + "From BGP without Zebra, only to configured NVE groups\n" + "Connected interfaces\n" + "From kernel routes\n" + "From Open Shortest Path First (OSPF)\n" + "From Routing Information Protocol (RIP)\n" "From Static routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int type; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + if (rfapi_str2route_type(argv[3]->arg, argv[4]->arg, &afi, &type)) { + vty_out(vty, "%% Invalid route type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + VNC_REDIST_DISABLE(bgp, afi, type); + + if (type == ZEBRA_ROUTE_BGP_DIRECT_EXT) { + if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { + free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); + bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; + } + bgp->rfapi_cfg->redist_bgp_exterior_view = NULL; + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_redistribute_bgp_exterior, + vnc_redistribute_bgp_exterior_cmd, + "vnc redistribute <ipv4|ipv6> bgp-direct-to-nve-groups view NAME", + VNC_CONFIG_STR + "Redistribute routes into VNC\n" + "IPv4 routes\n" + "IPv6 routes\n" + "From BGP without Zebra, only to configured NVE groups\n" + "From BGP view\n" "BGP view name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int type; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + if (rfapi_str2route_type(argv[2]->arg, "bgp-direct-to-nve-groups", &afi, + &type)) { + vty_out(vty, "%% Invalid route type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) + free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); + bgp->rfapi_cfg->redist_bgp_exterior_view_name = strdup(argv[5]->arg); + /* could be NULL if name is not defined yet */ + bgp->rfapi_cfg->redist_bgp_exterior_view = + bgp_lookup_by_name(argv[5]->arg); + + VNC_REDIST_ENABLE(bgp, afi, type); + + return CMD_SUCCESS; +} + +DEFUN (vnc_redistribute_nvegroup, + vnc_redistribute_nvegroup_cmd, + "vnc redistribute nve-group NAME", + VNC_CONFIG_STR + "Assign a NVE group to routes redistributed from another routing protocol\n" + "NVE group\n" "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VNC_VTY_CONFIG_CHECK(bgp); + + vnc_redistribute_prechange(bgp); + + /* + * OK if nve group doesn't exist yet; we'll set the pointer + * when the group is defined later + */ + bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname( + bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE); + if (bgp->rfapi_cfg->rfg_redist_name) + free(bgp->rfapi_cfg->rfg_redist_name); + bgp->rfapi_cfg->rfg_redist_name = strdup(argv[3]->arg); + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_redistribute_no_nvegroup, + vnc_redistribute_no_nvegroup_cmd, + "no vnc redistribute nve-group", + NO_STR + VNC_CONFIG_STR + "Redistribute from other protocol\n" + "Assign a NVE group to routes redistributed from another routing protocol\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + VNC_VTY_CONFIG_CHECK(bgp); + + vnc_redistribute_prechange(bgp); + + bgp->rfapi_cfg->rfg_redist = NULL; + if (bgp->rfapi_cfg->rfg_redist_name) + free(bgp->rfapi_cfg->rfg_redist_name); + bgp->rfapi_cfg->rfg_redist_name = NULL; + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + + +DEFUN (vnc_redistribute_lifetime, + vnc_redistribute_lifetime_cmd, + "vnc redistribute lifetime <LIFETIME|infinite>", + VNC_CONFIG_STR + "Redistribute\n" + "Assign a lifetime to routes redistributed from another routing protocol\n" + "lifetime value (32 bit)\n" + "Allow lifetime to never expire\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VNC_VTY_CONFIG_CHECK(bgp); + + vnc_redistribute_prechange(bgp); + + if (strmatch(argv[3]->text, "infinite")) { + bgp->rfapi_cfg->redist_lifetime = RFAPI_INFINITE_LIFETIME; + } else { + bgp->rfapi_cfg->redist_lifetime = + strtoul(argv[3]->arg, NULL, 10); + } + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +/*-- redist policy, non-nvegroup start --*/ + +DEFUN (vnc_redist_bgpdirect_no_prefixlist, + vnc_redist_bgpdirect_no_prefixlist_cmd, + "no vnc redistribute <bgp-direct|bgp-direct-to-nve-groups> <ipv4|ipv6> prefix-list", + NO_STR + VNC_CONFIG_STR + "Redistribute from other protocol\n" + "Redistribute from BGP directly\n" + "Redistribute from BGP without Zebra, only to configured NVE groups\n" + "IPv4 routes\n" + "IPv6 routes\n" "Prefix-list for filtering redistributed routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + afi_t afi; + struct rfapi_cfg *hc; + uint8_t route_type = 0; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[3]->text, "bgp-direct")) { + route_type = ZEBRA_ROUTE_BGP_DIRECT; + } else { + route_type = ZEBRA_ROUTE_BGP_DIRECT_EXT; + } + + if (strmatch(argv[4]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + vnc_redistribute_prechange(bgp); + + if (hc->plist_redist_name[route_type][afi]) + free(hc->plist_redist_name[route_type][afi]); + hc->plist_redist_name[route_type][afi] = NULL; + hc->plist_redist[route_type][afi] = NULL; + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_redist_bgpdirect_prefixlist, + vnc_redist_bgpdirect_prefixlist_cmd, + "vnc redistribute <bgp-direct|bgp-direct-to-nve-groups> <ipv4|ipv6> prefix-list NAME", + VNC_CONFIG_STR + "Redistribute from other protocol\n" + "Redistribute from BGP directly\n" + "Redistribute from BGP without Zebra, only to configured NVE groups\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering redistributed routes\n" + "prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + afi_t afi; + uint8_t route_type = 0; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[2]->text, "bgp-direct")) { + route_type = ZEBRA_ROUTE_BGP_DIRECT; + } else { + route_type = ZEBRA_ROUTE_BGP_DIRECT_EXT; + } + + if (strmatch(argv[3]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + vnc_redistribute_prechange(bgp); + + if (hc->plist_redist_name[route_type][afi]) + free(hc->plist_redist_name[route_type][afi]); + hc->plist_redist_name[route_type][afi] = strdup(argv[5]->arg); + hc->plist_redist[route_type][afi] = + prefix_list_lookup(afi, argv[5]->arg); + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_redist_bgpdirect_no_routemap, + vnc_redist_bgpdirect_no_routemap_cmd, + "no vnc redistribute <bgp-direct|bgp-direct-to-nve-groups> route-map", + NO_STR + VNC_CONFIG_STR + "Redistribute from other protocols\n" + "Redistribute from BGP directly\n" + "Redistribute from BGP without Zebra, only to configured NVE groups\n" + "Route-map for filtering redistributed routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + uint8_t route_type = 0; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[3]->text, "bgp-direct")) { + route_type = ZEBRA_ROUTE_BGP_DIRECT; + } else { + route_type = ZEBRA_ROUTE_BGP_DIRECT_EXT; + } + + vnc_redistribute_prechange(bgp); + + if (hc->routemap_redist_name[route_type]) + free(hc->routemap_redist_name[route_type]); + hc->routemap_redist_name[route_type] = NULL; + hc->routemap_redist[route_type] = NULL; + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_redist_bgpdirect_routemap, + vnc_redist_bgpdirect_routemap_cmd, + "vnc redistribute <bgp-direct|bgp-direct-to-nve-groups> route-map NAME", + VNC_CONFIG_STR + "Redistribute from other protocols\n" + "Redistribute from BGP directly\n" + "Redistribute from BGP without Zebra, only to configured NVE groups\n" + "Route-map for filtering exported routes\n" "route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + uint8_t route_type = 0; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[2]->text, "bgp-direct")) { + route_type = ZEBRA_ROUTE_BGP_DIRECT; + } else { + route_type = ZEBRA_ROUTE_BGP_DIRECT_EXT; + } + + vnc_redistribute_prechange(bgp); + + if (hc->routemap_redist_name[route_type]) + free(hc->routemap_redist_name[route_type]); + + /* If the old route map config overwrite with new + * route map config , old routemap counter have to be + * reduced. + */ + route_map_counter_decrement(hc->routemap_redist[route_type]); + hc->routemap_redist_name[route_type] = strdup(argv[4]->arg); + hc->routemap_redist[route_type] = + route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_redist[route_type]); + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +/*-- redist policy, non-nvegroup end --*/ + +/*-- redist policy, nvegroup start --*/ + +DEFUN (vnc_nve_group_redist_bgpdirect_no_prefixlist, + vnc_nve_group_redist_bgpdirect_no_prefixlist_cmd, + "no redistribute bgp-direct <ipv4|ipv6> prefix-list", + NO_STR + "Redistribute from other protocol\n" + "Redistribute from BGP directly\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering redistributed routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg) + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (strmatch(argv[3]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + vnc_redistribute_prechange(bgp); + + if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) + free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; + rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_redist_bgpdirect_prefixlist, + vnc_nve_group_redist_bgpdirect_prefixlist_cmd, + "redistribute bgp-direct <ipv4|ipv6> prefix-list NAME", + "Redistribute from other protocol\n" + "Redistribute from BGP directly\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering redistributed routes\n" + "prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (strmatch(argv[2]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + vnc_redistribute_prechange(bgp); + + if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) + free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = + strdup(argv[4]->arg); + rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = + prefix_list_lookup(afi, argv[4]->arg); + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap, + vnc_nve_group_redist_bgpdirect_no_routemap_cmd, + "no redistribute bgp-direct route-map", + NO_STR + "Redistribute from other protocols\n" + "Redistribute from BGP directly\n" + "Route-map for filtering redistributed routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vnc_redistribute_prechange(bgp); + + if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) + free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL; + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL; + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_redist_bgpdirect_routemap, + vnc_nve_group_redist_bgpdirect_routemap_cmd, + "redistribute bgp-direct route-map NAME", + "Redistribute from other protocols\n" + "Redistribute from BGP directly\n" + "Route-map for filtering exported routes\n" "route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + vnc_redistribute_prechange(bgp); + + if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) + free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = + strdup(argv[3]->arg); + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = + route_map_lookup_by_name(argv[3]->arg); + route_map_counter_increment( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); + + vnc_redistribute_postchange(bgp); + + return CMD_SUCCESS; +} + +/*-- redist policy, nvegroup end --*/ + +/*------------------------------------------------------------------------- + * export + *-----------------------------------------------------------------------*/ + +DEFUN (vnc_export_mode, + vnc_export_mode_cmd, + "vnc export <bgp|zebra> mode <group-nve|ce|none|registering-nve>", + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "Select export mode\n" + "Export routes with nve-group next-hops\n" + "Export routes with NVE connected router next-hops\n" + "Disable export\n" "Export routes with registering NVE as next-hop\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + uint32_t oldmode = 0; + uint32_t newmode = 0; + + VNC_VTY_CONFIG_CHECK(bgp); + + if (argv[2]->arg[0] == 'b') { + oldmode = bgp->rfapi_cfg->flags + & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS; + switch (argv[4]->arg[0]) { + case 'g': + newmode = BGP_VNC_CONFIG_EXPORT_BGP_MODE_GRP; + break; + case 'c': + newmode = BGP_VNC_CONFIG_EXPORT_BGP_MODE_CE; + break; + case 'n': + newmode = 0; + break; + case 'r': + newmode = BGP_VNC_CONFIG_EXPORT_BGP_MODE_RH; + break; + default: + vty_out(vty, "Invalid mode specified\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (newmode == oldmode) { + vty_out(vty, "Mode unchanged\n"); + return CMD_SUCCESS; + } + + vnc_export_bgp_prechange(bgp); + + bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS; + bgp->rfapi_cfg->flags |= newmode; + + vnc_export_bgp_postchange(bgp); + + + } else { + /* + * export to zebra with RH mode is not yet implemented + */ + vty_out(vty, + "Changing modes for zebra export not implemented yet\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +static struct rfapi_rfg_name *rfgn_new(void) +{ + return XCALLOC(MTYPE_RFAPI_RFG_NAME, sizeof(struct rfapi_rfg_name)); +} + +static void rfgn_free(struct rfapi_rfg_name *rfgn) +{ + XFREE(MTYPE_RFAPI_RFG_NAME, rfgn); +} + +DEFUN (vnc_export_nvegroup, + vnc_export_nvegroup_cmd, + "vnc export <bgp|zebra> group-nve group NAME", + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "NVE group, used in 'group-nve' export mode\n" + "NVE group\n" "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_nve_group_cfg *rfg_new; + + VNC_VTY_CONFIG_CHECK(bgp); + + rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg, + RFAPI_GROUP_CFG_NVE); + if (rfg_new == NULL) { + rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg, + RFAPI_GROUP_CFG_VRF); + if (rfg_new) + vnc_add_vrf_opener(bgp, rfg_new); + } + + if (rfg_new == NULL) { + vty_out(vty, "Can't find group named \"%s\".\n", argv[5]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argv[2]->arg[0] == 'b') { + + struct listnode *node; + struct rfapi_rfg_name *rfgn; + + /* + * Set group for export to BGP Direct + */ + + /* see if group is already included in export list */ + for (ALL_LIST_ELEMENTS_RO( + bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + + if (!strcmp(rfgn->name, argv[5]->arg)) { + /* already in the list: we're done */ + return CMD_SUCCESS; + } + } + + rfgn = rfgn_new(); + rfgn->name = strdup(argv[5]->arg); + rfgn->rfg = rfg_new; /* OK if not set yet */ + + listnode_add(bgp->rfapi_cfg->rfg_export_direct_bgp_l, rfgn); + + vnc_zlog_debug_verbose("%s: testing rfg_new", __func__); + if (rfg_new) { + vnc_zlog_debug_verbose( + "%s: testing bgp grp mode enabled", __func__); + if (VNC_EXPORT_BGP_GRP_ENABLED(bgp->rfapi_cfg)) + vnc_zlog_debug_verbose( + "%s: calling vnc_direct_bgp_add_group", + __func__); + vnc_direct_bgp_add_group(bgp, rfg_new); + } + + } else { + + struct listnode *node; + struct rfapi_rfg_name *rfgn; + + /* + * Set group for export to Zebra + */ + + /* see if group is already included in export list */ + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, + node, rfgn)) { + + if (!strcmp(rfgn->name, argv[5]->arg)) { + /* already in the list: we're done */ + return CMD_SUCCESS; + } + } + + rfgn = rfgn_new(); + rfgn->name = strdup(argv[5]->arg); + rfgn->rfg = rfg_new; /* OK if not set yet */ + + listnode_add(bgp->rfapi_cfg->rfg_export_zebra_l, rfgn); + + if (rfg_new) { + if (VNC_EXPORT_ZEBRA_GRP_ENABLED(bgp->rfapi_cfg)) + vnc_zebra_add_group(bgp, rfg_new); + } + } + + return CMD_SUCCESS; +} + +/* + * This command applies to routes exported from VNC to BGP directly + * without going though zebra + */ +DEFUN (vnc_no_export_nvegroup, + vnc_no_export_nvegroup_cmd, + "vnc export <bgp|zebra> group-nve no group NAME", + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "NVE group, used in 'group-nve' export mode\n" + "Disable export of VNC routes\n" "NVE group\n" "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct rfapi_rfg_name *rfgn; + + VNC_VTY_CONFIG_CHECK(bgp); + + if (argv[2]->arg[0] == 'b') { + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, + node, nnode, rfgn)) { + + if (rfgn->name && !strcmp(rfgn->name, argv[6]->arg)) { + vnc_zlog_debug_verbose("%s: matched \"%s\"", + __func__, rfgn->name); + if (rfgn->rfg) + vnc_direct_bgp_del_group(bgp, + rfgn->rfg); + free(rfgn->name); + list_delete_node( + bgp->rfapi_cfg->rfg_export_direct_bgp_l, + node); + rfgn_free(rfgn); + break; + } + } + } else { + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_zebra_l, node, + nnode, rfgn)) { + + vnc_zlog_debug_verbose("does rfg \"%s\" match?", + rfgn->name); + if (rfgn->name && !strcmp(rfgn->name, argv[6]->arg)) { + if (rfgn->rfg) + vnc_zebra_del_group(bgp, rfgn->rfg); + free(rfgn->name); + list_delete_node( + bgp->rfapi_cfg->rfg_export_zebra_l, + node); + rfgn_free(rfgn); + break; + } + } + } + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_export_no_prefixlist, + vnc_nve_group_export_no_prefixlist_cmd, + "no export <bgp|zebra> <ipv4|ipv6> prefix-list [NAME]", + NO_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering exported routes\n" "prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int idx = 0; + int is_bgp = 1; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) { + vty_out(vty, "%% Malformed Address Family\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argv[idx - 1]->text[0] == 'z') + is_bgp = 0; + idx += 2; /* skip afi and keyword */ + + if (is_bgp) { + if (idx == argc + || (rfg->plist_export_bgp_name[afi] + && strmatch(argv[idx]->arg, + rfg->plist_export_bgp_name[afi]))) { + if (rfg->plist_export_bgp_name[afi]) + free(rfg->plist_export_bgp_name[afi]); + rfg->plist_export_bgp_name[afi] = NULL; + rfg->plist_export_bgp[afi] = NULL; + + vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi); + } + } else { + if (idx == argc + || (rfg->plist_export_zebra_name[afi] + && strmatch(argv[idx]->arg, + rfg->plist_export_zebra_name[afi]))) { + if (rfg->plist_export_zebra_name[afi]) + free(rfg->plist_export_zebra_name[afi]); + rfg->plist_export_zebra_name[afi] = NULL; + rfg->plist_export_zebra[afi] = NULL; + + vnc_zebra_reexport_group_afi(bgp, rfg, afi); + } + } + return CMD_SUCCESS; +} + +ALIAS (vnc_nve_group_export_no_prefixlist, + vnc_vrf_policy_export_no_prefixlist_cmd, + "no export <ipv4|ipv6> prefix-list [NAME]", + NO_STR + "Export to VRF\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering exported routes\n" "prefix list name\n") + +DEFUN (vnc_nve_group_export_prefixlist, + vnc_nve_group_export_prefixlist_cmd, + "export <bgp|zebra> <ipv4|ipv6> prefix-list NAME", + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering exported routes\n" "prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int idx = 0; + int is_bgp = 1; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) { + vty_out(vty, "%% Malformed Address Family\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argv[idx - 1]->text[0] == 'z') + is_bgp = 0; + idx = argc - 1; + + if (is_bgp) { + if (rfg->plist_export_bgp_name[afi]) + free(rfg->plist_export_bgp_name[afi]); + rfg->plist_export_bgp_name[afi] = strdup(argv[idx]->arg); + rfg->plist_export_bgp[afi] = + prefix_list_lookup(afi, argv[idx]->arg); + + vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi); + + } else { + if (rfg->plist_export_zebra_name[afi]) + free(rfg->plist_export_zebra_name[afi]); + rfg->plist_export_zebra_name[afi] = strdup(argv[idx]->arg); + rfg->plist_export_zebra[afi] = + prefix_list_lookup(afi, argv[idx]->arg); + + vnc_zebra_reexport_group_afi(bgp, rfg, afi); + } + return CMD_SUCCESS; +} + +ALIAS (vnc_nve_group_export_prefixlist, + vnc_vrf_policy_export_prefixlist_cmd, + "export <ipv4|ipv6> prefix-list NAME", + "Export to VRF\n" + "IPv4 routes\n" + "IPv6 routes\n" + "Prefix-list for filtering exported routes\n" "prefix list name\n") + +DEFUN (vnc_nve_group_export_no_routemap, + vnc_nve_group_export_no_routemap_cmd, + "no export <bgp|zebra> route-map [NAME]", + NO_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "Route-map for filtering exported routes\n" "route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int idx = 2; + int is_bgp = 1; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + switch (argv[idx]->text[0]) { + case 'z': + is_bgp = 0; + /* fall thru */ + case 'b': + idx += 2; + break; + default: /* route-map */ + idx++; + break; + } + + if (is_bgp) { + if (idx == argc + || (rfg->routemap_export_bgp_name + && strmatch(argv[idx]->arg, + rfg->routemap_export_bgp_name))) { + if (rfg->routemap_export_bgp_name) + free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); + rfg->routemap_export_bgp_name = NULL; + rfg->routemap_export_bgp = NULL; + + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); + } + } else { + if (idx == argc + || (rfg->routemap_export_zebra_name + && strmatch(argv[idx]->arg, + rfg->routemap_export_zebra_name))) { + if (rfg->routemap_export_zebra_name) + free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); + rfg->routemap_export_zebra_name = NULL; + rfg->routemap_export_zebra = NULL; + + vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); + vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP6); + } + } + return CMD_SUCCESS; +} + +ALIAS (vnc_nve_group_export_no_routemap, + vnc_vrf_policy_export_no_routemap_cmd, + "no export route-map [NAME]", + NO_STR + "Export to VRF\n" + "Route-map for filtering exported routes\n" "route map name\n") + +DEFUN (vnc_nve_group_export_routemap, + vnc_nve_group_export_routemap_cmd, + "export <bgp|zebra> route-map NAME", + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "Route-map for filtering exported routes\n" "route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int idx = 0; + int is_bgp = 1; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argv[1]->text[0] == 'z') + is_bgp = 0; + idx = argc - 1; + + if (is_bgp) { + if (rfg->routemap_export_bgp_name) + free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); + rfg->routemap_export_bgp_name = strdup(argv[idx]->arg); + rfg->routemap_export_bgp = + route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_bgp); + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); + } else { + if (rfg->routemap_export_zebra_name) + free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); + rfg->routemap_export_zebra_name = strdup(argv[idx]->arg); + rfg->routemap_export_zebra = + route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_zebra); + vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); + vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP6); + } + return CMD_SUCCESS; +} + +ALIAS (vnc_nve_group_export_routemap, + vnc_vrf_policy_export_routemap_cmd, + "export route-map NAME", + "Export to VRF\n" + "Route-map for filtering exported routes\n" "route map name\n") + +DEFUN (vnc_nve_export_no_prefixlist, + vnc_nve_export_no_prefixlist_cmd, + "no vnc export <bgp|zebra> <ipv4|ipv6> prefix-list [NAME]", + NO_STR + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "IPv4 prefixes\n" + "IPv6 prefixes\n" + "Prefix-list for filtering exported routes\n" "Prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[4]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + if (argv[3]->arg[0] == 'b') { + if (((argc > 6) && hc->plist_export_bgp_name[afi] + && strmatch(argv[6]->text, hc->plist_export_bgp_name[afi])) + || (argc <= 6)) { + + free(hc->plist_export_bgp_name[afi]); + hc->plist_export_bgp_name[afi] = NULL; + hc->plist_export_bgp[afi] = NULL; + vnc_direct_bgp_reexport(bgp, afi); + } + } else { + if (((argc > 6) && hc->plist_export_zebra_name[afi] + && strmatch(argv[6]->text, + hc->plist_export_zebra_name[afi])) + || (argc <= 6)) { + + free(hc->plist_export_zebra_name[afi]); + hc->plist_export_zebra_name[afi] = NULL; + hc->plist_export_zebra[afi] = NULL; + /* TBD vnc_zebra_rh_reexport(bgp, afi); */ + } + } + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_export_prefixlist, + vnc_nve_export_prefixlist_cmd, + "vnc export <bgp|zebra> <ipv4|ipv6> prefix-list NAME", + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "IPv4 prefixes\n" + "IPv6 prefixes\n" + "Prefix-list for filtering exported routes\n" "Prefix list name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + afi_t afi; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (strmatch(argv[3]->text, "ipv4")) { + afi = AFI_IP; + } else { + afi = AFI_IP6; + } + + if (argv[2]->arg[0] == 'b') { + if (hc->plist_export_bgp_name[afi]) + free(hc->plist_export_bgp_name[afi]); + hc->plist_export_bgp_name[afi] = strdup(argv[5]->arg); + hc->plist_export_bgp[afi] = + prefix_list_lookup(afi, argv[5]->arg); + vnc_direct_bgp_reexport(bgp, afi); + } else { + if (hc->plist_export_zebra_name[afi]) + free(hc->plist_export_zebra_name[afi]); + hc->plist_export_zebra_name[afi] = strdup(argv[5]->arg); + hc->plist_export_zebra[afi] = + prefix_list_lookup(afi, argv[5]->arg); + /* TBD vnc_zebra_rh_reexport(bgp, afi); */ + } + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_export_no_routemap, + vnc_nve_export_no_routemap_cmd, + "no vnc export <bgp|zebra> route-map [NAME]", + NO_STR + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "Route-map for filtering exported routes\n" "Route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (argv[3]->arg[0] == 'b') { + if (((argc > 5) && hc->routemap_export_bgp_name + && strmatch(argv[5]->text, hc->routemap_export_bgp_name)) + || (argc <= 5)) { + + free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); + hc->routemap_export_bgp_name = NULL; + hc->routemap_export_bgp = NULL; + vnc_direct_bgp_reexport(bgp, AFI_IP); + vnc_direct_bgp_reexport(bgp, AFI_IP6); + } + } else { + if (((argc > 5) && hc->routemap_export_zebra_name + && strmatch(argv[5]->text, hc->routemap_export_zebra_name)) + || (argc <= 5)) { + + free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); + hc->routemap_export_zebra_name = NULL; + hc->routemap_export_zebra = NULL; + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ + } + } + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_export_routemap, + vnc_nve_export_routemap_cmd, + "vnc export <bgp|zebra> route-map NAME", + VNC_CONFIG_STR + "Export to other protocols\n" + "Export to BGP\n" + "Export to Zebra (experimental)\n" + "Route-map for filtering exported routes\n" "Route map name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_cfg *hc; + + VNC_VTY_CONFIG_CHECK(bgp); + hc = bgp->rfapi_cfg; + + if (argv[2]->arg[0] == 'b') { + if (hc->routemap_export_bgp_name) + free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); + hc->routemap_export_bgp_name = strdup(argv[4]->arg); + hc->routemap_export_bgp = + route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_bgp); + vnc_direct_bgp_reexport(bgp, AFI_IP); + vnc_direct_bgp_reexport(bgp, AFI_IP6); + } else { + if (hc->routemap_export_zebra_name) + free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); + hc->routemap_export_zebra_name = strdup(argv[4]->arg); + hc->routemap_export_zebra = + route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_zebra); + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ + } + return CMD_SUCCESS; +} + + +/* + * respond to changes in the global prefix list configuration + */ +void vnc_prefix_list_update(struct bgp *bgp) +{ + afi_t afi; + struct listnode *n; + struct rfapi_nve_group_cfg *rfg; + struct rfapi_cfg *hc; + int i; + + if (!bgp) { + vnc_zlog_debug_verbose("%s: No BGP process is configured", + __func__); + return; + } + + if (!(hc = bgp->rfapi_cfg)) { + vnc_zlog_debug_verbose("%s: rfapi not configured", __func__); + return; + } + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + /* + * Loop over nve groups + */ + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->nve_groups_sequential, + n, rfg)) { + + if (rfg->plist_export_bgp_name[afi]) { + rfg->plist_export_bgp[afi] = prefix_list_lookup( + afi, rfg->plist_export_bgp_name[afi]); + } + if (rfg->plist_export_zebra_name[afi]) { + rfg->plist_export_zebra + [afi] = prefix_list_lookup( + afi, rfg->plist_export_zebra_name[afi]); + } + for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { + if (rfg->plist_redist_name[i][afi]) { + rfg->plist_redist + [i][afi] = prefix_list_lookup( + afi, + rfg->plist_redist_name[i][afi]); + } + } + + vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi); + /* TBD vnc_zebra_reexport_group_afi(bgp, rfg, afi); */ + } + + /* + * RH config, too + */ + if (hc->plist_export_bgp_name[afi]) { + hc->plist_export_bgp[afi] = prefix_list_lookup( + afi, hc->plist_export_bgp_name[afi]); + } + if (hc->plist_export_zebra_name[afi]) { + hc->plist_export_zebra[afi] = prefix_list_lookup( + afi, hc->plist_export_zebra_name[afi]); + } + + for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { + if (hc->plist_redist_name[i][afi]) { + hc->plist_redist[i][afi] = prefix_list_lookup( + afi, hc->plist_redist_name[i][afi]); + } + } + } + + vnc_direct_bgp_reexport(bgp, AFI_IP); + vnc_direct_bgp_reexport(bgp, AFI_IP6); + + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ + + vnc_redistribute_prechange(bgp); + vnc_redistribute_postchange(bgp); +} + +/* + * respond to changes in the global route map configuration + */ +void vnc_routemap_update(struct bgp *bgp, const char *unused) +{ + struct listnode *n; + struct rfapi_nve_group_cfg *rfg; + struct rfapi_cfg *hc; + int i; + struct route_map *old = NULL; + + vnc_zlog_debug_verbose("%s(arg=%s)", __func__, unused); + + if (!bgp) { + vnc_zlog_debug_verbose("%s: No BGP process is configured", + __func__); + return; + } + + if (!(hc = bgp->rfapi_cfg)) { + vnc_zlog_debug_verbose("%s: rfapi not configured", __func__); + return; + } + + /* + * Loop over nve groups + */ + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->nve_groups_sequential, n, + rfg)) { + + if (rfg->routemap_export_bgp_name) { + old = rfg->routemap_export_bgp; + rfg->routemap_export_bgp = route_map_lookup_by_name( + rfg->routemap_export_bgp_name); + /* old is NULL. i.e Route map creation event. + * So update applied_counter. + * If Old is not NULL, i.e It may be routemap + * updation or deletion. + * So no need to update the counter. + */ + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); + } + if (rfg->routemap_export_zebra_name) { + old = rfg->routemap_export_bgp; + rfg->routemap_export_bgp = route_map_lookup_by_name( + rfg->routemap_export_zebra_name); + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); + } + for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { + if (rfg->routemap_redist_name[i]) { + old = rfg->routemap_redist[i]; + rfg->routemap_redist[i] = + route_map_lookup_by_name( + rfg->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + rfg->routemap_redist[i]); + } + } + + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); + vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); + /* TBD vnc_zebra_reexport_group_afi(bgp, rfg, afi); */ + } + + /* + * RH config, too + */ + if (hc->routemap_export_bgp_name) { + old = hc->routemap_export_bgp; + hc->routemap_export_bgp = + route_map_lookup_by_name(hc->routemap_export_bgp_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); + } + if (hc->routemap_export_zebra_name) { + old = hc->routemap_export_bgp; + hc->routemap_export_bgp = route_map_lookup_by_name( + hc->routemap_export_zebra_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); + } + for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { + if (hc->routemap_redist_name[i]) { + old = hc->routemap_redist[i]; + hc->routemap_redist[i] = route_map_lookup_by_name( + hc->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + hc->routemap_redist[i]); + } + } + + vnc_direct_bgp_reexport(bgp, AFI_IP); + vnc_direct_bgp_reexport(bgp, AFI_IP6); + + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ + /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ + + vnc_redistribute_prechange(bgp); + vnc_redistribute_postchange(bgp); + + vnc_zlog_debug_verbose("%s done", __func__); +} + +/*------------------------------------------------------------------------- + * nve-group + *-----------------------------------------------------------------------*/ + + +DEFUN_NOSH (vnc_nve_group, + vnc_nve_group_cmd, + "vnc nve-group NAME", + VNC_CONFIG_STR "Configure a NVE group\n" "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct rfapi_nve_group_cfg *rfg; + struct listnode *node, *nnode; + struct rfapi_rfg_name *rfgn; + + VNC_VTY_CONFIG_CHECK(bgp); + + /* Search for name */ + rfg = bgp_rfapi_cfg_match_byname(bgp, argv[2]->arg, + RFAPI_GROUP_CFG_NVE); + + if (!rfg) { + rfg = rfapi_group_new(bgp, RFAPI_GROUP_CFG_NVE, argv[2]->arg); + if (!rfg) { + /* Error out of memory */ + vty_out(vty, "Can't allocate memory for NVE group\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Copy defaults from struct rfapi_cfg */ + rfg->rd = bgp->rfapi_cfg->default_rd; + if (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_L2RD) { + rfg->l2rd = bgp->rfapi_cfg->default_l2rd; + rfg->flags |= RFAPI_RFG_L2RD; + } + rfg->rd = bgp->rfapi_cfg->default_rd; + rfg->response_lifetime = + bgp->rfapi_cfg->default_response_lifetime; + + if (bgp->rfapi_cfg->default_rt_export_list) { + rfg->rt_export_list = ecommunity_dup( + bgp->rfapi_cfg->default_rt_export_list); + } + + if (bgp->rfapi_cfg->default_rt_import_list) { + rfg->rt_import_list = ecommunity_dup( + bgp->rfapi_cfg->default_rt_import_list); + rfg->rfapi_import_table = rfapiImportTableRefAdd( + bgp, rfg->rt_import_list, rfg); + } + + /* + * If a redist nve group was named but the group was not + * defined, + * make the linkage now + */ + if (!bgp->rfapi_cfg->rfg_redist) { + if (bgp->rfapi_cfg->rfg_redist_name + && !strcmp(bgp->rfapi_cfg->rfg_redist_name, + rfg->name)) { + + vnc_redistribute_prechange(bgp); + bgp->rfapi_cfg->rfg_redist = rfg; + vnc_redistribute_postchange(bgp); + } + } + + /* + * Same treatment for bgp-direct export group + */ + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_direct_bgp_l, + node, nnode, rfgn)) { + + if (!strcmp(rfgn->name, rfg->name)) { + rfgn->rfg = rfg; + vnc_direct_bgp_add_group(bgp, rfg); + break; + } + } + + /* + * Same treatment for zebra export group + */ + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->rfg_export_zebra_l, node, + nnode, rfgn)) { + + vnc_zlog_debug_verbose( + "%s: ezport zebra: checking if \"%s\" == \"%s\"", + __func__, rfgn->name, rfg->name); + if (!strcmp(rfgn->name, rfg->name)) { + rfgn->rfg = rfg; + vnc_zebra_add_group(bgp, rfg); + break; + } + } + } + + /* + * XXX subsequent calls will need to make sure this item is still + * in the linked list and has the same name + */ + VTY_PUSH_CONTEXT_SUB(BGP_VNC_NVE_GROUP_NODE, rfg); + + return CMD_SUCCESS; +} + +static void bgp_rfapi_delete_nve_group(struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + struct rfapi_nve_group_cfg *rfg) +{ + struct list *orphaned_nves = NULL; + struct listnode *node, *nnode; + + /* + * If there are currently-open NVEs that belong to this group, + * zero out their references to this group structure. + */ + if (rfg->nves) { + struct rfapi_descriptor *rfd; + orphaned_nves = list_new(); + while ((rfd = listnode_head(rfg->nves))) { + rfd->rfg = NULL; + listnode_delete(rfg->nves, rfd); + listnode_add(orphaned_nves, rfd); + } + list_delete(&rfg->nves); + } + + /* delete it */ + free(rfg->name); + if (rfg->rfapi_import_table) + rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); + if (rfg->rt_import_list) + ecommunity_free(&rfg->rt_import_list); + if (rfg->rt_export_list) + ecommunity_free(&rfg->rt_export_list); + + if (rfg->vn_node) { + rfg->vn_node->info = NULL; + agg_unlock_node(rfg->vn_node); /* frees */ + } + if (rfg->un_node) { + rfg->un_node->info = NULL; + agg_unlock_node(rfg->un_node); /* frees */ + } + if (rfg->rfp_cfg) + XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); + listnode_delete(bgp->rfapi_cfg->nve_groups_sequential, rfg); + + QOBJ_UNREG(rfg); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg); + + /* + * Attempt to reassign the orphaned nves to a new group. If + * a NVE can not be reassigned, its rfd->rfg will remain NULL + * and it will become a zombie until released by rfapi_close(). + */ + if (orphaned_nves) { + struct rfapi_descriptor *rfd; + + for (ALL_LIST_ELEMENTS(orphaned_nves, node, nnode, rfd)) { + /* + * 1. rfapi_close() equivalent except: + * a. don't free original descriptor + * b. remember query list + * c. remember advertised route list + * 2. rfapi_open() equivalent except: + * a. reuse original descriptor + * 3. rfapi_register() on remembered advertised route + * list + * 4. rfapi_query on rememebred query list + */ + + int rc; + + rc = rfapi_reopen(rfd, bgp); + + if (!rc) { + list_delete_node(orphaned_nves, node); + if (vty) + vty_out(vty, + "WARNING: reassigned NVE vn="); + rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr); + if (vty) + vty_out(vty, " un="); + rfapiPrintRfapiIpAddr(vty, &rfd->un_addr); + if (vty) + vty_out(vty, " to new group \"%s\"\n", + rfd->rfg->name); + } + } + + for (ALL_LIST_ELEMENTS_RO(orphaned_nves, node, rfd)) { + if (vty) + vty_out(vty, "WARNING: orphaned NVE vn="); + rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr); + if (vty) + vty_out(vty, " un="); + rfapiPrintRfapiIpAddr(vty, &rfd->un_addr); + if (vty) + vty_out(vty, "\n"); + } + list_delete(&orphaned_nves); + } +} + +static int +bgp_rfapi_delete_named_nve_group(struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + const char *rfg_name, /* NULL = any */ + rfapi_group_cfg_type_t type) /* _MAX = any */ +{ + struct rfapi_nve_group_cfg *rfg = NULL; + struct listnode *node, *nnode; + struct rfapi_rfg_name *rfgn; + + /* Search for name */ + if (rfg_name) { + rfg = bgp_rfapi_cfg_match_byname(bgp, rfg_name, type); + if (!rfg) { + if (vty) + vty_out(vty, "No NVE group named \"%s\"\n", + rfg_name); + return CMD_WARNING_CONFIG_FAILED; + } + } + + /* + * If this group is the redist nve group, unlink it + */ + if (rfg_name == NULL || bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + bgp->rfapi_cfg->rfg_redist = NULL; + vnc_redistribute_postchange(bgp); + } + + + /* + * remove reference from bgp direct export list + */ + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + if (rfgn->rfg == rfg) { + rfgn->rfg = NULL; + /* remove exported routes from this group */ + vnc_direct_bgp_del_group(bgp, rfg); + break; + } + } + + /* + * remove reference from zebra export list + */ + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, + rfgn)) { + if (rfgn->rfg == rfg) { + rfgn->rfg = NULL; + /* remove exported routes from this group */ + vnc_zebra_del_group(bgp, rfg); + break; + } + } + if (rfg) { + if (rfg->rfd) + clear_vnc_vrf_closer(rfg); + bgp_rfapi_delete_nve_group(vty, bgp, rfg); + } else /* must be delete all */ + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->nve_groups_sequential, + node, nnode, rfg)) { + if (rfg->rfd) + clear_vnc_vrf_closer(rfg); + bgp_rfapi_delete_nve_group(vty, bgp, rfg); + } + return CMD_SUCCESS; +} + +DEFUN (vnc_no_nve_group, + vnc_no_nve_group_cmd, + "no vnc nve-group NAME", + NO_STR + VNC_CONFIG_STR + "Configure a NVE group\n" + "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + return bgp_rfapi_delete_named_nve_group(vty, bgp, argv[3]->arg, + RFAPI_GROUP_CFG_NVE); +} + +DEFUN (vnc_nve_group_prefix, + vnc_nve_group_prefix_cmd, + "prefix <vn|un> <A.B.C.D/M|X:X::X:X/M>", + "Specify prefixes matching NVE VN or UN interfaces\n" + "VN prefix\n" + "UN prefix\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + struct prefix p; + afi_t afi; + struct agg_table *rt; + struct agg_node *rn; + int is_un_prefix = 0; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!str2prefix(argv[2]->arg, &p)) { + vty_out(vty, "Malformed prefix \"%s\"\n", argv[2]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + afi = family2afi(p.family); + if (!afi) { + vty_out(vty, "Unsupported address family\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argv[1]->arg[0] == 'u') { + rt = bgp->rfapi_cfg->nve_groups_un[afi]; + is_un_prefix = 1; + } else { + rt = bgp->rfapi_cfg->nve_groups_vn[afi]; + } + + rn = agg_node_get(rt, &p); /* NB locks node */ + if (rn->info) { + /* + * There is already a group with this prefix + */ + agg_unlock_node(rn); + if (rn->info != rfg) { + /* + * different group name: fail + */ + vty_out(vty, + "nve group \"%s\" already has \"%s\" prefix %s\n", + ((struct rfapi_nve_group_cfg *)(rn->info)) + ->name, + argv[1]->arg, argv[2]->arg); + return CMD_WARNING_CONFIG_FAILED; + } else { + /* + * same group name: it's already in the correct place + * in the table, so we're done. + * + * Implies rfg->(vn|un)_prefix is already correct. + */ + return CMD_SUCCESS; + } + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + /* New prefix, new node */ + + if (is_un_prefix) { + + /* detach rfg from previous route table location */ + if (rfg->un_node) { + rfg->un_node->info = NULL; + agg_unlock_node(rfg->un_node); /* frees */ + } + rfg->un_node = rn; /* back ref */ + rfg->un_prefix = p; + + } else { + + /* detach rfg from previous route table location */ + if (rfg->vn_node) { + rfg->vn_node->info = NULL; + agg_unlock_node(rfg->vn_node); /* frees */ + } + rfg->vn_node = rn; /* back ref */ + rfg->vn_prefix = p; + } + + /* attach */ + rn->info = rfg; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_rt_import, + vnc_nve_group_rt_import_cmd, + "rt import RTLIST...", + "Specify route targets\n" + "Import filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int rc; + struct listnode *node; + struct rfapi_rfg_name *rfgn; + int is_export_bgp = 0; + int is_export_zebra = 0; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_import_list); + if (rc != CMD_SUCCESS) + return rc; + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_bgp = 1; + break; + } + } + + if (is_export_bgp) + vnc_direct_bgp_del_group(bgp, rfg); + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_zebra = 1; + break; + } + } + + if (is_export_zebra) + vnc_zebra_del_group(bgp, rfg); + + /* + * stop referencing old import table, now reference new one + */ + if (rfg->rfapi_import_table) + rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); + rfg->rfapi_import_table = + rfapiImportTableRefAdd(bgp, rfg->rt_import_list, rfg); + + if (is_export_bgp) + vnc_direct_bgp_add_group(bgp, rfg); + + if (is_export_zebra) + vnc_zebra_add_group(bgp, rfg); + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_rt_export, + vnc_nve_group_rt_export_cmd, + "rt export RTLIST...", + "Specify route targets\n" + "Export filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int rc; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_export_list); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return rc; +} + +DEFUN (vnc_nve_group_rt_both, + vnc_nve_group_rt_both_cmd, + "rt both RTLIST...", + "Specify route targets\n" + "Export+import filters\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + int rc; + int is_export_bgp = 0; + int is_export_zebra = 0; + struct listnode *node; + struct rfapi_rfg_name *rfgn; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_import_list); + if (rc != CMD_SUCCESS) + return rc; + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_bgp = 1; + break; + } + } + + if (is_export_bgp) + vnc_direct_bgp_del_group(bgp, rfg); + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_zebra = 1; + break; + } + } + + if (is_export_zebra) { + vnc_zlog_debug_verbose("%s: is_export_zebra", __func__); + vnc_zebra_del_group(bgp, rfg); + } + + /* + * stop referencing old import table, now reference new one + */ + if (rfg->rfapi_import_table) + rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); + rfg->rfapi_import_table = + rfapiImportTableRefAdd(bgp, rfg->rt_import_list, rfg); + + if (is_export_bgp) + vnc_direct_bgp_add_group(bgp, rfg); + + if (is_export_zebra) + vnc_zebra_add_group(bgp, rfg); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_export_list); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return rc; +} + +DEFUN (vnc_nve_group_l2rd, + vnc_nve_group_l2rd_cmd, + "l2rd <(1-255)|auto-vn>", + "Specify default Local Nve ID value to use in RD for L2 routes\n" + "Fixed value 1-255\n" + "use the low-order octet of the NVE's VN address\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (strmatch(argv[1]->text, "auto:vn")) { + rfg->l2rd = 0; + } else { + char *end = NULL; + unsigned long value_l = strtoul(argv[1]->arg, &end, 10); + uint8_t value = value_l & 0xff; + + if (!argv[1]->arg[0] || *end) { + vty_out(vty, "%% Malformed l2 nve ID \"%s\"\n", + argv[1]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + if ((value_l < 1) || (value_l > 0xff)) { + vty_out(vty, + "%% Malformed l2 nve id (must be greater than 0 and less than %u\n", + 0x100); + return CMD_WARNING_CONFIG_FAILED; + } + + rfg->l2rd = value; + } + rfg->flags |= RFAPI_RFG_L2RD; + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_no_l2rd, + vnc_nve_group_no_l2rd_cmd, + "no l2rd", + NO_STR + "Specify default Local Nve ID value to use in RD for L2 routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rfg->l2rd = 0; + rfg->flags &= ~RFAPI_RFG_L2RD; + + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_rd, + vnc_nve_group_rd_cmd, + "rd ASN:NN_OR_IP-ADDRESS:NN", + "Specify route distinguisher\n" + "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:vn:<number> )\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int ret; + struct prefix_rd prd; + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!strncmp(argv[1]->arg, "auto:vn:", 8)) { + /* + * use AF_UNIX to designate automatically-assigned RD + * auto:vn:nn where nn is a 2-octet quantity + */ + char *end = NULL; + uint32_t value32 = strtoul(argv[1]->arg + 8, &end, 10); + uint16_t value = value32 & 0xffff; + + if (!argv[1]->arg[8] || *end) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (value32 > 0xffff) { + vty_out(vty, "%% Malformed rd (must be less than %u\n", + 0x0ffff); + return CMD_WARNING_CONFIG_FAILED; + } + + memset(&prd, 0, sizeof(prd)); + prd.family = AF_UNIX; + prd.prefixlen = 64; + prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff; + prd.val[1] = RD_TYPE_IP & 0x0ff; + prd.val[6] = (value >> 8) & 0x0ff; + prd.val[7] = value & 0x0ff; + + } else { + + /* TODO: save RD format */ + ret = str2prefix_rd(argv[1]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rfg->rd = prd; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + return CMD_SUCCESS; +} + +DEFUN (vnc_nve_group_responselifetime, + vnc_nve_group_responselifetime_cmd, + "response-lifetime <LIFETIME|infinite>", + "Specify response lifetime\n" + "Response lifetime in seconds\n" "Infinite response lifetime\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + unsigned int rspint; + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + struct rfapi_descriptor *rfd; + struct listnode *hdnode; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (strmatch(argv[1]->text, "infinite")) { + rspint = RFAPI_INFINITE_LIFETIME; + } else { + rspint = strtoul(argv[1]->arg, NULL, 10); + } + + rfg->response_lifetime = rspint; + rfg->flags |= RFAPI_RFG_RESPONSE_LIFETIME; + if (rfg->nves) + for (ALL_LIST_ELEMENTS_RO(rfg->nves, hdnode, rfd)) + rfd->response_lifetime = rspint; + return CMD_SUCCESS; +} + +/* + * Sigh. This command, like exit-address-family, is a hack to deal + * with the lack of rigorous level control in the command handler. + * TBD fix command handler. + */ +DEFUN_NOSH (exit_vnc, + exit_vnc_cmd, + "exit-vnc", + "Exit VNC configuration mode\n") +{ + if (vty->node == BGP_VNC_DEFAULTS_NODE + || vty->node == BGP_VNC_NVE_GROUP_NODE + || vty->node == BGP_VNC_L2_GROUP_NODE) { + + vty->node = BGP_NODE; + } + return CMD_SUCCESS; +} + +static struct cmd_node bgp_vnc_defaults_node = { + .name = "bgp vnc defaults", + .node = BGP_VNC_DEFAULTS_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-vnc-defaults)# ", +}; + +static struct cmd_node bgp_vnc_nve_group_node = { + .name = "bgp vnc nve", + .node = BGP_VNC_NVE_GROUP_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-vnc-nve-group)# ", +}; + +/*------------------------------------------------------------------------- + * VNC nve-group + * Note there are two types of NVEs, one for VPNs one for RFP NVEs + *-----------------------------------------------------------------------*/ + +DEFUN_NOSH (vnc_vrf_policy, + vnc_vrf_policy_cmd, + "vrf-policy NAME", + "Configure a VRF policy group\n" + "VRF name\n") +{ + struct rfapi_nve_group_cfg *rfg; + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { + vty_out(vty, + "Can't configure vrf-policy within a BGP VRF instance\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Search for name */ + rfg = bgp_rfapi_cfg_match_byname(bgp, argv[1]->arg, + RFAPI_GROUP_CFG_VRF); + + if (!rfg) { + rfg = rfapi_group_new(bgp, RFAPI_GROUP_CFG_VRF, argv[1]->arg); + if (!rfg) { + /* Error out of memory */ + vty_out(vty, "Can't allocate memory for NVE group\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + /* + * XXX subsequent calls will need to make sure this item is still + * in the linked list and has the same name + */ + VTY_PUSH_CONTEXT_SUB(BGP_VRF_POLICY_NODE, rfg); + + return CMD_SUCCESS; +} + +DEFUN (vnc_no_vrf_policy, + vnc_no_vrf_policy_cmd, + "no vrf-policy NAME", + NO_STR + "Remove a VRF policy group\n" + "VRF name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* silently return */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) + return CMD_SUCCESS; + + return bgp_rfapi_delete_named_nve_group(vty, bgp, argv[2]->arg, + RFAPI_GROUP_CFG_VRF); +} + +DEFUN (vnc_vrf_policy_label, + vnc_vrf_policy_label_cmd, + "label (0-1048575)", + "Default label value for VRF\n" + "Label Value <0-1048575>\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + + uint32_t label; + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + label = strtoul(argv[1]->arg, NULL, 10); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rfg->label = label; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_no_label, + vnc_vrf_policy_no_label_cmd, + "no label", + NO_STR + "Remove VRF default label\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current VRF group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rfg->label = MPLS_LABEL_NONE; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_nexthop, + vnc_vrf_policy_nexthop_cmd, + "nexthop <A.B.C.D|X:X::X:X|self>", + "Specify next hop to use for VRF advertised prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Use configured router-id (default)\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + struct prefix p; + + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current VRF no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + if (!str2prefix(argv[1]->arg, &p) && p.family) { + // vty_out (vty, "Nexthop set to self\n"); + SET_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF); + memset(&rfg->vn_prefix, 0, sizeof(struct prefix)); + } else { + UNSET_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF); + rfg->vn_prefix = p; + rfg->un_prefix = p; + } + + /* TBD handle router-id/ nexthop changes when have advertised prefixes + */ + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return CMD_SUCCESS; +} + +/* The RT code should be refactored/simplified with above... */ +DEFUN (vnc_vrf_policy_rt_import, + vnc_vrf_policy_rt_import_cmd, + "rt import RTLIST...", + "Specify route targets\n" + "Import filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + int rc; + struct listnode *node; + struct rfapi_rfg_name *rfgn; + int is_export_bgp = 0; + int is_export_zebra = 0; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_import_list); + if (rc != CMD_SUCCESS) + return rc; + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_bgp = 1; + break; + } + } + + if (is_export_bgp) + vnc_direct_bgp_del_group(bgp, rfg); + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_zebra = 1; + break; + } + } + + if (is_export_zebra) + vnc_zebra_del_group(bgp, rfg); + + /* + * stop referencing old import table, now reference new one + */ + if (rfg->rfapi_import_table) + rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); + rfg->rfapi_import_table = + rfapiImportTableRefAdd(bgp, rfg->rt_import_list, rfg); + + if (is_export_bgp) + vnc_direct_bgp_add_group(bgp, rfg); + + if (is_export_zebra) + vnc_zebra_add_group(bgp, rfg); + + return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_rt_export, + vnc_vrf_policy_rt_export_cmd, + "rt export RTLIST...", + "Specify route targets\n" + "Export filter\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + int rc; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_export_list); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return rc; +} + +DEFUN (vnc_vrf_policy_rt_both, + vnc_vrf_policy_rt_both_cmd, + "rt both RTLIST...", + "Specify route targets\n" + "Export+import filters\n" + "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + int rc; + int is_export_bgp = 0; + int is_export_zebra = 0; + struct listnode *node; + struct rfapi_rfg_name *rfgn; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_import_list); + if (rc != CMD_SUCCESS) + return rc; + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_direct_bgp_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_bgp = 1; + break; + } + } + + if (is_export_bgp) + vnc_direct_bgp_del_group(bgp, rfg); + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->rfg_export_zebra_l, node, + rfgn)) { + + if (rfgn->rfg == rfg) { + is_export_zebra = 1; + break; + } + } + + if (is_export_zebra) { + vnc_zlog_debug_verbose("%s: is_export_zebra", __func__); + vnc_zebra_del_group(bgp, rfg); + } + + /* + * stop referencing old import table, now reference new one + */ + if (rfg->rfapi_import_table) + rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); + rfg->rfapi_import_table = + rfapiImportTableRefAdd(bgp, rfg->rt_import_list, rfg); + + if (is_export_bgp) + vnc_direct_bgp_add_group(bgp, rfg); + + if (is_export_zebra) + vnc_zebra_add_group(bgp, rfg); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rc = set_ecom_list(vty, argc - 2, argv + 2, &rfg->rt_export_list); + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + + return rc; +} + +DEFUN (vnc_vrf_policy_rd, + vnc_vrf_policy_rd_cmd, + "rd ASN:NN_OR_IP-ADDRESS:NN", + "Specify default VRF route distinguisher\n" + "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:nh:<number> )\n") +{ + int ret; + struct prefix_rd prd; + VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->nve_groups_sequential, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current NVE group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!strncmp(argv[1]->arg, "auto:nh:", 8)) { + /* + * use AF_UNIX to designate automatically-assigned RD + * auto:vn:nn where nn is a 2-octet quantity + */ + char *end = NULL; + uint32_t value32 = strtoul(argv[1]->arg + 8, &end, 10); + uint16_t value = value32 & 0xffff; + + if (!*(argv[1]->arg + 5) || *end) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (value32 > 0xffff) { + vty_out(vty, "%% Malformed rd (must be less than %u\n", + 0x0ffff); + return CMD_WARNING_CONFIG_FAILED; + } + + memset(&prd, 0, sizeof(prd)); + prd.family = AF_UNIX; + prd.prefixlen = 64; + prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff; + prd.val[1] = RD_TYPE_IP & 0x0ff; + prd.val[6] = (value >> 8) & 0x0ff; + prd.val[7] = value & 0x0ff; + + } else { + + /* TODO: save RD format */ + ret = str2prefix_rd(argv[1]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed rd\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_prechange(bgp); + } + + rfg->rd = prd; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { + vnc_redistribute_postchange(bgp); + } + return CMD_SUCCESS; +} + +DEFUN_NOSH (exit_vrf_policy, + exit_vrf_policy_cmd, + "exit-vrf-policy", + "Exit VRF policy configuration mode\n") +{ + if (vty->node == BGP_VRF_POLICY_NODE) { + vty->node = BGP_NODE; + } + return CMD_SUCCESS; +} + +static struct cmd_node bgp_vrf_policy_node = { + .name = "bgp vrf policy", + .node = BGP_VRF_POLICY_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-vrf-policy)# ", +}; + +/*------------------------------------------------------------------------- + * vnc-l2-group + *-----------------------------------------------------------------------*/ + + +DEFUN_NOSH (vnc_l2_group, + vnc_l2_group_cmd, + "vnc l2-group NAME", + VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n") +{ + struct rfapi_l2_group_cfg *rfg; + VTY_DECLVAR_CONTEXT(bgp, bgp); + VNC_VTY_CONFIG_CHECK(bgp); + + /* Search for name */ + rfg = rfapi_l2_group_lookup_byname(bgp, argv[2]->arg); + + if (!rfg) { + rfg = rfapi_l2_group_new(); + if (!rfg) { + /* Error out of memory */ + vty_out(vty, "Can't allocate memory for L2 group\n"); + return CMD_WARNING_CONFIG_FAILED; + } + rfg->name = strdup(argv[2]->arg); + /* add to tail of list */ + listnode_add(bgp->rfapi_cfg->l2_groups, rfg); + } + + /* + * XXX subsequent calls will need to make sure this item is still + * in the linked list and has the same name + */ + VTY_PUSH_CONTEXT_SUB(BGP_VNC_L2_GROUP_NODE, rfg); + return CMD_SUCCESS; +} + +static void bgp_rfapi_delete_l2_group(struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + struct rfapi_l2_group_cfg *rfg) +{ + /* delete it */ + free(rfg->name); + if (rfg->rt_import_list) + ecommunity_free(&rfg->rt_import_list); + if (rfg->rt_export_list) + ecommunity_free(&rfg->rt_export_list); + if (rfg->labels) + list_delete(&rfg->labels); + XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); + listnode_delete(bgp->rfapi_cfg->l2_groups, rfg); + + rfapi_l2_group_del(rfg); +} + +static int +bgp_rfapi_delete_named_l2_group(struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + const char *rfg_name) /* NULL = any */ +{ + struct rfapi_l2_group_cfg *rfg = NULL; + struct listnode *node, *nnode; + + /* Search for name */ + if (rfg_name) { + rfg = rfapi_l2_group_lookup_byname(bgp, rfg_name); + if (!rfg) { + if (vty) + vty_out(vty, "No L2 group named \"%s\"\n", + rfg_name); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (rfg) + bgp_rfapi_delete_l2_group(vty, bgp, rfg); + else /* must be delete all */ + for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->l2_groups, node, nnode, + rfg)) + bgp_rfapi_delete_l2_group(vty, bgp, rfg); + return CMD_SUCCESS; +} + +DEFUN (vnc_no_l2_group, + vnc_no_l2_group_cmd, + "no vnc l2-group NAME", + NO_STR + VNC_CONFIG_STR + "Configure a L2 group\n" + "Group name\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + return bgp_rfapi_delete_named_l2_group(vty, bgp, argv[3]->arg); +} + + +DEFUN (vnc_l2_group_lni, + vnc_l2_group_lni_cmd, + "logical-network-id (0-4294967295)", + "Specify Logical Network ID associated with group\n" + "value\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current L2 group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rfg->logical_net_id = strtoul(argv[1]->arg, NULL, 10); + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_labels, + vnc_l2_group_labels_cmd, + "labels (0-1048575)...", + "Specify label values associated with group\n" + "Space separated list of label values <0-1048575>\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct list *ll; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current L2 group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ll = rfg->labels; + if (ll == NULL) { + ll = list_new(); + rfg->labels = ll; + } + argc--; + argv++; + for (; argc; --argc, ++argv) { + uint32_t label; + label = strtoul(argv[0]->arg, NULL, 10); + if (!listnode_lookup(ll, (void *)(uintptr_t)label)) + listnode_add(ll, (void *)(uintptr_t)label); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_no_labels, + vnc_l2_group_no_labels_cmd, + "no labels (0-1048575)...", + NO_STR + "Specify label values associated with L2 group\n" + "Space separated list of label values <0-1048575>\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct list *ll; + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current L2 group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ll = rfg->labels; + if (ll == NULL) { + vty_out(vty, "Label no longer associated with group\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + argc -= 2; + argv += 2; + for (; argc; --argc, ++argv) { + uint32_t label; + label = strtoul(argv[0]->arg, NULL, 10); + listnode_delete(ll, (void *)(uintptr_t)label); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_rt, + vnc_l2_group_rt_cmd, + "rt <both|export|import> ASN:NN_OR_IP-ADDRESS:NN", + "Specify route targets\n" + "Export+import filters\n" + "Export filters\n" + "Import filters\n" + "A route target\n") +{ + VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); + VTY_DECLVAR_CONTEXT(bgp, bgp); + int rc = CMD_SUCCESS; + int do_import = 0; + int do_export = 0; + + switch (argv[1]->arg[0]) { + case 'b': + do_export = 1; /* fall through */ + case 'i': + do_import = 1; + break; + case 'e': + do_export = 1; + break; + default: + vty_out(vty, "Unknown option, %s\n", argv[1]->arg); + return CMD_ERR_NO_MATCH; + } + + /* make sure it's still in list */ + if (!listnode_lookup(bgp->rfapi_cfg->l2_groups, rfg)) { + /* Not in list anymore */ + vty_out(vty, "Current L2 group no longer exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (do_import) + rc = set_ecom_list(vty, argc - 2, argv + 2, + &rfg->rt_import_list); + if (rc == CMD_SUCCESS && do_export) + rc = set_ecom_list(vty, argc - 2, argv + 2, + &rfg->rt_export_list); + return rc; +} + + +static struct cmd_node bgp_vnc_l2_group_node = { + .name = "bgp vnc l2", + .node = BGP_VNC_L2_GROUP_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-vnc-l2-group)# ", +}; + +struct rfapi_l2_group_cfg * +bgp_rfapi_get_group_by_lni_label(struct bgp *bgp, uint32_t logical_net_id, + uint32_t label) +{ + struct rfapi_l2_group_cfg *rfg; + struct listnode *node; + + if (bgp->rfapi_cfg->l2_groups == NULL) /* not the best place for this */ + return NULL; + + label = label & 0xfffff; /* label is 20 bits! */ + + for (ALL_LIST_ELEMENTS_RO(bgp->rfapi_cfg->l2_groups, node, rfg)) { + if (rfg->logical_net_id == logical_net_id) { + struct listnode *lnode; + void *data; + for (ALL_LIST_ELEMENTS_RO(rfg->labels, lnode, data)) + if (((uint32_t)((uintptr_t)data)) + == label) { /* match! */ + return rfg; + } + } + } + return NULL; +} + +struct list *bgp_rfapi_get_labellist_by_lni_label(struct bgp *bgp, + uint32_t logical_net_id, + uint32_t label) +{ + struct rfapi_l2_group_cfg *rfg; + rfg = bgp_rfapi_get_group_by_lni_label(bgp, logical_net_id, label); + if (rfg) { + return rfg->labels; + } + return NULL; +} + +struct ecommunity * +bgp_rfapi_get_ecommunity_by_lni_label(struct bgp *bgp, uint32_t is_import, + uint32_t logical_net_id, uint32_t label) +{ + struct rfapi_l2_group_cfg *rfg; + rfg = bgp_rfapi_get_group_by_lni_label(bgp, logical_net_id, label); + if (rfg) { + if (is_import) + return rfg->rt_import_list; + else + return rfg->rt_export_list; + } + return NULL; +} + +void bgp_rfapi_cfg_init(void) +{ + install_node(&bgp_vnc_defaults_node); + install_node(&bgp_vnc_nve_group_node); + install_node(&bgp_vrf_policy_node); + install_node(&bgp_vnc_l2_group_node); + install_default(BGP_VRF_POLICY_NODE); + install_default(BGP_VNC_DEFAULTS_NODE); + install_default(BGP_VNC_NVE_GROUP_NODE); + install_default(BGP_VNC_L2_GROUP_NODE); + + /* + * Add commands + */ + install_element(BGP_NODE, &vnc_defaults_cmd); + install_element(BGP_NODE, &vnc_nve_group_cmd); + install_element(BGP_NODE, &vnc_no_nve_group_cmd); + install_element(BGP_NODE, &vnc_vrf_policy_cmd); + install_element(BGP_NODE, &vnc_no_vrf_policy_cmd); + install_element(BGP_NODE, &vnc_l2_group_cmd); + install_element(BGP_NODE, &vnc_no_l2_group_cmd); + install_element(BGP_NODE, &vnc_advertise_un_method_cmd); + install_element(BGP_NODE, &vnc_export_mode_cmd); + + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_rt_import_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_rt_export_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_rt_both_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_rd_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_l2rd_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &vnc_defaults_no_l2rd_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, + &vnc_defaults_responselifetime_cmd); + install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_cmd); + + install_element(BGP_NODE, &vnc_redistribute_protocol_cmd); + install_element(BGP_NODE, &vnc_no_redistribute_protocol_cmd); + install_element(BGP_NODE, &vnc_redistribute_nvegroup_cmd); + install_element(BGP_NODE, &vnc_redistribute_no_nvegroup_cmd); + install_element(BGP_NODE, &vnc_redistribute_lifetime_cmd); + install_element(BGP_NODE, &vnc_redistribute_rh_roo_localadmin_cmd); + install_element(BGP_NODE, &vnc_redistribute_mode_cmd); + install_element(BGP_NODE, &vnc_redistribute_bgp_exterior_cmd); + + install_element(BGP_NODE, &vnc_redist_bgpdirect_no_prefixlist_cmd); + install_element(BGP_NODE, &vnc_redist_bgpdirect_prefixlist_cmd); + install_element(BGP_NODE, &vnc_redist_bgpdirect_no_routemap_cmd); + install_element(BGP_NODE, &vnc_redist_bgpdirect_routemap_cmd); + + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_redist_bgpdirect_no_prefixlist_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_redist_bgpdirect_prefixlist_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_redist_bgpdirect_no_routemap_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_redist_bgpdirect_routemap_cmd); + + install_element(BGP_NODE, &vnc_export_nvegroup_cmd); + install_element(BGP_NODE, &vnc_no_export_nvegroup_cmd); + install_element(BGP_NODE, &vnc_nve_export_prefixlist_cmd); + install_element(BGP_NODE, &vnc_nve_export_routemap_cmd); + install_element(BGP_NODE, &vnc_nve_export_no_prefixlist_cmd); + install_element(BGP_NODE, &vnc_nve_export_no_routemap_cmd); + + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_l2rd_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_no_l2rd_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_prefix_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_rt_import_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_rt_export_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_rt_both_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &vnc_nve_group_rd_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_responselifetime_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_export_prefixlist_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_export_routemap_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_export_no_prefixlist_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, + &vnc_nve_group_export_no_routemap_cmd); + install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_cmd); + + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_label_cmd); + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_no_label_cmd); + // Reenable to support VRF controller use case and testing + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_nexthop_cmd); + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_import_cmd); + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_export_cmd); + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_both_cmd); + install_element(BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rd_cmd); + install_element(BGP_VRF_POLICY_NODE, + &vnc_vrf_policy_export_prefixlist_cmd); + install_element(BGP_VRF_POLICY_NODE, + &vnc_vrf_policy_export_routemap_cmd); + install_element(BGP_VRF_POLICY_NODE, + &vnc_vrf_policy_export_no_prefixlist_cmd); + install_element(BGP_VRF_POLICY_NODE, + &vnc_vrf_policy_export_no_routemap_cmd); + install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); + + install_element(BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_lni_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_labels_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_no_labels_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_rt_cmd); + install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_cmd); +} + +struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg) +{ + struct rfapi_cfg *h; + afi_t afi; + + h = XCALLOC(MTYPE_RFAPI_CFG, sizeof(struct rfapi_cfg)); + assert(h); + + h->nve_groups_sequential = list_new(); + assert(h->nve_groups_sequential); + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + h->nve_groups_vn[afi] = agg_table_init(); + h->nve_groups_un[afi] = agg_table_init(); + } + h->default_response_lifetime = + BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT; + h->rfg_export_direct_bgp_l = list_new(); + h->rfg_export_zebra_l = list_new(); + h->resolve_nve_roo_local_admin = + BGP_VNC_CONFIG_RESOLVE_NVE_ROO_LOCAL_ADMIN_DEFAULT; + + SET_FLAG(h->flags, BGP_VNC_CONFIG_FLAGS_DEFAULT); + + if (cfg == NULL) { + h->rfp_cfg.download_type = RFAPI_RFP_DOWNLOAD_PARTIAL; + h->rfp_cfg.ftd_advertisement_interval = + RFAPI_RFP_CFG_DEFAULT_FTD_ADVERTISEMENT_INTERVAL; + h->rfp_cfg.holddown_factor = + RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR; + h->rfp_cfg.use_updated_response = 0; + h->rfp_cfg.use_removes = 0; + } else { + h->rfp_cfg.download_type = cfg->download_type; + h->rfp_cfg.ftd_advertisement_interval = + cfg->ftd_advertisement_interval; + h->rfp_cfg.holddown_factor = cfg->holddown_factor; + h->rfp_cfg.use_updated_response = cfg->use_updated_response; + h->rfp_cfg.use_removes = cfg->use_removes; + if (cfg->use_updated_response) + h->flags &= ~BGP_VNC_CONFIG_CALLBACK_DISABLE; + else + h->flags |= BGP_VNC_CONFIG_CALLBACK_DISABLE; + if (cfg->use_removes) + h->flags &= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE; + else + h->flags |= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE; + } + return h; +} + +static void bgp_rfapi_rfgn_list_delete(void *data) +{ + struct rfapi_rfg_name *rfgn = data; + free(rfgn->name); + rfgn_free(rfgn); +} + +void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h) +{ + afi_t afi; + if (h == NULL) + return; + + bgp_rfapi_delete_named_nve_group(NULL, bgp, NULL, RFAPI_GROUP_CFG_MAX); + bgp_rfapi_delete_named_l2_group(NULL, bgp, NULL); + if (h->l2_groups != NULL) + list_delete(&h->l2_groups); + list_delete(&h->nve_groups_sequential); + + h->rfg_export_direct_bgp_l->del = bgp_rfapi_rfgn_list_delete; + list_delete(&h->rfg_export_direct_bgp_l); + + h->rfg_export_zebra_l->del = bgp_rfapi_rfgn_list_delete; + list_delete(&h->rfg_export_zebra_l); + + if (h->default_rt_export_list) + ecommunity_free(&h->default_rt_export_list); + if (h->default_rt_import_list) + ecommunity_free(&h->default_rt_import_list); + XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, h->default_rfp_cfg); + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + agg_table_finish(h->nve_groups_vn[afi]); + agg_table_finish(h->nve_groups_un[afi]); + } + XFREE(MTYPE_RFAPI_CFG, h); +} + +int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp) +{ + struct listnode *node, *nnode; + struct rfapi_nve_group_cfg *rfg; + struct rfapi_cfg *hc = bgp->rfapi_cfg; + struct rfapi_rfg_name *rfgn; + int write = 0; + afi_t afi; + int type; + if (bgp->rfapi == NULL || hc == NULL) + return write; + + vty_out(vty, "!\n"); + for (ALL_LIST_ELEMENTS(hc->nve_groups_sequential, node, nnode, rfg)) + if (rfg->type == RFAPI_GROUP_CFG_VRF) { + ++write; + vty_out(vty, " vrf-policy %s\n", rfg->name); + if (rfg->label <= MPLS_LABEL_MAX) { + vty_out(vty, " label %u\n", rfg->label); + } + if (CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF)) { + vty_out(vty, " nexthop self\n"); + + } else { + if (rfg->vn_prefix.family) { + char buf[BUFSIZ]; + buf[0] = buf[BUFSIZ - 1] = 0; + inet_ntop(rfg->vn_prefix.family, + &rfg->vn_prefix.u.prefix, buf, + sizeof(buf)); + if (!buf[0] || buf[BUFSIZ - 1]) { + // vty_out (vty, "nexthop + // self\n"); + } else { + vty_out(vty, " nexthop %s\n", + buf); + } + } + } + + if (rfg->rd.prefixlen) { + if (AF_UNIX == rfg->rd.family) { + + uint16_t value = 0; + + value = ((rfg->rd.val[6] << 8) + & 0x0ff00) + | (rfg->rd.val[7] & 0x0ff); + + vty_out(vty, " rd auto:nh:%d\n", + value); + + } else + vty_out(vty, " rd %pRDP\n", &rfg->rd); + } + + if (rfg->rt_import_list && rfg->rt_export_list + && ecommunity_cmp(rfg->rt_import_list, + rfg->rt_export_list)) { + char *b = ecommunity_ecom2str( + rfg->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt both %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + if (rfg->rt_import_list) { + char *b = ecommunity_ecom2str( + rfg->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt import %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + if (rfg->rt_export_list) { + char *b = ecommunity_ecom2str( + rfg->rt_export_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt export %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + } + + /* + * route filtering: prefix-lists and route-maps + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + const char *afistr = + (afi == AFI_IP) ? "ipv4" : "ipv6"; + + if (rfg->plist_export_bgp_name[afi]) { + vty_out(vty, + " export %s%s prefix-list %s\n", + (rfg->type == RFAPI_GROUP_CFG_VRF + ? "" + : "bgp "), + afistr, + rfg->plist_export_bgp_name + [afi]); + } + if (rfg->plist_export_zebra_name[afi]) { + vty_out(vty, + " export %s%s prefix-list %s\n", + (rfg->type == RFAPI_GROUP_CFG_VRF + ? "" + : "zebra "), + afistr, + rfg->plist_export_zebra_name + [afi]); + } + /* + * currently we only support redist plists for + * bgp-direct. + * If we later add plist support for + * redistributing other + * protocols, we'll need to loop over protocols + * here + */ + if (rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT][afi]) { + vty_out(vty, + " redistribute bgp-direct %s prefix-list %s\n", + afistr, + rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT] + [afi]); + } + if (rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT][afi]) { + vty_out(vty, + " redistribute bgp-direct-to-nve-groups %s prefix-list %s\n", + afistr, + rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT] + [afi]); + } + } + + if (rfg->routemap_export_bgp_name) { + vty_out(vty, " export %sroute-map %s\n", + (rfg->type == RFAPI_GROUP_CFG_VRF + ? "" + : "bgp "), + rfg->routemap_export_bgp_name); + } + if (rfg->routemap_export_zebra_name) { + vty_out(vty, " export %sroute-map %s\n", + (rfg->type == RFAPI_GROUP_CFG_VRF + ? "" + : "zebra "), + rfg->routemap_export_zebra_name); + } + if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) { + vty_out(vty, + " redistribute bgp-direct route-map %s\n", + rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT]); + } + if (rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT]) { + vty_out(vty, + " redistribute bgp-direct-to-nve-groups route-map %s\n", + rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT]); + } + vty_out(vty, " exit-vrf-policy\n"); + vty_out(vty, "!\n"); + } + if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP) { + vty_out(vty, " vnc advertise-un-method encap-safi\n"); + write++; + } + + { /* was based on listen ports */ + /* for now allow both old and new */ + if (bgp->rfapi->rfp_methods.cfg_cb) + write += (bgp->rfapi->rfp_methods.cfg_cb)( + vty, bgp->rfapi->rfp); + + if (write) + vty_out(vty, "!\n"); + + if (hc->l2_groups) { + struct rfapi_l2_group_cfg *rfgc = NULL; + struct listnode *gnode; + for (ALL_LIST_ELEMENTS_RO(hc->l2_groups, gnode, rfgc)) { + struct listnode *lnode; + void *data; + ++write; + vty_out(vty, " vnc l2-group %s\n", rfgc->name); + if (rfgc->logical_net_id != 0) + vty_out(vty, + " logical-network-id %u\n", + rfgc->logical_net_id); + if (rfgc->labels != NULL + && listhead(rfgc->labels) != NULL) { + vty_out(vty, " labels "); + for (ALL_LIST_ELEMENTS_RO(rfgc->labels, + lnode, + data)) { + vty_out(vty, "%hu ", + (uint16_t)( + (uintptr_t) + data)); + } + vty_out(vty, "\n"); + } + + if (rfgc->rt_import_list && rfgc->rt_export_list + && ecommunity_cmp(rfgc->rt_import_list, + rfgc->rt_export_list)) { + char *b = ecommunity_ecom2str( + rfgc->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt both %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + if (rfgc->rt_import_list) { + char *b = ecommunity_ecom2str( + rfgc->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt import %s\n", + b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + if (rfgc->rt_export_list) { + char *b = ecommunity_ecom2str( + rfgc->rt_export_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt export %s\n", + b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + } + if (bgp->rfapi->rfp_methods.cfg_group_cb) + write += (bgp->rfapi->rfp_methods + .cfg_group_cb)( + vty, bgp->rfapi->rfp, + RFAPI_RFP_CFG_GROUP_L2, + rfgc->name, rfgc->rfp_cfg); + vty_out(vty, " exit-vnc\n"); + vty_out(vty, "!\n"); + } + } + + if (hc->default_rd.prefixlen + || hc->default_response_lifetime + != BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT + || hc->default_rt_import_list || hc->default_rt_export_list + || hc->nve_groups_sequential->count) { + + + ++write; + vty_out(vty, " vnc defaults\n"); + + if (hc->default_rd.prefixlen) { + if (AF_UNIX == hc->default_rd.family) { + uint16_t value = 0; + + value = ((hc->default_rd.val[6] << 8) + & 0x0ff00) + | (hc->default_rd.val[7] + & 0x0ff); + + vty_out(vty, " rd auto:vn:%d\n", + value); + + } else + vty_out(vty, " rd %pRDP\n", + &hc->default_rd); + } + if (hc->default_response_lifetime + != BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT) { + vty_out(vty, " response-lifetime "); + if (hc->default_response_lifetime != UINT32_MAX) + vty_out(vty, "%d", + hc->default_response_lifetime); + else + vty_out(vty, "infinite"); + vty_out(vty, "\n"); + } + if (hc->default_rt_import_list + && hc->default_rt_export_list + && ecommunity_cmp(hc->default_rt_import_list, + hc->default_rt_export_list)) { + char *b = ecommunity_ecom2str( + hc->default_rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt both %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + if (hc->default_rt_import_list) { + char *b = ecommunity_ecom2str( + hc->default_rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt import %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + if (hc->default_rt_export_list) { + char *b = ecommunity_ecom2str( + hc->default_rt_export_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt export %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + } + if (bgp->rfapi->rfp_methods.cfg_group_cb) + write += (bgp->rfapi->rfp_methods.cfg_group_cb)( + vty, bgp->rfapi->rfp, + RFAPI_RFP_CFG_GROUP_DEFAULT, NULL, + bgp->rfapi_cfg->default_rfp_cfg); + vty_out(vty, " exit-vnc\n"); + vty_out(vty, "!\n"); + } + + for (ALL_LIST_ELEMENTS(hc->nve_groups_sequential, node, nnode, + rfg)) + if (rfg->type == RFAPI_GROUP_CFG_NVE) { + ++write; + vty_out(vty, " vnc nve-group %s\n", rfg->name); + + if (rfg->vn_prefix.family && rfg->vn_node) + vty_out(vty, " prefix %s %pFX\n", "vn", + &rfg->vn_prefix); + + if (rfg->un_prefix.family && rfg->un_node) + vty_out(vty, " prefix %s %pFX\n", "un", + &rfg->un_prefix); + + + if (rfg->rd.prefixlen) { + if (AF_UNIX == rfg->rd.family) { + + uint16_t value = 0; + + value = ((rfg->rd.val[6] << 8) + & 0x0ff00) + | (rfg->rd.val[7] + & 0x0ff); + + vty_out(vty, + " rd auto:vn:%d\n", + value); + + } else + vty_out(vty, " rd %pRDP\n", + &rfg->rd); + } + if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) { + vty_out(vty, " response-lifetime "); + if (rfg->response_lifetime + != UINT32_MAX) + vty_out(vty, "%d", + rfg->response_lifetime); + else + vty_out(vty, "infinite"); + vty_out(vty, "\n"); + } + + if (rfg->rt_import_list && rfg->rt_export_list + && ecommunity_cmp(rfg->rt_import_list, + rfg->rt_export_list)) { + char *b = ecommunity_ecom2str( + rfg->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt both %s\n", b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + if (rfg->rt_import_list) { + char *b = ecommunity_ecom2str( + rfg->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt import %s\n", + b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + if (rfg->rt_export_list) { + char *b = ecommunity_ecom2str( + rfg->rt_export_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt export %s\n", + b); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } + } + + /* + * route filtering: prefix-lists and route-maps + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + const char *afistr = (afi == AFI_IP) + ? "ipv4" + : "ipv6"; + + if (rfg->plist_export_bgp_name[afi]) { + vty_out(vty, + " export bgp %s prefix-list %s\n", + afistr, + rfg->plist_export_bgp_name + [afi]); + } + if (rfg->plist_export_zebra_name[afi]) { + vty_out(vty, + " export zebra %s prefix-list %s\n", + afistr, + rfg->plist_export_zebra_name + [afi]); + } + /* + * currently we only support redist + * plists for bgp-direct. + * If we later add plist support for + * redistributing other + * protocols, we'll need to loop over + * protocols here + */ + if (rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT] + [afi]) { + vty_out(vty, + " redistribute bgp-direct %s prefix-list %s\n", + afistr, + rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT] + [afi]); + } + if (rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT] + [afi]) { + vty_out(vty, + " redistribute bgp-direct-to-nve-groups %s prefix-list %s\n", + afistr, + rfg->plist_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT] + [afi]); + } + } + + if (rfg->routemap_export_bgp_name) { + vty_out(vty, + " export bgp route-map %s\n", + rfg->routemap_export_bgp_name); + } + if (rfg->routemap_export_zebra_name) { + vty_out(vty, + " export zebra route-map %s\n", + rfg->routemap_export_zebra_name); + } + if (rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT]) { + vty_out(vty, + " redistribute bgp-direct route-map %s\n", + rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT]); + } + if (rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT]) { + vty_out(vty, + " redistribute bgp-direct-to-nve-groups route-map %s\n", + rfg->routemap_redist_name + [ZEBRA_ROUTE_BGP_DIRECT_EXT]); + } + if (bgp->rfapi->rfp_methods.cfg_group_cb) + write += (bgp->rfapi->rfp_methods + .cfg_group_cb)( + vty, bgp->rfapi->rfp, + RFAPI_RFP_CFG_GROUP_NVE, + rfg->name, rfg->rfp_cfg); + vty_out(vty, " exit-vnc\n"); + vty_out(vty, "!\n"); + } + } /* have listen ports */ + + /* + * route export to other protocols + */ + if (VNC_EXPORT_BGP_GRP_ENABLED(hc)) { + vty_out(vty, " vnc export bgp mode group-nve\n"); + } else if (VNC_EXPORT_BGP_RH_ENABLED(hc)) { + vty_out(vty, " vnc export bgp mode registering-nve\n"); + } else if (VNC_EXPORT_BGP_CE_ENABLED(hc)) { + vty_out(vty, " vnc export bgp mode ce\n"); + } + + if (VNC_EXPORT_ZEBRA_GRP_ENABLED(hc)) { + vty_out(vty, " vnc export zebra mode group-nve\n"); + } else if (VNC_EXPORT_ZEBRA_RH_ENABLED(hc)) { + vty_out(vty, " vnc export zebra mode registering-nve\n"); + } + + if (hc->rfg_export_direct_bgp_l) { + for (ALL_LIST_ELEMENTS(hc->rfg_export_direct_bgp_l, node, nnode, + rfgn)) { + + vty_out(vty, " vnc export bgp group-nve group %s\n", + rfgn->name); + } + } + + if (hc->rfg_export_zebra_l) { + for (ALL_LIST_ELEMENTS(hc->rfg_export_zebra_l, node, nnode, + rfgn)) { + + vty_out(vty, " vnc export zebra group-nve group %s\n", + rfgn->name); + } + } + + + if (hc->rfg_redist_name) { + vty_out(vty, " vnc redistribute nve-group %s\n", + hc->rfg_redist_name); + } + if (hc->redist_lifetime) { + vty_out(vty, " vnc redistribute lifetime %d\n", + hc->redist_lifetime); + } + if (hc->resolve_nve_roo_local_admin + != BGP_VNC_CONFIG_RESOLVE_NVE_ROO_LOCAL_ADMIN_DEFAULT) { + + vty_out(vty, + " vnc redistribute resolve-nve roo-ec-local-admin %d\n", + hc->resolve_nve_roo_local_admin); + } + + if (hc->redist_mode) /* ! default */ + { + const char *s = ""; + + switch (hc->redist_mode) { + case VNC_REDIST_MODE_PLAIN: + s = "plain"; + break; + case VNC_REDIST_MODE_RFG: + s = "nve-group"; + break; + case VNC_REDIST_MODE_RESOLVE_NVE: + s = "resolve-nve"; + break; + } + if (s) { + vty_out(vty, " vnc redistribute mode %s\n", s); + } + } + + /* + * route filtering: prefix-lists and route-maps + */ + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + const char *afistr = (afi == AFI_IP) ? "ipv4" : "ipv6"; + + if (hc->plist_export_bgp_name[afi]) { + vty_out(vty, " vnc export bgp %s prefix-list %s\n", + afistr, hc->plist_export_bgp_name[afi]); + } + if (hc->plist_export_zebra_name[afi]) { + vty_out(vty, " vnc export zebra %s prefix-list %s\n", + afistr, hc->plist_export_zebra_name[afi]); + } + if (hc->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) { + vty_out(vty, + " vnc redistribute bgp-direct %s prefix-list %s\n", + afistr, + hc->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT] + [afi]); + } + } + + if (hc->routemap_export_bgp_name) { + vty_out(vty, " vnc export bgp route-map %s\n", + hc->routemap_export_bgp_name); + } + if (hc->routemap_export_zebra_name) { + vty_out(vty, " vnc export zebra route-map %s\n", + hc->routemap_export_zebra_name); + } + if (hc->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) { + vty_out(vty, " vnc redistribute bgp-direct route-map %s\n", + hc->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + } + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + for (type = 0; type < ZEBRA_ROUTE_MAX; ++type) { + if (hc->redist[afi][type]) { + if (type == ZEBRA_ROUTE_BGP_DIRECT_EXT + && hc->redist_bgp_exterior_view_name) { + vty_out(vty, + " vnc redistribute %s %s view %s\n", + ((afi == AFI_IP) ? "ipv4" + : "ipv6"), + zebra_route_string(type), + hc->redist_bgp_exterior_view_name); + } else { + vty_out(vty, + " vnc redistribute %s %s\n", + ((afi == AFI_IP) ? "ipv4" + : "ipv6"), + zebra_route_string(type)); + } + } + } + } + return write; +} + +void bgp_rfapi_show_summary(struct bgp *bgp, struct vty *vty) +{ + struct rfapi_cfg *hc = bgp->rfapi_cfg; + afi_t afi; + int type, redist = 0; + char tmp[40]; + if (hc == NULL) + return; + + vty_out(vty, "%-39s %-19s %s\n", "VNC Advertise method:", + (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP + ? "Encapsulation SAFI" + : "Tunnel Encap attribute"), + ((hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP) + == (BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP + & BGP_VNC_CONFIG_FLAGS_DEFAULT) + ? "(default)" + : "")); + /* export */ + vty_out(vty, "%-39s ", "Export from VNC:"); + /* + * route export to other protocols + */ + if (VNC_EXPORT_BGP_GRP_ENABLED(hc)) { + redist++; + vty_out(vty, "ToBGP Groups={"); + if (hc->rfg_export_direct_bgp_l) { + int cnt = 0; + struct listnode *node, *nnode; + struct rfapi_rfg_name *rfgn; + for (ALL_LIST_ELEMENTS(hc->rfg_export_direct_bgp_l, + node, nnode, rfgn)) { + if (cnt++ != 0) + vty_out(vty, ","); + + vty_out(vty, "%s", rfgn->name); + } + } + vty_out(vty, "}"); + } else if (VNC_EXPORT_BGP_RH_ENABLED(hc)) { + redist++; + vty_out(vty, "ToBGP {Registering NVE}"); + /* note filters, route-maps not shown */ + } else if (VNC_EXPORT_BGP_CE_ENABLED(hc)) { + redist++; + vty_out(vty, "ToBGP {NVE connected router:%d}", + hc->resolve_nve_roo_local_admin); + /* note filters, route-maps not shown */ + } + + if (VNC_EXPORT_ZEBRA_GRP_ENABLED(hc)) { + redist++; + vty_out(vty, "%sToZebra Groups={", (redist == 1 ? "" : " ")); + if (hc->rfg_export_zebra_l) { + int cnt = 0; + struct listnode *node, *nnode; + struct rfapi_rfg_name *rfgn; + for (ALL_LIST_ELEMENTS(hc->rfg_export_zebra_l, node, + nnode, rfgn)) { + if (cnt++ != 0) + vty_out(vty, ","); + vty_out(vty, "%s", rfgn->name); + } + } + vty_out(vty, "}"); + } else if (VNC_EXPORT_ZEBRA_RH_ENABLED(hc)) { + redist++; + vty_out(vty, "%sToZebra {Registering NVE}", + (redist == 1 ? "" : " ")); + /* note filters, route-maps not shown */ + } + vty_out(vty, "%-19s %s\n", (redist ? "" : "Off"), + (redist ? "" : "(default)")); + + /* Redistribution */ + redist = 0; + vty_out(vty, "%-39s ", "Redistribution into VNC:"); + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + for (type = 0; type < ZEBRA_ROUTE_MAX; ++type) { + if (hc->redist[afi][type]) { + vty_out(vty, "{%s,%s} ", + ((afi == AFI_IP) ? "ipv4" : "ipv6"), + zebra_route_string(type)); + redist++; + } + } + } + vty_out(vty, "%-19s %s\n", (redist ? "" : "Off"), + (redist ? "" : "(default)")); + + vty_out(vty, "%-39s %3u%-16s %s\n", + "RFP Registration Hold-Down Factor:", + hc->rfp_cfg.holddown_factor, "%", + (hc->rfp_cfg.holddown_factor + == RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR + ? "(default)" + : "")); + vty_out(vty, "%-39s %-19s %s\n", "RFP Updated responses:", + (hc->rfp_cfg.use_updated_response == 0 ? "Off" : "On"), + (hc->rfp_cfg.use_updated_response == 0 ? "(default)" : "")); + vty_out(vty, "%-39s %-19s %s\n", "RFP Removal responses:", + (hc->rfp_cfg.use_removes == 0 ? "Off" : "On"), + (hc->rfp_cfg.use_removes == 0 ? "(default)" : "")); + vty_out(vty, "%-39s %-19s %s\n", "RFP Full table download:", + (hc->rfp_cfg.download_type == RFAPI_RFP_DOWNLOAD_FULL ? "On" + : "Off"), + (hc->rfp_cfg.download_type == RFAPI_RFP_DOWNLOAD_PARTIAL + ? "(default)" + : "")); + snprintf(tmp, sizeof(tmp), "%u seconds", + hc->rfp_cfg.ftd_advertisement_interval); + vty_out(vty, "%-39s %-19s %s\n", " Advertisement Interval:", tmp, + (hc->rfp_cfg.ftd_advertisement_interval + == RFAPI_RFP_CFG_DEFAULT_FTD_ADVERTISEMENT_INTERVAL + ? "(default)" + : "")); + vty_out(vty, "%-39s %d seconds\n", "Default RFP response lifetime:", + hc->default_response_lifetime); + vty_out(vty, "\n"); + return; +} + +struct rfapi_cfg *bgp_rfapi_get_config(struct bgp *bgp) +{ + struct rfapi_cfg *hc = NULL; + if (bgp == NULL) + bgp = bgp_get_default(); + if (bgp != NULL) + hc = bgp->rfapi_cfg; + return hc; +} + +#endif /* ENABLE_BGP_VNC */ |