On Sat, Nov 10, 2012 at 06:52:17PM +0100, Claudio Jeker wrote:
> 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.

Another bug found by Florian Obser. This time the "netxhop neighbor"
feature crashed the rde because the asp passed around in the filter is not
linked and therefor asp->peer is NULL. Oups.
Since rde_filter() already carries the from peer just pass that info down.

-- 
: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 20:56:14 -0000
@@ -26,7 +26,7 @@
 #include "rde.h"
 
 int    rde_filter_match(struct filter_rule *, struct rde_aspath *,
-           struct bgpd_addr *, u_int8_t, struct rde_peer *);
+           struct bgpd_addr *, u_int8_t, struct rde_peer *, struct rde_peer *);
 int    filterset_equal(struct filter_set_head *, struct filter_set_head *);
 
 enum filter_actions
@@ -58,7 +58,7 @@ rde_filter(u_int16_t ribid, struct rde_a
                if (f->peer.peerid != 0 &&
                    f->peer.peerid != peer->conf.id)
                        continue;
-               if (rde_filter_match(f, asp, prefix, prefixlen, peer)) {
+               if (rde_filter_match(f, asp, prefix, prefixlen, peer, from)) {
                        if (asp != NULL && new != NULL) {
                                /* asp may get modified so create a copy */
                                if (*new == NULL) {
@@ -267,7 +267,8 @@ rde_apply_set(struct rde_aspath *asp, st
 
 int
 rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
-    struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer)
+    struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer,
+    struct rde_peer *from)
 {
        u_int32_t       pas;
        int             cas, type;
@@ -383,6 +384,34 @@ rde_filter_match(struct filter_rule *f, 
                        return (plen > f->match.prefixlen.len_min);
                }
                /* 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 = &from->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  */

Reply via email to