On 19/02/18(Mon) 14:00, Sebastian Benoit wrote:
> Martin Pieuchot(m...@openbsd.org) on 2018.02.12 15:23:45 +0100:
> > On 12/02/18(Mon) 12:02, Sebastian Benoit wrote:
> > > routefilter currently filters the default route,
> > > if it's priority is higher than the filter prio.
> > 
> > Then why not change the priority of the default route?
> > 
> > > This might not be a good idea - for example you might want to
> > > redistribute a default route into ospf, for that you need it in the
> > > routing table but it is configured with a low priority (high value) as
> > > a route of last resort or maybe even as a reject/blackhole.
> > 
> > Are you using multiple default routes?  I don't understand why priority
> > matter, a default route will always be the last resort.
> 
> Because we cannot guarantee that the default route has prio 8. For example
> bgpd might inject the default route with prio 48, and you want to
> redistribute it into ospf. Thats just how the interaction between our
> routing daemons works.
> 
> I admit that this is a bit of a hack, because we kind of also want filters
> for any prefix (because you could have "redistribute 8.8.8.0/24" in your
> config) and route labels later on. I havent tackled that yet, so we only
> filter on prio and the default route special case and turn of the prio
> filter when we find a configuration that needs to see all routes.
> 
> We are trying to optimize the ammount of data going over the route socket
> here. Shoveling information through it thats not needed is just useless
> work for the cpus.
>  
> > > Treat the default route as a special case and always pass it.
> > 
> > I'm not fan of adding more complexity to route_input().
> 
> I understand that, but where else on the kernel side would you put filters?
> If i continue with this, i'm happy to make the code cleaner.
> 
> > This function
> > does not deal with address nor mask, it is just delivering already built
> > messages.  Now if this is unavoidable it would be nice if isdefault()
> > could be reused in if_group_routechange(), rt_ifa_addlocal() and
> > rt_ifa_dellocal().
> 
> I saw that, but did not want to mix it into this diff. Will send one when
> this gets in.
> 
> so ok?

I understand, I have a comment below but sure, I'm ok with the idea :)

> > > diff --git sys/net/rtsock.c sys/net/rtsock.c
> > > index 70497d29a93..2e94fdbc0b1 100644
> > > --- sys/net/rtsock.c
> > > +++ sys/net/rtsock.c
> > > @@ -110,7 +110,9 @@ int   route_output(struct mbuf *, struct socket *, 
> > > struct sockaddr *,
> > >  int      route_ctloutput(int, struct socket *, int, int, struct mbuf *);
> > >  int      route_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
> > >       struct mbuf *, struct proc *);
> > > -void     route_input(struct mbuf *m0, struct socket *, sa_family_t);
> > > +int      route_is_default(struct sockaddr *, struct sockaddr *);
> > > +void     route_input(struct mbuf *m0, struct socket *, struct 
> > > rt_addrinfo *,
> > > +     sa_family_t);
> > >  int      route_arp_conflict(struct rtentry *, struct rt_addrinfo *);
> > >  int      route_cleargateway(struct rtentry *, void *, unsigned int);
> > >  void     route_senddesync(void *);
> > > @@ -403,8 +405,33 @@ route_senddesync(void *data)
> > >   timeout_add(&rop->timeout, ROUTE_DESYNC_RESEND_TIMEOUT);
> > >  }
> > >  
> > > +int
> > > +route_is_default(struct sockaddr *dst, struct sockaddr *mask)
> > > +{
> > > + /* see if.c if_group_routechange() */
> > > + switch (dst->sa_family) {
> > > + case AF_INET:
> > > +         if (satosin(dst)->sin_addr.s_addr == INADDR_ANY &&
> > > +             mask && (mask->sa_len == 0 ||
> > > +             satosin(mask)->sin_addr.s_addr == INADDR_ANY))
> > > +                 return (1);
> > > +         break;
> > > +#ifdef INET6
> > > + case AF_INET6:
> > > +         if (IN6_ARE_ADDR_EQUAL(&(satosin6(dst))->sin6_addr,
> > > +             &in6addr_any) && mask && (mask->sa_len == 0 ||
> > > +             IN6_ARE_ADDR_EQUAL(&(satosin6(mask))->sin6_addr,
> > > +             &in6addr_any)))
> > > +                 return (1);
> > > +         break;
> > > +#endif
> > > + }
> > > + return (0);
> > > +}
> > > +
> > >  void
> > > -route_input(struct mbuf *m0, struct socket *so, sa_family_t sa_family)
> > > +route_input(struct mbuf *m0, struct socket *so, struct rt_addrinfo *info,
> > > +    sa_family_t sa_family)
> > >  {
> > >   struct routecb *rop;
> > >   struct rawcb *rp;
> > > @@ -447,8 +474,16 @@ route_input(struct mbuf *m0, struct socket *so, 
> > > sa_family_t sa_family)
> > >           if (rtm->rtm_type != RTM_DESYNC && rop->msgfilter != 0 &&
> > >               !(rop->msgfilter & (1 << rtm->rtm_type)))
> > >                   continue;
> > > -         if (rop->priority != 0 && rop->priority < rtm->rtm_priority)
> > > -                 continue;
> > > +         /* priority filter */
> > > +         if (rop->priority != 0)
> > > +                 if ((info == NULL &&
> > > +                     rop->priority < rtm->rtm_priority) ||
> > > +                     (info != NULL &&
> > > +                     !route_is_default(info->rti_info[RTAX_DST],
> > > +                     info->rti_info[RTAX_NETMASK]) &&
> > > +                     rop->priority < rtm->rtm_priority))
> > > +                         continue;

I'd suggest to rewrite this like:

                 if (filter && rop->priority != 0 &&
                     rop->priority < rtm->rtm_priority)
                        continue;

And have the following signature for route_input():

        route_input(struct mbuf *, struct socket *, sa_family_t, int filter);

So you'll call route_is_default() only once per route_input() instead of
once per socket().  And you don't need to pass a 'struct rt_addrinfo *'
to route_input() ;)

> > >           switch (rtm->rtm_type) {
> > >           case RTM_IFANNOUNCE:
> > >           case RTM_DESYNC:
> > > @@ -767,7 +802,7 @@ fail:
> > >           free(rtm, M_RTABLE, len);
> > >   }
> > >   if (m)
> > > -         route_input(m, so, info.rti_info[RTAX_DST] ?
> > > +         route_input(m, so, &info, info.rti_info[RTAX_DST] ?
> > >               info.rti_info[RTAX_DST]->sa_family : AF_UNSPEC);

This will become:
                
                af = info.rti_info[RTAX_DST] ? ...->sa_family : AF_UNSPEC;
                filter = !route_is_default(...);
                route_input(m, so, af, filter);

The resulting code is ready to be extend with arbitrary filers ;)

Reply via email to