On Sat, Nov 10, 2012 at 03:38:15PM +0100, Claudio Jeker wrote: > In some cases it helps to be able to restrict nexthops from pathes > received. E.g. at IXP where only routes originating from the neighbor > should be accepted. > > This diff implements this for bgpd.
Updated diff that fixes a missing break. Found by Florian. -- :wq Claudio Index: bgpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v retrieving revision 1.121 diff -u -p -r1.121 bgpd.conf.5 --- bgpd.conf.5 24 Aug 2012 17:04:06 -0000 1.121 +++ bgpd.conf.5 28 Oct 2012 13:38:06 -0000 @@ -1175,6 +1175,17 @@ is repeated more than .Ar len times. .Pp +.It Ic nexthop Ar address +This rule applies only to +.Em UPDATES +where the nexthop is equal to +.Ar address. +The +.Ar address +can be set to +.Em neighbor +in which case the nexthop is compared against the address of the neighbor. +.Pp .It Xo .Ic prefix .Ar address Ns Li / Ns Ar len Index: bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.273 diff -u -p -r1.273 bgpd.h --- bgpd.h 18 Sep 2012 10:10:00 -0000 1.273 +++ bgpd.h 28 Oct 2012 13:00:03 -0000 @@ -749,6 +749,13 @@ struct filter_prefix { u_int8_t len; }; +struct filter_nexthop { + struct bgpd_addr addr; + u_int8_t flags; +#define FILTER_NEXTHOP_ADDR 1 +#define FILTER_NEXTHOP_NEIGHBOR 2 +}; + struct filter_prefixlen { enum comp_ops op; u_int8_t aid; @@ -759,6 +766,7 @@ struct filter_prefixlen { struct filter_match { struct filter_prefix prefix; struct filter_prefixlen prefixlen; + struct filter_nexthop nexthop; struct filter_as as; struct filter_aslen aslen; struct filter_community community; Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.264 diff -u -p -r1.264 parse.y --- parse.y 23 Sep 2012 09:39:17 -0000 1.264 +++ parse.y 28 Oct 2012 13:29:16 -0000 @@ -1700,6 +1700,26 @@ filter_elm : filter_prefix_h { } fmopts.aid = AID_INET6; } + | NEXTHOP address { + if (fmopts.m.nexthop.flags) { + yyerror("nexthop already specified"); + YYERROR; + } + if (fmopts.aid && fmopts.aid != $2.aid) { + yyerror("nexthop address family doesn't match " + "rule address family"); + YYERROR; + } + fmopts.m.nexthop.addr = $2; + fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; + } + | NEXTHOP NEIGHBOR { + if (fmopts.m.nexthop.flags) { + yyerror("nexthop already specified"); + YYERROR; + } + fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; + } ; prefixlenop : unaryop NUMBER { Index: printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v retrieving revision 1.88 diff -u -p -r1.88 printconf.c --- printconf.c 23 Sep 2012 09:39:18 -0000 1.88 +++ printconf.c 28 Oct 2012 13:33:58 -0000 @@ -561,6 +561,13 @@ print_rule(struct peer *peer_l, struct f } } + if (r->match.nexthop.flags) { + if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR) + printf("nexthop neighbor "); + else + printf("nexthop %s ", log_addr(&r->match.nexthop.addr)); + } + if (r->match.as.type) { if (r->match.as.type == AS_ALL) printf("AS %s ", log_as(r->match.as.as)); Index: rde_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v retrieving revision 1.67 diff -u -p -r1.67 rde_filter.c --- rde_filter.c 20 Sep 2011 21:19:06 -0000 1.67 +++ rde_filter.c 10 Nov 2012 17:50:31 -0000 @@ -384,6 +384,34 @@ rde_filter_match(struct filter_rule *f, } /* NOTREACHED */ } + if (f->match.nexthop.flags != 0) { + struct bgpd_addr *nexthop, *cmpaddr; + if (asp->nexthop == NULL) + /* no nexthop, skip */ + return (0); + nexthop = &asp->nexthop->exit_nexthop; + if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR) + cmpaddr = &f->match.nexthop.addr; + else + cmpaddr = &asp->peer->remote_addr; + if (cmpaddr->aid != nexthop->aid) + /* don't use IPv4 rules for IPv6 and vice versa */ + return (0); + + switch (cmpaddr->aid) { + case AID_INET: + if (cmpaddr->v4.s_addr != nexthop->v4.s_addr) + return (0); + break; + case AID_INET6: + if (memcmp(&cmpaddr->v6, &nexthop->v6, + sizeof(struct in6_addr))) + return (0); + break; + default: + fatalx("King Bula lost in address space"); + } + } /* matched somewhen or is anymatch rule */ return (1);