bgpd: Filter BGP routes by prefix version

The idea is to find out prefixes including specific BGP table version and
above.

Let's say I have a converged network and suddently I noticed a couple of
prefixes seems hijacked.

I want to look what new prefixes arrived with a specific BGP table version.

```
exit1-debian-9# show ip bgp version 8
BGP table version is 9, local router ID is 192.168.100.1, vrf id 0
Default local pref 100, local AS 65534
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*  192.168.2.0/24   192.168.0.2              0             0 65030 ?
*>                  192.168.0.2              0             0 65030 ?
*  192.168.3.0/24   192.168.0.2              0             0 65030 ?
*>                  192.168.0.2              0             0 65030 ?

Displayed  2 routes and 18 total paths
exit1-debian-9#
```

```
exit1-debian-9# show ip bgp version 8 json
{
 "vrfId": 0,
 "vrfName": "default",
 "tableVersion": 9,
 "routerId": "192.168.100.1",
 "defaultLocPrf": 100,
 "localAS": 65534,
 "routes": { "192.168.2.0/24": [
  {
    "valid":true,
    "pathFrom":"external",
    "prefix":"192.168.2.0",
    "prefixLen":24,
    "network":"192.168.2.0\/24",
    "version":8,
    "metric":0,
    "weight":0,
    "peerId":"2a02:bbd::2",
    "path":"65030",
    "origin":"incomplete",
    "nexthops":[
      {
        "ip":"192.168.0.2",
        "hostname":"home-spine1.donatas.net",
        "afi":"ipv4",
        "used":true
      }
    ]
  },
  {
    "valid":true,
    "bestpath":true,
    "selectionReason":"Neighbor IP",
    "pathFrom":"external",
    "prefix":"192.168.2.0",
    "prefixLen":24,
    "network":"192.168.2.0\/24",
    "version":8,
    "metric":0,
    "weight":0,
    "peerId":"192.168.0.2",
    "path":"65030",
    "origin":"incomplete",
    "nexthops":[
      {
        "ip":"192.168.0.2",
        "hostname":"home-spine1.donatas.net",
        "afi":"ipv4",
        "used":true
      }
    ]
  }
],"192.168.3.0/24": [
  {
    "valid":true,
    "pathFrom":"external",
    "prefix":"192.168.3.0",
    "prefixLen":24,
    "network":"192.168.3.0\/24",
    "version":9,
    "metric":0,
    "weight":0,
    "peerId":"2a02:bbd::2",
    "path":"65030",
    "origin":"incomplete",
    "nexthops":[
      {
        "ip":"192.168.0.2",
        "hostname":"home-spine1.donatas.net",
        "afi":"ipv4",
        "used":true
      }
    ]
  },
  {
    "valid":true,
    "bestpath":true,
    "selectionReason":"Neighbor IP",
    "pathFrom":"external",
    "prefix":"192.168.3.0",
    "prefixLen":24,
    "network":"192.168.3.0\/24",
    "version":9,
    "metric":0,
    "weight":0,
    "peerId":"192.168.0.2",
    "path":"65030",
    "origin":"incomplete",
    "nexthops":[
      {
        "ip":"192.168.0.2",
        "hostname":"home-spine1.donatas.net",
        "afi":"ipv4",
        "used":true
      }
    ]
  }
] }  }

```

Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
This commit is contained in:
Donatas Abraitis 2021-04-09 09:33:41 +03:00
parent 9119ef3a8b
commit 7d3cae70b2
4 changed files with 62 additions and 23 deletions

View File

