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);

Reply via email to