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.
OK?
-- 
: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        29 Oct 2012 06:55:06 -0000
@@ -384,6 +384,33 @@ 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);
+               default:
+                       fatalx("King Bula lost in address space");
+               }
+       }
 
        /* matched somewhen or is anymatch rule  */
        return (1);

Reply via email to