Arista EOS Support (#35)

Add Arista EOS support

Thanks Brooks!

This adds support for Arista EOS using a new flag: -e. EOS shares a lot of similarities with IOS,
but there is a difference in the syntax of prefix-lists that I wanted to fix.

The difference can be seen with bgpq4 -S ARIN -4 -s AS36459, which returns:

no ip prefix-list NN
ip prefix-list NN seq 1 permit 192.30.252.0/22
ip prefix-list NN seq 2 permit 192.30.252.0/23
ip prefix-list NN seq 3 permit 192.30.252.0/24
ip prefix-list NN seq 4 permit 192.30.253.0/24
ip prefix-list NN seq 5 permit 192.30.254.0/24
ip prefix-list NN seq 6 permit 192.30.255.0/24

Interestingly, this syntax works fine in EOS, but EOS isn't able to handle the same syntax for ipv6
prefix-lists. Instead, the seq and permit/deny that compose the rule needs to be inside the prefix-list
block.

Now bgpq4 -S ARIN -4 -e AS36459 generates:

no ip prefix-list NN
ip prefix-list NN
    seq 1 permit 192.30.252.0/22
    seq 2 permit 192.30.252.0/23
    seq 3 permit 192.30.252.0/24
    seq 4 permit 192.30.253.0/24
    seq 5 permit 192.30.254.0/24
    seq 6 permit 192.30.255.0/24
This commit is contained in:
Brooks Swinnerton
2020-12-23 10:07:23 -05:00
committed by GitHub
parent 884a982718
commit d000627465
5 changed files with 93 additions and 6 deletions

View File

@@ -7,7 +7,7 @@ SYNOPSIS
--------
```
bgpq4 [-h host[:port]] [-S sources] [-Ez] [-f asn | -F fmt | -G asn | -t] [-46ABbDdJjNnpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS
bgpq4 [-h host[:port]] [-S sources] [-Ez] [-f asn | -F fmt | -G asn | -t] [-46ABbDdeJjNnpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS
```
DESCRIPTION
@@ -54,6 +54,10 @@ Generate extended access-list (Cisco) or policy-statement term using
route-filters (Juniper), [ip|ipv6]-prefix-list (Nokia) or prefix-filter
(OpenBGPD)
#### -e
Generate output in Arista EOS format.
#### -f `AS number`
Generate input as-path access-list for adjacent as `AS number`.

View File

@@ -71,6 +71,8 @@ generate output in OpenBGPD format (default: Cisco)
generate output in BIRD format (default: Cisco).
.It Fl d
enable some debugging output.
.It Fl e
generate output in Arista EOS format (default: Cisco).
.It Fl E
generate extended access-list (Cisco), policy-statement term using
route-filters (Juniper), [ip|ipv6]-prefix-list (Nokia) or prefix-sets

20
bgpq4.c
View File

@@ -40,6 +40,7 @@ usage(int ecode)
printf(" -N : Nokia SR OS (Classic CLI)\n");
printf(" -n : Nokia SR OS (MD-CLI)\n");
printf(" -B : OpenBSD OpenBGPD\n");
printf(" -e : Arista EOS\n");
printf(" -F fmt : User defined format (example: '-F %%n/%%l')\n");
printf("\nInput filters:\n");
@@ -107,7 +108,8 @@ vendor_exclusive()
{
fprintf(stderr, "-b (BIRD), -B (OpenBGPD), -F (formatted), -J (Junos),"
" -j (JSON), -N (Nokia SR OS Classic), -n (Nokia SR OS MD-CLI),"
" -U (Huawei) and -X (IOS XR) options are mutually exclusive\n");
" -U (Huawei), -e (Arista) and -X (IOS XR) options are mutually"
" exclusive\n");
exit(1);
}
@@ -167,7 +169,7 @@ main(int argc, char* argv[])
if (getenv("IRRD_SOURCES"))
expander.sources=getenv("IRRD_SOURCES");
while ((c = getopt(argc,argv,"346a:AbBdDEF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsvz"))
while ((c = getopt(argc,argv,"346a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsvz"))
!=EOF) {
switch (c) {
case '3':
@@ -220,6 +222,12 @@ main(int argc, char* argv[])
exclusive();
expander.generation = T_EACL;
break;
case 'e':
if (expander.vendor)
vendor_exclusive();
expander.vendor = V_ARISTA;
expander.sequence = 1;
break;
case 'F':
if (expander.vendor)
exclusive();
@@ -420,6 +428,8 @@ main(int argc, char* argv[])
} else if (expander.vendor == V_NOKIA ||
expander.vendor == V_NOKIA_MD) {
expander.aswidth = 8;
} else if (expander.vendor == V_ARISTA) {
expander.aswidth = 4;
}
} else if (expander.generation == T_OASPATH) {
if (expander.vendor == V_CISCO) {
@@ -431,6 +441,8 @@ main(int argc, char* argv[])
} else if (expander.vendor == V_NOKIA ||
expander.vendor == V_NOKIA_MD) {
expander.aswidth = 8;
} else if (expander.vendor == V_ARISTA) {
expander.aswidth = 5;
}
}
}
@@ -507,9 +519,9 @@ main(int argc, char* argv[])
exit(1);
}
if (expander.sequence && expander.vendor != V_CISCO) {
if (expander.sequence && (expander.vendor != V_CISCO && expander.vendor != V_ARISTA)) {
sx_report(SX_FATAL, "Sorry, prefix-lists sequencing (-s) supported"
" only for IOS\n");
" only for IOS and EOS\n");
exit(1);
}

