bgpd: Create BGP alias names for community/large-community

Show alias name instead of numerical value in `show bgp <prefix>. E.g.:

```
root@exit1-debian-9:~/frr# vtysh -c 'sh run' | grep 'bgp community alias'
bgp community alias 65001:123 community-1
bgp community alias 65001:123:1 lcommunity-1
root@exit1-debian-9:~/frr#
```

```
exit1-debian-9# sh ip bgp 172.16.16.1/32
BGP routing table entry for 172.16.16.1/32, version 21
Paths: (2 available, best #2, table default)
  Advertised to non peer-group peers:
  65030
    192.168.0.2 from home-spine1.donatas.net(192.168.0.2) (172.16.16.1)
      Origin incomplete, metric 0, valid, external, best (Neighbor IP)
      Community: 65001:12 65001:13 community-1 65001:65534
      Large Community: lcommunity-1 65001:123:2
      Last update: Fri Apr 16 12:51:27 2021
exit1-debian-9#
```

Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
This commit is contained in:
Donatas Abraitis 2021-04-21 22:34:12 +03:00
parent 6038682d46
commit ed0e57e3f0
14 changed files with 304 additions and 9 deletions

View File

@ -28,6 +28,7 @@
#include "bgpd/bgp_memory.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_community_alias.h"
/* Hash of community attribute. */
static struct hash *comhash;
@ -292,7 +293,7 @@ static void set_community_string(struct community *com, bool make_json)
len += strlen(" no-peer");
break;
default:
len += strlen(" 65536:65535");
len = BUFSIZ;
break;
}
}
@ -450,7 +451,7 @@ static void set_community_string(struct community *com, bool make_json)
val = comval & 0xFFFF;
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
strlcat(str, buf, len);
strlcat(str, bgp_community2alias(buf), len);
if (make_json) {
json_string = json_object_new_string(buf);
json_object_array_add(json_community_list,

154
bgpd/bgp_community_alias.c Normal file
View File

@ -0,0 +1,154 @@
/* BGP community, large-community aliasing.
*
* Copyright (C) 2021 Donatas Abraitis <donatas.abraitis@gmail.com>
*
* This file is part of FRRouting (FRR).
*
* FRR is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* FRR is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "memory.h"
#include "lib/jhash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community_alias.h"
static struct hash *bgp_ca_alias_hash;
static struct hash *bgp_ca_community_hash;
static unsigned int bgp_ca_community_hash_key(const void *p)
{
const struct community_alias *ca = p;
return jhash(ca->community, sizeof(ca->community), 0);
}
static bool bgp_ca_community_hash_cmp(const void *p1, const void *p2)
{
const struct community_alias *ca1 = p1;
const struct community_alias *ca2 = p2;
return (strncmp(ca1->community, ca2->community,
sizeof(struct community_alias))
== 0);
}
static unsigned int bgp_ca_alias_hash_key(const void *p)
{
const struct community_alias *ca = p;
return jhash(ca->alias, sizeof(ca->alias), 0);
}
static bool bgp_ca_alias_hash_cmp(const void *p1, const void *p2)
{
const struct community_alias *ca1 = p1;
const struct community_alias *ca2 = p2;
return (strncmp(ca1->alias, ca2->alias, sizeof(struct community_alias))
== 0);
}
static void *bgp_community_alias_alloc(void *p)
{
const struct community_alias *ca = p;
struct communtiy_alias *new;
new = XCALLOC(MTYPE_COMMUNITY_ALIAS, sizeof(struct community_alias));
memcpy(new, ca, sizeof(struct community_alias));
return new;
}
void bgp_community_alias_init(void)
{
bgp_ca_community_hash = hash_create(bgp_ca_community_hash_key,
bgp_ca_community_hash_cmp,
"BGP community alias (community)");
bgp_ca_alias_hash =
hash_create(bgp_ca_alias_hash_key, bgp_ca_alias_hash_cmp,
"BGP community alias (alias)");
}
void bgp_community_alias_finish(void)
{
hash_free(bgp_ca_community_hash);
hash_free(bgp_ca_alias_hash);
}
static void bgp_community_alias_show_iterator(struct hash_bucket *hb,
struct vty *vty)
{
struct community_alias *ca = hb->data;
vty_out(vty, "bgp community alias %s %s\n", ca->community, ca->alias);
}
int bgp_community_alias_write(struct vty *vty)
{
hash_iterate(bgp_ca_community_hash,
(void (*)(struct hash_bucket *,
void *))bgp_community_alias_show_iterator,
vty);
return 1;
}
void bgp_ca_community_insert(struct community_alias *ca)
{
hash_get(bgp_ca_community_hash, ca, bgp_community_alias_alloc);
}
void bgp_ca_alias_insert(struct community_alias *ca)
{
hash_get(bgp_ca_alias_hash, ca, bgp_community_alias_alloc);
}
void bgp_ca_community_delete(struct community_alias *ca)
{
struct community_alias *data = hash_release(bgp_ca_community_hash, ca);
XFREE(MTYPE_COMMUNITY_ALIAS, data);
}
void bgp_ca_alias_delete(struct community_alias *ca)
{
struct community_alias *data = hash_release(bgp_ca_alias_hash, ca);
XFREE(MTYPE_COMMUNITY_ALIAS, data);
}
struct community_alias *bgp_ca_community_lookup(struct community_alias *ca)
{
return hash_lookup(bgp_ca_community_hash, ca);
}
struct community_alias *bgp_ca_alias_lookup(struct community_alias *ca)
{
return hash_lookup(bgp_ca_alias_hash, ca);
}
const char *bgp_community2alias(char *community)
{
struct community_alias ca;
struct community_alias *find;
memset(&ca, 0, sizeof(ca));
strlcpy(ca.community, community, sizeof(ca.community));
find = bgp_ca_community_lookup(&ca);
if (find)
return find->alias;
return community;
}

View File

@ -0,0 +1,46 @@
/* BGP community, large-community aliasing.
*
* Copyright (C) 2021 Donatas Abraitis <donatas.abraitis@gmail.com>
*
* This file is part of FRRouting (FRR).
*
* FRR is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* FRR is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bgpd/bgp_lcommunity.h"
#ifndef FRR_BGP_COMMUNITY_ALIAS_H
#define FRR_BGP_COMMUNITY_ALIAS_H
struct community_alias {
/* Human readable community string */
char community[LCOMMUNITY_SIZE * 3];
/* Human readable community alias */
char alias[BUFSIZ];
};
extern void bgp_community_alias_init(void);
extern void bgp_community_alias_finish(void);
extern struct community_alias *bgp_ca_alias_lookup(struct community_alias *ca);
extern struct community_alias *
bgp_ca_community_lookup(struct community_alias *ca);
extern void bgp_ca_community_insert(struct community_alias *ca);
extern void bgp_ca_alias_insert(struct community_alias *ca);
extern void bgp_ca_community_delete(struct community_alias *ca);
extern void bgp_ca_alias_delete(struct community_alias *ca);
extern int bgp_community_alias_write(struct vty *vty);
extern const char *bgp_community2alias(char *community);
#endif /* FRR_BGP_COMMUNITY_ALIAS_H */

View File

@ -30,6 +30,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
@ -213,7 +214,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
}
/* 1 space + lcom->size lcom strings + null terminator */
size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2;
size_t str_buf_sz = BUFSIZ;
str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
for (i = 0; i < lcom->size; i++) {
@ -231,7 +232,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
local2);
len = strlcat(str_buf, lcsb, str_buf_sz);
len = strlcat(str_buf, bgp_community2alias(lcsb), str_buf_sz);
assert((unsigned int)len < str_buf_sz);
if (make_json) {

View File

@ -66,6 +66,7 @@
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_routemap_nb.h"
#include "bgpd/bgp_community_alias.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@ -220,6 +221,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
/* reverse bgp_dump_init */
bgp_dump_finish();
/* BGP community aliases */
bgp_community_alias_finish();
/* reverse bgp_route_init */
bgp_route_finish();

View File

@ -65,6 +65,8 @@ DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list");
DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter");
DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str");
DEFINE_MTYPE(BGPD, COMMUNITY_ALIAS, "community");
DEFINE_MTYPE(BGPD, COMMUNITY, "community");
DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val");
DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str");

View File

@ -61,6 +61,8 @@ DECLARE_MTYPE(AS_LIST);
DECLARE_MTYPE(AS_FILTER);
DECLARE_MTYPE(AS_FILTER_STR);
DECLARE_MTYPE(COMMUNITY_ALIAS);
DECLARE_MTYPE(COMMUNITY);
DECLARE_MTYPE(COMMUNITY_VAL);
DECLARE_MTYPE(COMMUNITY_STR);

View File

@ -51,6 +51,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_clist.h"

View File

@ -46,6 +46,7 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
@ -1497,6 +1498,62 @@ void cli_show_router_bgp_router_id(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " bgp router-id %s\n", yang_dnode_get_string(dnode, NULL));
}
DEFPY(bgp_community_alias, bgp_community_alias_cmd,
"[no$no] bgp community alias WORD$community WORD$alias",
NO_STR BGP_STR
"Add community specific parameters\n"
"Create an alias for a community\n"
"Community (AA:BB or AA:BB:CC)\n"
"Alias name\n")
{
struct community_alias ca1;
struct community_alias ca2;
struct community_alias *lookup_community;
struct community_alias *lookup_alias;
if (!community_str2com(community) && !lcommunity_str2com(community)) {
vty_out(vty, "Invalid community format\n");
return CMD_WARNING;
}
memset(&ca1, 0, sizeof(ca1));
memset(&ca2, 0, sizeof(ca2));
strlcpy(ca1.community, community, sizeof(ca1.community));
strlcpy(ca1.alias, alias, sizeof(ca1.alias));
lookup_community = bgp_ca_community_lookup(&ca1);
lookup_alias = bgp_ca_alias_lookup(&ca1);
if (no) {
bgp_ca_alias_delete(&ca1);
bgp_ca_community_delete(&ca1);
} else {
if (lookup_alias) {
/* Lookup if community hash table has an item
* with the same alias name.
*/
strlcpy(ca2.community, lookup_alias->community,
sizeof(ca2.community));
if (bgp_ca_community_lookup(&ca2)) {
vty_out(vty,
"community (%s) already has this alias (%s)\n",
lookup_alias->community,
lookup_alias->alias);
return CMD_WARNING;
}
bgp_ca_alias_delete(&ca1);
}
if (lookup_community)
bgp_ca_community_delete(&ca1);
bgp_ca_alias_insert(&ca1);
bgp_ca_community_insert(&ca1);
}
return CMD_SUCCESS;
}
DEFPY (bgp_global_suppress_fib_pending,
bgp_global_suppress_fib_pending_cmd,
"[no] bgp suppress-fib-pending",
@ -19261,6 +19318,8 @@ void bgp_vty_init(void)
/* Community-list. */
community_list_vty();
community_alias_vty();
/* vpn-policy commands */
install_element(BGP_IPV4_NODE, &af_rd_vpn_export_cmd);
install_element(BGP_IPV6_NODE, &af_rd_vpn_export_cmd);
@ -20467,3 +20526,18 @@ static void community_list_vty(void)
install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd);
install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd);
}
static struct cmd_node community_alias_node = {
.name = "community alias",
.node = COMMUNITY_ALIAS_NODE,
.prompt = "",
.config_write = bgp_community_alias_write,
};
void community_alias_vty(void)
{
install_node(&community_alias_node);
/* Community-list. */
install_element(CONFIG_NODE, &bgp_community_alias_cmd);
}

View File

@ -154,6 +154,7 @@ struct bgp;
} while (0)
extern void bgp_vty_init(void);
extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type inst_type);

View File

@ -55,6 +55,7 @@
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_conditional_adv.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_regex.h"
@ -7697,6 +7698,7 @@ void bgp_init(unsigned short instance)
/* BGP inits. */
bgp_attr_init();
bgp_debug_init();
bgp_community_alias_init();
bgp_dump_init();
bgp_route_init();
bgp_route_map_init();

View File

@ -57,6 +57,7 @@ bgpd_libbgp_a_SOURCES = \
bgpd/bgp_bfd.c \
bgpd/bgp_clist.c \
bgpd/bgp_community.c \
bgpd/bgp_community_alias.c \
bgpd/bgp_conditional_adv.c \
bgpd/bgp_damp.c \
bgpd/bgp_debug.c \
@ -137,6 +138,7 @@ noinst_HEADERS += \
bgpd/bgp_bfd.h \
bgpd/bgp_clist.h \
bgpd/bgp_community.h \
bgpd/bgp_community_alias.h \
bgpd/bgp_conditional_adv.h \
bgpd/bgp_damp.h \
bgpd/bgp_debug.h \

View File

@ -137,6 +137,7 @@ enum node_type {
PREFIX_IPV6_NODE, /* Prefix list node. */
AS_LIST_NODE, /* AS list node. */
COMMUNITY_LIST_NODE, /* Community list node. */
COMMUNITY_ALIAS_NODE, /* Community alias node. */
RMAP_NODE, /* Route map node. */
PBRMAP_NODE, /* PBR map node. */
SMUX_NODE, /* SNMP configuration node. */

View File

@ -380,6 +380,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen("bgp large-community-list"))
== 0)
config = config_get(COMMUNITY_LIST_NODE, line);
else if (strncmp(line, "bgp community alias",
strlen("bgp community alias")) == 0)
config = config_get(COMMUNITY_ALIAS_NODE, line);
else if (strncmp(line, "ip route", strlen("ip route")) == 0)
config = config_get(IP_NODE, line);
else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
@ -452,11 +455,12 @@ void vtysh_config_parse_line(void *arg, const char *line)
#define NO_DELIMITER(I) \
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
|| (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
|| (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
|| (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
|| (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \
|| (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE)
|| (I) == COMMUNITY_ALIAS_NODE || (I) == ACCESS_IPV6_NODE \
|| (I) == ACCESS_MAC_NODE || (I) == PREFIX_IPV6_NODE \
|| (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
|| (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \
|| (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \
|| (I) == MPLS_NODE)
/* Display configuration to file pointer. */
void vtysh_config_dump(void)