Published : 2013-05-31

OpenOSPF patch

Because we are installing a new intersite link, with new border routers (BGP+OSPF) on OpenBSD, i have realized that OpenOSPF has some technical limitations.

Indeed my routers to distribute routes via GRE+OSPF redistribute default route (mandatory for internal routers) and this route is also redistributed on the GRE tunnel and create a routing loop on the WAN.

The second limitation is BGP and OSPF. OSPF overrides BGP and if we double the border routers, the default route is learnt from the other border router and incude a routing loop.

OpenOSPF didn’t have filtering meaning, and i need to get a meaning faster, i have decided to patch the service to add filtering option which keep SPF algorithm coherence and forbid system to add route.

I share you this little patch (147 lines) which permit you to add this function (based on OpenOSPF on OpenBSD 5.3), under BSD license.

--- /root/ospfd/ospfd.c 2011-11-15 05:17:46.000000000 +0100
+++ /usr/src/usr.sbin/ospfd/ospfd.c     2013-05-31 22:38:22.202030731 +0200
@@ -1,6 +1,7 @@
-/*   $OpenBSD: ospfd.c,v 1.78 2011/08/20 11:16:09 sthen Exp $ */
+/*   $OpenBSD: ospfd.c,v 1.79 2013/05/31 22:35:17 sthen Exp $ */

 /*
+ * Copyright (c) 2013 Loic Blot <loic.blot@unix-experience.fr>
  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -680,6 +681,7 @@
        struct area             *a, *xa, *na;
        struct iface            *iface;
        struct redistribute     *r;
+       struct kroute_filter *rf, *nrf;
        int                      rchange = 0;

        /* change of rtr_id needs a restart */
@@ -701,6 +703,14 @@
                        SIMPLEQ_REMOVE_HEAD(&xconf->redist_list, entry);
                        SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry);
                }
+               for (rf = LIST_FIRST(&conf->kroute_filter_list); rf != NULL; rf =
nrf) {
+                       nrf = LIST_NEXT(rf, entry);
+                       kr_filter_del(rf);
+               }
+               for (rf = LIST_FIRST(&xconf->kroute_filter_list); rf != NULL; rf =
nrf) {
+                       nrf = LIST_NEXT(rf, entry);
+                       LIST_INSERT_HEAD(&conf->kroute_filter_list, rf, entry);
+               }
                goto done;
        }

@@ -891,3 +901,26 @@
                        return (i);
        return (NULL);
 }
+
+int
+kr_filter_do(struct kroute *kr)
+{
+       struct kroute_filter    *i;
+       
+       LIST_FOREACH(i, &ospfd_conf->kroute_filter_list, entry) {
+               /*
+                * TODO: filter all routes for one nexthop
+                */
+               if (i->prefix.s_addr == kr->prefix.s_addr &&
+                   i->prefixlen == kr->prefixlen &&
+                   (i->nexthop.s_addr == kr->nexthop.s_addr ||
+                   i->nexthop.s_addr == INADDR_ANY)) {
+                               log_info("ospfd_filternexthop: filtering route %s/%u",
+                                       inet_ntoa(i->prefix), i->prefixlen);
+                               log_info("ospfd_filternexthop: nexthop is %s",
+                                       inet_ntoa(i->nexthop));
+                               return (1);
+               }
+       }
+       return (0);
+}

--- /root/ospfd/ospfd.h 2013-02-16 04:03:42.000000000 +0100
+++ /usr/src/usr.sbin/ospfd/ospfd.h     2013-05-31 22:38:44.768029188 +0200
@@ -1,6 +1,7 @@
-/*   $OpenBSD: ospfd.h,v 1.91 2013/01/17 10:07:56 markus Exp $ */
+/*   $OpenBSD: ospfd.h,v 1.92 2013/05/31 22:38:56 markus Exp $ */

 /*
+ * Copyright (c) 2013 Loic Blot <loic.blot@unix-experience.fr>
  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
  *
@@ -387,6 +388,7 @@
        u_int8_t                border;
        u_int8_t                redistribute;
        u_int                   rdomain;
+       LIST_HEAD(, kroute_filter)      kroute_filter_list;
        char                    *csock;
 };

@@ -526,6 +528,14 @@
        int                      level;
 };

+/* kernel route filtering */
+struct kroute_filter {
+       LIST_ENTRY(kroute_filter)       entry;
+       struct in_addr           prefix;
+       struct in_addr           nexthop;
+       u_int8_t                 prefixlen;
+};
+
 /* area.c */
 struct area    *area_new(void);
 int             area_del(struct area *);
@@ -564,6 +574,9 @@
 void            kr_ifinfo(char *, pid_t);
 struct kif     *kif_findname(char *, struct in_addr, struct kif_addr **);
 void            kr_reload(void);
+struct kroute_filter *kr_filter_new(struct in_addr, struct in_addr,
u_int8_t);
+void kr_filter_del(struct kroute_filter *);
+struct kroute_filter *kr_filter_find(struct ospfd_conf *, struct
in_addr, struct in_addr, u_int8_t);

 u_int8_t       mask2prefixlen(in_addr_t);
 in_addr_t      prefixlen2mask(u_int8_t);
@@ -592,6 +605,7 @@
 void   imsg_event_add(struct imsgev *);
 int    imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
            pid_t, int, void *, u_int16_t);