View File

@@ -21,7 +21,8 @@ typedef enum {
V_NOKIA,
V_HUAWEI,
V_MIKROTIK,
V_NOKIA_MD
V_NOKIA_MD,
V_ARISTA
} bgpq_vendor_t;
typedef enum {

View File

@@ -772,6 +772,8 @@ bgpq4_print_aspath(FILE* f, struct bgpq_expander* b)
return bgpq4_print_nokia_md_aspath(f, b);
case V_HUAWEI:
return bgpq4_print_huawei_aspath(f, b);
case V_ARISTA:
return bgpq4_print_cisco_aspath(f, b);
default:
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
}
@@ -797,6 +799,8 @@ bgpq4_print_oaspath(FILE* f, struct bgpq_expander* b)
return bgpq4_print_nokia_md_oaspath(f, b);
case V_HUAWEI:
return bgpq4_print_huawei_oaspath(f, b);
case V_ARISTA:
return bgpq4_print_cisco_oaspath(f, b);
default:
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
}
@@ -1241,6 +1245,39 @@ checkSon:
bgpq4_print_hprefix(n->son, ff);
}
void
bgpq4_print_eprefix(struct sx_radix_node* n, void* ff)
{
char prefix[128], seqno[16] = "";
FILE* f = (FILE*)ff;
if (!f)
f = stdout;
if (n->isGlue)
goto checkSon;
sx_prefix_snprintf(n->prefix,prefix,sizeof(prefix));
snprintf(seqno, sizeof(seqno), " seq %i", seq++);
if (n->isAggregate) {
if (n->aggregateLow>n->prefix->masklen) {
fprintf(f," %s permit %s ge %u le %u\n",
seqno, prefix, n->aggregateLow, n->aggregateHi);
} else {
fprintf(f," %s permit %s le %u\n",
seqno, prefix, n->aggregateHi);
}
} else {
fprintf(f," %s permit %s\n", seqno, prefix);
}
checkSon:
if (n->son)
bgpq4_print_eprefix(n->son,ff);
}
void
bgpq4_print_ceacl(struct sx_radix_node* n, void* ff)
@@ -1626,6 +1663,33 @@ bgpq4_print_huawei_prefixlist(FILE* f, struct bgpq_expander* b)
return 0;
}
int
bgpq4_print_arista_prefixlist(FILE* f, struct bgpq_expander* b)
{
bname = b->name ? b->name : "NN";
seq = b->sequence;
fprintf(f, "no %s prefix-list %s\n",
b->family == AF_INET ? "ip" : "ipv6",
bname);
if (!sx_radix_tree_empty(b->tree)) {
fprintf(f,"%s prefix-list %s\n",
b->family == AF_INET ? "ip" : "ipv6",
bname);
sx_radix_tree_foreach(b->tree, bgpq4_print_eprefix, f);
} else {
fprintf(f, "! generated prefix-list %s is empty\n", bname);
fprintf(f, "%s prefix-list %s\n seq %i deny %s\n",
b->family==AF_INET ? "ip" : "ipv6",
bname,
seq,
b->family==AF_INET ? "0.0.0.0/0" : "::/0");
}
return 0;
}
struct fpcbdata {
FILE* f;
@@ -1862,6 +1926,8 @@ bgpq4_print_prefixlist(FILE* f, struct bgpq_expander* b)
return bgpq4_print_huawei_prefixlist(f, b);
case V_MIKROTIK:
return bgpq4_print_mikrotik_prefixlist(f, b);
case V_ARISTA:
return bgpq4_print_arista_prefixlist(f, b);
}
return 0;
@@ -1893,6 +1959,8 @@ bgpq4_print_eacl(FILE* f, struct bgpq_expander* b)
return sx_report(SX_FATAL, "unreachable point\n");
case V_HUAWEI:
return sx_report(SX_FATAL, "unreachable point\n");
case V_ARISTA:
return bgpq4_print_cisco_eacl(f, b);
}
return 0;