I'll give it a try when I get home :)

On Mon, Mar 31, 2014 at 6:30 PM, Martin Pieuchot <mpieuc...@nolizard.org> wrote:
> On 27/03/14(Thu) 15:14, Martin Pieuchot wrote:
>> If you do, please test the diff below and make sure it does not change
>> anything in your routing table!
>>
>> This diff is a first step to merge all the various code paths that
>> manipulate auto-magically created routes.  While the code in sys/netinet
>> makes use of rtinit() to create routes with the RTP_CONNECTED priority,
>> in sys/netinet6 land there is no equivalent.
>>
>> The diff below only deals with routes to loopback for IPv6 addresses.
>> These routes are used to indicate that an address is local and that lo0
>> should be used instead of the interface to output packets.  When you
>> look at your routing table these routes have "lo0" as Iface but their
>> prefix correspond to the real interface, for example:
>>
>>
>> Destination                        Gateway                        Flags   
>> Refs      Use   Mtu  Prio Iface
>> ...
>> fe80::200:5eff:fe00:102%carp2      00:00:5e:00:01:02              UHL        
>> 0        0     -     4 lo0
>>
>>
>>
>> So the diff below makes use of the actual rtinit() code to create such
>> routes, but introduce a new interface: rt_ifa_addloop() & rt_ifa_delloop()
>>
>> The next step will be to replace rtinit() by the underlying functions
>> introduced in this diff: rt_ifa_add() and rt_ifa_del(), and document
>> them.  Once that's done we should be able to replace any custom code
>> creating or deleting a route with RTP_CONNECTED by one of these
>> functions.
>>
>> Here is the diff, ok?
>
> Anybody?
>
>>
>> Index: net/route.c
>> ===================================================================
>> RCS file: /home/ncvs/src/sys/net/route.c,v
>> retrieving revision 1.157
>> diff -u -p -r1.157 route.c
>> --- net/route.c       27 Mar 2014 10:39:23 -0000      1.157
>> +++ net/route.c       27 Mar 2014 13:48:39 -0000
>> @@ -150,6 +150,9 @@ int       rtflushclone1(struct radix_node *, v
>>  void rtflushclone(struct radix_node_head *, struct rtentry *);
>>  int  rt_if_remove_rtdelete(struct radix_node *, void *, u_int);
>>
>> +int  rt_ifa_add(struct ifaddr *, int, struct sockaddr *);
>> +int  rt_ifa_del(struct ifaddr *, int, struct sockaddr *);
>> +
>>  #define      LABELID_MAX     50000
>>
>>  struct rt_label {
>> @@ -1083,67 +1086,46 @@ rt_maskedcopy(struct sockaddr *src, stru
>>  int
>>  rtinit(struct ifaddr *ifa, int cmd, int flags)
>>  {
>> -     struct rtentry          *rt;
>> -     struct sockaddr         *dst, *deldst;
>> -     struct mbuf             *m = NULL;
>> -     struct rtentry          *nrt = NULL;
>> -     int                      error;
>> -     struct rt_addrinfo       info;
>> +     struct sockaddr         *dst;
>> +     int error;
>> +
>> +     KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE);
>> +
>> +     dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
>> +
>> +     if (cmd == RTM_ADD)
>> +             error = rt_ifa_add(ifa, flags, dst);
>> +     else
>> +             error = rt_ifa_del(ifa, flags, dst);
>> +
>> +     return (error);
>> +}
>> +
>> +int
>> +rt_ifa_add(struct ifaddr *ifa, int flags, struct sockaddr *dst)
>> +{
>> +     struct rtentry          *rt, *nrt = NULL;
>>       struct sockaddr_rtlabel  sa_rl;
>> +     struct rt_addrinfo       info;
>>       u_short                  rtableid = ifa->ifa_ifp->if_rdomain;
>> +     int                      error;
>>
>> -     dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
>> -     if (cmd == RTM_DELETE) {
>> -             if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
>> -                     m = m_get(M_DONTWAIT, MT_SONAME);
>> -                     if (m == NULL)
>> -                             return (ENOBUFS);
>> -                     deldst = mtod(m, struct sockaddr *);
>> -                     rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
>> -                     dst = deldst;
>> -             }
>> -             if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
>> -                     rt->rt_refcnt--;
>> -                     /* try to find the right route */
>> -                     while (rt && rt->rt_ifa != ifa)
>> -                             rt = (struct rtentry *)
>> -                                 ((struct radix_node *)rt)->rn_dupedkey;
>> -                     if (!rt) {
>> -                             if (m != NULL)
>> -                                     (void) m_free(m);
>> -                             return (flags & RTF_HOST ? EHOSTUNREACH
>> -                                                     : ENETUNREACH);
>> -                     }
>> -             }
>> -     }
>> -     bzero(&info, sizeof(info));
>> +     memset(&info, 0, sizeof(info));
>>       info.rti_ifa = ifa;
>>       info.rti_flags = flags;
>>       info.rti_info[RTAX_DST] = dst;
>> -     if (cmd == RTM_ADD)
>> -             info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
>> +     info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
>>       info.rti_info[RTAX_LABEL] =
>>           rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
>>
>>       if ((flags & RTF_HOST) == 0)
>>               info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
>>
>> -     error = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt, rtableid);
>> -     if (cmd == RTM_DELETE) {
>> -             if (error == 0 && (rt = nrt) != NULL) {
>> -                     rt_newaddrmsg(cmd, ifa, error, nrt);
>> -                     if (rt->rt_refcnt <= 0) {
>> -                             rt->rt_refcnt++;
>> -                             rtfree(rt);
>> -                     }
>> -             }
>> -             if (m != NULL)
>> -                     (void) m_free(m);
>> -     }
>> -     if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) {
>> +     error = rtrequest1(RTM_ADD, &info, RTP_CONNECTED, &nrt, rtableid);
>> +     if (error == 0 && (rt = nrt) != NULL) {
>>               rt->rt_refcnt--;
>>               if (rt->rt_ifa != ifa) {
>> -                     printf("rtinit: wrong ifa (%p) was (%p)\n",
>> +                     printf("%s: wrong ifa (%p) was (%p)\n", __func__,
>>                           ifa, rt->rt_ifa);
>>                       if (rt->rt_ifa->ifa_rtrequest)
>>                               rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt);
>> @@ -1154,9 +1136,107 @@ rtinit(struct ifaddr *ifa, int cmd, int
>>                       if (ifa->ifa_rtrequest)
>>                               ifa->ifa_rtrequest(RTM_ADD, rt);
>>               }
>> -             rt_newaddrmsg(cmd, ifa, error, nrt);
>> +             rt_newaddrmsg(RTM_ADD, ifa, error, nrt);
>> +     }
>> +     return (error);
>> +}
>> +
>> +int
>> +rt_ifa_del(struct ifaddr *ifa, int flags, struct sockaddr *dst)
>> +{
>> +     struct rtentry          *rt, *nrt = NULL;
>> +     struct mbuf             *m = NULL;
>> +     struct sockaddr         *deldst;
>> +     struct rt_addrinfo       info;
>> +     struct sockaddr_rtlabel  sa_rl;
>> +     u_short                  rtableid = ifa->ifa_ifp->if_rdomain;
>> +     int                      error;
>> +
>> +     if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
>> +             m = m_get(M_DONTWAIT, MT_SONAME);
>> +             if (m == NULL)
>> +                     return (ENOBUFS);
>> +             deldst = mtod(m, struct sockaddr *);
>> +             rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
>> +             dst = deldst;
>> +     }
>> +     if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
>> +             rt->rt_refcnt--;
>> +             /* try to find the right route */
>> +             while (rt && rt->rt_ifa != ifa)
>> +                     rt = (struct rtentry *)
>> +                         ((struct radix_node *)rt)->rn_dupedkey;
>> +             if (!rt) {
>> +                     if (m != NULL)
>> +                             (void) m_free(m);
>> +                     return (flags & RTF_HOST ? EHOSTUNREACH
>> +                                             : ENETUNREACH);
>> +             }
>> +     }
>> +
>> +     memset(&info, 0, sizeof(info));
>> +     info.rti_ifa = ifa;
>> +     info.rti_flags = flags;
>> +     info.rti_info[RTAX_DST] = dst;
>> +     info.rti_info[RTAX_LABEL] =
>> +         rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
>> +
>> +     if ((flags & RTF_HOST) == 0)
>> +             info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
>> +
>> +     error = rtrequest1(RTM_DELETE, &info, RTP_CONNECTED, &nrt, rtableid);
>> +     if (error == 0 && (rt = nrt) != NULL) {
>> +             rt_newaddrmsg(RTM_DELETE, ifa, error, nrt);
>> +             if (rt->rt_refcnt <= 0) {
>> +                     rt->rt_refcnt++;
>> +                     rtfree(rt);
>> +             }
>>       }
>> +     if (m != NULL)
>> +             m_free(m);
>> +
>>       return (error);
>> +}
>> +
>> +/*
>> + * Add ifa's address as a loopback rtentry.
>> + */
>> +void
>> +rt_ifa_addloop(struct ifaddr *ifa)
>> +{
>> +     struct rtentry *rt;
>> +
>> +     /* If there is no loopback entry, allocate one. */
>> +     rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
>> +     if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
>> +         (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
>> +             rt_ifa_add(ifa, RTF_UP| RTF_HOST | RTF_LLINFO, ifa->ifa_addr);
>> +     if (rt)
>> +             rt->rt_refcnt--;
>> +}
>> +
>> +/*
>> + * Remove loopback rtentry of ifa's addresss if it exists.
>> + */
>> +void
>> +rt_ifa_delloop(struct ifaddr *ifa)
>> +{
>> +     struct rtentry *rt;
>> +
>> +     /*
>> +      * Before deleting, check if a corresponding loopbacked host
>> +      * route surely exists.  With this check, we can avoid to
>> +      * delete an interface direct route whose destination is same
>> +      * as the address being removed.  This can happen when removing
>> +      * a subnet-router anycast address on an interface attached
>> +      * to a shared medium.
>> +      */
>> +     rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
>> +     if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
>> +         (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0)
>> +             rt_ifa_del(ifa,  RTF_HOST | RTF_LLINFO,  ifa->ifa_addr);
>> +     if (rt)
>> +             rt->rt_refcnt--;
>>  }
>>
>>  /*
>> Index: net/route.h
>> ===================================================================
>> RCS file: /home/ncvs/src/sys/net/route.h,v
>> retrieving revision 1.89
>> diff -u -p -r1.89 route.h
>> --- net/route.h       21 Mar 2014 10:44:42 -0000      1.89
>> +++ net/route.h       27 Mar 2014 13:48:39 -0000
>> @@ -402,6 +402,8 @@ struct rtentry *
>>  void  rtfree(struct rtentry *);
>>  int   rt_getifa(struct rt_addrinfo *, u_int);
>>  int   rtinit(struct ifaddr *, int, int);
>> +void  rt_ifa_addloop(struct ifaddr *);
>> +void  rt_ifa_delloop(struct ifaddr *);
>>  int   rtioctl(u_long, caddr_t, struct proc *);
>>  void  rtredirect(struct sockaddr *, struct sockaddr *,
>>                        struct sockaddr *, int, struct sockaddr *,
>> Index: netinet6/in6.c
>> ===================================================================
>> RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
>> retrieving revision 1.133
>> diff -u -p -r1.133 in6.c
>> --- netinet6/in6.c    27 Mar 2014 10:39:23 -0000      1.133
>> +++ netinet6/in6.c    27 Mar 2014 13:48:39 -0000
>> @@ -122,156 +122,11 @@ const struct in6_addr in6mask128 = IN6MA
>>  int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, struct ifnet *);
>>  int in6_ifinit(struct ifnet *, struct in6_ifaddr *, int);
>>  void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
>> -void in6_ifloop_request(int, struct ifaddr *);
>>
>>  const struct sockaddr_in6 sa6_any = {
>>       sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0
>>  };
>>
>> -/*
>> - * Subroutine for in6_ifaddloop() and in6_ifremloop().
>> - * This routine does actual work.
>> - */
>> -void
>> -in6_ifloop_request(int cmd, struct ifaddr *ifa)
>> -{
>> -     struct rt_addrinfo info;
>> -     struct rtentry *nrt = NULL;
>> -     int e;
>> -
>> -     /*
>> -      * We specify the address itself as the gateway, and set the
>> -      * RTF_LLINFO flag, so that the corresponding host route would have
>> -      * the flag, and thus applications that assume traditional behavior
>> -      * would be happy.  Note that we assume the caller of the function
>> -      * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
>> -      * which changes the outgoing interface to the loopback interface.
>> -      * XXX only table 0 for now
>> -      */
>> -     bzero(&info, sizeof(info));
>> -     info.rti_flags = RTF_UP | RTF_HOST | RTF_LLINFO;
>> -     info.rti_info[RTAX_DST] = ifa->ifa_addr;
>> -     if (cmd != RTM_DELETE)
>> -             info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
>> -     e = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt,
>> -         ifa->ifa_ifp->if_rdomain);
>> -     if (e != 0) {
>> -             char addr[INET6_ADDRSTRLEN];
>> -             log(LOG_ERR, "in6_ifloop_request: "
>> -                 "%s operation failed for %s (errno=%d)\n",
>> -                 cmd == RTM_ADD ? "ADD" : "DELETE",
>> -                 inet_ntop(AF_INET6,
>> -                     &ifatoia6(ifa)->ia_addr.sin6_addr, addr, sizeof(addr)),
>> -                 e);
>> -     }
>> -
>> -     /*
>> -      * Make sure rt_ifa be equal to IFA, the second argument of the
>> -      * function.
>> -      * We need this because when we refer to rt_ifa->ia6_flags in
>> -      * ip6_input, we assume that the rt_ifa points to the address instead
>> -      * of the loopback address.
>> -      */
>> -     if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
>> -             ifafree(nrt->rt_ifa);
>> -             ifa->ifa_refcnt++;
>> -             nrt->rt_ifa = ifa;
>> -     }
>> -
>> -     /*
>> -      * Report the addition/removal of the address to the routing socket.
>> -      * XXX: since we called rtinit for a p2p interface with a destination,
>> -      *      we end up reporting twice in such a case.  Should we rather
>> -      *      omit the second report?
>> -      */
>> -     if (nrt) {
>> -             rt_newaddrmsg(cmd, ifa, e, nrt);
>> -             if (cmd == RTM_DELETE) {
>> -                     if (nrt->rt_refcnt <= 0) {
>> -                             /* XXX: we should free the entry ourselves. */
>> -                             nrt->rt_refcnt++;
>> -                             rtfree(nrt);
>> -                     }
>> -             } else {
>> -                     /* the cmd must be RTM_ADD here */
>> -                     nrt->rt_refcnt--;
>> -             }
>> -     }
>> -}
>> -
>> -/*
>> - * Add ownaddr as loopback rtentry.  We previously add the route only if
>> - * necessary (ex. on a p2p link).  However, since we now manage addresses
>> - * separately from prefixes, we should always add the route.  We can't
>> - * rely on the cloning mechanism from the corresponding interface route
>> - * any more.
>> - */
>> -void
>> -in6_ifaddloop(struct ifaddr *ifa)
>> -{
>> -     struct rtentry *rt;
>> -
>> -     /* If there is no loopback entry, allocate one. */
>> -     rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
>> -     if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
>> -         (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
>> -             in6_ifloop_request(RTM_ADD, ifa);
>> -     if (rt)
>> -             rt->rt_refcnt--;
>> -}
>> -
>> -/*
>> - * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
>> - * if it exists.
>> - */
>> -void
>> -in6_ifremloop(struct ifaddr *ifa)
>> -{
>> -     struct in6_ifaddr *ia6;
>> -     struct rtentry *rt;
>> -     int ia_count = 0;
>> -
>> -     /*
>> -      * Some of BSD variants do not remove cloned routes
>> -      * from an interface direct route, when removing the direct route
>> -      * (see comments in net/net_osdep.h).  Even for variants that do remove
>> -      * cloned routes, they could fail to remove the cloned routes when
>> -      * we handle multple addresses that share a common prefix.
>> -      * So, we should remove the route corresponding to the deleted address.
>> -      */
>> -
>> -     /*
>> -      * Delete the entry only if exact one ifa exists.  More than one ifa
>> -      * can exist if we assign a same single address to multiple
>> -      * (probably p2p) interfaces.
>> -      * XXX: we should avoid such a configuration in IPv6...
>> -      */
>> -     TAILQ_FOREACH(ia6, &in6_ifaddr, ia_list) {
>> -             if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia6->ia_addr.sin6_addr)) 
>> {
>> -                     ia_count++;
>> -                     if (ia_count > 1)
>> -                             break;
>> -             }
>> -     }
>> -
>> -     if (ia_count == 1) {
>> -             /*
>> -              * Before deleting, check if a corresponding loopbacked host
>> -              * route surely exists.  With this check, we can avoid to
>> -              * delete an interface direct route whose destination is same
>> -              * as the address being removed.  This can happen when removing
>> -              * a subnet-router anycast address on an interface attached
>> -              * to a shared medium.
>> -              */
>> -             rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
>> -             if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
>> -                 (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
>> -                     rt->rt_refcnt--;
>> -                     in6_ifloop_request(RTM_DELETE, ifa);
>> -             }
>> -     }
>> -}
>> -
>>  int
>>  in6_mask2len(struct in6_addr *mask, u_char *lim0)
>>  {
>> @@ -1151,8 +1006,9 @@ void
>>  in6_purgeaddr(struct ifaddr *ifa)
>>  {
>>       struct ifnet *ifp = ifa->ifa_ifp;
>> -     struct in6_ifaddr *ia6 = ifatoia6(ifa);
>> +     struct in6_ifaddr *tmp, *ia6 = ifatoia6(ifa);
>>       struct in6_multi_mship *imm;
>> +     int ia6_count = 0;
>>
>>       /* stop DAD processing */
>>       nd6_dad_stop(ifa);
>> @@ -1178,8 +1034,32 @@ in6_purgeaddr(struct ifaddr *ifa)
>>                       ia6->ia_flags &= ~IFA_ROUTE;
>>       }
>>
>> -     /* Remove ownaddr's loopback rtentry, if it exists. */
>> -     in6_ifremloop(&(ia6->ia_ifa));
>> +     /* Remove ownaddr's loopback rtentry, if it exists.
>> +      *
>> +      * Some of BSD variants do not remove cloned routes from an
>> +      * interface direct route, when removing the direct route (see
>> +      * comments in net/net_osdep.h).  Even for variants that do
>> +      * remove cloned routes, they could fail to remove the cloned
>> +      * routes when we handle multiple addresses that share a common
>> +      * prefix.  So, we should remove the route corresponding to the
>> +      * deleted address.
>> +      *
>> +      * Delete the entry only if exact one ifa exists.  More than one
>> +      * ifa can exist if we assign a same single address to multiple
>> +      * (probably p2p) interfaces.
>> +      * XXX: we should avoid such a configuration in IPv6...
>> +      */
>> +     TAILQ_FOREACH(tmp, &in6_ifaddr, ia_list) {
>> +             if (IN6_ARE_ADDR_EQUAL(&tmp->ia_addr.sin6_addr,
>> +                 &ia6->ia_addr.sin6_addr)) {
>> +                     ia6_count++;
>> +                     if (ia6_count > 1)
>> +                             break;
>> +             }
>> +     }
>> +
>> +     if (ia6_count == 1)
>> +             rt_ifa_delloop(&(ia6->ia_ifa));
>>
>>       /*
>>        * leave from multicast groups we have joined for the interface
>> @@ -1517,7 +1397,7 @@ in6_ifinit(struct ifnet *ifp, struct in6
>>       if (newhost) {
>>               /* set the rtrequest function to create llinfo */
>>               ia6->ia_ifa.ifa_rtrequest = nd6_rtrequest;
>> -             in6_ifaddloop(&(ia6->ia_ifa));
>> +             rt_ifa_addloop(&(ia6->ia_ifa));
>>       }
>>
>>       return (error);
>> Index: netinet6/in6_var.h
>> ===================================================================
>> RCS file: /home/ncvs/src/sys/netinet6/in6_var.h,v
>> retrieving revision 1.48
>> diff -u -p -r1.48 in6_var.h
>> --- netinet6/in6_var.h        27 Mar 2014 10:39:23 -0000      1.48
>> +++ netinet6/in6_var.h        27 Mar 2014 13:48:39 -0000
>> @@ -524,8 +524,6 @@ int       in6_matchlen(struct in6_addr *, stru
>>  int  in6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int);
>>  void in6_prefixlen2mask(struct in6_addr *, int);
>>  void in6_purgeprefix(struct ifnet *);
>> -void in6_ifaddloop(struct ifaddr *);
>> -void in6_ifremloop(struct ifaddr *);
>>  #endif /* _KERNEL */
>>
>>  #endif /* _NETINET6_IN6_VAR_H_ */
>>
>



-- 
This message is strictly personal and the opinions expressed do not
represent those of my employers, either past or present.

Reply via email to