mirror of
https://github.com/bgp/bgpq4
synced 2025-02-28 08:53:11 +00:00
Some checks failed
Build and test (latest Ubuntu/macOS) / build (ubuntu-latest) (push) Successful in 30s
Build and test (latest Ubuntu/macOS) / build (macos-latest) (push) Has been cancelled
basic unit tests / output unit tests (push) Has been cancelled
CodeQL analysis / Analyze (cpp) (push) Failing after 1m20s
* Remove extraneous space in Arista prefixlist When diffing config generated with bgpq4 with config exported from an Arista device, many lines are returned as changed. This is because prefixlist on Arista device use 3 spaces and bgpq4 uses 4 spaces. * Update eos--4.txt * Update eos--6.txt
2009 lines
43 KiB
C
2009 lines
43 KiB
C
/*
|
|
* Copyright (c) 2019-2021 Job Snijders <job@sobornost.net>
|
|
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/tree.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
|
|
#include "extern.h"
|
|
#include "sx_report.h"
|
|
|
|
extern int debug_expander;
|
|
|
|
#define max(a,b) \
|
|
({ \
|
|
__typeof__ (a) _a = (a); \
|
|
__typeof__ (b) _b = (b); \
|
|
_a > _b ? _a : _b; \
|
|
})
|
|
|
|
static void
|
|
bgpq4_print_cisco_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "no ip as-path access-list %s\n", b->name);
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "ip as-path access-list %s deny .*\n", b->name);
|
|
return;
|
|
}
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "ip as-path access-list %s permit ^%u(_%u)*$\n",
|
|
b->name, res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc)
|
|
fprintf(f, "ip as-path access-list %s permit"
|
|
" ^%u(_[0-9]+)*_(%u", b->name, b->asnumber,
|
|
asne->asn);
|
|
else
|
|
fprintf(f,"|%u", asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$\n");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f,")$\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cisco_xr_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, comma = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "as-path-set %s", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "\n ios-regex '^%u(_%u)*$'", res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
comma = 1;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, "%s\n ios-regex '^%u(_[0-9]+)*_(%u",
|
|
comma ? "," : "",
|
|
b->asnumber,
|
|
asne->asn);
|
|
comma = 1;
|
|
} else
|
|
fprintf(f, "|%u", asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$'");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$'");
|
|
|
|
fprintf(f, "\nend-set\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cisco_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "no ip as-path access-list %s\n", b->name);
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "ip as-path access-list %s deny .*\n", b->name);
|
|
return;
|
|
}
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "ip as-path access-list %s permit ^(_%u)*$\n",
|
|
b->name, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc)
|
|
fprintf(f,"ip as-path access-list %s permit"
|
|
" ^(_[0-9]+)*_(%u", b->name, asne->asn);
|
|
else
|
|
fprintf(f,"|%u",asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f,")$\n");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$\n");
|
|
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cisco_xr_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, comma = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "as-path-set %s", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "\n ios-regex '^(_%u)*$'", res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
comma = 1;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f,"%s\n ios-regex '^(_[0-9]+)*_(%u",
|
|
comma ? "," : "", asne->asn);
|
|
comma = 1;
|
|
} else
|
|
fprintf(f,"|%u",asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f,")$'");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f,")$'");
|
|
|
|
fprintf(f,"\nend-set\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f,"policy-options {\nreplace:\n as-path-group %s {\n",
|
|
b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " as-path a0 \"^%u(%u)*$\";\n", res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, " as-path a%u \"^%u(.)*(%u",
|
|
lineNo, b->asnumber,
|
|
asne->asn);
|
|
} else {
|
|
fprintf(f,"|%u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$\";\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$\";\n");
|
|
else if (lineNo == 0)
|
|
fprintf(f, " as-path aNone \"!.*\";\n");
|
|
|
|
fprintf(f, " }\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f,"policy-options {\nreplace:\n as-path-group %s {\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " as-path a%u \"^%u(%u)*$\";\n", lineNo,
|
|
res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f," as-path a%u \"^(.)*(%u",
|
|
lineNo,
|
|
asne->asn);
|
|
} else {
|
|
fprintf(f, "|%u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$\";\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$\";\n");
|
|
else if (lineNo == 0)
|
|
fprintf(f, " as-path aNone \"!.*\";\n");
|
|
|
|
fprintf(f, " }\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_aslist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f,"policy-options {\nreplace:\n as-list-group %s {\n",
|
|
b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " as-list a0 members %u;\n", res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, " as-list a%u members [",
|
|
lineNo);
|
|
}
|
|
|
|
// Filter out AS 0
|
|
// "error: RPD Policy: Invalid AS 0"
|
|
if (asne->asn != 0)
|
|
fprintf(f," %u", asne->asn);
|
|
|
|
nc++;
|
|
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, " ];\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, " ];\n");
|
|
|
|
fprintf(f, " }\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
struct asn_entry *asne;
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "deny to AS %u\n", b->asnumber);
|
|
return;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist)
|
|
fprintf(f, "allow to AS %u AS %u\n", b->asnumber, asne->asn);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 1;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "configure router policy-options\n"
|
|
"begin\nno as-path-group \"%s\"\n", b->name);
|
|
|
|
fprintf(f, "as-path-group \"%s\"\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " entry 1 expression \"%u+\"\n", res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f," entry %u expression \"%u.*[%u",
|
|
lineNo, b->asnumber, asne->asn);
|
|
} else {
|
|
fprintf(f, " %u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, "]\"\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, "]\"\n");
|
|
|
|
fprintf(f,"exit\ncommit\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 1;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f,"/configure policy-options\ndelete as-path-group \"%s\"\n",
|
|
b->name);
|
|
fprintf(f,"as-path-group \"%s\" {\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f," entry 1 {\n expression \"%u+\"\n }\n",
|
|
res->asn);
|
|
lineNo++;
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f," entry %u {\n expression \"%u.*[%u",
|
|
lineNo, b->asnumber, asne->asn);
|
|
} else {
|
|
fprintf(f, " %u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f,"]\"\n }\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f,"]\"\n }\n");
|
|
|
|
fprintf(f, "}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "undo ip as-path-filter %s\n", b->name);
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f,"ip as-path-filter %s deny .*\n", b->name);
|
|
return;
|
|
}
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "ip as-path-filter %s permit ^%u(_%u)*$\n",
|
|
b->name, res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc)
|
|
fprintf(f, "ip as-path-filter %s permit ^%u(_[0-9]+)*"
|
|
"_(%u", b->name, b->asnumber, asne->asn);
|
|
else
|
|
fprintf(f, "|%u", asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$\n");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_xpl_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, comma = 1;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "xpl as-path-list %s", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "\n regular ^%u(_%u)*$", res->asn, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, "%s\n regular ^%u(_[0-9]+)*_(%u",
|
|
comma ? "," : "",
|
|
b->asnumber,
|
|
asne->asn);
|
|
comma = 1;
|
|
} else
|
|
fprintf(f, "|%u", asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$");
|
|
|
|
fprintf(f, "\nend-list\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f,"undo ip as-path-filter %s\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f,"ip as-path-filter %s permit ^(_%u)*$\n",
|
|
b->name, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
}
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "ip as-path-filter %s deny .*\n", b->name);
|
|
return;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, "ip as-path-filter %s permit ^(_[0-9]+)*_(%u",
|
|
b->name, asne->asn);
|
|
} else {
|
|
fprintf(f, "|%u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, ")$\n");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, ")$\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_xpl_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, comma = 0;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "xpl as-path-list %s", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, "\n regular ^(_%u)*$", res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
comma = 1;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f,"%s\n regular ^(_[0-9]+)*_(%u",
|
|
comma ? "," : "", asne->asn);
|
|
comma = 1;
|
|
} else
|
|
fprintf(f,"|%u",asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f,")$");
|
|
nc = 0;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f,")$");
|
|
|
|
fprintf(f,"\nend-list\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 1;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "configure router policy-options\nbegin\nno as-path-group"
|
|
"\"%s\"\n", b->name);
|
|
fprintf(f, "as-path-group \"%s\"\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " entry %u expression \"%u+\"\n", lineNo,
|
|
b->asnumber);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f," entry %u expression \".*[%u",
|
|
lineNo, asne->asn);
|
|
} else {
|
|
fprintf(f," %u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f,"]\"\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f, "]\"\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0, lineNo = 1;
|
|
struct asn_entry *asne, find, *res;
|
|
|
|
fprintf(f, "/configure policy-options\ndelete as-path-group \"%s\"\n",
|
|
b->name);
|
|
fprintf(f, "as-path-group \"%s\" {\n", b->name);
|
|
|
|
find.asn = b->asnumber;
|
|
if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) {
|
|
fprintf(f, " entry %u {\n expression \"%u+\"\n }\n",
|
|
lineNo, res->asn);
|
|
RB_REMOVE(asn_tree, &b->asnlist, res);
|
|
lineNo++;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f," entry %u {\n expression \".*[%u",
|
|
lineNo, asne->asn);
|
|
} else {
|
|
fprintf(f, " %u", asne->asn);
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth) {
|
|
fprintf(f, "]\"\n }\n");
|
|
nc = 0;
|
|
lineNo++;
|
|
}
|
|
}
|
|
|
|
if (nc)
|
|
fprintf(f,"]\"\n }\n");
|
|
|
|
fprintf(f, "}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_jprefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
return;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
fprintf(f," %s;\n", prefix);
|
|
}
|
|
|
|
static int needscomma = 0;
|
|
|
|
static void
|
|
bgpq4_print_json_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_jsnprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": true }",
|
|
needscomma ? "," : "", prefix);
|
|
} else if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": false,\n"
|
|
" \"greater-equal\": %u, \"less-equal\": %u }",
|
|
needscomma ? "," : "", prefix, n->aggregateLow,
|
|
n->aggregateHi);
|
|
} else {
|
|
fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": false, "
|
|
"\"less-equal\": %u }", needscomma ? "," : "", prefix,
|
|
n->aggregateHi);
|
|
}
|
|
|
|
needscomma = 1;
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_json_prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_json_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne;
|
|
|
|
fprintf(f, "{\"%s\": [", b->name);
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, "%s\n %u",
|
|
needscomma ? "," : "",
|
|
asne->asn);
|
|
needscomma = 1;
|
|
} else {
|
|
fprintf(f, "%s%u",
|
|
needscomma ? "," : "",
|
|
asne->asn);
|
|
needscomma = 1;
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth)
|
|
nc = 0;
|
|
}
|
|
|
|
fprintf(f,"\n]}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_bird_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, "%s\n %s", needscomma ? "," : "", prefix);
|
|
} else if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f, "%s\n %s{%u,%u}", needscomma ? "," : "", prefix,
|
|
n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f, "%s\n %s{%u,%u}", needscomma ? "," : "", prefix,
|
|
n->prefix->masklen, n->aggregateHi);
|
|
}
|
|
|
|
needscomma = 1;
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_bird_prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_bird_aspath(FILE* f, struct bgpq_expander* b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne;
|
|
|
|
fprintf(f, "%s = [", b->name);
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "];\n");
|
|
return;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
if (!nc) {
|
|
fprintf(f, "%s\n %u", needscomma ? "," : "",
|
|
asne->asn);
|
|
needscomma = 1;
|
|
} else {
|
|
fprintf(f, ", %u", asne->asn);
|
|
needscomma = 1;
|
|
}
|
|
|
|
nc++;
|
|
if (nc == b->aswidth)
|
|
nc = 0;
|
|
}
|
|
|
|
fprintf(f, "\n];\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, "\n\t%s", prefix);
|
|
} else if (n->aggregateLow == n->aggregateHi) {
|
|
fprintf(f, "\n\t%s prefixlen = %u", prefix, n->aggregateHi);
|
|
} else if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f, "\n\t%s prefixlen %u - %u",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f, "\n\t%s prefixlen %u - %u",
|
|
prefix, n->prefix->masklen, n->aggregateHi);
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_openbgpd_prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_asset(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
int nc = 0;
|
|
struct asn_entry *asne;
|
|
|
|
fprintf(f, "as-set %s {", b->name);
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist) {
|
|
fprintf(f, "%s%u", nc == 0 ? "\n\t" : " ", asne->asn);
|
|
|
|
nc++;
|
|
if (nc == b->aswidth)
|
|
nc = 0;
|
|
}
|
|
|
|
fprintf(f, "\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
struct asn_entry *asne;
|
|
|
|
if (RB_EMPTY(&b->asnlist)) {
|
|
fprintf(f, "deny from AS %u\n", b->asnumber);
|
|
return;
|
|
}
|
|
|
|
RB_FOREACH(asne, asn_tree, &b->asnlist)
|
|
fprintf(f, "allow from AS %u AS %u\n", b->asnumber, asne->asn);
|
|
}
|
|
|
|
void
|
|
bgpq4_print_aspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_aspath(f, b);
|
|
break;
|
|
case V_CISCO:
|
|
case V_ARISTA:
|
|
bgpq4_print_cisco_aspath(f, b);
|
|
break;
|
|
case V_CISCO_XR:
|
|
bgpq4_print_cisco_xr_aspath(f, b);
|
|
break;
|
|
case V_JSON:
|
|
bgpq4_print_json_aspath(f, b);
|
|
break;
|
|
case V_BIRD:
|
|
bgpq4_print_bird_aspath(f, b);
|
|
break;
|
|
case V_OPENBGPD:
|
|
bgpq4_print_openbgpd_aspath(f, b);
|
|
break;
|
|
case V_NOKIA:
|
|
bgpq4_print_nokia_aspath(f, b);
|
|
break;
|
|
case V_NOKIA_MD:
|
|
bgpq4_print_nokia_md_aspath(f, b);
|
|
break;
|
|
case V_HUAWEI:
|
|
bgpq4_print_huawei_aspath(f, b);
|
|
break;
|
|
case V_HUAWEI_XPL:
|
|
bgpq4_print_huawei_xpl_aspath(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpq4_print_oaspath(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_oaspath(f, b);
|
|
break;
|
|
case V_CISCO:
|
|
case V_ARISTA:
|
|
bgpq4_print_cisco_oaspath(f, b);
|
|
break;
|
|
case V_CISCO_XR:
|
|
bgpq4_print_cisco_xr_oaspath(f, b);
|
|
break;
|
|
case V_OPENBGPD:
|
|
bgpq4_print_openbgpd_oaspath(f, b);
|
|
break;
|
|
case V_NOKIA:
|
|
bgpq4_print_nokia_oaspath(f, b);
|
|
break;
|
|
case V_NOKIA_MD:
|
|
bgpq4_print_nokia_md_oaspath(f, b);
|
|
break;
|
|
case V_HUAWEI:
|
|
bgpq4_print_huawei_oaspath(f, b);
|
|
break;
|
|
case V_HUAWEI_XPL:
|
|
bgpq4_print_huawei_xpl_oaspath(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpq4_print_aslist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_aslist(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpq4_print_asset(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JSON:
|
|
bgpq4_print_json_aspath(f, b);
|
|
break;
|
|
case V_OPENBGPD:
|
|
bgpq4_print_openbgpd_asset(f, b);
|
|
break;
|
|
case V_BIRD:
|
|
bgpq4_print_bird_aspath(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL, "as-sets (-t) supported for JSON, "
|
|
"OpenBGPD, and BIRD only\n");
|
|
}
|
|
}
|
|
|
|
static int jrfilter_prefixed = 1;
|
|
|
|
static void
|
|
bgpq4_print_jrfilter(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, " %s%s exact;\n",
|
|
jrfilter_prefixed ? "route-filter " : "", prefix);
|
|
} else {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f," %s%s prefix-length-range /%u-/%u;\n",
|
|
jrfilter_prefixed ? "route-filter " : "",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f," %s%s upto /%u;\n",
|
|
jrfilter_prefixed ? "route-filter " : "",
|
|
prefix, n->aggregateHi);
|
|
}
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_jrfilter(n->son, ff);
|
|
}
|
|
|
|
static char* bname = NULL;
|
|
static int seq = 0;
|
|
|
|
static void
|
|
bgpq4_print_cprefix(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));
|
|
|
|
if (seq)
|
|
snprintf(seqno, sizeof(seqno), " seq %i", seq++);
|
|
|
|
if (n->isAggregate) {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f,"%s prefix-list %s%s permit %s ge %u le %u\n",
|
|
n->prefix->family == AF_INET ? "ip" : "ipv6",
|
|
bname ? bname : "NN", seqno, prefix,
|
|
n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f,"%s prefix-list %s%s permit %s le %u\n",
|
|
n->prefix->family == AF_INET ? "ip" : "ipv6",
|
|
bname?bname:"NN", seqno, prefix,
|
|
n->aggregateHi);
|
|
}
|
|
} else {
|
|
fprintf(f,"%s prefix-list %s%s permit %s\n",
|
|
(n->prefix->family == AF_INET) ? "ip" : "ipv6",
|
|
bname ? bname : "NN", seqno, prefix);
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_cprefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cprefixxr(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (n->isAggregate) {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f,"%s%s ge %u le %u",
|
|
needscomma ? ",\n " : " ",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f,"%s%s le %u",
|
|
needscomma ? ",\n " : " ",
|
|
prefix, n->aggregateHi);
|
|
}
|
|
} else {
|
|
fprintf(f, "%s%s",
|
|
needscomma ? ",\n " : " ",
|
|
prefix);
|
|
}
|
|
|
|
needscomma = 1;
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_cprefixxr(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_hprefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf_sep(n->prefix, prefix, sizeof(prefix), " ");
|
|
|
|
if (n->isAggregate) {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f,"ip %s-prefix %s permit %s greater-equal %u "
|
|
"less-equal %u\n",
|
|
n->prefix->family == AF_INET ? "ip" : "ipv6",
|
|
bname ? bname : "NN",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f,"ip %s-prefix %s permit %s less-equal %u\n",
|
|
n->prefix->family == AF_INET ? "ip" : "ipv6",
|
|
bname ? bname : "NN",
|
|
prefix, n->aggregateHi);
|
|
}
|
|
} else {
|
|
fprintf(f,"ip %s-prefix %s permit %s\n",
|
|
n->prefix->family == AF_INET ? "ip" : "ipv6",
|
|
bname ? bname : "NN",
|
|
prefix);
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_hprefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_hprefixxpl(struct sx_radix_node* n, void* ff)
|
|
{
|
|
char prefix[128];
|
|
FILE* f = (FILE*)ff;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf_sep(n->prefix, prefix, sizeof(prefix), " ");
|
|
|
|
if (n->isAggregate) {
|
|
if (n->aggregateLow>n->prefix->masklen) {
|
|
fprintf(f,"%s %s ge %u le %u",
|
|
needscomma ? ",\n " : " ",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f,"%s %s le %u",
|
|
needscomma ? ",\n " : " ",
|
|
prefix, n->aggregateHi);
|
|
}
|
|
} else {
|
|
fprintf(f, "%s %s",
|
|
needscomma ? ",\n " : " ",
|
|
prefix);
|
|
}
|
|
|
|
needscomma = 1;
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_hprefixxpl(n->son, ff);
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_ceacl(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
char *c;
|
|
struct in_addr netmask;
|
|
|
|
netmask.s_addr = 0xfffffffful;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
c = strchr(prefix, '/');
|
|
|
|
if (c)
|
|
*c = 0;
|
|
|
|
if (n->prefix->masklen == 32)
|
|
netmask.s_addr = 0;
|
|
else {
|
|
netmask.s_addr <<= (32 - n->prefix->masklen);
|
|
netmask.s_addr &= 0xfffffffful;
|
|
}
|
|
|
|
netmask.s_addr = htonl(netmask.s_addr);
|
|
|
|
if (n->isAggregate) {
|
|
struct in_addr mask, wildaddr, wild2addr, wildmask;
|
|
int masklen = n->aggregateLow;
|
|
|
|
mask.s_addr = 0xfffffffful;
|
|
wildaddr.s_addr = 0xfffffffful >> n->prefix->masklen;
|
|
|
|
if (n->aggregateHi == 32)
|
|
wild2addr.s_addr = 0;
|
|
else
|
|
wild2addr.s_addr = 0xfffffffful >> n->aggregateHi;
|
|
|
|
wildaddr.s_addr = wildaddr.s_addr & (~wild2addr.s_addr);
|
|
|
|
if (masklen == 32)
|
|
mask.s_addr = 0xfffffffful;
|
|
else
|
|
mask.s_addr = 0xfffffffful & (0xfffffffful << (32 - masklen));
|
|
|
|
if (n->aggregateHi == 32)
|
|
wild2addr.s_addr = 0;
|
|
else
|
|
wild2addr.s_addr = 0xfffffffful >> n->aggregateHi;
|
|
|
|
wildmask.s_addr = (0xfffffffful >> n->aggregateLow)
|
|
& (~wild2addr.s_addr);
|
|
|
|
mask.s_addr = htonl(mask.s_addr);
|
|
wildaddr.s_addr = htonl(wildaddr.s_addr);
|
|
wildmask.s_addr = htonl(wildmask.s_addr);
|
|
|
|
if (wildaddr.s_addr) {
|
|
fprintf(f, " permit ip %s ",
|
|
inet_ntoa(n->prefix->addr.addr));
|
|
fprintf(f, "%s ", inet_ntoa(wildaddr));
|
|
} else {
|
|
fprintf(f, " permit ip host %s ",
|
|
inet_ntoa(n->prefix->addr.addr));
|
|
}
|
|
|
|
if (wildmask.s_addr) {
|
|
fprintf(f, "%s ", inet_ntoa(mask));
|
|
fprintf(f, "%s\n", inet_ntoa(wildmask));
|
|
} else {
|
|
fprintf(f, "host %s\n", inet_ntoa(mask));
|
|
}
|
|
} else {
|
|
fprintf(f, " permit ip host %s host %s\n", prefix,
|
|
inet_ntoa(netmask));
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_ceacl(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_ipfilter(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
fprintf(f, " prefix %s\n", prefix);
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_nokia_ipfilter(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_ipfilter(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
fprintf(f, " prefix %s { }\n", prefix);
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_nokia_md_ipfilter(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, " prefix %s exact\n", prefix);
|
|
} else {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f," prefix %s prefix-length-range %u-%u\n",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f," prefix %s prefix-length-range %u-%u\n",
|
|
prefix, n->prefix->masklen, n->aggregateHi);
|
|
}
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_nokia_prefix(n->son, ff);
|
|
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, " prefix %s type exact {\n }\n", prefix);
|
|
} else {
|
|
if (n->aggregateLow > n->prefix->masklen) {
|
|
fprintf(f," prefix %s type range {\n"
|
|
" start-length %u\n"
|
|
" end-length %u\n }\n",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
} else {
|
|
fprintf(f," prefix %s type through {\n "
|
|
"through-length %u\n }\n", prefix,
|
|
n->aggregateHi);
|
|
}
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_nokia_md_prefix(n->son, ff);
|
|
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_srl_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
if (!n->isAggregate) {
|
|
fprintf(f, " prefix %s mask-length-range exact { }\n", prefix);
|
|
} else {
|
|
fprintf(f, " prefix %s mask-length-range %u..%u { }\n", prefix,
|
|
max(n->aggregateLow,n->prefix->masklen), n->aggregateHi);
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_nokia_srl_prefix(n->son, ff);
|
|
}
|
|
|
|
typedef struct {
|
|
FILE *f;
|
|
int seq;
|
|
} NOKIA_SRL_IPFILTER_PARAMS;
|
|
|
|
static void
|
|
bgpq4_print_nokia_srl_ipfilter(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
NOKIA_SRL_IPFILTER_PARAMS *params = (NOKIA_SRL_IPFILTER_PARAMS*) ff;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!params->f)
|
|
params->f = stdout;
|
|
|
|
sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix));
|
|
|
|
fprintf(params->f, " entry %d {\n action { accept { } }\n match { source-ip { prefix %s } } }\n", params->seq, prefix);
|
|
params->seq += 10;
|
|
|
|
checkSon:
|
|
if (n->son) {
|
|
bgpq4_print_nokia_srl_ipfilter(n->son, ff);
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
fprintf(f, "policy-options {\nreplace:\n prefix-list %s {\n",
|
|
b->name ? b->name : "NN");
|
|
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_jprefix, f);
|
|
|
|
fprintf(f, " }\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_routefilter(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
char *c = NULL;
|
|
|
|
if (b->name && (c = strchr(b->name,'/'))) {
|
|
*c = 0;
|
|
fprintf(f, "policy-options {\n policy-statement %s {\n"
|
|
" term %s {\n"
|
|
"replace:\n from {\n",
|
|
b->name, c + 1);
|
|
if (b->match)
|
|
fprintf(f, " %s;\n", b->match);
|
|
} else {
|
|
fprintf(f, "policy-options {\n policy-statement %s { \n"
|
|
"replace:\n from {\n", b->name ? b->name : "NN");
|
|
if (b->match)
|
|
fprintf(f, " %s;\n", b->match);
|
|
}
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
jrfilter_prefixed = 1;
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_jrfilter, f);
|
|
} else {
|
|
fprintf(f, " route-filter %s/0 orlonger reject;\n",
|
|
b->tree->family == AF_INET ? "0.0.0.0" : "::");
|
|
}
|
|
|
|
if (c) {
|
|
fprintf(f, " }\n }\n }\n}\n");
|
|
} else {
|
|
fprintf(f, " }\n }\n}\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
if (sx_radix_tree_empty(b->tree)) {
|
|
fprintf(f, "# generated prefix-list %s (AS %u) is empty\n",
|
|
b->name, b->asnumber);
|
|
if (!b->asnumber)
|
|
fprintf(f, "# use -a <asn> to generate \"deny from "
|
|
"ASN <asn>\" instead of this list\n");
|
|
}
|
|
|
|
if (!sx_radix_tree_empty(b->tree) || !b->asnumber) {
|
|
if (b->name) {
|
|
if (strcmp(b->name, "NN") != 0) {
|
|
fprintf(f, "%s=\"", b->name);
|
|
}
|
|
}
|
|
fprintf(f, "prefix { ");
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_openbgpd_prefix, f);
|
|
fprintf(f, "\n\t}");
|
|
if (b->name) {
|
|
if (strcmp(b->name, "NN") != 0) {
|
|
fprintf(f, "\"");
|
|
}
|
|
}
|
|
fprintf(f, "\n");
|
|
} else {
|
|
fprintf(f, "deny from AS %u\n", b->asnumber);
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_openbgpd_prefixset(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f, "prefix-set %s {", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree))
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_openbgpd_prefix, f);
|
|
|
|
fprintf(f, "\n}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cisco_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)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_cprefix, f);
|
|
} else {
|
|
fprintf(f, "! generated prefix-list %s is empty\n", bname);
|
|
fprintf(f, "%s prefix-list %s%s deny %s\n",
|
|
(b->family == AF_INET) ? "ip" : "ipv6",
|
|
bname,
|
|
seq ? " seq 1" : "",
|
|
(b->family == AF_INET) ? "0.0.0.0/0" : "::/0");
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_ciscoxr_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
fprintf(f, "no prefix-set %s\n", b->name);
|
|
fprintf(f, "prefix-set %s\n", b->name);
|
|
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_cprefixxr, f);
|
|
|
|
fprintf(f, "\nend-set\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_json_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
fprintf(f, "{ \"%s\": [", b->name);
|
|
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_json_prefix, f);
|
|
|
|
fprintf(f,"\n] }\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_bird_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
fprintf(f,"%s = [",
|
|
b->name ? b->name : "NN");
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_bird_prefix, f);
|
|
fprintf(f, "\n];\n");
|
|
} else {
|
|
SX_DEBUG(debug_expander, "skip empty prefix-list in BIRD format\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
seq = b->sequence;
|
|
|
|
fprintf(f,"undo ip %s-prefix %s\n",
|
|
(b->family == AF_INET) ? "ip" : "ipv6", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_hprefix, f);
|
|
} else {
|
|
fprintf(f, "ip %s-prefix %s%s deny %s\n",
|
|
(b->family == AF_INET) ? "ip" : "ipv6",
|
|
bname,
|
|
seq ? " seq 1" : "",
|
|
(b->family == AF_INET) ? "0.0.0.0/0" : "::/0");
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_huawei_xpl_prefixlist(FILE* f, struct bgpq_expander* b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f, "no xpl %s-prefix-list %s\nxpl %s-prefix-list %s\n", b->family==AF_INET ? "ip" : "ipv6", bname, b->family==AF_INET ? "ip" : "ipv6", bname);
|
|
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_hprefixxpl, f);
|
|
|
|
fprintf(f, "\nend-list\n");
|
|
}
|
|
|
|
static void
|
|
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");
|
|
}
|
|
}
|
|
|
|
struct fpcbdata {
|
|
FILE *f;
|
|
struct bgpq_expander *b;
|
|
};
|
|
|
|
static void
|
|
bgpq4_print_format_prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
struct fpcbdata *fpc = (struct fpcbdata*)ff;
|
|
FILE *f = fpc->f;
|
|
struct bgpq_expander *b = fpc->b;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (!n->isAggregate) {
|
|
sx_prefix_snprintf_fmt(n->prefix, f,
|
|
b->name ? b->name : "NN",
|
|
b->format,
|
|
n->prefix->masklen,
|
|
n->prefix->masklen);
|
|
} else if (n->aggregateLow > n->prefix->masklen) {
|
|
sx_prefix_snprintf_fmt(n->prefix, f,
|
|
b->name ? b->name : "NN",
|
|
b->format,
|
|
n->aggregateLow,
|
|
n->aggregateHi);
|
|
} else {
|
|
sx_prefix_snprintf_fmt(n->prefix, f,
|
|
b->name ? b->name : "NN",
|
|
b->format,
|
|
n->prefix->masklen,
|
|
n->aggregateHi);
|
|
}
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_format_prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_format_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
struct fpcbdata ff = {.f=f, .b=b};
|
|
int len = strlen(b->format);
|
|
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_format_prefix, &ff);
|
|
|
|
// Add newline if format doesn't already end with one.
|
|
if (len < 2 ||
|
|
!(b->format[len-2] == '\\' && b->format[len-1] == 'n'))
|
|
fprintf(f, "\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
fprintf(f,"configure router policy-options\nbegin\nno prefix-list \"%s\"\n",
|
|
bname);
|
|
fprintf(f,"prefix-list \"%s\"\n", bname);
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_prefix, f);
|
|
fprintf(f,"exit\ncommit\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_cisco_eacl(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f,"no ip access-list extended %s\n", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
fprintf(f, "ip access-list extended %s\n", bname);
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_ceacl, f);
|
|
} else {
|
|
fprintf(f, "! generated access-list %s is empty\n", bname);
|
|
fprintf(f, "ip access-list extended %s deny any any\n", bname);
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_ipprefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f, "configure filter match-list\nno %s-prefix-list \"%s\"\n",
|
|
(b->tree->family == AF_INET) ? "ip" : "ipv6", bname);
|
|
|
|
fprintf(f, "%s-prefix-list \"%s\" create\n",
|
|
b->tree->family == AF_INET ? "ip":"ipv6", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_ipfilter, f);
|
|
} else {
|
|
fprintf(f, "# generated ip-prefix-list %s is empty\n", bname);
|
|
}
|
|
|
|
fprintf(f,"exit\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f,"/configure filter match-list\ndelete %s-prefix-list \"%s\"\n",
|
|
b->tree->family == AF_INET ? "ip" : "ipv6", bname);
|
|
|
|
fprintf(f,"%s-prefix-list \"%s\" {\n",
|
|
b->tree->family == AF_INET ? "ip" : "ipv6", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_md_ipfilter, f);
|
|
} else {
|
|
fprintf(f,"# generated %s-prefix-list %s is empty\n",
|
|
b->tree->family == AF_INET ? "ip" : "ipv6", bname);
|
|
}
|
|
|
|
fprintf(f,"}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_md_ipprefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f, "/configure policy-options\ndelete prefix-list \"%s\"\n",
|
|
bname);
|
|
|
|
fprintf(f, "prefix-list \"%s\" {\n", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_md_prefix, f);
|
|
}
|
|
|
|
fprintf(f,"}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_srl_prefixset(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f, "/routing-policy\ndelete prefix-set \"%s\"\n",
|
|
bname);
|
|
|
|
fprintf(f, "prefix-set \"%s\" {\n", bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_srl_prefix, f);
|
|
}
|
|
|
|
fprintf(f,"}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_nokia_srl_aclipfilter(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
|
|
fprintf(f,"/acl \ndelete ipv%c-filter \"%s\"\n",
|
|
b->tree->family == AF_INET ? '4' : '6', bname);
|
|
|
|
fprintf(f,"ipv%c-filter \"%s\" {\n",
|
|
b->tree->family == AF_INET ? '4' : '6', bname);
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
NOKIA_SRL_IPFILTER_PARAMS params = { f, 10 };
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_nokia_srl_ipfilter, ¶ms);
|
|
} else {
|
|
fprintf(f,"# generated ipv%c-filter '%s' is empty\n",
|
|
b->tree->family == AF_INET ? '4' : '6', bname);
|
|
}
|
|
|
|
fprintf(f,"}\n");
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_k6prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf_sep(n->prefix, prefix, sizeof(prefix), "/");
|
|
|
|
if (n->isAggregate)
|
|
fprintf(f,"/routing filter add action=accept chain=\""
|
|
"%s-%s\" prefix=%s prefix-length=%d-%d\n",
|
|
bname ? bname : "NN",
|
|
n->prefix->family == AF_INET ? "V4" : "V6",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
else
|
|
fprintf(f,"/routing filter add action=accept chain=\""
|
|
"%s-%s\" prefix=%s\n",
|
|
bname ? bname : "NN",
|
|
n->prefix->family == AF_INET ? "V4" : "V6",
|
|
prefix);
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_k6prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_k7prefix(struct sx_radix_node *n, void *ff)
|
|
{
|
|
char prefix[128];
|
|
FILE *f = (FILE*)ff;
|
|
|
|
if (!f)
|
|
f = stdout;
|
|
|
|
if (n->isGlue)
|
|
goto checkSon;
|
|
|
|
sx_prefix_snprintf_sep(n->prefix, prefix, sizeof(prefix), "/");
|
|
|
|
if (n->isAggregate)
|
|
fprintf(f,"/routing filter rule add chain=\""
|
|
"%s-%s\" rule=\"if (dst in %s && dst-len in %d-%d) {accept}\"\n",
|
|
bname ? bname : "NN",
|
|
n->prefix->family == AF_INET ? "V4" : "V6",
|
|
prefix, n->aggregateLow, n->aggregateHi);
|
|
else
|
|
fprintf(f,"/routing filter rule add chain=\""
|
|
"%s-%s\" rule=\"if (dst==%s) {accept}\"\n",
|
|
bname ? bname : "NN",
|
|
n->prefix->family == AF_INET ? "V4" : "V6",
|
|
prefix);
|
|
|
|
checkSon:
|
|
if (n->son)
|
|
bgpq4_print_k7prefix(n->son, ff);
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_mikrotik_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
bname = b->name ? b->name : "NN";
|
|
void *cbfunc = bgpq4_print_k6prefix;
|
|
|
|
if (b->vendor == V_MIKROTIK7)
|
|
cbfunc = bgpq4_print_k7prefix;
|
|
|
|
if (!sx_radix_tree_empty(b->tree)) {
|
|
sx_radix_tree_foreach(b->tree, cbfunc, f);
|
|
} else {
|
|
fprintf(f, "# generated prefix-list %s is empty\n", bname);
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpq4_print_prefixlist(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_prefixlist(f, b);
|
|
break;
|
|
case V_CISCO:
|
|
bgpq4_print_cisco_prefixlist(f, b);
|
|
break;
|
|
case V_CISCO_XR:
|
|
bgpq4_print_ciscoxr_prefixlist(f, b);
|
|
break;
|
|
case V_JSON:
|
|
bgpq4_print_json_prefixlist(f, b);
|
|
break;
|
|
case V_BIRD:
|
|
bgpq4_print_bird_prefixlist(f, b);
|
|
break;
|
|
case V_OPENBGPD:
|
|
bgpq4_print_openbgpd_prefixlist(f, b);
|
|
break;
|
|
case V_FORMAT:
|
|
bgpq4_print_format_prefixlist(f, b);
|
|
break;
|
|
case V_NOKIA:
|
|
bgpq4_print_nokia_prefixlist(f, b);
|
|
break;
|
|
case V_NOKIA_MD:
|
|
bgpq4_print_nokia_md_ipprefixlist(f, b);
|
|
break;
|
|
case V_NOKIA_SRL:
|
|
bgpq4_print_nokia_srl_prefixset(f, b);
|
|
break;
|
|
case V_HUAWEI:
|
|
bgpq4_print_huawei_prefixlist(f, b);
|
|
break;
|
|
case V_HUAWEI_XPL:
|
|
bgpq4_print_huawei_xpl_prefixlist(f, b);
|
|
break;
|
|
case V_MIKROTIK6:
|
|
case V_MIKROTIK7:
|
|
bgpq4_print_mikrotik_prefixlist(f, b);
|
|
break;
|
|
case V_ARISTA:
|
|
bgpq4_print_arista_prefixlist(f, b);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
bgpq4_print_eacl(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch (b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_routefilter(f, b);
|
|
break;
|
|
case V_CISCO:
|
|
case V_ARISTA:
|
|
bgpq4_print_cisco_eacl(f, b);
|
|
break;
|
|
case V_OPENBGPD:
|
|
bgpq4_print_openbgpd_prefixset(f, b);
|
|
break;
|
|
case V_NOKIA:
|
|
bgpq4_print_nokia_ipprefixlist(f, b);
|
|
break;
|
|
case V_NOKIA_MD:
|
|
bgpq4_print_nokia_md_prefixlist(f, b);
|
|
break;
|
|
case V_NOKIA_SRL:
|
|
bgpq4_print_nokia_srl_aclipfilter(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL, "unreachable point\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
bgpq4_print_juniper_route_filter_list(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
fprintf(f, "policy-options {\nreplace:\n route-filter-list %s {\n",
|
|
b->name ? b->name : "NN");
|
|
|
|
if (sx_radix_tree_empty(b->tree)) {
|
|
fprintf(f, " %s/0 orlonger reject;\n",
|
|
b->tree->family == AF_INET ? "0.0.0.0" : "::");
|
|
} else {
|
|
jrfilter_prefixed = 0;
|
|
sx_radix_tree_foreach(b->tree, bgpq4_print_jrfilter, f);
|
|
}
|
|
|
|
fprintf(f, " }\n}\n");
|
|
}
|
|
|
|
void
|
|
bgpq4_print_route_filter_list(FILE *f, struct bgpq_expander *b)
|
|
{
|
|
switch(b->vendor) {
|
|
case V_JUNIPER:
|
|
bgpq4_print_juniper_route_filter_list(f, b);
|
|
break;
|
|
default:
|
|
sx_report(SX_FATAL, "unreachable point\n");
|
|
}
|
|
}
|