summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpctl
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2005-05-23 20:09:01 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2005-05-23 20:09:01 +0000
commit4288617b8956c4d3682de202b8ea9910aa6562e4 (patch)
tree9cfb4f7d7a73e93a4ac7b997d0f607d3b3f11883 /usr.sbin/bgpctl
parentc114f2f1476430301aa197bb366ec0728071e8d3 (diff)
Make it possible to dynamicaly add networks with attributes like communities
or metrics. Requested by beck@ OK henning@
Diffstat (limited to 'usr.sbin/bgpctl')
-rw-r--r--usr.sbin/bgpctl/bgpctl.c17
-rw-r--r--usr.sbin/bgpctl/parser.c328
-rw-r--r--usr.sbin/bgpctl/parser.h3
3 files changed, 340 insertions, 8 deletions
diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c
index fb1c5c28661..fdedf94076a 100644
--- a/usr.sbin/bgpctl/bgpctl.c
+++ b/usr.sbin/bgpctl/bgpctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpctl.c,v 1.78 2005/04/18 11:09:51 claudio Exp $ */
+/* $OpenBSD: bgpctl.c,v 1.79 2005/05/23 20:08:59 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
@@ -68,6 +68,7 @@ void show_rib_summary_head(void);
void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
const char * print_origin(u_int8_t, int);
int show_rib_summary_msg(struct imsg *);
+void send_filterset(struct imsgbuf *, struct filter_set_head *);
struct imsgbuf *ibuf;
@@ -225,6 +226,7 @@ main(int argc, char *argv[])
if (res->action == NETWORK_ADD) {
imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
&net, sizeof(net));
+ send_filterset(ibuf, &res->set);
imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1,
NULL, 0);
} else
@@ -966,3 +968,16 @@ show_rib_summary_msg(struct imsg *imsg)
return (0);
}
+void
+send_filterset(struct imsgbuf *i, struct filter_set_head *set)
+{
+ struct filter_set *s;
+
+ while ((s = SIMPLEQ_FIRST(set)) != NULL) {
+ imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
+ sizeof(struct filter_set));
+ SIMPLEQ_REMOVE_HEAD(set, entry);
+ free(s);
+ }
+}
+
diff --git a/usr.sbin/bgpctl/parser.c b/usr.sbin/bgpctl/parser.c
index 3b47eb99b79..618f637b020 100644
--- a/usr.sbin/bgpctl/parser.c
+++ b/usr.sbin/bgpctl/parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.c,v 1.12 2004/12/23 17:55:59 henning Exp $ */
+/* $OpenBSD: parser.c,v 1.13 2005/05/23 20:09:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -34,7 +34,15 @@ enum token_type {
ASNUM,
ASTYPE,
PREFIX,
- PEERDESC
+ PEERDESC,
+ COMMUNITY,
+ LOCALPREF,
+ MED,
+ NEXTHOP,
+ PFTABLE,
+ PREPNBR,
+ PREPSELF,
+ WEIGHT
};
struct token {
@@ -56,15 +64,24 @@ static const struct token t_neighbor_modifiers[];
static const struct token t_show_as[];
static const struct token t_show_prefix[];
static const struct token t_show_ip[];
-static const struct token t_nexthop[];
+static const struct token t_network[];
static const struct token t_prefix[];
+static const struct token t_set[];
+static const struct token t_community[];
+static const struct token t_localpref[];
+static const struct token t_med[];
+static const struct token t_nexthop[];
+static const struct token t_pftable[];
+static const struct token t_prepnbr[];
+static const struct token t_prepself[];
+static const struct token t_weight[];
static const struct token t_main[] = {
{ KEYWORD, "reload", RELOAD, NULL},
{ KEYWORD, "show", SHOW, t_show},
{ KEYWORD, "fib", FIB, t_fib},
{ KEYWORD, "neighbor", NEIGHBOR, t_neighbor},
- { KEYWORD, "network", NONE, t_nexthop},
+ { KEYWORD, "network", NONE, t_network},
{ ENDTOKEN, "", NONE, NULL}
};
@@ -151,7 +168,7 @@ static const struct token t_show_ip[] = {
{ ENDTOKEN, "", NONE, NULL}
};
-static const struct token t_nexthop[] = {
+static const struct token t_network[] = {
{ KEYWORD, "add", NETWORK_ADD, t_prefix},
{ KEYWORD, "delete", NETWORK_REMOVE, t_prefix},
{ KEYWORD, "flush", NETWORK_FLUSH, NULL},
@@ -160,10 +177,65 @@ static const struct token t_nexthop[] = {
};
static const struct token t_prefix[] = {
- { PREFIX, "", NONE, NULL},
+ { PREFIX, "", NONE, t_set},
{ ENDTOKEN, "", NONE, NULL}
};
+static const struct token t_set[] = {
+ { NOTOKEN, "", NONE, NULL},
+ { KEYWORD, "community", NONE, t_community},
+ { KEYWORD, "localpref", NONE, t_localpref},
+ { KEYWORD, "med", NONE, t_med},
+ { KEYWORD, "metric", NONE, t_med},
+ { KEYWORD, "nexthop", NONE, t_nexthop},
+ { KEYWORD, "pftable", NONE, t_pftable},
+ { KEYWORD, "prepend-neighbor", NONE, t_prepnbr},
+ { KEYWORD, "prepend-self", NONE, t_prepself},
+ { KEYWORD, "weight", NONE, t_weight},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_community[] = {
+ { COMMUNITY, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_localpref[] = {
+ { LOCALPREF, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_med[] = {
+ { MED, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_nexthop[] = {
+ { NEXTHOP, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_pftable[] = {
+ { PFTABLE, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_prepnbr[] = {
+ { PREPNBR, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_prepself[] = {
+ { PREPSELF, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_weight[] = {
+ { WEIGHT, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+
static struct parse_result res;
const struct token *match_token(const char *, const struct token []);
@@ -172,6 +244,11 @@ int parse_addr(const char *, struct bgpd_addr *);
int parse_prefix(const char *, struct bgpd_addr *,
u_int8_t *);
int parse_asnum(const char *, u_int16_t *);
+int parse_number(const char *, struct parse_result *,
+ enum token_type);
+int getcommunity(const char *);
+int parse_community(const char *, struct parse_result *);
+int parse_nexthop(const char *, struct parse_result *);
struct parse_result *
parse(int argc, char *argv[])
@@ -180,6 +257,7 @@ parse(int argc, char *argv[])
const struct token *match;
bzero(&res, sizeof(res));
+ SIMPLEQ_INIT(&res.set);
while (argc > 0) {
if ((match = match_token(argv[0], table)) == NULL) {
@@ -210,6 +288,7 @@ match_token(const char *word, const struct token table[])
{
u_int i, match;
const struct token *t = NULL;
+ struct filter_set *fs;
match = 0;
@@ -278,6 +357,49 @@ match_token(const char *word, const struct token table[])
t = &table[i];
}
break;
+ case COMMUNITY:
+ if (word != NULL && strlen(word) > 0 &&
+ parse_community(word, &res)) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case LOCALPREF:
+ case MED:
+ case PREPNBR:
+ case PREPSELF:
+ case WEIGHT:
+ if (word != NULL && strlen(word) > 0 &&
+ parse_number(word, &res, table[i].type)) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case NEXTHOP:
+ if (word != NULL && strlen(word) > 0 &&
+ parse_nexthop(word, &res)) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case PFTABLE:
+ if (word != NULL && strlen(word) > 0) {
+ if ((fs = calloc(1,
+ sizeof(struct filter_set))) == NULL)
+ err(1, NULL);
+ if (strlcpy(fs->action.pftable, word,
+ sizeof(fs->action.pftable)) >=
+ sizeof(fs->action.pftable)) {
+ fprintf(stderr,
+ "pftable name too long");
+ free(fs);
+ break;
+ }
+ SIMPLEQ_INSERT_TAIL(&res.set, fs, entry);
+ match++;
+ t = &table[i];
+ }
+ break;
case ENDTOKEN:
break;
}
@@ -321,6 +443,22 @@ show_valid_args(const struct token table[])
case PEERDESC:
fprintf(stderr, " <neighbor description>\n");
break;
+ case COMMUNITY:
+ fprintf(stderr, " <community>\n");
+ break;
+ case LOCALPREF:
+ case MED:
+ case PREPNBR:
+ case PREPSELF:
+ case WEIGHT:
+ fprintf(stderr, " <number>\n");
+ break;
+ case NEXTHOP:
+ fprintf(stderr, " <address>\n");
+ break;
+ case PFTABLE:
+ fprintf(stderr, " <pftable>\n");
+ break;
case ENDTOKEN:
break;
}
@@ -395,3 +533,181 @@ parse_asnum(const char *word, u_int16_t *asnum)
*asnum = (u_int16_t)ulval;
return (1);
}
+
+int
+parse_number(const char *word, struct parse_result *r, enum token_type type)
+{
+ struct filter_set *fs;
+ u_long ulval;
+ char *ep;
+
+ if (word == NULL)
+ return (0);
+
+ errno = 0;
+ ulval = strtoul(word, &ep, 0);
+ if (word[0] == '\0' || *ep != '\0')
+ return (0);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (0);
+ if (ulval > UINT_MAX)
+ return (0);
+
+ /* number was parseable */
+ if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
+ err(1, NULL);
+ switch (type) {
+ case LOCALPREF:
+ fs->type = ACTION_SET_LOCALPREF;
+ fs->action.metric = ulval;
+ break;
+ case MED:
+ fs->type = ACTION_SET_MED;
+ fs->action.metric = ulval;
+ break;
+ case PREPNBR:
+ if (ulval > 128) {
+ free(fs);
+ return (0);
+ }
+ fs->type = ACTION_SET_PREPEND_PEER;
+ fs->action.prepend = ulval;
+ break;
+ case PREPSELF:
+ if (ulval > 128) {
+ free(fs);
+ return (0);
+ }
+ fs->type = ACTION_SET_PREPEND_SELF;
+ fs->action.prepend = ulval;
+ break;
+ case WEIGHT:
+ fs->type = ACTION_SET_WEIGHT;
+ fs->action.metric = ulval;
+ break;
+ default:
+ errx(1, "king bula sez bad things happen");
+ }
+
+ SIMPLEQ_INSERT_TAIL(&r->set, fs, entry);
+ return (1);
+}
+
+int
+getcommunity(const char *s)
+{
+ char *ep;
+ u_long ulval;
+
+ if (strcmp(s, "*") == 0)
+ return (COMMUNITY_ANY);
+
+ errno = 0;
+ ulval = strtoul(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0')
+ return (COMMUNITY_ERROR);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (COMMUNITY_ERROR);
+ if (ulval > USHRT_MAX)
+ return (COMMUNITY_ERROR);
+
+ return (ulval);
+}
+
+int
+parse_community(const char *word, struct parse_result *r)
+{
+ struct filter_set *fs;
+ char *p;
+ int i;
+ u_int16_t as, type;
+
+ /* Well-known communities */
+ if (strcasecmp(word, "NO_EXPORT") == 0) {
+ as = COMMUNITY_WELLKNOWN;
+ type = COMMUNITY_NO_EXPORT;
+ goto done;
+ } else if (strcasecmp(word, "NO_ADVERTISE") == 0) {
+ as = COMMUNITY_WELLKNOWN;
+ type = COMMUNITY_NO_ADVERTISE;
+ goto done;
+ } else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) {
+ as = COMMUNITY_WELLKNOWN;
+ type = COMMUNITY_NO_EXPSUBCONFED;
+ goto done;
+ } else if (strcasecmp(word, "NO_PEER") == 0) {
+ as = COMMUNITY_WELLKNOWN;
+ type = COMMUNITY_NO_PEER;
+ goto done;
+ }
+
+ if ((p = strchr(word, ':')) == NULL) {
+ fprintf(stderr, "Bad community syntax\n");
+ return (0);
+ }
+ *p++ = 0;
+
+ if ((i = getcommunity(word)) == COMMUNITY_ERROR) {
+ fprintf(stderr, "\"%s\" is not a number or too big", word);
+ return (0);
+ }
+ as = i;
+
+ if ((i = getcommunity(p)) == COMMUNITY_ERROR) {
+ fprintf(stderr, "\"%s\" is not a number or too big", p);
+ return (0);
+ }
+ type = i;
+
+done:
+ if (as == 0 || as == USHRT_MAX) {
+ fprintf(stderr, "Invalid community\n");
+ return (0);
+ }
+ if (as == COMMUNITY_WELLKNOWN)
+ switch (type) {
+ case COMMUNITY_NO_EXPORT:
+ case COMMUNITY_NO_ADVERTISE:
+ case COMMUNITY_NO_EXPSUBCONFED:
+ /* valid */
+ break;
+ default:
+ /* unknown */
+ fprintf(stderr, "Invalid well-known community\n");
+ return (0);
+ }
+
+ if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
+ err(1, NULL);
+ fs->type = ACTION_SET_COMMUNITY;
+ fs->action.community.as = as;
+ fs->action.community.type = type;
+
+ SIMPLEQ_INSERT_TAIL(&r->set, fs, entry);
+ return (1);
+}
+
+int
+parse_nexthop(const char *word, struct parse_result *r)
+{
+ struct filter_set *fs;
+
+ if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
+ err(1, NULL);
+
+ if (strcmp(word, "blackhole") == 0)
+ fs->type = ACTION_SET_NEXTHOP_BLACKHOLE;
+ else if (strcmp(word, "reject") == 0)
+ fs->type = ACTION_SET_NEXTHOP_REJECT;
+ else if (strcmp(word, "no-modify") == 0)
+ fs->type = ACTION_SET_NEXTHOP_NOMODIFY;
+ else if (parse_addr(word, &fs->action.nexthop)) {
+ fs->type = ACTION_SET_NEXTHOP;
+ } else {
+ free(fs);
+ return (0);
+ }
+
+ SIMPLEQ_INSERT_TAIL(&r->set, fs, entry);
+ return (1);
+}
diff --git a/usr.sbin/bgpctl/parser.h b/usr.sbin/bgpctl/parser.h
index 44b0706affb..87b0aab439a 100644
--- a/usr.sbin/bgpctl/parser.h
+++ b/usr.sbin/bgpctl/parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.h,v 1.7 2004/12/23 17:26:51 henning Exp $ */
+/* $OpenBSD: parser.h,v 1.8 2005/05/23 20:09:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -51,6 +51,7 @@ struct parse_result {
enum actions action;
int flags;
u_int8_t prefixlen;
+ struct filter_set_head set;
};
struct parse_result *parse(int, char *[]);