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/rfapi_vty.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/rfapi_vty.c')
-rw-r--r-- | bgpd/rfapi/rfapi_vty.c | 5008 |
1 files changed, 5008 insertions, 0 deletions
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c new file mode 100644 index 0000000..252b6d6 --- /dev/null +++ b/bgpd/rfapi/rfapi_vty.c @@ -0,0 +1,5008 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * Copyright 2009-2016, LabN Consulting, L.L.C. + * + */ + +#include "lib/zebra.h" +#include "lib/prefix.h" +#include "lib/agg_table.h" +#include "lib/vty.h" +#include "lib/memory.h" +#include "lib/routemap.h" +#include "lib/log.h" +#include "lib/linklist.h" +#include "lib/command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h" + +#include "bgpd/rfapi/bgp_rfapi_cfg.h" +#include "bgpd/rfapi/rfapi.h" +#include "bgpd/rfapi/rfapi_backend.h" + +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_vnc_types.h" +#include "bgpd/bgp_label.h" + +#include "bgpd/rfapi/rfapi_import.h" +#include "bgpd/rfapi/rfapi_private.h" +#include "bgpd/rfapi/rfapi_monitor.h" +#include "bgpd/rfapi/rfapi_rib.h" +#include "bgpd/rfapi/rfapi_vty.h" +#include "bgpd/rfapi/rfapi_ap.h" +#include "bgpd/rfapi/rfapi_encap_tlv.h" +#include "bgpd/rfapi/vnc_debug.h" + +#define DEBUG_L2_EXTRA 0 +#define DEBUG_SHOW_EXTRA 0 + +#define VNC_SHOW_STR "VNC information\n" + +/* format related utilies */ + + +#define FMT_MIN 60 /* seconds */ +#define FMT_HOUR (60 * FMT_MIN) +#define FMT_DAY (24 * FMT_HOUR) +#define FMT_YEAR (365 * FMT_DAY) + +char *rfapiFormatSeconds(uint32_t seconds, char *buf, size_t len) +{ + int year, day, hour, min; + + if (seconds >= FMT_YEAR) { + year = seconds / FMT_YEAR; + seconds -= year * FMT_YEAR; + } else + year = 0; + + if (seconds >= FMT_DAY) { + day = seconds / FMT_DAY; + seconds -= day * FMT_DAY; + } else + day = 0; + + if (seconds >= FMT_HOUR) { + hour = seconds / FMT_HOUR; + seconds -= hour * FMT_HOUR; + } else + hour = 0; + + if (seconds >= FMT_MIN) { + min = seconds / FMT_MIN; + seconds -= min * FMT_MIN; + } else + min = 0; + + if (year > 0) { + snprintf(buf, len, "%dy%dd%dh", year, day, hour); + } else if (day > 0) { + snprintf(buf, len, "%dd%dh%dm", day, hour, min); + } else { + snprintf(buf, len, "%02d:%02d:%02d", hour, min, seconds); + } + + return buf; +} + +char *rfapiFormatAge(time_t age, char *buf, size_t len) +{ + time_t now, age_adjusted; + + now = monotime(NULL); + age_adjusted = now - age; + + return rfapiFormatSeconds(age_adjusted, buf, len); +} + + +/* + * Reimplementation of quagga/lib/prefix.c function, but + * for RFAPI-style prefixes + */ +void rfapiRprefixApplyMask(struct rfapi_ip_prefix *rprefix) +{ + uint8_t *pnt; + int index; + int offset; + + static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; + + switch (rprefix->prefix.addr_family) { + case AF_INET: + index = rprefix->length / 8; + if (index < 4) { + pnt = (uint8_t *)&rprefix->prefix.addr.v4; + offset = rprefix->length % 8; + pnt[index] &= maskbit[offset]; + index++; + while (index < 4) + pnt[index++] = 0; + } + break; + + case AF_INET6: + index = rprefix->length / 8; + if (index < 16) { + pnt = (uint8_t *)&rprefix->prefix.addr.v6; + offset = rprefix->length % 8; + pnt[index] &= maskbit[offset]; + index++; + while (index < 16) + pnt[index++] = 0; + } + break; + + default: + assert(0); + } +} + +/* + * translate a quagga prefix into a rfapi IP address. The + * prefix is REQUIRED to be 32 bits for IPv4 and 128 bits for IPv6 + * + * RETURNS: + * + * 0 Success + * <0 Error + */ +int rfapiQprefix2Raddr(struct prefix *qprefix, struct rfapi_ip_addr *raddr) +{ + memset(raddr, 0, sizeof(struct rfapi_ip_addr)); + raddr->addr_family = qprefix->family; + switch (qprefix->family) { + case AF_INET: + if (qprefix->prefixlen != IPV4_MAX_BITLEN) + return -1; + raddr->addr.v4 = qprefix->u.prefix4; + break; + case AF_INET6: + if (qprefix->prefixlen != IPV6_MAX_BITLEN) + return -1; + raddr->addr.v6 = qprefix->u.prefix6; + break; + default: + return -1; + } + return 0; +} + +/* + * Translate Quagga prefix to RFAPI prefix + */ +/* rprefix->cost set to 0 */ +void rfapiQprefix2Rprefix(const struct prefix *qprefix, + struct rfapi_ip_prefix *rprefix) +{ + memset(rprefix, 0, sizeof(struct rfapi_ip_prefix)); + rprefix->length = qprefix->prefixlen; + rprefix->prefix.addr_family = qprefix->family; + switch (qprefix->family) { + case AF_INET: + rprefix->prefix.addr.v4 = qprefix->u.prefix4; + break; + case AF_INET6: + rprefix->prefix.addr.v6 = qprefix->u.prefix6; + break; + default: + assert(0); + } +} + +int rfapiRprefix2Qprefix(struct rfapi_ip_prefix *rprefix, + struct prefix *qprefix) +{ + memset(qprefix, 0, sizeof(struct prefix)); + qprefix->prefixlen = rprefix->length; + qprefix->family = rprefix->prefix.addr_family; + + switch (rprefix->prefix.addr_family) { + case AF_INET: + qprefix->u.prefix4 = rprefix->prefix.addr.v4; + break; + case AF_INET6: + qprefix->u.prefix6 = rprefix->prefix.addr.v6; + break; + default: + return EAFNOSUPPORT; + } + return 0; +} + +/* + * returns 1 if prefixes have same addr family, prefix len, and address + * Note that host bits matter in this comparison! + * + * For paralellism with quagga/lib/prefix.c. if we need a comparison + * where host bits are ignored, call that function rfapiRprefixCmp. + */ +int rfapiRprefixSame(struct rfapi_ip_prefix *hp1, struct rfapi_ip_prefix *hp2) +{ + if (hp1->prefix.addr_family != hp2->prefix.addr_family) + return 0; + if (hp1->length != hp2->length) + return 0; + if (hp1->prefix.addr_family == AF_INET) + if (IPV4_ADDR_SAME(&hp1->prefix.addr.v4, &hp2->prefix.addr.v4)) + return 1; + if (hp1->prefix.addr_family == AF_INET6) + if (IPV6_ADDR_SAME(&hp1->prefix.addr.v6, &hp2->prefix.addr.v6)) + return 1; + return 0; +} + +int rfapiRaddr2Qprefix(struct rfapi_ip_addr *hia, struct prefix *pfx) +{ + memset(pfx, 0, sizeof(struct prefix)); + pfx->family = hia->addr_family; + + switch (hia->addr_family) { + case AF_INET: + pfx->prefixlen = IPV4_MAX_BITLEN; + pfx->u.prefix4 = hia->addr.v4; + break; + case AF_INET6: + pfx->prefixlen = IPV6_MAX_BITLEN; + pfx->u.prefix6 = hia->addr.v6; + break; + default: + return EAFNOSUPPORT; + } + return 0; +} + +void rfapiL2o2Qprefix(struct rfapi_l2address_option *l2o, struct prefix *pfx) +{ + memset(pfx, 0, sizeof(struct prefix)); + pfx->family = AF_ETHERNET; + pfx->prefixlen = 48; + pfx->u.prefix_eth = l2o->macaddr; +} + +char *rfapiEthAddr2Str(const struct ethaddr *ea, char *buf, int bufsize) +{ + return prefix_mac2str(ea, buf, bufsize); +} + +int rfapiStr2EthAddr(const char *str, struct ethaddr *ea) +{ + unsigned int a[6]; + int i; + + if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1, a + 2, a + 3, + a + 4, a + 5) + != 6) { + + return EINVAL; + } + + for (i = 0; i < 6; ++i) + ea->octet[i] = a[i] & 0xff; + + return 0; +} + +const char *rfapi_ntop(int af, const void *src, char *buf, socklen_t size) +{ + if (af == AF_ETHERNET) { + return rfapiEthAddr2Str((const struct ethaddr *)src, buf, size); + } + + return inet_ntop(af, src, buf, size); +} + +int rfapiDebugPrintf(void *dummy, const char *format, ...) +{ + va_list args; + va_start(args, format); + vzlog(LOG_DEBUG, format, args); + va_end(args); + return 0; +} + +PRINTFRR(2, 3) +static int rfapiStdioPrintf(void *stream, const char *format, ...) +{ + FILE *file = NULL; + + va_list args; + va_start(args, format); + + switch ((uintptr_t)stream) { + case 1: + file = stdout; + break; + case 2: + file = stderr; + break; + default: + assert(0); + } + + vfprintf(file, format, args); + va_end(args); + return 0; +} + +/* Fake out for debug logging */ +static struct vty vty_dummy_zlog; +static struct vty vty_dummy_stdio; +#define HVTYNL ((vty == &vty_dummy_zlog)? "": "\n") + +static const char *str_vty_newline(struct vty *vty) +{ + if (vty == &vty_dummy_zlog) + return ""; + return "\n"; +} + +int rfapiStream2Vty(void *stream, /* input */ + int (**fp)(void *, const char *, ...), /* output */ + struct vty **vty, /* output */ + void **outstream, /* output */ + const char **vty_newline) /* output */ +{ + + if (!stream) { + vty_dummy_zlog.type = VTY_SHELL; /* for VTYNL */ + *vty = &vty_dummy_zlog; + *fp = (int (*)(void *, const char *, ...))rfapiDebugPrintf; + *outstream = NULL; + *vty_newline = str_vty_newline(*vty); + return 1; + } + + if (((uintptr_t)stream == (uintptr_t)1) + || ((uintptr_t)stream == (uintptr_t)2)) { + + vty_dummy_stdio.type = VTY_SHELL; /* for VTYNL */ + *vty = &vty_dummy_stdio; + *fp = (int (*)(void *, const char *, ...))rfapiStdioPrintf; + *outstream = stream; + *vty_newline = str_vty_newline(*vty); + return 1; + } + + *vty = stream; /* VTYNL requires vty to be legit */ + *fp = (int (*)(void *, const char *, ...))vty_out; + *outstream = stream; + *vty_newline = str_vty_newline(*vty); + return 1; +} + +/* called from bgpd/bgp_vty.c'route_vty_out() */ +void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, + struct bgp_path_info *bpi, safi_t safi) +{ + char *s; + uint32_t lifetime; + + /* + * Print, on an indented line: + * UN address [if VPN route and VNC UN addr subtlv] + * EC list + * VNC lifetime + */ + vty_out(vty, " "); + + if (safi == SAFI_MPLS_VPN) { + struct prefix pfx_un; + + if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { + char buf[BUFSIZ]; + + vty_out(vty, "UN=%s", + inet_ntop(pfx_un.family, pfx_un.u.val, buf, + sizeof(buf))); + } + } + + if (bgp_attr_get_ecommunity(bpi->attr)) { + s = ecommunity_ecom2str(bgp_attr_get_ecommunity(bpi->attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out(vty, " EC{%s}", s); + XFREE(MTYPE_ECOMMUNITY_STR, s); + } + + if (bpi->extra != NULL) { + if (bpi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + vty_out(vty, " label=VRF2VRF"); + else + vty_out(vty, " label=%u", + decode_label(&bpi->extra->label[0])); + + if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { + struct in6_addr *sid_tmp = + bpi->attr->srv6_l3vpn + ? (&bpi->attr->srv6_l3vpn->sid) + : (&bpi->attr->srv6_vpn->sid); + vty_out(vty, " sid=%pI6", sid_tmp); + + if (bpi->attr->srv6_l3vpn && + bpi->attr->srv6_l3vpn->loc_block_len != 0) { + vty_out(vty, " sid_structure=[%d,%d,%d,%d]", + bpi->attr->srv6_l3vpn->loc_block_len, + bpi->attr->srv6_l3vpn->loc_node_len, + bpi->attr->srv6_l3vpn->func_len, + bpi->attr->srv6_l3vpn->arg_len); + } + } + } + + if (!rfapiGetVncLifetime(bpi->attr, &lifetime)) { + vty_out(vty, " life=%d", lifetime); + } + + vty_out(vty, " type=%s, subtype=%d", zebra_route_string(bpi->type), + bpi->sub_type); + + vty_out(vty, "%s", HVTYNL); +} + +void rfapiPrintAttrPtrs(void *stream, struct attr *attr) +{ + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + struct transit *transit; + struct cluster_list *cluster; + struct ecommunity *ecomm; + struct community *comm; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + fp(out, "Attr[%p]:%s", attr, HVTYNL); + if (!attr) + return; + + /* IPv4 Nexthop */ + fp(out, " nexthop=%pI4%s", &attr->nexthop, HVTYNL); + + fp(out, " aspath=%p, refcnt=%d%s", attr->aspath, + (attr->aspath ? attr->aspath->refcnt : 0), HVTYNL); + + comm = bgp_attr_get_community(attr); + fp(out, " community=%p, refcnt=%d%s", comm, (comm ? comm->refcnt : 0), + HVTYNL); + + ecomm = bgp_attr_get_ecommunity(attr); + fp(out, " ecommunity=%p, refcnt=%d%s", ecomm, + (ecomm ? ecomm->refcnt : 0), HVTYNL); + + cluster = bgp_attr_get_cluster(attr); + fp(out, " cluster=%p, refcnt=%d%s", cluster, + (cluster ? cluster->refcnt : 0), HVTYNL); + + transit = bgp_attr_get_transit(attr); + fp(out, " transit=%p, refcnt=%d%s", transit, + (transit ? transit->refcnt : 0), HVTYNL); +} + +/* + * Print BPI in an Import Table + */ +void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) +{ + char buf[BUFSIZ]; + char *s; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + + char line[BUFSIZ]; + char *p = line; + int r; + int has_macaddr = 0; + struct ethaddr macaddr = {{0}}; + struct rfapi_l2address_option l2o_buf; + uint8_t l2hid = 0; /* valid if has_macaddr */ + +#define REMAIN (BUFSIZ - (p-line)) +#define INCP {p += (r > REMAIN)? REMAIN: r;} + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + if (!bpi) + return; + + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra + && bpi->extra->vnc.import.timer) { + struct event *t = (struct event *)bpi->extra->vnc.import.timer; + + r = snprintf(p, REMAIN, " [%4lu] ", + event_timer_remain_second(t)); + INCP; + + } else { + r = snprintf(p, REMAIN, " "); + INCP; + } + + if (bpi->extra) { + /* TBD This valid only for SAFI_MPLS_VPN, but not for encap */ + if (decode_rd_type(bpi->extra->vnc.import.rd.val) + == RD_TYPE_VNC_ETH) { + has_macaddr = 1; + memcpy(macaddr.octet, bpi->extra->vnc.import.rd.val + 2, + 6); + l2hid = bpi->extra->vnc.import.rd.val[1]; + } + } + + /* + * Print these items: + * type/subtype + * nexthop address + * lifetime + * RFP option sizes (they are opaque values) + * extended communities (RTs) + */ + uint32_t lifetime; + int printed_1st_gol = 0; + struct bgp_attr_encap_subtlv *pEncap; + struct prefix pfx_un; + int af = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len); + + /* Nexthop */ + if (af == AF_INET) { + r = snprintfrr(p, REMAIN, "%pI4", + &bpi->attr->mp_nexthop_global_in); + INCP; + } else if (af == AF_INET6) { + r = snprintfrr(p, REMAIN, "%pI6", + &bpi->attr->mp_nexthop_global); + INCP; + } else { + r = snprintf(p, REMAIN, "?"); + INCP; + } + + /* + * VNC tunnel subtlv, if present, contains UN address + */ + if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { + r = snprintf(p, REMAIN, " un=%s", + inet_ntop(pfx_un.family, pfx_un.u.val, buf, + sizeof(buf))); + INCP; + } + + /* Lifetime */ + if (rfapiGetVncLifetime(bpi->attr, &lifetime)) { + r = snprintf(p, REMAIN, " nolife"); + INCP; + } else { + if (lifetime == 0xffffffff) + r = snprintf(p, REMAIN, " %6s", "infini"); + else + r = snprintf(p, REMAIN, " %6u", lifetime); + INCP; + } + + /* RFP option lengths */ + for (pEncap = bgp_attr_get_vnc_subtlvs(bpi->attr); pEncap; + pEncap = pEncap->next) { + + if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) { + if (printed_1st_gol) { + r = snprintf(p, REMAIN, ","); + INCP; + } else { + r = snprintf(p, REMAIN, + " "); /* leading space */ + INCP; + } + r = snprintf(p, REMAIN, "%d", pEncap->length); + INCP; + printed_1st_gol = 1; + } + } + + /* RT list */ + if (bgp_attr_get_ecommunity(bpi->attr)) { + s = ecommunity_ecom2str(bgp_attr_get_ecommunity(bpi->attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + r = snprintf(p, REMAIN, " %s", s); + INCP; + XFREE(MTYPE_ECOMMUNITY_STR, s); + } + + r = snprintf(p, REMAIN, " bpi@%p", bpi); + INCP; + + r = snprintf(p, REMAIN, " p@%p", bpi->peer); + INCP; + + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { + r = snprintf(p, REMAIN, " HD=yes"); + INCP; + } else { + r = snprintf(p, REMAIN, " HD=no"); + INCP; + } + + if (bpi->attr->weight) { + r = snprintf(p, REMAIN, " W=%d", bpi->attr->weight); + INCP; + } + + if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { + r = snprintf(p, REMAIN, " LP=%d", bpi->attr->local_pref); + INCP; + } else { + r = snprintf(p, REMAIN, " LP=unset"); + INCP; + } + + r = snprintf(p, REMAIN, " %c:%u", zebra_route_char(bpi->type), + bpi->sub_type); + INCP; + + fp(out, "%s%s", line, HVTYNL); + + if (has_macaddr) { + fp(out, " RD HID=%d ETH=%02x:%02x:%02x:%02x:%02x:%02x%s", + l2hid, macaddr.octet[0], macaddr.octet[1], macaddr.octet[2], + macaddr.octet[3], macaddr.octet[4], macaddr.octet[5], + HVTYNL); + } + + if (!rfapiGetL2o(bpi->attr, &l2o_buf)) { + fp(out, + " L2O ETH=%02x:%02x:%02x:%02x:%02x:%02x LBL=%d LNI=%d LHI=%hhu%s", + l2o_buf.macaddr.octet[0], l2o_buf.macaddr.octet[1], + l2o_buf.macaddr.octet[2], l2o_buf.macaddr.octet[3], + l2o_buf.macaddr.octet[4], l2o_buf.macaddr.octet[5], + l2o_buf.label, l2o_buf.logical_net_id, l2o_buf.local_nve_id, + HVTYNL); + } + if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + const char *sp; + + sp = rfapi_ntop(bpi->extra->vnc.import.aux_prefix.family, + &bpi->extra->vnc.import.aux_prefix.u.prefix, + buf, BUFSIZ); + buf[BUFSIZ - 1] = 0; + if (sp) { + fp(out, " IP: %s%s", sp, HVTYNL); + } + } + { + struct rfapi_un_option *uo = + rfapi_encap_tlv_to_un_option(bpi->attr); + if (uo) { + rfapi_print_tunneltype_option(stream, 8, &uo->v.tunnel); + rfapi_un_options_free(uo); + } + } +} + +char *rfapiMonitorVpn2Str(struct rfapi_monitor_vpn *m, char *buf, int size) +{ + char buf_pfx[BUFSIZ]; + char buf_vn[BUFSIZ]; + char buf_un[BUFSIZ]; + int rc; + + rfapiRfapiIpAddr2Str(&m->rfd->un_addr, buf_vn, BUFSIZ); + rfapiRfapiIpAddr2Str(&m->rfd->vn_addr, buf_un, BUFSIZ); + + rc = snprintf(buf, size, + "m=%p, next=%p, rfd=%p(vn=%s un=%s), p=%s/%d, node=%p", m, + m->next, m->rfd, buf_vn, buf_un, + inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx, + sizeof(buf_pfx)), + m->p.prefixlen, m->node); + buf[size - 1] = 0; + if (rc >= size) + return NULL; + return buf; +} + +static void rfapiDebugPrintMonitorVpn(void *stream, struct rfapi_monitor_vpn *m) +{ + char buf[BUFSIZ]; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + rfapiMonitorVpn2Str(m, buf, BUFSIZ); + fp(out, " Mon %s%s", buf, HVTYNL); +} + +static void rfapiDebugPrintMonitorEncap(void *stream, + struct rfapi_monitor_encap *m) +{ + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out = NULL; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + fp(out, " Mon m=%p, next=%p, node=%p, bpi=%p%s", m, m->next, m->node, + m->bpi, HVTYNL); +} + +void rfapiShowItNode(void *stream, struct agg_node *rn) +{ + struct bgp_path_info *bpi; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + fp(out, "%pRN @%p #%d%s", rn, rn, agg_node_get_lock_count(rn), HVTYNL); + + for (bpi = rn->info; bpi; bpi = bpi->next) { + rfapiPrintBi(stream, bpi); + } + + /* doesn't show montors */ +} + +void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt, + int isvpn) +{ + struct agg_node *rn; + char buf[BUFSIZ]; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + fp(out, "Import Table [%s]%s", label, HVTYNL); + + for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { + struct bgp_path_info *bpi; + const struct prefix *p = agg_node_get_prefix(rn); + + if (p->family == AF_ETHERNET) { + rfapiEthAddr2Str(&p->u.prefix_eth, buf, sizeof(buf)); + } else { + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)); + } + + fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn, + agg_node_get_lock_count(rn) + - 1, /* account for loop iterator locking */ + HVTYNL); + + for (bpi = rn->info; bpi; bpi = bpi->next) { + rfapiPrintBi(stream, bpi); + } + + if (isvpn) { + struct rfapi_monitor_vpn *m; + for (m = RFAPI_MONITOR_VPN(rn); m; m = m->next) { + rfapiDebugPrintMonitorVpn(stream, m); + } + } else { + struct rfapi_monitor_encap *m; + for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) { + rfapiDebugPrintMonitorEncap(stream, m); + } + } + } +} + +int rfapiShowVncQueries(void *stream, struct prefix *pfx_match) +{ + struct bgp *bgp; + struct rfapi *h; + struct listnode *node; + struct rfapi_descriptor *rfd; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + + int printedheader = 0; + int queries_total = 0; + int queries_displayed = 0; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return CMD_WARNING; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + if (!bgp) { + vty_out(vty, "No BGP instance\n"); + return CMD_WARNING; + } + + h = bgp->rfapi; + if (!h) { + vty_out(vty, "No RFAPI instance\n"); + return CMD_WARNING; + } + + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) { + + struct agg_node *rn; + int printedquerier = 0; + + if (!rfd->mon && + !(rfd->mon_eth && skiplist_count(rfd->mon_eth))) + continue; + + /* + * IP Queries + */ + if (rfd->mon) { + for (rn = agg_route_top(rfd->mon); rn; + rn = agg_route_next(rn)) { + const struct prefix *p = + agg_node_get_prefix(rn); + struct rfapi_monitor_vpn *m; + char buf_remain[BUFSIZ]; + char buf_pfx[BUFSIZ]; + + if (!rn->info) + continue; + + m = rn->info; + + ++queries_total; + + if (pfx_match && !prefix_match(pfx_match, p) + && !prefix_match(p, pfx_match)) + continue; + + ++queries_displayed; + + if (!printedheader) { + ++printedheader; + fp(out, "\n"); + fp(out, "%-15s %-15s %-15s %-10s\n", + "VN Address", "UN Address", "Target", + "Remaining"); + } + + if (!printedquerier) { + char buf_vn[BUFSIZ]; + char buf_un[BUFSIZ]; + + rfapiRfapiIpAddr2Str(&rfd->un_addr, + buf_un, BUFSIZ); + rfapiRfapiIpAddr2Str(&rfd->vn_addr, + buf_vn, BUFSIZ); + + fp(out, "%-15s %-15s", buf_vn, buf_un); + printedquerier = 1; + } else + fp(out, "%-15s %-15s", "", ""); + buf_remain[0] = 0; + rfapiFormatSeconds( + event_timer_remain_second(m->timer), + buf_remain, BUFSIZ); + fp(out, " %-15s %-10s\n", + inet_ntop(m->p.family, &m->p.u.prefix, + buf_pfx, sizeof(buf_pfx)), + buf_remain); + } + } + + /* + * Ethernet Queries + */ + if (rfd->mon_eth && skiplist_count(rfd->mon_eth)) { + + int rc; + void *cursor; + struct rfapi_monitor_eth *mon_eth; + + for (cursor = NULL, + rc = skiplist_next(rfd->mon_eth, NULL, + (void **)&mon_eth, &cursor); + rc == 0; + rc = skiplist_next(rfd->mon_eth, NULL, + (void **)&mon_eth, &cursor)) { + + char buf_remain[BUFSIZ]; + char buf_pfx[BUFSIZ]; + struct prefix pfx_mac; + + ++queries_total; + + vnc_zlog_debug_verbose( + "%s: checking rfd=%p mon_eth=%p", + __func__, rfd, mon_eth); + + memset((void *)&pfx_mac, 0, + sizeof(struct prefix)); + pfx_mac.family = AF_ETHERNET; + pfx_mac.prefixlen = 48; + pfx_mac.u.prefix_eth = mon_eth->macaddr; + + if (pfx_match + && !prefix_match(pfx_match, &pfx_mac) + && !prefix_match(&pfx_mac, pfx_match)) + continue; + + ++queries_displayed; + + if (!printedheader) { + ++printedheader; + fp(out, "\n"); + fp(out, + "%-15s %-15s %-17s %10s %-10s\n", + "VN Address", "UN Address", "Target", + "LNI", "Remaining"); + } + + if (!printedquerier) { + char buf_vn[BUFSIZ]; + char buf_un[BUFSIZ]; + + rfapiRfapiIpAddr2Str(&rfd->un_addr, + buf_un, BUFSIZ); + rfapiRfapiIpAddr2Str(&rfd->vn_addr, + buf_vn, BUFSIZ); + + fp(out, "%-15s %-15s", buf_vn, buf_un); + printedquerier = 1; + } else + fp(out, "%-15s %-15s", "", ""); + buf_remain[0] = 0; + rfapiFormatSeconds(event_timer_remain_second( + mon_eth->timer), + buf_remain, BUFSIZ); + fp(out, " %-17s %10d %-10s\n", + rfapi_ntop(pfx_mac.family, &pfx_mac.u.prefix, + buf_pfx, BUFSIZ), + mon_eth->logical_net_id, buf_remain); + } + } + } + + if (queries_total) { + fp(out, "\n"); + fp(out, "Displayed %d out of %d total queries\n", + queries_displayed, queries_total); + } + return CMD_SUCCESS; +} + +static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, + struct agg_node *rn, struct bgp_path_info *bpi) +{ + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + struct prefix pfx_un; + struct prefix pfx_vn; + uint8_t cost; + uint32_t lifetime; + bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/ + + char buf_pfx[BUFSIZ]; + char buf_ntop[BUFSIZ]; + char buf_un[BUFSIZ]; + char buf_vn[BUFSIZ]; + char buf_lifetime[BUFSIZ]; + int nlines = 0; + const struct prefix *p = agg_node_get_prefix(rn); + + if (!stream) + return 0; /* for debug log, print into buf & call output once */ + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return 0; + + /* + * Prefix + */ + buf_pfx[0] = 0; + snprintf( + buf_pfx, sizeof(buf_pfx), "%s/%d", + rfapi_ntop(p->family, &p->u.prefix, buf_ntop, sizeof(buf_ntop)), + p->prefixlen); + buf_pfx[BUFSIZ - 1] = 0; + nlines++; + + /* + * UN addr + */ + buf_un[0] = 0; + if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) { + snprintf(buf_un, sizeof(buf_un), "%s", + inet_ntop(pfx_un.family, &pfx_un.u.prefix, buf_ntop, + sizeof(buf_ntop))); + } + + bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type); + /* + * VN addr + */ + buf_vn[0] = 0; + rfapiNexthop2Prefix(bpi->attr, &pfx_vn); + if (tun_type == BGP_ENCAP_TYPE_MPLS) { + /* MPLS carries un in nrli next hop (same as vn for IP tunnels) + */ + snprintf(buf_un, sizeof(buf_un), "%s", + inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, + sizeof(buf_ntop))); + if (bpi->extra) { + uint32_t l = decode_label(&bpi->extra->label[0]); + snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l); + } else /* should never happen */ + { + snprintf(buf_vn, sizeof(buf_vn), "Label: N/A"); + } + } else { + snprintf(buf_vn, sizeof(buf_vn), "%s", + inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, + sizeof(buf_ntop))); + } + buf_vn[BUFSIZ - 1] = 0; + buf_un[BUFSIZ - 1] = 0; + + /* + * Cost is encoded in local_pref as (255-cost) + * See rfapi_import.c'rfapiRouteInfo2NextHopEntry() for conversion + * back to cost. + */ + uint32_t local_pref; + + if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + local_pref = bpi->attr->local_pref; + else + local_pref = 0; + cost = (local_pref > 255) ? 0 : 255 - local_pref; + + fp(out, "%-20s ", buf_pfx); + fp(out, "%-15s ", buf_vn); + fp(out, "%-15s ", buf_un); + fp(out, "%-4d ", cost); + + /* Lifetime */ + /* NB rfapiGetVncLifetime sets infinite value when returning !0 */ + if (rfapiGetVncLifetime(bpi->attr, &lifetime) + || (lifetime == RFAPI_INFINITE_LIFETIME)) { + + fp(out, "%-10s ", "infinite"); + } else { + time_t t_lifetime = lifetime; + rfapiFormatSeconds(t_lifetime, buf_lifetime, BUFSIZ); + fp(out, "%-10s ", buf_lifetime); + } + + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra + && bpi->extra->vnc.import.timer) { + + uint32_t remaining; + time_t age; + char buf_age[BUFSIZ]; + + struct event *t = (struct event *)bpi->extra->vnc.import.timer; + remaining = event_timer_remain_second(t); + +#ifdef RFAPI_REGISTRATIONS_REPORT_AGE + /* + * Calculate when the timer started. Doing so here saves + * us a timestamp field in "struct bgp_path_info". + * + * See rfapi_import.c'rfapiBiStartWithdrawTimer() for the + * original calculation. + */ + age = rfapiGetHolddownFromLifetime(lifetime, factor) + - remaining; +#else /* report remaining time */ + age = remaining; +#endif + rfapiFormatSeconds(age, buf_age, BUFSIZ); + + fp(out, "%-10s ", buf_age); + + } else if (RFAPI_LOCAL_BI(bpi)) { + + char buf_age[BUFSIZ]; + + if (bpi->extra && bpi->extra->vnc.import.create_time) { + rfapiFormatAge(bpi->extra->vnc.import.create_time, + buf_age, BUFSIZ); + } else { + buf_age[0] = '?'; + buf_age[1] = 0; + } + fp(out, "%-10s ", buf_age); + } + fp(out, "%s", HVTYNL); + + if (p->family == AF_ETHERNET) { + /* + * If there is a corresponding IP address && != VN address, + * print that on the next line + */ + + if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + const char *sp; + + sp = rfapi_ntop( + bpi->extra->vnc.import.aux_prefix.family, + &bpi->extra->vnc.import.aux_prefix.u.prefix, + buf_ntop, BUFSIZ); + buf_ntop[BUFSIZ - 1] = 0; + + if (sp && strcmp(buf_vn, sp) != 0) { + fp(out, " IP: %s", sp); + if (nlines == 1) + nlines++; + } + } + } + if (tun_type != BGP_ENCAP_TYPE_MPLS && bpi->extra) { + uint32_t l = decode_label(&bpi->extra->label[0]); + + if (!MPLS_LABEL_IS_NULL(l)) { + fp(out, " Label: %d", l); + if (nlines == 1) + nlines++; + } + } + if (nlines > 1) + fp(out, "%s", HVTYNL); + + return 1; +} + +static int rfapiShowRemoteRegistrationsIt(struct bgp *bgp, void *stream, + struct rfapi_import_table *it, + struct prefix *prefix_only, + int show_expiring, /* either/or */ + int show_local, int show_remote, + int show_imported, /* either/or */ + uint32_t *pLni) /* AFI_L2VPN only */ +{ + afi_t afi; + int printed_rtlist_hdr = 0; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + int total = 0; + int printed = 0; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return printed; + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + + struct agg_node *rn; + + if (!it->imported_vpn[afi]) + continue; + + for (rn = agg_route_top(it->imported_vpn[afi]); rn; + rn = agg_route_next(rn)) { + const struct prefix *p = agg_node_get_prefix(rn); + struct bgp_path_info *bpi; + int count_only; + + /* allow for wider or more narrow mask from user */ + if (prefix_only && !prefix_match(prefix_only, p) + && !prefix_match(p, prefix_only)) + count_only = 1; + else + count_only = 0; + + for (bpi = rn->info; bpi; bpi = bpi->next) { + + if (!show_local && RFAPI_LOCAL_BI(bpi)) { + + /* local route from RFP */ + continue; + } + + if (!show_remote && !RFAPI_LOCAL_BI(bpi)) { + + /* remote route */ + continue; + } + + if (show_expiring + && !CHECK_FLAG(bpi->flags, + BGP_PATH_REMOVED)) + continue; + + if (!show_expiring + && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) + continue; + + if (bpi->type == ZEBRA_ROUTE_BGP_DIRECT + || bpi->type + == ZEBRA_ROUTE_BGP_DIRECT_EXT) { + if (!show_imported) + continue; + } else { + if (show_imported) + continue; + } + + total++; + if (count_only == 1) + continue; + if (!printed_rtlist_hdr) { + const char *agetype = ""; + char *s; + const char *type = ""; + if (show_imported) { + type = "Imported"; + } else { + if (show_expiring) { + type = "Holddown"; + } else { + if (RFAPI_LOCAL_BI( + bpi)) { + type = "Local"; + } else { + type = "Remote"; + } + } + } + + s = ecommunity_ecom2str( + it->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (pLni) { + fp(out, + "%s[%s] L2VPN Network 0x%x (%u) RT={%s}", + HVTYNL, type, *pLni, + (*pLni & 0xfff), s); + } else { + fp(out, "%s[%s] Prefix RT={%s}", + HVTYNL, type, s); + } + XFREE(MTYPE_ECOMMUNITY_STR, s); + + if (it->rfg && it->rfg->name) { + fp(out, " %s \"%s\"", + (it->rfg->type == RFAPI_GROUP_CFG_VRF + ? "VRF" + : "NVE group"), + it->rfg->name); + } + fp(out, "%s", HVTYNL); + if (show_expiring) { +#ifdef RFAPI_REGISTRATIONS_REPORT_AGE + agetype = "Age"; +#else + agetype = "Remaining"; +#endif + } else if (show_local) { + agetype = "Age"; + } + + printed_rtlist_hdr = 1; + + fp(out, + "%-20s %-15s %-15s %4s %-10s %-10s%s", + (pLni ? "L2 Address/IP" : "Prefix"), + "VN Address", "UN Address", "Cost", + "Lifetime", agetype, HVTYNL); + } + printed += rfapiPrintRemoteRegBi(bgp, stream, + rn, bpi); + } + } + } + + if (printed > 0) { + + const char *type = "prefixes"; + + if (show_imported) { + type = "imported prefixes"; + } else { + if (show_expiring) { + type = "prefixes in holddown"; + } else { + if (show_local && !show_remote) { + type = "locally registered prefixes"; + } else if (!show_local && show_remote) { + type = "remotely registered prefixes"; + } + } + } + + fp(out, "Displayed %d out of %d %s%s", printed, total, type, + HVTYNL); +#if DEBUG_SHOW_EXTRA + fp(out, "IT table above: it=%p%s", it, HVTYNL); +#endif + } + return printed; +} + + +/* + * rfapiShowRemoteRegistrations + * + * Similar to rfapiShowImportTable() above. This function + * is mean to produce the "remote" portion of the output + * of "show vnc registrations". + */ +int rfapiShowRemoteRegistrations(void *stream, struct prefix *prefix_only, + int show_expiring, int show_local, + int show_remote, int show_imported) +{ + struct bgp *bgp; + struct rfapi *h; + struct rfapi_import_table *it; + int printed = 0; + + bgp = bgp_get_default(); + if (!bgp) { + return printed; + } + + h = bgp->rfapi; + if (!h) { + return printed; + } + + for (it = h->imports; it; it = it->next) { + printed += rfapiShowRemoteRegistrationsIt( + bgp, stream, it, prefix_only, show_expiring, show_local, + show_remote, show_imported, NULL); + } + + if (h->import_mac) { + void *cursor = NULL; + int rc; + uintptr_t lni_as_ptr; + uint32_t lni; + uint32_t *pLni; + + for (rc = skiplist_next(h->import_mac, (void **)&lni_as_ptr, + (void **)&it, &cursor); + !rc; + rc = skiplist_next(h->import_mac, (void **)&lni_as_ptr, + (void **)&it, &cursor)) { + pLni = NULL; + if ((lni_as_ptr & 0xffffffff) == lni_as_ptr) { + lni = (uint32_t)(lni_as_ptr & 0xffffffff); + pLni = &lni; + } + + printed += rfapiShowRemoteRegistrationsIt( + bgp, stream, it, prefix_only, show_expiring, + show_local, show_remote, show_imported, pLni); + } + } + + return printed; +} + +/*------------------------------------------ + * rfapiRfapiIpAddr2Str + * + * UI helper: generate string from rfapi_ip_addr + * + * input: + * a IP v4/v6 address + * + * output + * buf put string here + * bufsize max space to write + * + * return value: + * NULL conversion failed + * non-NULL pointer to buf + --------------------------------------------*/ +const char *rfapiRfapiIpAddr2Str(struct rfapi_ip_addr *a, char *buf, + int bufsize) +{ + const char *rc = NULL; + + switch (a->addr_family) { + case AF_INET: + rc = inet_ntop(a->addr_family, &a->addr.v4, buf, bufsize); + break; + case AF_INET6: + rc = inet_ntop(a->addr_family, &a->addr.v6, buf, bufsize); + break; + } + return rc; +} + +void rfapiPrintRfapiIpAddr(void *stream, struct rfapi_ip_addr *a) +{ + char buf[BUFSIZ]; + const char *rc = NULL; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out = NULL; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + rc = rfapiRfapiIpAddr2Str(a, buf, BUFSIZ); + + if (rc) + fp(out, "%s", buf); +} + +const char *rfapiRfapiIpPrefix2Str(struct rfapi_ip_prefix *p, char *buf, + int bufsize) +{ + struct rfapi_ip_addr *a = &p->prefix; + const char *rc = NULL; + + switch (a->addr_family) { + case AF_INET: + rc = inet_ntop(a->addr_family, &a->addr.v4, buf, bufsize); + break; + case AF_INET6: + rc = inet_ntop(a->addr_family, &a->addr.v6, buf, bufsize); + break; + } + + if (rc) { + int alen = strlen(buf); + int remaining = bufsize - alen - 1; + int slen; + + if (remaining > 0) { + slen = snprintf(buf + alen, remaining, "/%u", + p->length); + if (slen < remaining) /* see man page for snprintf(3) */ + return rc; + } + } + + return NULL; +} + +void rfapiPrintRfapiIpPrefix(void *stream, struct rfapi_ip_prefix *p) +{ + char buf[BUFSIZ]; + const char *rc; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out = NULL; + const char *vty_newline; + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + rc = rfapiRfapiIpPrefix2Str(p, buf, BUFSIZ); + + if (rc) + fp(out, "%s:%u", buf, p->cost); + else + fp(out, "?/?:?"); +} + +void rfapiPrintAdvertisedInfo(struct vty *vty, struct rfapi_descriptor *rfd, + safi_t safi, struct prefix *p) +{ + afi_t afi; /* of the VN address */ + struct bgp_dest *bd; + struct bgp_path_info *bpi; + uint8_t type = ZEBRA_ROUTE_BGP; + struct bgp *bgp; + int printed = 0; + struct prefix_rd prd0; + struct prefix_rd *prd; + + /* + * Find the bgp_path in the RIB corresponding to this + * prefix and rfd + */ + + afi = family2afi(p->family); + assert(afi == AFI_IP || afi == AFI_IP6); + + bgp = bgp_get_default(); /* assume 1 instance for now */ + assert(bgp); + + if (safi == SAFI_ENCAP) { + memset(&prd0, 0, sizeof(prd0)); + prd0.family = AF_UNSPEC; + prd0.prefixlen = 64; + prd = &prd0; + } else { + prd = &rfd->rd; + } + bd = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); + + vty_out(vty, " bd=%p%s", bd, HVTYNL); + + for (bpi = bgp_dest_get_bgp_path_info(bd); bpi; bpi = bpi->next) { + if (bpi->peer == rfd->peer && bpi->type == type + && bpi->sub_type == BGP_ROUTE_RFP && bpi->extra + && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { + + rfapiPrintBi(vty, bpi); + printed = 1; + } + } + + if (!printed) { + vty_out(vty, " --?--%s", HVTYNL); + return; + } +} + +void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd) +{ + /* pHD un-addr vn-addr pCB cookie rd lifetime */ + /* RT export list */ + /* RT import list */ + /* list of advertised prefixes */ + /* dump import table */ + + char *s; + void *cursor; + int rc; + afi_t afi; + struct rfapi_adb *adb; + + vty_out(vty, "%-10p ", rfd); + rfapiPrintRfapiIpAddr(vty, &rfd->un_addr); + vty_out(vty, " "); + rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr); + vty_out(vty, " %p %p ", rfd->response_cb, rfd->cookie); + vty_out(vty, "%pRDP", &rfd->rd); + vty_out(vty, " %d", rfd->response_lifetime); + vty_out(vty, " %s", (rfd->rfg ? rfd->rfg->name : "<orphaned>")); + vty_out(vty, "%s", HVTYNL); + + vty_out(vty, " Peer %p #%d%s", rfd->peer, rfd->peer->lock, HVTYNL); + + /* export RT list */ + if (rfd->rt_export_list) { + s = ecommunity_ecom2str(rfd->rt_export_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out(vty, " Export %s%s", s, HVTYNL); + XFREE(MTYPE_ECOMMUNITY_STR, s); + } else { + vty_out(vty, " Export (nil)%s", HVTYNL); + } + + /* import RT list */ + if (rfd->import_table) { + s = ecommunity_ecom2str(rfd->import_table->rt_import_list, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + vty_out(vty, " Import %s%s", s, HVTYNL); + XFREE(MTYPE_ECOMMUNITY_STR, s); + } else { + vty_out(vty, " Import (nil)%s", HVTYNL); + } + + for (afi = AFI_IP; afi < AFI_MAX; ++afi) { + uint8_t family; + + family = afi2family(afi); + if (!family) + continue; + + cursor = NULL; + for (rc = skiplist_next(rfd->advertised.ipN_by_prefix, NULL, + (void **)&adb, &cursor); + rc == 0; + rc = skiplist_next(rfd->advertised.ipN_by_prefix, NULL, + (void **)&adb, &cursor)) { + + /* group like family prefixes together in output */ + if (family != adb->u.s.prefix_ip.family) + continue; + + vty_out(vty, " Adv Pfx: %pFX%s", &adb->u.s.prefix_ip, + HVTYNL); + rfapiPrintAdvertisedInfo(vty, rfd, SAFI_MPLS_VPN, + &adb->u.s.prefix_ip); + } + } + for (rc = skiplist_next(rfd->advertised.ip0_by_ether, NULL, + (void **)&adb, &cursor); + rc == 0; rc = skiplist_next(rfd->advertised.ip0_by_ether, NULL, + (void **)&adb, &cursor)) { + vty_out(vty, " Adv Pfx: %pFX%s", &adb->u.s.prefix_eth, HVTYNL); + + /* TBD update the following function to print ethernet info */ + /* Also need to pass/use rd */ + rfapiPrintAdvertisedInfo(vty, rfd, SAFI_MPLS_VPN, + &adb->u.s.prefix_ip); + } + vty_out(vty, "%s", HVTYNL); +} + +/* + * test scripts rely on first line for each nve starting in 1st column, + * leading whitespace for additional detail of that nve + */ +void rfapiPrintMatchingDescriptors(struct vty *vty, struct prefix *vn_prefix, + struct prefix *un_prefix) +{ + struct bgp *bgp; + struct rfapi *h; + struct listnode *ln; + struct rfapi_descriptor *rfd; + int printed = 0; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + if (!bgp) + return; + + h = bgp->rfapi; + assert(h); + + for (ln = listhead(&h->descriptors); ln; ln = listnextnode(ln)) { + rfd = listgetdata(ln); + + struct prefix pfx; + + if (vn_prefix) { + assert(!rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx)); + if (!prefix_match(vn_prefix, &pfx)) + continue; + } + + if (un_prefix) { + assert(!rfapiRaddr2Qprefix(&rfd->un_addr, &pfx)); + if (!prefix_match(un_prefix, &pfx)) + continue; + } + + if (!printed) { + /* print column header */ + vty_out(vty, "%s %s %s %s %s %s %s %s%s", "descriptor", + "un-addr", "vn-addr", "callback", "cookie", + "RD", "lifetime", "group", HVTYNL); + } + rfapiPrintDescriptor(vty, rfd); + printed = 1; + } +} + + +/* + * Parse an address and put into a struct prefix + */ +int rfapiCliGetPrefixAddr(struct vty *vty, const char *str, struct prefix *p) +{ + if (!str2prefix(str, p)) { + vty_out(vty, "Malformed address \"%s\"%s", str ? str : "null", + HVTYNL); + return CMD_WARNING; + } + switch (p->family) { + case AF_INET: + if (p->prefixlen != IPV4_MAX_BITLEN) { + vty_out(vty, "Not a host address: \"%s\"%s", str, + HVTYNL); + return CMD_WARNING; + } + break; + case AF_INET6: + if (p->prefixlen != IPV6_MAX_BITLEN) { + vty_out(vty, "Not a host address: \"%s\"%s", str, + HVTYNL); + return CMD_WARNING; + } + break; + default: + vty_out(vty, "Invalid address \"%s\"%s", str, HVTYNL); + return CMD_WARNING; + } + return 0; +} + +int rfapiCliGetRfapiIpAddr(struct vty *vty, const char *str, + struct rfapi_ip_addr *hai) +{ + struct prefix pfx; + int rc; + + rc = rfapiCliGetPrefixAddr(vty, str, &pfx); + if (rc) + return rc; + + hai->addr_family = pfx.family; + if (pfx.family == AF_INET) + hai->addr.v4 = pfx.u.prefix4; + else + hai->addr.v6 = pfx.u.prefix6; + + return 0; +} + +/* + * Note: this function does not flush vty output, so if it is called + * with a stream pointing to a vty, the user will have to type something + * before the callback output shows up + */ +void rfapiPrintNhl(void *stream, struct rfapi_next_hop_entry *next_hops) +{ + struct rfapi_next_hop_entry *nh; + int count; + + int (*fp)(void *, const char *, ...); + struct vty *vty; + void *out; + const char *vty_newline; + +#define REMAIN (BUFSIZ - (p-line)) +#define INCP {p += (r > REMAIN)? REMAIN: r;} + + if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) + return; + + for (nh = next_hops, count = 1; nh; nh = nh->next, ++count) { + + char line[BUFSIZ]; + char *p = line; + int r; + + r = snprintf(p, REMAIN, "%3d pfx=", count); + INCP; + + if (rfapiRfapiIpPrefix2Str(&nh->prefix, p, REMAIN)) { + /* it fit, so count length */ + r = strlen(p); + } else { + /* didn't fit */ + goto truncate; + } + INCP; + + r = snprintf(p, REMAIN, ", un="); + INCP; + + if (rfapiRfapiIpAddr2Str(&nh->un_address, p, REMAIN)) { + /* it fit, so count length */ + r = strlen(p); + } else { + /* didn't fit */ + goto truncate; + } + INCP; + + r = snprintf(p, REMAIN, ", vn="); + INCP; + + if (rfapiRfapiIpAddr2Str(&nh->vn_address, p, REMAIN)) { + /* it fit, so count length */ + r = strlen(p); + } else { + /* didn't fit */ + goto truncate; + } + INCP; + + truncate: + line[BUFSIZ - 1] = 0; + fp(out, "%s%s", line, HVTYNL); + + /* + * options + */ + if (nh->vn_options) { + struct rfapi_vn_option *vo; + char offset[] = " "; + + for (vo = nh->vn_options; vo; vo = vo->next) { + char pbuf[100]; + + switch (vo->type) { + case RFAPI_VN_OPTION_TYPE_L2ADDR: + rfapiEthAddr2Str(&vo->v.l2addr.macaddr, + pbuf, sizeof(pbuf)); + fp(out, + "%sL2 %s LBL=0x%06x NETID=0x%06x NVEID=%d%s", + offset, pbuf, + (vo->v.l2addr.label & 0x00ffffff), + (vo->v.l2addr.logical_net_id + & 0x00ffffff), + vo->v.l2addr.local_nve_id, HVTYNL); + break; + + case RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP: + fp(out, "%sLNH %pFX cost=%d%s", offset, + &vo->v.local_nexthop.addr, + vo->v.local_nexthop.cost, HVTYNL); + break; + + case RFAPI_VN_OPTION_TYPE_INTERNAL_RD: + fp(out, + "%svn option type %d (unknown)%s", + offset, vo->type, HVTYNL); + break; + } + } + } + if (nh->un_options) { + struct rfapi_un_option *uo; + char offset[] = " "; + + for (uo = nh->un_options; uo; uo = uo->next) { + switch (uo->type) { + case RFAPI_UN_OPTION_TYPE_TUNNELTYPE: + rfapi_print_tunneltype_option( + stream, 8, &uo->v.tunnel); + break; + case RFAPI_UN_OPTION_TYPE_PROVISIONAL: + fp(out, "%sUN Option type %d%s", offset, + uo->type, vty_newline); + break; + } + } + } + } +} + +/*********************************************************************** + * STATIC ROUTES + ***********************************************************************/ + +/* + * Add another nexthop to the NHL + */ +static void rfapiAddDeleteLocalRfpPrefix(struct rfapi_ip_addr *un_addr, + struct rfapi_ip_addr *vn_addr, + struct rfapi_ip_prefix *rprefix, + int is_add, + uint32_t lifetime, /* add only */ + struct rfapi_vn_option *vn_options, + struct rfapi_next_hop_entry **head, + struct rfapi_next_hop_entry **tail) +{ + struct rfapi_next_hop_entry *new; + + /* + * construct NHL + */ + + new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry)); + new->prefix = *rprefix; + new->un_address = *un_addr; + new->vn_address = *vn_addr; + + new->vn_options = vn_options; + if (is_add) { + new->lifetime = lifetime; + } else { + new->lifetime = RFAPI_REMOVE_RESPONSE_LIFETIME; + } + + if (*tail) + (*tail)->next = new; + *tail = new; + if (!*head) { + *head = new; + } +} + + +static int +register_add(struct vty *vty, struct cmd_token *carg_prefix, + struct cmd_token *carg_vn, struct cmd_token *carg_un, + struct cmd_token *carg_cost, /* optional */ + struct cmd_token *carg_lifetime, /* optional */ + struct cmd_token *carg_macaddr, /* optional */ + struct cmd_token + *carg_vni, /* mac present=>mandatory Virtual Network ID */ + int argc, struct cmd_token **argv) +{ + const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL; + const char *arg_vn = carg_vn ? carg_vn->arg : NULL; + const char *arg_un = carg_un ? carg_un->arg : NULL; + const char *arg_cost = carg_cost ? carg_cost->arg : NULL; + const char *arg_lifetime = carg_lifetime ? carg_lifetime->arg : NULL; + const char *arg_macaddr = carg_macaddr ? carg_macaddr->arg : NULL; + const char *arg_vni = carg_vni ? carg_vni->arg : NULL; + struct rfapi_ip_addr vn_address; + struct rfapi_ip_addr un_address; + struct prefix pfx; + struct rfapi_ip_prefix rpfx; + uint32_t cost; + uint32_t lnh_cost; + uint32_t lifetime; + rfapi_handle rfd; + struct rfapi_vn_option optary[10]; /* XXX must be big enough */ + struct rfapi_vn_option *opt = NULL; + int opt_next = 0; + + int rc = CMD_WARNING_CONFIG_FAILED; + char *endptr; + struct bgp *bgp; + struct rfapi *h; + struct rfapi_cfg *rfapi_cfg; + + const char *arg_lnh = NULL; + const char *arg_lnh_cost = NULL; + + bgp = bgp_get_default(); /* assume 1 instance for now */ + if (!bgp) { + if (vty) + vty_out(vty, "BGP not configured\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + h = bgp->rfapi; + rfapi_cfg = bgp->rfapi_cfg; + if (!h || !rfapi_cfg) { + if (vty) + vty_out(vty, "RFAPI not configured\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + for (; argc; --argc, ++argv) { + if (strmatch(argv[0]->text, "local-next-hop")) { + if (arg_lnh) { + vty_out(vty, + "local-next-hop specified more than once\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc <= 1) { + vty_out(vty, + "Missing parameter for local-next-hop\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ++argv; + --argc; + arg_lnh = argv[0]->arg; + } + if (strmatch(argv[0]->text, "local-cost")) { + if (arg_lnh_cost) { + vty_out(vty, + "local-cost specified more than once\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc <= 1) { + vty_out(vty, + "Missing parameter for local-cost\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ++argv; + --argc; + arg_lnh_cost = argv[0]->arg; + } + } + + if ((rc = rfapiCliGetRfapiIpAddr(vty, arg_vn, &vn_address))) + goto fail; + if ((rc = rfapiCliGetRfapiIpAddr(vty, arg_un, &un_address))) + goto fail; + + /* arg_prefix is optional if mac address is given */ + if (arg_macaddr && !arg_prefix) { + /* + * fake up a 0/32 or 0/128 prefix + */ + switch (vn_address.addr_family) { + case AF_INET: + arg_prefix = "0.0.0.0/32"; + break; + case AF_INET6: + arg_prefix = "0::0/128"; + break; + default: + vty_out(vty, + "Internal error, unknown VN address family\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (!str2prefix(arg_prefix, &pfx)) { + vty_out(vty, "Malformed prefix \"%s\"\n", arg_prefix); + goto fail; + } + if (pfx.family != AF_INET && pfx.family != AF_INET6) { + vty_out(vty, "prefix \"%s\" has invalid address family\n", + arg_prefix); + goto fail; + } + + + memset(optary, 0, sizeof(optary)); + + if (arg_cost) { + endptr = NULL; + cost = strtoul(arg_cost, &endptr, 10); + if (*endptr != '\0' || cost > 255) { + vty_out(vty, "%% Invalid %s value\n", "cost"); + goto fail; + } + } else { + cost = 255; + } + + if (arg_lifetime) { + if (!strcmp(arg_lifetime, "infinite")) { + lifetime = RFAPI_INFINITE_LIFETIME; + } else { + endptr = NULL; + lifetime = strtoul(arg_lifetime, &endptr, 10); + if (*endptr != '\0') { + vty_out(vty, "%% Invalid %s value\n", + "lifetime"); + goto fail; + } + } + } else { + lifetime = RFAPI_INFINITE_LIFETIME; /* default infinite */ + } + + if (arg_lnh_cost) { + if (!arg_lnh) { + vty_out(vty, + "%% %s may only be specified with local-next-hop\n", + "local-cost"); + goto fail; + } + endptr = NULL; + lnh_cost = strtoul(arg_lnh_cost, &endptr, 10); + if (*endptr != '\0' || lnh_cost > 255) { + vty_out(vty, "%% Invalid %s value\n", "local-cost"); + goto fail; + } + } else { + lnh_cost = 255; + } + + if (arg_lnh) { + if (!arg_prefix) { + vty_out(vty, + "%% %s may only be specified with prefix\n", + "local-next-hop"); + goto fail; + } + if ((rc = rfapiCliGetPrefixAddr( + vty, arg_lnh, + &optary[opt_next].v.local_nexthop.addr))) { + + goto fail; + } + + optary[opt_next].v.local_nexthop.cost = lnh_cost; + optary[opt_next].type = RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP; + + if (opt_next) { + optary[opt_next - 1].next = optary + opt_next; + } else { + opt = optary; + } + ++opt_next; + } + + if (arg_vni && !arg_macaddr) { + vty_out(vty, "%% %s may only be specified with mac address\n", + "virtual-network-identifier"); + goto fail; + } + + if (arg_macaddr) { + if (!arg_vni) { + vty_out(vty, + "Missing \"vni\" parameter (mandatory with mac)\n"); + return CMD_WARNING_CONFIG_FAILED; + } + optary[opt_next].v.l2addr.logical_net_id = + strtoul(arg_vni, NULL, 10); + + if ((rc = rfapiStr2EthAddr( + arg_macaddr, + &optary[opt_next].v.l2addr.macaddr))) { + vty_out(vty, "Invalid %s value\n", "mac address"); + goto fail; + } + /* TBD label, NVE ID */ + + optary[opt_next].type = RFAPI_VN_OPTION_TYPE_L2ADDR; + + if (opt_next) { + optary[opt_next - 1].next = optary + opt_next; + } else { + opt = optary; + } + ++opt_next; + } + + vnc_zlog_debug_verbose( + "%s: vn=%s, un=%s, prefix=%s, cost=%s, lifetime=%s, lnh=%s", + __func__, arg_vn, arg_un, arg_prefix, + (arg_cost ? arg_cost : "NULL"), + (arg_lifetime ? arg_lifetime : "NULL"), + (arg_lnh ? arg_lnh : "NULL")); + + rfapiQprefix2Rprefix(&pfx, &rpfx); + + rpfx.cost = cost & 255; + + /* look up rf descriptor, call open if it doesn't exist */ + rc = rfapi_find_rfd(bgp, &vn_address, &un_address, + (struct rfapi_descriptor **)&rfd); + if (rc) { + if (ENOENT == rc) { + struct rfapi_un_option uo; + + /* + * flag descriptor as provisionally opened for static + * route + * registration so that we can fix up the other + * parameters + * when the real open comes along + */ + memset(&uo, 0, sizeof(uo)); + uo.type = RFAPI_UN_OPTION_TYPE_PROVISIONAL; + + rc = rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp), + &vn_address, &un_address, + &uo, /* flags */ + NULL, NULL, /* no userdata */ + &rfd); + if (rc) { + vty_out(vty, + "Can't open session for this NVE: %s\n", + rfapi_error_str(rc)); + rc = CMD_WARNING_CONFIG_FAILED; + goto fail; + } + } else { + vty_out(vty, "Can't find session for this NVE: %s\n", + rfapi_error_str(rc)); + goto fail; + } + } + + rc = rfapi_register(rfd, &rpfx, lifetime, NULL, opt, + RFAPI_REGISTER_ADD); + if (!rc) { + struct rfapi_next_hop_entry *head = NULL; + struct rfapi_next_hop_entry *tail = NULL; + struct rfapi_vn_option *vn_opt_new; + + vnc_zlog_debug_verbose( + "%s: rfapi_register succeeded, returning 0", __func__); + + if (h->rfp_methods.local_cb) { + struct rfapi_descriptor *r = + (struct rfapi_descriptor *)rfd; + vn_opt_new = rfapi_vn_options_dup(opt); + + rfapiAddDeleteLocalRfpPrefix(&r->un_addr, &r->vn_addr, + &rpfx, 1, lifetime, + vn_opt_new, &head, &tail); + if (head) { + h->flags |= RFAPI_INCALLBACK; + (*h->rfp_methods.local_cb)(head, r->cookie); + h->flags &= ~RFAPI_INCALLBACK; + } + head = tail = NULL; + } + return 0; + } + + vnc_zlog_debug_verbose("%s: rfapi_register failed", __func__); + vty_out(vty, "\n"); + vty_out(vty, "Registration failed.\n"); + vty_out(vty, + "Confirm that either the VN or UN address matches a configured NVE group.\n"); + return CMD_WARNING_CONFIG_FAILED; + +fail: + vnc_zlog_debug_verbose("%s: fail, rc=%d", __func__, rc); + return rc; +} + +/************************************************************************ + * Add prefix With LNH_OPTIONS... + ************************************************************************/ +DEFUN (add_vnc_prefix_cost_life_lnh, + add_vnc_prefix_cost_life_lnh_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) lifetime (1-4294967295) LNH_OPTIONS...", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n" + "[local-next-hop (A.B.C.D|X:X::X:X)] [local-cost <0-255>]\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[9], argv[11], + /* mac vni */ + NULL, NULL, argc - 12, argv + 12); +} + +DEFUN (add_vnc_prefix_life_cost_lnh, + add_vnc_prefix_life_cost_lnh_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295) cost (0-255) LNH_OPTIONS...", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "[local-next-hop (A.B.C.D|X:X::X:X)] [local-cost <0-255>]\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[11], argv[9], + /* mac vni */ + NULL, NULL, argc - 12, argv + 12); +} + +DEFUN (add_vnc_prefix_cost_lnh, + add_vnc_prefix_cost_lnh_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) LNH_OPTIONS...", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "[local-next-hop (A.B.C.D|X:X::X:X)] [local-cost <0-255>]\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[9], NULL, + /* mac vni */ + NULL, NULL, argc - 10, argv + 10); +} + +DEFUN (add_vnc_prefix_life_lnh, + add_vnc_prefix_life_lnh_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295) LNH_OPTIONS...", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n" + "[local-next-hop (A.B.C.D|X:X::X:X)] [local-cost <0-255>]\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], NULL, argv[9], + /* mac vni */ + NULL, NULL, argc - 10, argv + 10); +} + +DEFUN (add_vnc_prefix_lnh, + add_vnc_prefix_lnh_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> LNH_OPTIONS...", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "[local-next-hop (A.B.C.D|X:X::X:X)] [local-cost <0-255>]\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], NULL, NULL, + /* mac vni */ + NULL, NULL, argc - 8, argv + 8); +} + +/************************************************************************ + * Add prefix Without LNH_OPTIONS... + ************************************************************************/ +DEFUN (add_vnc_prefix_cost_life, + add_vnc_prefix_cost_life_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[9], argv[11], + /* mac vni */ + NULL, NULL, 0, NULL); +} + +DEFUN (add_vnc_prefix_life_cost, + add_vnc_prefix_life_cost_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295) cost (0-255)", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[11], argv[9], + /* mac vni */ + NULL, NULL, 0, NULL); +} + +DEFUN (add_vnc_prefix_cost, + add_vnc_prefix_cost_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255)", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], argv[9], NULL, + /* mac vni */ + NULL, NULL, 0, NULL); +} + +DEFUN (add_vnc_prefix_life, + add_vnc_prefix_life_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], NULL, argv[9], + /* mac vni */ + NULL, NULL, 0, NULL); +} + +DEFUN (add_vnc_prefix, + add_vnc_prefix_cmd, + "add vnc prefix <A.B.C.D/M|X:X::X:X/M> vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>", + "Add registration\n" + "VNC Information\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[3], argv[5], argv[7], NULL, NULL, + /* mac vni */ + NULL, NULL, 0, NULL); +} + +/************************************************************************ + * Mac address registrations + ************************************************************************/ +DEFUN (add_vnc_mac_vni_prefix_cost_life, + add_vnc_mac_vni_prefix_cost_life_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255) lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[11], argv[7], argv[9], argv[13], argv[15], + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + + +DEFUN (add_vnc_mac_vni_prefix_life, + add_vnc_mac_vni_prefix_life_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[11], argv[7], argv[9], NULL, argv[13], + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + +DEFUN (add_vnc_mac_vni_prefix_cost, + add_vnc_mac_vni_prefix_cost_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> cost (0-255)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Administrative cost [default: 255]\n" "Administrative cost\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[11], argv[7], argv[9], argv[13], NULL, + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + +DEFUN (add_vnc_mac_vni_prefix, + add_vnc_mac_vni_prefix_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M>", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" "IPv6 prefix\n") +{ + /* pfx vn un cost life */ + return register_add(vty, argv[11], argv[7], argv[9], NULL, NULL, + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + +DEFUN (add_vnc_mac_vni_cost_life, + add_vnc_mac_vni_cost_life_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255) lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" + "Administrative cost\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, NULL, argv[7], argv[9], argv[11], argv[13], + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + + +DEFUN (add_vnc_mac_vni_cost, + add_vnc_mac_vni_cost_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> cost (0-255)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Administrative cost [default: 255]\n" "Administrative cost\n") +{ + /* pfx vn un cost life */ + return register_add(vty, NULL, argv[7], argv[9], argv[11], NULL, + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + + +DEFUN (add_vnc_mac_vni_life, + add_vnc_mac_vni_life_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lifetime (1-4294967295)", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Registration lifetime [default: infinite]\n" + "Lifetime value in seconds\n") +{ + /* pfx vn un cost life */ + return register_add(vty, NULL, argv[7], argv[9], NULL, argv[11], + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + + +DEFUN (add_vnc_mac_vni, + add_vnc_mac_vni_cmd, + "add vnc mac X:X:X:X:X:X virtual-network-identifier (1-4294967295) vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>", + "Add registration\n" + "VNC Information\n" + "Add/modify mac address information\n" + "MAC address\n" + "Virtual Network Identifier follows\n" + "Virtual Network Identifier\n" + "VN address of NVE\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "UN IPv4 interface address\n" "UN IPv6 interface address\n") +{ + /* pfx vn un cost life */ + return register_add(vty, NULL, argv[7], argv[9], NULL, NULL, + /* mac vni */ + argv[3], argv[5], 0, NULL); +} + +/************************************************************************ + * Delete prefix + ************************************************************************/ + +struct rfapi_local_reg_delete_arg { + /* + * match parameters + */ + struct bgp *bgp; + struct rfapi_ip_addr un_address; /* AF==0: wildcard */ + struct rfapi_ip_addr vn_address; /* AF==0: wildcard */ + struct prefix prefix; /* AF==0: wildcard */ + struct prefix_rd rd; /* plen!=64: wildcard */ + struct rfapi_nve_group_cfg *rfg; /* NULL: wildcard */ + + struct rfapi_l2address_option_match l2o; + + /* + * result parameters + */ + struct vty *vty; + uint32_t reg_count; + uint32_t pfx_count; + uint32_t query_count; + + uint32_t failed_pfx_count; + + uint32_t nve_count; + struct skiplist *nves; + + uint32_t remote_active_nve_count; + uint32_t remote_active_pfx_count; + uint32_t remote_holddown_nve_count; + uint32_t remote_holddown_pfx_count; +}; + +struct nve_addr { + struct rfapi_ip_addr vn; + struct rfapi_ip_addr un; + struct rfapi_descriptor *rfd; + struct rfapi_local_reg_delete_arg *cda; +}; + +static void nve_addr_free(void *hap) +{ + ((struct nve_addr *)hap)->cda->nve_count += 1; + XFREE(MTYPE_RFAPI_NVE_ADDR, hap); +} + +static int nve_addr_cmp(const void *k1, const void *k2) +{ + const struct nve_addr *a = (struct nve_addr *)k1; + const struct nve_addr *b = (struct nve_addr *)k2; + int ret = 0; + + if (!a || !b) { + return (a - b); + } + if (a->un.addr_family != b->un.addr_family) { + return (a->un.addr_family - b->un.addr_family); + } + if (a->vn.addr_family != b->vn.addr_family) { + return (a->vn.addr_family - b->vn.addr_family); + } + if (a->un.addr_family == AF_INET) { + ret = IPV4_ADDR_CMP(&a->un.addr.v4, &b->un.addr.v4); + if (ret != 0) { + return ret; + } + } else if (a->un.addr_family == AF_INET6) { + ret = IPV6_ADDR_CMP(&a->un.addr.v6, &b->un.addr.v6); + if (ret != 0) { + return ret; + } + } else { + assert(0); + } + if (a->vn.addr_family == AF_INET) { + ret = IPV4_ADDR_CMP(&a->vn.addr.v4, &b->vn.addr.v4); + if (ret != 0) + return ret; + } else if (a->vn.addr_family == AF_INET6) { + ret = IPV6_ADDR_CMP(&a->vn.addr.v6, &b->vn.addr.v6); + if (ret == 0) { + return ret; + } + } else { + assert(0); + } + return 0; +} + +static int parse_deleter_args(struct vty *vty, struct bgp *bgp, + const char *arg_prefix, const char *arg_vn, + const char *arg_un, const char *arg_l2addr, + const char *arg_vni, const char *arg_rd, + struct rfapi_nve_group_cfg *arg_rfg, + struct rfapi_local_reg_delete_arg *rcdarg) +{ + int rc = CMD_WARNING; + + memset(rcdarg, 0, sizeof(struct rfapi_local_reg_delete_arg)); + + rcdarg->vty = vty; + if (bgp == NULL) + bgp = bgp_get_default(); + rcdarg->bgp = bgp; + rcdarg->rfg = arg_rfg; /* may be NULL */ + + if (arg_vn && strcmp(arg_vn, "*")) { + if ((rc = rfapiCliGetRfapiIpAddr(vty, arg_vn, + &rcdarg->vn_address))) + return rc; + } + if (arg_un && strcmp(arg_un, "*")) { + if ((rc = rfapiCliGetRfapiIpAddr(vty, arg_un, + &rcdarg->un_address))) + return rc; + } + if (arg_prefix && strcmp(arg_prefix, "*")) { + + if (!str2prefix(arg_prefix, &rcdarg->prefix)) { + vty_out(vty, "Malformed prefix \"%s\"\n", arg_prefix); + return rc; + } + } + + if (arg_l2addr) { + if (!arg_vni) { + vty_out(vty, "Missing VNI\n"); + return rc; + } + if (strcmp(arg_l2addr, "*")) { + if ((rc = rfapiStr2EthAddr(arg_l2addr, + &rcdarg->l2o.o.macaddr))) { + vty_out(vty, "Malformed L2 Address \"%s\"\n", + arg_l2addr); + return rc; + } + rcdarg->l2o.flags |= RFAPI_L2O_MACADDR; + } + if (strcmp(arg_vni, "*")) { + rcdarg->l2o.o.logical_net_id = + strtoul(arg_vni, NULL, 10); + rcdarg->l2o.flags |= RFAPI_L2O_LNI; + } + } + if (arg_rd) { + if (!str2prefix_rd(arg_rd, &rcdarg->rd)) { + vty_out(vty, "Malformed RD \"%s\"\n", arg_rd); + return rc; + } + } + + return CMD_SUCCESS; +} + +static int +parse_deleter_tokens(struct vty *vty, struct bgp *bgp, + struct cmd_token *carg_prefix, struct cmd_token *carg_vn, + struct cmd_token *carg_un, struct cmd_token *carg_l2addr, + struct cmd_token *carg_vni, struct cmd_token *carg_rd, + struct rfapi_nve_group_cfg *arg_rfg, + struct rfapi_local_reg_delete_arg *rcdarg) +{ + const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL; + const char *arg_vn = carg_vn ? carg_vn->arg : NULL; + const char *arg_un = carg_un ? carg_un->arg : NULL; + const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL; + const char *arg_vni = carg_vni ? carg_vni->arg : NULL; + const char *arg_rd = carg_rd ? carg_rd->arg : NULL; + return parse_deleter_args(vty, bgp, arg_prefix, arg_vn, arg_un, + arg_l2addr, arg_vni, arg_rd, arg_rfg, rcdarg); +} + +static void record_nve_in_cda_list(struct rfapi_local_reg_delete_arg *cda, + struct rfapi_ip_addr *un_address, + struct rfapi_ip_addr *vn_address, + struct rfapi_descriptor *rfd) +{ + struct nve_addr ha; + struct nve_addr *hap; + + memset(&ha, 0, sizeof(ha)); + ha.un = *un_address; + ha.vn = *vn_address; + ha.rfd = rfd; + + if (!cda->nves) + cda->nves = skiplist_new(0, nve_addr_cmp, nve_addr_free); + + if (skiplist_search(cda->nves, &ha, (void *)&hap)) { + hap = XCALLOC(MTYPE_RFAPI_NVE_ADDR, sizeof(struct nve_addr)); + assert(hap); + ha.cda = cda; + *hap = ha; + skiplist_insert(cda->nves, hap, hap); + } +} + +static void clear_vnc_responses(struct rfapi_local_reg_delete_arg *cda) +{ + struct rfapi *h; + struct rfapi_descriptor *rfd; + int query_count = 0; + struct listnode *node; + struct bgp *bgp_default = bgp_get_default(); + + if (cda->vn_address.addr_family && cda->un_address.addr_family) { + /* + * Single nve case + */ + if (rfapi_find_rfd(bgp_default, &cda->vn_address, + &cda->un_address, &rfd)) + return; + + rfapiRibClear(rfd); + rfapi_query_done_all(rfd, &query_count); + cda->query_count += query_count; + + /* + * Track unique nves seen + */ + record_nve_in_cda_list(cda, &rfd->un_addr, &rfd->vn_addr, rfd); + return; + } + + /* + * wildcard case + */ + + if (!bgp_default) + return; /* ENXIO */ + + h = bgp_default->rfapi; + + if (!h) + return; /* ENXIO */ + + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) { + /* + * match un, vn addresses of NVEs + */ + if (cda->un_address.addr_family + && rfapi_ip_addr_cmp(&cda->un_address, &rfd->un_addr)) { + continue; + } + if (cda->vn_address.addr_family + && rfapi_ip_addr_cmp(&cda->vn_address, &rfd->vn_addr)) { + continue; + } + + rfapiRibClear(rfd); + + rfapi_query_done_all(rfd, &query_count); + cda->query_count += query_count; + + /* + * Track unique nves seen + */ + record_nve_in_cda_list(cda, &rfd->un_addr, &rfd->vn_addr, rfd); + } +} + +/* + * TBD need to count deleted prefixes and nves? + * + * ENXIO BGP or VNC not configured + */ +static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda, + struct rfapi_descriptor *rfd) +{ + struct rfapi_ip_addr *pUn; /* NULL = wildcard */ + struct rfapi_ip_addr *pVn; /* NULL = wildcard */ + struct prefix *pPrefix; /* NULL = wildcard */ + struct prefix_rd *pPrd; /* NULL = wildcard */ + + struct rfapi_ip_prefix rprefix; + struct rfapi_next_hop_entry *head = NULL; + struct rfapi_next_hop_entry *tail = NULL; + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose("%s: entry", __func__); +#endif + + pUn = (cda->un_address.addr_family ? &cda->un_address : NULL); + pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL); + pPrefix = (cda->prefix.family ? &cda->prefix : NULL); + pPrd = (cda->rd.prefixlen == 64 ? &cda->rd : NULL); + + if (pPrefix) { + rfapiQprefix2Rprefix(pPrefix, &rprefix); + } + + do /* to preserve old code structure */ + { + struct rfapi *h = cda->bgp->rfapi; + ; + struct rfapi_adb *adb; + int rc; + int deleted_from_this_nve; + struct nve_addr ha; + struct nve_addr *hap; + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose("%s: rfd=%p", __func__, rfd); +#endif + + /* + * match un, vn addresses of NVEs + */ + if (pUn && (rfapi_ip_addr_cmp(pUn, &rfd->un_addr))) + break; + if (pVn && (rfapi_ip_addr_cmp(pVn, &rfd->vn_addr))) + break; + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose("%s: un, vn match", __func__); +#endif + + /* + * match prefix + */ + + deleted_from_this_nve = 0; + + { + struct skiplist *sl; + struct rfapi_ip_prefix rp; + void *cursor; + struct list *adb_delete_list; + + /* + * The advertisements are stored in a skiplist. + * Withdrawing + * the registration deletes the advertisement from the + * skiplist, which we can't do while iterating over that + * same skiplist using the current skiplist API. + * + * Strategy: iterate over the skiplist and build another + * list containing only the matching ADBs. Then delete + * _everything_ in that second list (which can be done + * using either skiplists or quagga linklists). + */ + adb_delete_list = list_new(); + + /* + * Advertised IP prefixes (not 0/32 or 0/128) + */ + sl = rfd->advertised.ipN_by_prefix; + + for (cursor = NULL, + rc = skiplist_next(sl, NULL, (void **)&adb, + &cursor); + !rc; rc = skiplist_next(sl, NULL, (void **)&adb, + &cursor)) { + + if (pPrefix) { + if (!prefix_same(pPrefix, + &adb->u.s.prefix_ip)) { +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: adb=%p, prefix doesn't match, skipping", + __func__, adb); +#endif + continue; + } + } + if (pPrd) { + if (memcmp(pPrd->val, adb->u.s.prd.val, + 8) + != 0) { +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: adb=%p, RD doesn't match, skipping", + __func__, adb); +#endif + continue; + } + } + if (CHECK_FLAG(cda->l2o.flags, + RFAPI_L2O_MACADDR)) { + if (memcmp(cda->l2o.o.macaddr.octet, + adb->u.s.prefix_eth.u + .prefix_eth.octet, + ETH_ALEN)) { +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: adb=%p, macaddr doesn't match, skipping", + __func__, adb); +#endif + continue; + } + } + + if (CHECK_FLAG(cda->l2o.flags, RFAPI_L2O_LNI)) { + if (cda->l2o.o.logical_net_id + != adb->l2o.logical_net_id) { +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: adb=%p, LNI doesn't match, skipping", + __func__, adb); +#endif + continue; + } + } + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: ipN adding adb %p to delete list", + __func__, adb); +#endif + + listnode_add(adb_delete_list, adb); + } + + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(adb_delete_list, node, adb)) { + int this_advertisement_prefix_count; + struct rfapi_vn_option optary[3]; + struct rfapi_vn_option *opt = NULL; + int cur_opt = 0; + + this_advertisement_prefix_count = 1; + + rfapiQprefix2Rprefix(&adb->u.s.prefix_ip, &rp); + + memset(optary, 0, sizeof(optary)); + + /* if mac addr present in advert, make l2o vn + * option */ + if (adb->u.s.prefix_eth.family == AF_ETHERNET) { + if (opt != NULL) + opt->next = &optary[cur_opt]; + opt = &optary[cur_opt++]; + opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR; + opt->v.l2addr.macaddr = + adb->u.s.prefix_eth.u + .prefix_eth; + ++this_advertisement_prefix_count; + } + /* + * use saved RD value instead of trying to + * invert + * complex RD computation in rfapi_register() + */ + if (opt != NULL) + opt->next = &optary[cur_opt]; + opt = &optary[cur_opt++]; + opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD; + opt->v.internal_rd = adb->u.s.prd; + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: ipN killing reg from adb %p ", + __func__, adb); +#endif + + rc = rfapi_register(rfd, &rp, 0, NULL, + (cur_opt ? optary : NULL), + RFAPI_REGISTER_KILL); + if (!rc) { + cda->pfx_count += + this_advertisement_prefix_count; + cda->reg_count += 1; + deleted_from_this_nve = 1; + } + if (h->rfp_methods.local_cb) { + rfapiAddDeleteLocalRfpPrefix( + &rfd->un_addr, &rfd->vn_addr, + &rp, 0, 0, NULL, &head, &tail); + } + } + list_delete_all_node(adb_delete_list); + + if (!(pPrefix && !RFAPI_0_PREFIX(pPrefix))) { + /* + * Caller didn't specify a prefix, or specified + * (0/32 or 0/128) + */ + + /* + * Advertised 0/32 and 0/128 (indexed by + * ethernet address) + */ + sl = rfd->advertised.ip0_by_ether; + + for (cursor = NULL, + rc = skiplist_next(sl, NULL, (void **)&adb, + &cursor); + !rc; + rc = skiplist_next(sl, NULL, (void **)&adb, + &cursor)) { + + if (CHECK_FLAG(cda->l2o.flags, + RFAPI_L2O_MACADDR)) { + if (memcmp(cda->l2o.o.macaddr + .octet, + adb->u.s.prefix_eth.u + .prefix_eth + .octet, + ETH_ALEN)) { + + continue; + } + } + if (CHECK_FLAG(cda->l2o.flags, + RFAPI_L2O_LNI)) { + if (cda->l2o.o.logical_net_id + != adb->l2o.logical_net_id) { + continue; + } + } +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: ip0 adding adb %p to delete list", + __func__, adb); +#endif + listnode_add(adb_delete_list, adb); + } + + + for (ALL_LIST_ELEMENTS_RO(adb_delete_list, node, + adb)) { + + struct rfapi_vn_option vn; + + rfapiQprefix2Rprefix( + &adb->u.s.prefix_ip, &rp); + + memset(&vn, 0, sizeof(vn)); + vn.type = RFAPI_VN_OPTION_TYPE_L2ADDR; + vn.v.l2addr = adb->l2o; + +#if DEBUG_L2_EXTRA + vnc_zlog_debug_verbose( + "%s: ip0 killing reg from adb %p ", + __func__, adb); +#endif + + rc = rfapi_register( + rfd, &rp, 0, NULL, &vn, + RFAPI_REGISTER_KILL); + if (!rc) { + cda->pfx_count += 1; + cda->reg_count += 1; + deleted_from_this_nve = 1; + } + if (h->rfp_methods.local_cb) { + struct rfapi_vn_option + *vn_opt_new; + + vn_opt_new = + rfapi_vn_options_dup( + &vn); + rfapiAddDeleteLocalRfpPrefix( + &rfd->un_addr, + &rfd->vn_addr, &rp, 0, + 0, vn_opt_new, &head, + &tail); + } + } + list_delete_all_node(adb_delete_list); + } + list_delete(&adb_delete_list); + } + + + if (head) { /* should not be set if (NULL == + rfapi_cfg->local_cb) */ + h->flags |= RFAPI_INCALLBACK; + (*h->rfp_methods.local_cb)(head, rfd->cookie); + h->flags &= ~RFAPI_INCALLBACK; + head = tail = NULL; + } + + if (deleted_from_this_nve) { + /* + * track unique NVEs seen + */ + memset(&ha, 0, sizeof(ha)); + ha.un = rfd->un_addr; + ha.vn = rfd->vn_addr; + + if (!cda->nves) + cda->nves = skiplist_new(0, nve_addr_cmp, + nve_addr_free); + if (skiplist_search(cda->nves, &ha, (void **)&hap)) { + hap = XCALLOC(MTYPE_RFAPI_NVE_ADDR, + sizeof(struct nve_addr)); + assert(hap); + ha.cda = cda; + *hap = ha; + skiplist_insert(cda->nves, hap, hap); + } + } + } while (0); /* to preserve old code structure */ + + return 0; +} + +static int rfapiDeleteLocalPrefixes(struct rfapi_local_reg_delete_arg *cda) +{ + int rc = 0; + + if (cda->rfg) { + if (cda->rfg->rfd) /* if not open, nothing to delete */ + rc = rfapiDeleteLocalPrefixesByRFD(cda, cda->rfg->rfd); + } else { + struct bgp *bgp = cda->bgp; + struct rfapi *h; + struct rfapi_cfg *rfapi_cfg; + + struct listnode *node; + struct rfapi_descriptor *rfd; + if (!bgp) + return ENXIO; + h = bgp->rfapi; + rfapi_cfg = bgp->rfapi_cfg; + if (!h || !rfapi_cfg) + return ENXIO; + vnc_zlog_debug_verbose("%s: starting descriptor loop", + __func__); + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) { + rc = rfapiDeleteLocalPrefixesByRFD(cda, rfd); + } + } + return rc; +} + +/* + * clear_vnc_prefix + * + * Deletes local and remote prefixes that match + */ +static void clear_vnc_prefix(struct rfapi_local_reg_delete_arg *cda) +{ + struct prefix pfx_un; + struct prefix pfx_vn; + + struct prefix *pUN = NULL; + struct prefix *pVN = NULL; + struct prefix *pPrefix = NULL; + + struct rfapi_import_table *it = NULL; + + /* + * Delete matching remote prefixes in holddown + */ + if (cda->vn_address.addr_family) { + if (!rfapiRaddr2Qprefix(&cda->vn_address, &pfx_vn)) + pVN = &pfx_vn; + } + if (cda->un_address.addr_family) { + if (!rfapiRaddr2Qprefix(&cda->un_address, &pfx_un)) + pUN = &pfx_un; + } + if (cda->prefix.family) { + pPrefix = &cda->prefix; + } + if (cda->rfg) { + it = cda->rfg->rfapi_import_table; + } + rfapiDeleteRemotePrefixes( + pUN, pVN, pPrefix, it, 0, 1, &cda->remote_active_pfx_count, + &cda->remote_active_nve_count, &cda->remote_holddown_pfx_count, + &cda->remote_holddown_nve_count); + + /* + * Now do local prefixes + */ + rfapiDeleteLocalPrefixes(cda); +} + +static void print_cleared_stats(struct rfapi_local_reg_delete_arg *cda) +{ + struct vty *vty = cda->vty; /* for benefit of VTYNL */ + + /* Our special element-deleting function counts nves */ + if (cda->nves) { + skiplist_free(cda->nves); + cda->nves = NULL; + } + if (cda->failed_pfx_count) + vty_out(vty, "Failed to delete %d prefixes\n", + cda->failed_pfx_count); + + /* left as "prefixes" even in single case for ease of machine parsing */ + vty_out(vty, + "[Local] Cleared %u registrations, %u prefixes, %u responses from %d NVEs\n", + cda->reg_count, cda->pfx_count, cda->query_count, + cda->nve_count); + + /* + * We don't currently allow deletion of active remote prefixes from + * the command line + */ + + vty_out(vty, "[Holddown] Cleared %u prefixes from %u NVEs\n", + cda->remote_holddown_pfx_count, cda->remote_holddown_nve_count); +} + +/* + * Caller has already deleted registrations and queries for this/these + * NVEs. Now we just have to close their descriptors. + */ +static void clear_vnc_nve_closer(struct rfapi_local_reg_delete_arg *cda) +{ + struct skiplist *sl = cda->nves; /* contains affected NVEs */ + struct nve_addr *pKey; + struct nve_addr *pValue; + void *cursor = NULL; + int rc; + + if (!sl) + return; + + for (rc = skiplist_next(sl, (void **)&pKey, (void **)&pValue, &cursor); + !rc; rc = skiplist_next(sl, (void **)&pKey, (void **)&pValue, + &cursor)) { + + if (pValue->rfd) { + pValue->rfd->flags |= + RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY; + rfapi_close(pValue->rfd); + } + } +} + +DEFUN (clear_vnc_nve_all, + clear_vnc_nve_all_cmd, + "clear vnc nve *", + "clear\n" + "VNC Information\n" + "Clear per NVE information\n" + "For all NVEs\n") +{ + + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_args(vty, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &cda))) + return rc; + + cda.vty = vty; + + clear_vnc_responses(&cda); + clear_vnc_prefix(&cda); + clear_vnc_nve_closer(&cda); + + print_cleared_stats(&cda); + + return 0; +} + +DEFUN (clear_vnc_nve_vn_un, + clear_vnc_nve_vn_un_cmd, + "clear vnc nve vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "VN address of NVE\n" + "For all NVEs\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "For all UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[4], argv[6], NULL, + NULL, NULL, NULL, &cda))) + return rc; + + cda.vty = vty; + + clear_vnc_responses(&cda); + clear_vnc_prefix(&cda); + clear_vnc_nve_closer(&cda); + + print_cleared_stats(&cda); + + return 0; +} + +DEFUN (clear_vnc_nve_un_vn, + clear_vnc_nve_un_vn_cmd, + "clear vnc nve un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "UN address of NVE\n" + "For all un NVEs\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "VN address of NVE\n" + "For all vn NVEs\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[6], argv[4], NULL, + NULL, NULL, NULL, &cda))) + return rc; + + cda.vty = vty; + + clear_vnc_responses(&cda); + clear_vnc_prefix(&cda); + clear_vnc_nve_closer(&cda); + + print_cleared_stats(&cda); + + return 0; +} + +DEFUN (clear_vnc_nve_vn, + clear_vnc_nve_vn_cmd, + "clear vnc nve vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "VN address of NVE\n" + "All addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[4], NULL, NULL, + NULL, NULL, NULL, &cda))) + return rc; + + cda.vty = vty; + + clear_vnc_responses(&cda); + clear_vnc_prefix(&cda); + clear_vnc_nve_closer(&cda); + + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_nve_un, + clear_vnc_nve_un_cmd, + "clear vnc nve un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "UN address of NVE\n" + "All un nves\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, NULL, NULL, argv[4], NULL, + NULL, NULL, NULL, &cda))) + return rc; + + cda.vty = vty; + + clear_vnc_responses(&cda); + clear_vnc_prefix(&cda); + clear_vnc_nve_closer(&cda); + + print_cleared_stats(&cda); + return 0; +} + +/*------------------------------------------------- + * Clear VNC Prefix + *-------------------------------------------------*/ + +/* + * This function is defined in this file (rather than in rfp_registration.c) + * because here we have access to all the task handles. + */ +DEFUN (clear_vnc_prefix_vn_un, + clear_vnc_prefix_vn_un_cmd, + "clear vnc prefix <*|A.B.C.D/M|X:X::X:X/M> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, argv[3], argv[5], argv[7], + NULL, NULL, NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_prefix_un_vn, + clear_vnc_prefix_un_vn_cmd, + "clear vnc prefix <*|A.B.C.D/M|X:X::X:X/M> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, argv[3], argv[7], argv[5], + NULL, NULL, NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_prefix_un, + clear_vnc_prefix_un_cmd, + "clear vnc prefix <*|A.B.C.D/M|X:X::X:X/M> un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, argv[3], NULL, argv[5], NULL, + NULL, NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_prefix_vn, + clear_vnc_prefix_vn_cmd, + "clear vnc prefix <*|A.B.C.D/M|X:X::X:X/M> vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "UN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, argv[3], argv[5], NULL, NULL, + NULL, NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_prefix_all, + clear_vnc_prefix_all_cmd, + "clear vnc prefix <*|A.B.C.D/M|X:X::X:X/M> *", + "clear\n" + "VNC Information\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "From any NVE\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + if ((rc = parse_deleter_tokens(vty, NULL, argv[3], NULL, NULL, NULL, + NULL, NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +/*------------------------------------------------- + * Clear VNC MAC + *-------------------------------------------------*/ + +/* + * This function is defined in this file (rather than in rfp_registration.c) + * because here we have access to all the task handles. + */ +DEFUN (clear_vnc_mac_vn_un, + clear_vnc_mac_vn_un_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[7], argv[9], + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_un_vn, + clear_vnc_mac_un_vn_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[9], argv[7], + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_un, + clear_vnc_mac_un_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, NULL, NULL, argv[7], argv[3], + argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_vn, + clear_vnc_mac_vn_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, NULL, argv[7], NULL, argv[3], + argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_all, + clear_vnc_mac_all_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> *", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "From any NVE\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, NULL, NULL, NULL, argv[3], + argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +/*------------------------------------------------- + * Clear VNC MAC PREFIX + *-------------------------------------------------*/ + +DEFUN (clear_vnc_mac_vn_un_prefix, + clear_vnc_mac_vn_un_prefix_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, argv[11], argv[7], argv[9], + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_un_vn_prefix, + clear_vnc_mac_un_vn_prefix_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M> prefix <*|A.B.C.D/M|X:X::X:X/M>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "VN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 prefix\n" + "IPv6 prefix\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, argv[11], argv[9], argv[7], + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_un_prefix, + clear_vnc_mac_un_prefix_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> un <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All UN addresses\n" + "UN IPv4 interface address\n" + "UN IPv6 interface address\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 Prefix\n" + "IPv6 Prefix\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, argv[9], NULL, argv[7], + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_vn_prefix, + clear_vnc_mac_vn_prefix_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> vn <*|A.B.C.D|X:X::X:X> prefix <*|A.B.C.D/M|X:X::X:X/M>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n" + "Clear prefix registration information\n" + "All prefixes\n" + "IPv4 Prefix\n" + "IPv6 Prefix\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, argv[9], argv[7], NULL, + argv[3], argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +DEFUN (clear_vnc_mac_all_prefix, + clear_vnc_mac_all_prefix_cmd, + "clear vnc mac <*|X:X:X:X:X:X> virtual-network-identifier <*|(1-4294967295)> prefix <*|A.B.C.D/M|X:X::X:X/M>", + "clear\n" + "VNC Information\n" + "Clear mac registration information\n" + "All macs\n" + "MAC address\n" + "VNI keyword\n" + "Any virtual network identifier\n" + "Virtual network identifier\n" + "UN address of NVE\n" + "All VN addresses\n" + "VN IPv4 interface address\n" + "VN IPv6 interface address\n") +{ + struct rfapi_local_reg_delete_arg cda; + int rc; + + /* pfx vn un L2 VNI */ + if ((rc = parse_deleter_tokens(vty, NULL, argv[7], NULL, NULL, argv[3], + argv[5], NULL, NULL, &cda))) + return rc; + cda.vty = vty; + clear_vnc_prefix(&cda); + print_cleared_stats(&cda); + return 0; +} + +/************************************************************************ + * Show commands + ************************************************************************/ + + +/* copied from rfp_vty.c */ +static int check_and_display_is_vnc_running(struct vty *vty) +{ + if (bgp_rfapi_is_vnc_configured(NULL) == 0) + return 1; /* is running */ + + if (vty) { + vty_out(vty, "VNC is not configured.\n"); + } + return 0; /* not running */ +} + +static int rfapi_vty_show_nve_summary(struct vty *vty, + show_nve_summary_t show_type) +{ + struct bgp *bgp_default = bgp_get_default(); + struct rfapi *h; + int is_vnc_running = (bgp_rfapi_is_vnc_configured(bgp_default) == 0); + + int active_local_routes; + int active_remote_routes; + int holddown_remote_routes; + int imported_remote_routes; + + if (!bgp_default) + goto notcfg; + + h = bgp_default->rfapi; + + if (!h) + goto notcfg; + + /* don't show local info if not running RFP */ + if (is_vnc_running || show_type == SHOW_NVE_SUMMARY_REGISTERED) { + + switch (show_type) { + + case SHOW_NVE_SUMMARY_ACTIVE_NVES: + vty_out(vty, "%-24s ", "NVEs:"); + vty_out(vty, "%-8s %-8u ", + "Active:", h->descriptors.count); + vty_out(vty, "%-8s %-8u ", + "Maximum:", h->stat.max_descriptors); + vty_out(vty, "%-8s %-8u", + "Unknown:", h->stat.count_unknown_nves); + break; + + case SHOW_NVE_SUMMARY_REGISTERED: + /* + * NB: With the introduction of L2 route support, we no + * longer have a one-to-one correspondence between + * locally-originated route advertisements and routes in + * the import tables that have local origin. This + * discrepancy arises because a single advertisement + * may contain both an IP prefix and a MAC address. + * Such an advertisement results in two import table + * entries: one indexed by IP prefix, the other indexed + * by MAC address. + * + * TBD: update computation and display of registration + * statistics to reflect the underlying semantics. + */ + if (is_vnc_running) { + vty_out(vty, "%-24s ", "Registrations:"); + vty_out(vty, "%-8s %-8u ", "Active:", + rfapiApCountAll(bgp_default)); + vty_out(vty, "%-8s %-8u ", "Failed:", + h->stat.count_registrations_failed); + vty_out(vty, "%-8s %-8u", + "Total:", h->stat.count_registrations); + vty_out(vty, "\n"); + } + vty_out(vty, "%-24s ", "Prefixes registered:"); + vty_out(vty, "\n"); + + rfapiCountAllItRoutes(&active_local_routes, + &active_remote_routes, + &holddown_remote_routes, + &imported_remote_routes); + + /* local */ + if (is_vnc_running) { + vty_out(vty, " %-20s ", "Locally:"); + vty_out(vty, "%-8s %-8u ", + "Active:", active_local_routes); + vty_out(vty, "\n"); + } + + + vty_out(vty, " %-20s ", "Remotely:"); + vty_out(vty, "%-8s %-8u", + "Active:", active_remote_routes); + vty_out(vty, "\n"); + vty_out(vty, " %-20s ", "In Holddown:"); + vty_out(vty, "%-8s %-8u", + "Active:", holddown_remote_routes); + vty_out(vty, "\n"); + vty_out(vty, " %-20s ", "Imported:"); + vty_out(vty, "%-8s %-8u", + "Active:", imported_remote_routes); + break; + + case SHOW_NVE_SUMMARY_QUERIES: + vty_out(vty, "%-24s ", "Queries:"); + vty_out(vty, "%-8s %-8u ", + "Active:", rfapi_monitor_count(NULL)); + vty_out(vty, "%-8s %-8u ", + "Failed:", h->stat.count_queries_failed); + vty_out(vty, "%-8s %-8u", + "Total:", h->stat.count_queries); + break; + + case SHOW_NVE_SUMMARY_RESPONSES: + rfapiRibShowResponsesSummary(vty); + + case SHOW_NVE_SUMMARY_UNKNOWN_NVES: + case SHOW_NVE_SUMMARY_MAX: + break; + } + vty_out(vty, "\n"); + } + return 0; + +notcfg: + vty_out(vty, "VNC is not configured.\n"); + return CMD_WARNING; +} + +static int rfapi_show_nves(struct vty *vty, struct prefix *vn_prefix, + struct prefix *un_prefix) +{ + // struct hash *rfds; + // struct rfp_rfapi_descriptor_param param; + + struct bgp *bgp_default = bgp_get_default(); + struct rfapi *h; + struct listnode *node; + struct rfapi_descriptor *rfd; + + int total = 0; + int printed = 0; + int rc; + + if (!bgp_default) + goto notcfg; + + h = bgp_default->rfapi; + + if (!h) + goto notcfg; + + rc = rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_ACTIVE_NVES); + if (rc) + return rc; + + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) { + struct prefix pfx; + char vn_addr_buf[INET6_ADDRSTRLEN] = { + 0, + }; + char un_addr_buf[INET6_ADDRSTRLEN] = { + 0, + }; + char age[10]; + + ++total; + + if (vn_prefix) { + assert(!rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx)); + if (!prefix_match(vn_prefix, &pfx)) + continue; + } + + if (un_prefix) { + assert(!rfapiRaddr2Qprefix(&rfd->un_addr, &pfx)); + if (!prefix_match(un_prefix, &pfx)) + continue; + } + + rfapiRfapiIpAddr2Str(&rfd->vn_addr, vn_addr_buf, + INET6_ADDRSTRLEN); + rfapiRfapiIpAddr2Str(&rfd->un_addr, un_addr_buf, + INET6_ADDRSTRLEN); + + if (!printed) { + /* print out a header */ + vty_out(vty, + " Active Next Hops\n"); + vty_out(vty, "%-15s %-15s %-5s %-5s %-6s %-6s %s\n", + "VN Address", "UN Address", "Regis", "Resps", + "Reach", "Remove", "Age"); + } + + ++printed; + + vty_out(vty, "%-15s %-15s %-5u %-5u %-6u %-6u %s\n", + vn_addr_buf, un_addr_buf, rfapiApCount(rfd), + rfapi_monitor_count(rfd), rfd->stat_count_nh_reachable, + rfd->stat_count_nh_removal, + rfapiFormatAge(rfd->open_time, age, 10)); + } + + if (printed > 0 || vn_prefix || un_prefix) + vty_out(vty, "Displayed %d out of %d active NVEs\n", printed, + total); + + return 0; + +notcfg: + vty_out(vty, "VNC is not configured.\n"); + return CMD_WARNING; +} + + +DEFUN (vnc_show_summary, + vnc_show_summary_cmd, + "show vnc summary", + SHOW_STR + VNC_SHOW_STR + "Display VNC status summary\n") +{ + if (!check_and_display_is_vnc_running(vty)) + return CMD_SUCCESS; + bgp_rfapi_show_summary(bgp_get_default(), vty); + vty_out(vty, "\n"); + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_ACTIVE_NVES); + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_QUERIES); + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_RESPONSES); + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_REGISTERED); + return CMD_SUCCESS; +} + +DEFUN (vnc_show_nves, + vnc_show_nves_cmd, + "show vnc nves", + SHOW_STR + VNC_SHOW_STR + "List known NVEs\n") +{ + rfapi_show_nves(vty, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN (vnc_show_nves_ptct, + vnc_show_nves_ptct_cmd, + "show vnc nves <vn|un> <A.B.C.D|X:X::X:X>", + SHOW_STR + VNC_SHOW_STR + "List known NVEs\n" + "VN address of NVE\n" + "UN address of NVE\n" + "IPv4 interface address\n" + "IPv6 interface address\n") +{ + struct prefix pfx; + + if (!check_and_display_is_vnc_running(vty)) + return CMD_SUCCESS; + + if (!str2prefix(argv[4]->arg, &pfx)) { + vty_out(vty, "Malformed address \"%s\"\n", argv[4]->arg); + return CMD_WARNING; + } + if (pfx.family != AF_INET && pfx.family != AF_INET6) { + vty_out(vty, "Invalid address \"%s\"\n", argv[4]->arg); + return CMD_WARNING; + } + + if (argv[3]->arg[0] == 'u') { + rfapi_show_nves(vty, NULL, &pfx); + } else { + rfapi_show_nves(vty, &pfx, NULL); + } + + return CMD_SUCCESS; +} + +/* adapted from rfp_registration_cache_log() */ +static void rfapi_show_registrations(struct vty *vty, + struct prefix *restrict_to, int show_local, + int show_remote, int show_holddown, + int show_imported) +{ + int printed = 0; + + if (!vty) + return; + + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_REGISTERED); + + if (show_local) { + /* non-expiring, local */ + printed += rfapiShowRemoteRegistrations(vty, restrict_to, 0, 1, + 0, 0); + } + if (show_remote) { + /* non-expiring, non-local */ + printed += rfapiShowRemoteRegistrations(vty, restrict_to, 0, 0, + 1, 0); + } + if (show_holddown) { + /* expiring, including local */ + printed += rfapiShowRemoteRegistrations(vty, restrict_to, 1, 1, + 1, 0); + } + if (show_imported) { + /* non-expiring, non-local */ + printed += rfapiShowRemoteRegistrations(vty, restrict_to, 0, 0, + 1, 1); + } + if (!printed) { + vty_out(vty, "\n"); + } +} + +DEFUN (vnc_show_registrations_pfx, + vnc_show_registrations_pfx_cmd, + "show vnc registrations [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]", + SHOW_STR + VNC_SHOW_STR + "List active prefix registrations\n" + "Limit output to a particualr IPV4 address\n" + "Limit output to a particular IPv4 prefix\n" + "Limit output to a particualr IPV6 address\n" + "Limit output to a particular IPv6 prefix\n" + "Limit output to a particular MAC address\n") +{ + struct prefix p; + struct prefix *p_addr = NULL; + + if (argc > 3) { + if (!str2prefix(argv[3]->arg, &p)) { + vty_out(vty, "Invalid prefix: %s\n", argv[3]->arg); + return CMD_SUCCESS; + } else { + p_addr = &p; + } + } + + rfapi_show_registrations(vty, p_addr, 1, 1, 1, 1); + return CMD_SUCCESS; +} + +DEFUN (vnc_show_registrations_some_pfx, + vnc_show_registrations_some_pfx_cmd, + "show vnc registrations <all|holddown|imported|local|remote> [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]", + SHOW_STR + VNC_SHOW_STR + "List active prefix registrations\n" + "show all registrations\n" + "show only registrations in holddown\n" + "show only imported prefixes\n" + "show only local registrations\n" + "show only remote registrations\n" + "Limit output to a particualr IPV4 address\n" + "Limit output to a particular IPv4 prefix\n" + "Limit output to a particualr IPV6 address\n" + "Limit output to a particular IPv6 prefix\n" + "Limit output to a particular MAC address\n") +{ + struct prefix p; + struct prefix *p_addr = NULL; + + int show_local = 0; + int show_remote = 0; + int show_holddown = 0; + int show_imported = 0; + + if (argc > 4) { + if (!str2prefix(argv[4]->arg, &p)) { + vty_out(vty, "Invalid prefix: %s\n", argv[4]->arg); + return CMD_SUCCESS; + } else { + p_addr = &p; + } + } + switch (argv[3]->arg[0]) { + case 'a': + show_local = 1; + show_remote = 1; + show_holddown = 1; + show_imported = 1; + break; + + case 'h': + show_holddown = 1; + break; + + case 'i': + show_imported = 1; + break; + + case 'l': + show_local = 1; + break; + + case 'r': + show_remote = 1; + break; + } + + rfapi_show_registrations(vty, p_addr, show_local, show_remote, + show_holddown, show_imported); + return CMD_SUCCESS; +} + +DEFUN (vnc_show_responses_pfx, + vnc_show_responses_pfx_cmd, + "show vnc responses [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]", + SHOW_STR + VNC_SHOW_STR + "List recent query responses\n" + "Limit output to a particualr IPV4 address\n" + "Limit output to a particular IPv4 prefix\n" + "Limit output to a particualr IPV6 address\n" + "Limit output to a particular IPv6 prefix\n" + "Limit output to a particular MAC address\n" ) +{ + struct prefix p; + struct prefix *p_addr = NULL; + + if (argc > 3) { + if (!str2prefix(argv[3]->arg, &p)) { + vty_out(vty, "Invalid prefix: %s\n", argv[3]->arg); + return CMD_SUCCESS; + } else { + p_addr = &p; + } + } + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_QUERIES); + + rfapiRibShowResponsesSummary(vty); + + rfapiRibShowResponses(vty, p_addr, 0); + rfapiRibShowResponses(vty, p_addr, 1); + + return CMD_SUCCESS; +} + +DEFUN (vnc_show_responses_some_pfx, + vnc_show_responses_some_pfx_cmd, + "show vnc responses <active|removed> [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]", + SHOW_STR + VNC_SHOW_STR + "List recent query responses\n" + "show only active query responses\n" + "show only removed query responses\n" + "Limit output to a particualr IPV4 address\n" + "Limit output to a particular IPv4 prefix\n" + "Limit output to a particualr IPV6 address\n" + "Limit output to a particular IPv6 prefix\n" + "Limit output to a particular MAC address\n") +{ + struct prefix p; + struct prefix *p_addr = NULL; + + int show_active = 0; + int show_removed = 0; + + if (!check_and_display_is_vnc_running(vty)) + return CMD_SUCCESS; + + if (argc > 4) { + if (!str2prefix(argv[4]->arg, &p)) { + vty_out(vty, "Invalid prefix: %s\n", argv[4]->arg); + return CMD_SUCCESS; + } else { + p_addr = &p; + } + } + + switch (argv[3]->arg[0]) { + case 'a': + show_active = 1; + break; + + case 'r': + show_removed = 1; + break; + } + + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_QUERIES); + + rfapiRibShowResponsesSummary(vty); + + if (show_active) + rfapiRibShowResponses(vty, p_addr, 0); + if (show_removed) + rfapiRibShowResponses(vty, p_addr, 1); + + return CMD_SUCCESS; +} + +DEFUN (show_vnc_queries_pfx, + show_vnc_queries_pfx_cmd, + "show vnc queries [<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M|X:X:X:X:X:X>]", + SHOW_STR + VNC_SHOW_STR + "List active queries\n" + "Limit output to a particualr IPV4 address\n" + "Limit output to a particular IPv4 prefix\n" + "Limit output to a particualr IPV6 address\n" + "Limit output to a particular IPv6 prefix\n" + "Limit output to a particualr MAC address\n") +{ + struct prefix pfx; + struct prefix *p = NULL; + + if (argc > 3) { + if (!str2prefix(argv[3]->arg, &pfx)) { + vty_out(vty, "Invalid prefix: %s\n", argv[3]->arg); + return CMD_WARNING; + } + p = &pfx; + } + + rfapi_vty_show_nve_summary(vty, SHOW_NVE_SUMMARY_QUERIES); + + return rfapiShowVncQueries(vty, p); +} + +DEFUN (vnc_clear_counters, + vnc_clear_counters_cmd, + "clear vnc counters", + CLEAR_STR + VNC_SHOW_STR + "Reset VNC counters\n") +{ + struct bgp *bgp_default = bgp_get_default(); + struct rfapi *h; + struct listnode *node; + struct rfapi_descriptor *rfd; + + if (!bgp_default) + goto notcfg; + + h = bgp_default->rfapi; + + if (!h) + goto notcfg; + + /* per-rfd */ + for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) { + rfd->stat_count_nh_reachable = 0; + rfd->stat_count_nh_removal = 0; + } + + /* global */ + memset(&h->stat, 0, sizeof(h->stat)); + + /* + * 151122 per bug 103, set count_registrations = number active. + * Do same for queries + */ + h->stat.count_registrations = rfapiApCountAll(bgp_default); + h->stat.count_queries = rfapi_monitor_count(NULL); + + rfapiRibShowResponsesSummaryClear(); + + return CMD_SUCCESS; + +notcfg: + vty_out(vty, "VNC is not configured.\n"); + return CMD_WARNING; +} + +/************************************************************************ + * Add prefix with vrf + * + * add [vrf <vrf-name>] prefix <prefix> + * [rd <value>] [label <value>] [local-preference <0-4294967295>] + ************************************************************************/ +void vnc_add_vrf_opener(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg) +{ + if (rfg->rfd == NULL) { /* need new rfapi_handle */ + /* based on rfapi_open */ + struct rfapi_descriptor *rfd; + + rfd = XCALLOC(MTYPE_RFAPI_DESC, + sizeof(struct rfapi_descriptor)); + rfd->bgp = bgp; + rfg->rfd = rfd; + /* leave most fields empty as will get from (dynamic) config + * when needed */ + rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS; + rfd->cookie = rfg; + if (rfg->vn_prefix.family + && !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF)) { + rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr); + } else { + memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr)); + rfd->vn_addr.addr_family = AF_INET; + rfd->vn_addr.addr.v4 = bgp->router_id; + } + rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for + lookups */ + vnc_zlog_debug_verbose("%s: Opening RFD for VRF %s", __func__, + rfg->name); + rfapi_init_and_open(bgp, rfd, rfg); + } +} + +/* NOTE: this functions parallels vnc_direct_add_rn_group_rd */ +static int vnc_add_vrf_prefix(struct vty *vty, const char *arg_vrf, + const char *arg_prefix, + const char *arg_rd, /* optional */ + const char *arg_label, /* optional */ + const char *arg_pref) /* optional */ +{ + struct bgp *bgp; + struct rfapi_nve_group_cfg *rfg; + struct prefix pfx; + struct rfapi_ip_prefix rpfx; + uint32_t pref = 0; + struct rfapi_vn_option optary[3]; + struct rfapi_vn_option *opt = NULL; + int cur_opt = 0; + + bgp = bgp_get_default(); /* assume main instance for now */ + if (!bgp) { + vty_out(vty, "No BGP process is configured\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (!bgp->rfapi || !bgp->rfapi_cfg) { + vty_out(vty, "VRF support not configured\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rfg = bgp_rfapi_cfg_match_byname(bgp, arg_vrf, RFAPI_GROUP_CFG_VRF); + /* arg checks */ + if (!rfg) { + vty_out(vty, "VRF \"%s\" appears not to be configured.\n", + arg_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + if (!rfg->rt_export_list || !rfg->rfapi_import_table) { + vty_out(vty, + "VRF \"%s\" is missing RT import/export RT configuration.\n", + arg_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + if (!rfg->rd.prefixlen && !arg_rd) { + vty_out(vty, + "VRF \"%s\" isn't configured with an RD, so RD must be provided.\n", + arg_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + if (rfg->label > MPLS_LABEL_MAX && !arg_label) { + vty_out(vty, + "VRF \"%s\" isn't configured with a default labels, so a label must be provided.\n", + arg_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + if (!str2prefix(arg_prefix, &pfx)) { + vty_out(vty, "Malformed prefix \"%s\"\n", arg_prefix); + return CMD_WARNING_CONFIG_FAILED; + } + rfapiQprefix2Rprefix(&pfx, &rpfx); + memset(optary, 0, sizeof(optary)); + if (arg_rd) { + opt = &optary[cur_opt++]; + opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD; + /* TODO: save RD format */ + if (!str2prefix_rd(arg_rd, &opt->v.internal_rd)) { + vty_out(vty, "Malformed RD \"%s\"\n", arg_rd); + return CMD_WARNING_CONFIG_FAILED; + } + } + if (rfg->label <= MPLS_LABEL_MAX || arg_label) { + struct rfapi_l2address_option *l2o; + if (opt != NULL) + opt->next = &optary[cur_opt]; + opt = &optary[cur_opt++]; + opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR; + l2o = &opt->v.l2addr; + if (arg_label) { + int32_t label; + label = strtoul(arg_label, NULL, 10); + l2o->label = label; + } else + l2o->label = rfg->label; + } + if (arg_pref) { + char *endptr = NULL; + pref = strtoul(arg_pref, &endptr, 10); + if (*endptr != '\0') { + vty_out(vty, + "%% Invalid local-preference value \"%s\"\n", + arg_pref); + return CMD_WARNING_CONFIG_FAILED; + } + } + rpfx.cost = 255 - (pref & 255); + vnc_add_vrf_opener(bgp, rfg); + + if (!rfapi_register(rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL, + (cur_opt ? optary : NULL), RFAPI_REGISTER_ADD)) { + struct rfapi_next_hop_entry *head = NULL; + struct rfapi_next_hop_entry *tail = NULL; + struct rfapi_vn_option *vn_opt_new; + + vnc_zlog_debug_verbose("%s: rfapi_register succeeded", + __func__); + + if (bgp->rfapi->rfp_methods.local_cb) { + struct rfapi_descriptor *r = + (struct rfapi_descriptor *)rfg->rfd; + vn_opt_new = rfapi_vn_options_dup(opt); + + rfapiAddDeleteLocalRfpPrefix(&r->un_addr, &r->vn_addr, + &rpfx, 1, + RFAPI_INFINITE_LIFETIME, + vn_opt_new, &head, &tail); + if (head) { + bgp->rfapi->flags |= RFAPI_INCALLBACK; + (*bgp->rfapi->rfp_methods.local_cb)(head, + r->cookie); + bgp->rfapi->flags &= ~RFAPI_INCALLBACK; + } + head = tail = NULL; + } + vnc_zlog_debug_verbose( + "%s completed, count=%d/%d", __func__, + rfg->rfapi_import_table->local_count[AFI_IP], + rfg->rfapi_import_table->local_count[AFI_IP6]); + return CMD_SUCCESS; + } + + vnc_zlog_debug_verbose("%s: rfapi_register failed", __func__); + vty_out(vty, "Add failed.\n"); + return CMD_WARNING_CONFIG_FAILED; +} + +DEFUN (add_vrf_prefix_rd_label_pref, + add_vrf_prefix_rd_label_pref_cmd, + "add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [{rd ASN:NN_OR_IP-ADDRESS|label (0-1048575)|preference (0-4294967295)}]", + "Add\n" + "To a VRF\n" + "VRF name\n" + "Add/modify prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Override configured VRF Route Distinguisher\n" + "<as-number>:<number> or <ip-address>:<number>\n" + "Override configured VRF label\n" + "Label Value <0-1048575>\n" + "Set advertised local preference\n" + "local preference (higher=more preferred)\n") +{ + char *arg_vrf = argv[2]->arg; + char *arg_prefix = argv[4]->arg; + char *arg_rd = NULL; /* optional */ + char *arg_label = NULL; /* optional */ + char *arg_pref = NULL; /* optional */ + int pargc = 5; + argc--; /* don't parse argument */ + while (pargc < argc) { + switch (argv[pargc++]->arg[0]) { + case 'r': + arg_rd = argv[pargc]->arg; + break; + case 'l': + arg_label = argv[pargc]->arg; + break; + case 'p': + arg_pref = argv[pargc]->arg; + break; + default: + break; + } + pargc++; + } + + return vnc_add_vrf_prefix(vty, arg_vrf, arg_prefix, arg_rd, arg_label, + arg_pref); +} + +/************************************************************************ + * del prefix with vrf + * + * clear [vrf <vrf-name>] prefix <prefix> [rd <value>] + ************************************************************************/ +static int rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg) +{ + int count = 0; + + if (rfg->rfapi_import_table == NULL) + return 0; + + afi_t afi = AFI_MAX; + while (afi-- > 0) { + count += rfg->rfapi_import_table->local_count[afi]; + } + return count; +} + +void clear_vnc_vrf_closer(struct rfapi_nve_group_cfg *rfg) +{ + struct rfapi_descriptor *rfd = rfg->rfd; + afi_t afi; + + if (rfd == NULL) + return; + /* check if IT is empty */ + for (afi = 0; + afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0; + afi++) + ; + + if (afi == AFI_MAX) { + vnc_zlog_debug_verbose("%s: closing RFD for VRF %s", __func__, + rfg->name); + rfg->rfd = NULL; + rfapi_close(rfd); + } else { + vnc_zlog_debug_verbose( + "%s: VRF %s afi=%d count=%d", __func__, rfg->name, afi, + rfg->rfapi_import_table->local_count[afi]); + } +} + +static int vnc_clear_vrf(struct vty *vty, struct bgp *bgp, const char *arg_vrf, + const char *arg_prefix, /* NULL = all */ + const char *arg_rd) /* optional */ +{ + struct rfapi_nve_group_cfg *rfg; + struct rfapi_local_reg_delete_arg cda; + int rc; + int start_count; + + if (bgp == NULL) + bgp = bgp_get_default(); /* assume main instance for now */ + if (!bgp) { + vty_out(vty, "No BGP process is configured\n"); + return CMD_WARNING; + } + if (!bgp->rfapi || !bgp->rfapi_cfg) { + vty_out(vty, "VRF support not configured\n"); + return CMD_WARNING; + } + rfg = bgp_rfapi_cfg_match_byname(bgp, arg_vrf, RFAPI_GROUP_CFG_VRF); + /* arg checks */ + if (!rfg) { + vty_out(vty, "VRF \"%s\" appears not to be configured.\n", + arg_vrf); + return CMD_WARNING; + } + rc = parse_deleter_args(vty, bgp, arg_prefix, NULL, NULL, NULL, NULL, + arg_rd, rfg, &cda); + if (rc != CMD_SUCCESS) /* parse error */ + return rc; + + start_count = rfapi_cfg_group_it_count(rfg); + clear_vnc_prefix(&cda); + vty_out(vty, "Cleared %u out of %d prefixes.\n", cda.pfx_count, + start_count); + print_cleared_stats(&cda); /* frees lists in cda */ + return CMD_SUCCESS; +} + +DEFUN (clear_vrf_prefix_rd, + clear_vrf_prefix_rd_cmd, + "clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:NN_OR_IP-ADDRESS]", + "Clear stored data\n" + "From a VRF\n" + "VRF name\n" + "Prefix related information\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "Specific VRF Route Distinguisher\n" + "<as-number>:<number> or <ip-address>:<number>\n") +{ + char *arg_vrf = argv[2]->arg; + char *arg_prefix = NULL; /* optional */ + char *arg_rd = NULL; /* optional */ + int pargc = 3; + argc--; /* don't check parameter */ + while (pargc < argc) { + switch (argv[pargc++]->arg[0]) { + case 'r': + arg_rd = argv[pargc]->arg; + break; + case 'p': + arg_prefix = argv[pargc]->arg; + break; + default: + break; + } + pargc++; + } + return vnc_clear_vrf(vty, NULL, arg_vrf, arg_prefix, arg_rd); +} + +DEFUN (clear_vrf_all, + clear_vrf_all_cmd, + "clear vrf NAME all", + "Clear stored data\n" + "From a VRF\n" + "VRF name\n" + "All prefixes\n") +{ + char *arg_vrf = argv[2]->arg; + return vnc_clear_vrf(vty, NULL, arg_vrf, NULL, NULL); +} + +void rfapi_vty_init(void) +{ + install_element(ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_life_cost_lnh_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_cost_lnh_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_life_lnh_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_lnh_cmd); + + install_element(ENABLE_NODE, &add_vnc_prefix_cost_life_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_life_cost_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_cost_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_life_cmd); + install_element(ENABLE_NODE, &add_vnc_prefix_cmd); + + install_element(ENABLE_NODE, &add_vnc_mac_vni_prefix_cost_life_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_prefix_life_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_prefix_cost_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_prefix_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_cost_life_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_cost_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_life_cmd); + install_element(ENABLE_NODE, &add_vnc_mac_vni_cmd); + + install_element(ENABLE_NODE, &add_vrf_prefix_rd_label_pref_cmd); + + install_element(ENABLE_NODE, &clear_vnc_nve_all_cmd); + install_element(ENABLE_NODE, &clear_vnc_nve_vn_un_cmd); + install_element(ENABLE_NODE, &clear_vnc_nve_un_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_nve_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_nve_un_cmd); + + install_element(ENABLE_NODE, &clear_vnc_prefix_vn_un_cmd); + install_element(ENABLE_NODE, &clear_vnc_prefix_un_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_prefix_un_cmd); + install_element(ENABLE_NODE, &clear_vnc_prefix_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_prefix_all_cmd); + + install_element(ENABLE_NODE, &clear_vnc_mac_vn_un_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_un_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_un_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_vn_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_all_cmd); + + install_element(ENABLE_NODE, &clear_vnc_mac_vn_un_prefix_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_un_vn_prefix_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_un_prefix_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_vn_prefix_cmd); + install_element(ENABLE_NODE, &clear_vnc_mac_all_prefix_cmd); + + install_element(ENABLE_NODE, &clear_vrf_prefix_rd_cmd); + install_element(ENABLE_NODE, &clear_vrf_all_cmd); + + install_element(ENABLE_NODE, &vnc_clear_counters_cmd); + + install_element(VIEW_NODE, &vnc_show_summary_cmd); + install_element(VIEW_NODE, &vnc_show_nves_cmd); + install_element(VIEW_NODE, &vnc_show_nves_ptct_cmd); + + install_element(VIEW_NODE, &vnc_show_registrations_pfx_cmd); + install_element(VIEW_NODE, &vnc_show_registrations_some_pfx_cmd); + install_element(VIEW_NODE, &vnc_show_responses_pfx_cmd); + install_element(VIEW_NODE, &vnc_show_responses_some_pfx_cmd); + install_element(VIEW_NODE, &show_vnc_queries_pfx_cmd); +} |