@ -8223,8 +8223,8 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
}
/* Static function to display route. */
static void route_vty_out_route(const struct prefix *p, struct vty *vty,
json_object *json, bool wide)
static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
struct vty *vty, json_object *json, bool wide)
{
int len = 0;
char buf[BUFSIZ];
@ -8241,6 +8241,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty,
json_object_int_add(json, "prefixLen", p->prefixlen);
prefix2str(p, buf2, PREFIX_STRLEN);
json_object_string_add(json, "network", buf2);
json_object_int_add(json, "version", dest->version);
}
} else if (p->family == AF_ETHERNET) {
len = vty_out(vty, "%pFX", p);
@ -8265,6 +8266,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty,
json_object_int_add(json, "prefixLen", p->prefixlen);
prefix2str(p, buf2, PREFIX_STRLEN);
json_object_string_add(json, "network", buf2);
json_object_int_add(json, "version", dest->version);
}
}
@ -8460,11 +8462,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
if (!json_paths) {
/* print prefix and mask */
if (!display)
route_vty_out_route(p, vty, json_path, wide);
route_vty_out_route(path->net, p, vty, json_path, wide);
else
vty_out(vty, "%*s", (wide ? 45 : 17), " ");
} else {
route_vty_out_route(p, vty, json_path, wide);
route_vty_out_route(path->net, p, vty, json_path, wide);
}
/*
@ -8924,9 +8926,9 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
}
/* called from terminal list command */
void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
struct attr *attr, safi_t safi, bool use_json,
json_object *json_ar, bool wide)
void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
const struct prefix *p, struct attr *attr, safi_t safi,
bool use_json, json_object *json_ar, bool wide)
{
json_object *json_status = NULL;
json_object *json_net = NULL;
@ -8958,7 +8960,7 @@ void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
json_object_string_add(json_net, "network", buff);
}
} else
route_vty_out_route(p, vty, NULL, wide);
route_vty_out_route(dest, p, vty, NULL, wide);
/* Print attribute */
if (attr) {
@ -9106,7 +9108,7 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p,
/* print prefix and mask */
if (json == NULL) {
if (!display)
route_vty_out_route(p, vty, NULL, false);
route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
@ -9208,7 +9210,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
/* print prefix and mask */
if (!display)
route_vty_out_route(p, vty, json_path, false);
route_vty_out_route(path->net, p, vty, json_path, false);
else
vty_out(vty, "%*s", 17, " ");
@ -9313,7 +9315,7 @@ static void damp_route_vty_out(struct vty *vty, const struct prefix *p,
/* print prefix and mask */
if (!use_json) {
if (!display)
route_vty_out_route(p, vty, NULL, false);
route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
@ -9384,7 +9386,7 @@ static void flap_route_vty_out(struct vty *vty, const struct prefix *p,
/* print prefix and mask */
if (!use_json) {
if (!display)
route_vty_out_route(p, vty, NULL, false);
route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
@ -10121,6 +10123,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, ", valid");
}
if (json_paths)
json_object_int_add(json_path, "version", bn->version);
if (path->peer != bgp->peer_self) {
if (path->peer->as == path->peer->local_as) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
@ -10616,6 +10621,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
for (; pi; pi = pi->next) {
total_count++;
if (type == bgp_show_type_prefix_version) {
uint32_t version =
strtoul(output_arg, NULL, 10);
if (dest->version < version)
continue;
}
if (type == bgp_show_type_rpki) {
if (dest_p->family == AF_INET
|| dest_p->family == AF_INET6)
@ -11892,6 +11904,7 @@ DEFPY (show_ip_bgp_json,
|route-filter-v4|route-filter-translated-v6\
|route-filter-translated-v4] [exact-match]\
|rpki <invalid|valid|notfound>\
|version (1-4294967295)\
] [json$uj | wide$wide]",
SHOW_STR
IP_STR
@ -11925,6 +11938,8 @@ DEFPY (show_ip_bgp_json,
"A valid path as determined by rpki\n"
"A invalid path as determined by rpki\n"
"A path that has no rpki data\n"
"Display prefixes with matching version numbers\n"
"Version number and above\n"
JSON_STR
"Increase table width for longer prefixes\n")
{
@ -11935,6 +11950,7 @@ DEFPY (show_ip_bgp_json,
int idx = 0;
int exact_match = 0;
char *community = NULL;
char *prefix_version = NULL;
bool first = true;
uint8_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
@ -12002,12 +12018,22 @@ DEFPY (show_ip_bgp_json,
rpki_target_state = RPKI_INVALID;
}
/* Display prefixes with matching version numbers */
if (argv_find(argv, argc, "version", &idx)) {
sh_type = bgp_show_type_prefix_version;
prefix_version = argv[idx + 1]->arg;
}
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
exact_match, afi, safi,
show_flags);
else if (prefix_version)
return bgp_show(vty, bgp, afi, safi, sh_type,
prefix_version, show_flags,
rpki_target_state);
else
return bgp_show(vty, bgp, afi, safi, sh_type, NULL,
show_flags, rpki_target_state);
@ -12045,6 +12071,11 @@ DEFPY (show_ip_bgp_json,
bgp_show_community(vty, bgp, community,
exact_match, afi,
safi, show_flags);
else if (prefix_version)
return bgp_show(vty, bgp, afi, safi,
sh_type, prefix_version,
show_flags,
rpki_target_state);
else
bgp_show(vty, bgp, afi, safi, sh_type,
NULL, show_flags,
@ -12077,6 +12108,11 @@ DEFPY (show_ip_bgp_json,
bgp_show_community(vty, bgp, community,
exact_match, afi,
safi, show_flags);
else if (prefix_version)
return bgp_show(vty, bgp, afi, safi,
sh_type, prefix_version,
show_flags,
rpki_target_state);
else
bgp_show(vty, bgp, afi, safi, sh_type,
NULL, show_flags,
@ -13289,7 +13325,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
&& (route_filtered || ret == RMAP_DENY))
(*filtered_count)++;
route_vty_out_tmp(vty, rn_p, &attr, safi,
route_vty_out_tmp(vty, dest, rn_p, &attr, safi,
use_json, json_ar, wide);
bgp_attr_undup(&attr, ain->attr);
(*output_count)++;
@ -13331,8 +13367,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
}
}
route_vty_out_tmp(
vty, rn_p, &attr, safi,
use_json, json_ar,
vty, dest, rn_p, &attr,
safi, use_json, json_ar,
wide);
(*output_count)++;
} else {
@ -13356,7 +13392,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
continue;
route_vty_out_tmp(vty,
route_vty_out_tmp(vty, dest,
bgp_dest_get_prefix(dest),
pi->attr, safi, use_json,
json_ar, wide);

View File

@ -58,6 +58,7 @@ enum bgp_show_type {
bgp_show_type_damp_neighbor,
bgp_show_type_detail,
bgp_show_type_rpki,
bgp_show_type_prefix_version,
};
enum bgp_show_adj_route_type {
@ -714,9 +715,10 @@ extern void route_vty_out(struct vty *vty, const struct prefix *p,
extern void route_vty_out_tag(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
safi_t safi, json_object *json);
extern void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
struct attr *attr, safi_t safi, bool use_json,
json_object *json_ar, bool wide);
extern void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
const struct prefix *p, struct attr *attr,
safi_t safi, bool use_json, json_object *json_ar,
bool wide);
extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json);

View File

@ -267,7 +267,7 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
}
if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv
&& adj->adv->baa) {
route_vty_out_tmp(vty, dest_p,
route_vty_out_tmp(vty, dest, dest_p,
adj->adv->baa->attr,
SUBGRP_SAFI(subgrp),
0, NULL, false);
@ -275,7 +275,7 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
}
if ((flags & UPDWALK_FLAGS_ADVERTISED)
&& adj->attr) {
route_vty_out_tmp(vty, dest_p,
route_vty_out_tmp(vty, dest, dest_p,
adj->attr,
SUBGRP_SAFI(subgrp),
0, NULL, false);

View File

@ -229,8 +229,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
}
rd_header = 0;
}
route_vty_out_tmp(vty, bgp_dest_get_prefix(rm), attr,
safi, use_json, json_routes, false);
route_vty_out_tmp(vty, rm, bgp_dest_get_prefix(rm),
attr, safi, use_json, json_routes,
false);
output_count++;
}