+int             kr_filter_do(struct kroute *);

 /* printconf.c */
 void   print_config(struct ospfd_conf *);

--- /root/ospfd/parse.y 2010-12-20 19:09:24.000000000 +0100
+++ /usr/src/usr.sbin/ospfd/parse.y     2013-05-31 22:39:09.098027524 +0200
@@ -1,6 +1,7 @@
-/*   $OpenBSD: parse.y,v 1.73 2010/12/13 13:43:37 bluhm Exp $ */
+/*   $OpenBSD: parse.y,v 1.74 2013/05/31 22:12:08 bluhm Exp $ */

 /*
+ * Copyright (c) 2013 Loic Blot <loic.blot@unix-experience.fr>
  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -116,12 +117,14 @@

 %}

-%token AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
-%token RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
+%token AREA INTERFACE ROUTERID FIBUPDATE
+%token REDISTRIBUTE RTLABEL RDOMAIN RFC1583COMPAT STUB ROUTER SPFDELAY
+%token SPFHOLDTIME EXTTAG
 %token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
 %token METRIC PASSIVE
 %token HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY
 %token RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
+%token KROUTEIGNOREINSERT PREFIXLEN NEXTHOP
 %token SET TYPE
 %token YES NO
 %token MSEC MINIMAL
@@ -435,7 +438,32 @@
                }
                ;

-defaults       : METRIC NUMBER {
+defaults       : KROUTEIGNOREINSERT STRING PREFIXLEN NUMBER NEXTHOP STRING {
+                       struct kroute_filter* kroute_filter;
+                       struct in_addr prefix;
+                       struct in_addr nexthop;
+                       u_int8_t prefixlen;
+                       
+                       if (!inet_aton($2, &prefix)) {
+                               yyerror("bad network: %llu/%llu", $2, $4);
+                               free($2);
+                               YYERROR;
+                       }
+                       
+                       if (!inet_aton($6, &nexthop)) {
+                               yyerror("bad network: %llu/%llu", $2, $4);
+                               free($2);
+                               YYERROR;
+                       }
+                       
+                       prefixlen = $4;
+                       
+                       kroute_filter = kr_filter_new(nexthop,prefix,prefixlen);
+                       LIST_INSERT_HEAD(&conf->kroute_filter_list, kroute_filter, entry);
+                       
+                       free($2);
+               }
+               | METRIC NUMBER {
                        if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
                                yyerror("metric out of range (%d-%d)",
                                    MIN_METRIC, MAX_METRIC);
@@ -508,7 +536,6 @@
                | MINIMAL {
                        $ = FAST_RTR_DEAD_TIME;
                }
-
 optnl          : '\n' optnl
                |
                ;
@@ -726,11 +753,14 @@
                {"hello-interval",      HELLOINTERVAL},
                {"include",             INCLUDE},
                {"interface",           INTERFACE},
+               {"kroute-ignore-insert", KROUTEIGNOREINSERT},
                {"metric",              METRIC},
                {"minimal",             MINIMAL},
                {"msec",                MSEC},
+               {"nexthop",             NEXTHOP},
                {"no",                  NO},
                {"passive",             PASSIVE},
+               {"prefixlen",   PREFIXLEN},
                {"rdomain",             RDOMAIN},
                {"redistribute",        REDISTRIBUTE},
                {"retransmit-interval", RETRANSMITINTERVAL},
@@ -1101,6 +1131,7 @@
        LIST_INIT(&conf->area_list);
        LIST_INIT(&conf->cand_list);
        SIMPLEQ_INIT(&conf->redist_list);
+       LIST_INIT(&conf->kroute_filter_list);

        yyparse();
        errors = file->errors;

--- /root/ospfd/printconf.c     2010-02-20 19:02:25.000000000 +0100
+++ /usr/src/usr.sbin/ospfd/printconf.c 2013-05-31 22:39:27.174026288
+0200
@@ -1,4 +1,4 @@
-/*   $OpenBSD: printconf.c,v 1.15 2010/02/16 08:39:05 dlg Exp $ */
+/*   $OpenBSD: printconf.c,v 1.16 2013/05/31 21:59:48 dlg Exp $ */

 /*
  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -32,6 +32,7 @@
 const char *print_no(u_int16_t);
 void   print_redistribute(struct redist_list *);
 void   print_rtlabel(struct ospfd_conf *);
+void   print_kroute_filter(struct ospfd_conf *);
 void   print_iface(struct iface *);

 void
@@ -54,6 +55,7 @@

        print_redistribute(&conf->redist_list);
        print_rtlabel(conf);
+       print_kroute_filter(conf);

        printf("spf-delay msec %u\n", conf->spf_delay);
        printf("spf-holdtime msec %u\n", conf->spf_hold_time);
@@ -109,6 +111,19 @@
 }

 void
+print_kroute_filter(struct ospfd_conf *conf)
+{
+       struct kroute_filter    *kroute_filter;
+       
+       LIST_FOREACH(kroute_filter, &conf->kroute_filter_list, entry) {
+               printf("kroute-ignore-insert %s prefixlen %u",
+                       inet_ntoa(kroute_filter->prefix),kroute_filter->prefixlen);
+               printf(" nexthop %s\n",
+                       inet_ntoa(kroute_filter->nexthop));
+       }
+}
+
+void
 print_iface(struct iface *iface)
 {
        struct auth_md  *md;