Instead of having a separate function to check for MPATH conflicts
simply pass the gateway to rtable_insert().  Some regress tests
outputs will need an update as we're now doing one more rtalloc(9)
call in RTM_ADD. 

This is a step towards MPATH by default.

ok?

Index: net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.262
diff -u -p -r1.262 route.c
--- net/route.c 25 Oct 2015 11:58:11 -0000      1.262
+++ net/route.c 25 Oct 2015 14:14:28 -0000
@@ -837,15 +837,6 @@ rtrequest1(int req, struct rt_addrinfo *
                else
                        memcpy(ndst, info->rti_info[RTAX_DST], dlen);
 
-#ifndef SMALL_KERNEL
-               /* Do not permit exactly the same dst/mask/gw pair. */
-               if (rtable_mpath_conflict(tableid, ndst,
-                   info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
-                   prio, info->rti_flags & RTF_MPATH)) {
-                       free(ndst, M_RTABLE, dlen);
-                       return (EEXIST);
-               }
-#endif
                rt = pool_get(&rtentry_pool, PR_NOWAIT | PR_ZERO);
                if (rt == NULL) {
                        free(ndst, M_RTABLE, dlen);
@@ -953,13 +944,15 @@ rtrequest1(int req, struct rt_addrinfo *
                }
 
                error = rtable_insert(tableid, ndst,
-                   info->rti_info[RTAX_NETMASK], rt->rt_priority, rt);
+                   info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
+                   rt->rt_priority, rt);
                if (error != 0 && (crt = rtalloc(ndst, 0, tableid)) != NULL) {
                        /* overwrite cloned route */
                        if ((crt->rt_flags & RTF_CLONED) != 0) {
                                rtdeletemsg(crt, tableid);
                                error = rtable_insert(tableid, ndst,
                                    info->rti_info[RTAX_NETMASK],
+                                   info->rti_info[RTAX_GATEWAY],
                                    rt->rt_priority, rt);
                        }
                        rtfree(crt);
Index: net/rtable.c
===================================================================
RCS file: /cvs/src/sys/net/rtable.c,v
retrieving revision 1.14
diff -u -p -r1.14 rtable.c
--- net/rtable.c        22 Oct 2015 17:19:38 -0000      1.14
+++ net/rtable.c        25 Oct 2015 14:13:57 -0000
@@ -292,7 +292,8 @@ rtable_match(unsigned int rtableid, stru
 
 int
 rtable_insert(unsigned int rtableid, struct sockaddr *dst,
-    struct sockaddr *mask, uint8_t prio, struct rtentry *rt)
+    struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio,
+    struct rtentry *rt)
 {
        struct radix_node_head  *rnh;
        struct radix_node       *rn = (struct radix_node *)rt;
@@ -301,6 +302,15 @@ rtable_insert(unsigned int rtableid, str
        if (rnh == NULL)
                return (EAFNOSUPPORT);
 
+#ifndef SMALL_KERNEL
+       if (rnh->rnh_multipath) {
+               /* Do not permit exactly the same dst/mask/gw pair. */
+               if (rt_mpath_conflict(rnh, dst, mask, gateway, prio,
+                   ISSET(rt->rt_flags, RTF_MPATH)))
+                       return (EEXIST);
+       }
+#endif
+
        rn = rn_addroute(dst, mask, rnh, rn, prio);
        if (rn == NULL)
                return (ESRCH);
@@ -382,22 +392,6 @@ rtable_mpath_match(unsigned int rtableid
        return (rt);
 }
 
-int
-rtable_mpath_conflict(unsigned int rtableid, struct sockaddr *dst,
-    struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio, int mpathok)
-{
-       struct radix_node_head  *rnh;
-
-       rnh = rtable_get(rtableid, dst->sa_family);
-       if (rnh == NULL)
-               return (EAFNOSUPPORT);
-
-       if (rnh->rnh_multipath == 0)
-               return (0);
-
-       return (rt_mpath_conflict(rnh, dst, mask, gateway, prio, mpathok));
-}
-
 /* Gateway selection by Hash-Threshold (RFC 2992) */
 struct rtentry *
 rtable_mpath_select(struct rtentry *rt, uint32_t hash)
@@ -526,7 +520,8 @@ rtable_match(unsigned int rtableid, stru
 
 int
 rtable_insert(unsigned int rtableid, struct sockaddr *dst,
-    struct sockaddr *mask, uint8_t prio, struct rtentry *rt)
+    struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio,
+    struct rtentry *rt)
 {
 #ifndef SMALL_KERNEL
        struct rtentry                  *mrt;
@@ -545,6 +540,29 @@ rtable_insert(unsigned int rtableid, str
        if (plen == -1)
                return (EINVAL);
 
+#ifndef SMALL_KERNEL
+       /* Do not permit exactly the same dst/mask/gw pair. */
+       an = art_lookup(ar, addr, plen);
+       if (an != NULL && an->an_plen == plen &&
+           !memcmp(an->an_dst, dst, dst->sa_len)) {
+               struct rtentry  *mrt;
+               int              mpathok = ISSET(rt->rt_flags, RTF_MPATH);
+
+               LIST_FOREACH(mrt, &an->an_rtlist, rt_next) {
+                       if (prio != RTP_ANY &&
+                           (mrt->rt_priority & RTP_MASK) != (prio & RTP_MASK))
+                               continue;
+
+                       if (!mpathok)
+                               return (EEXIST);
+
+                       if (mrt->rt_gateway->sa_len == gateway->sa_len &&
+                           !memcmp(mrt->rt_gateway, gateway, gateway->sa_len))
+                               return (EEXIST);
+               }
+       }
+#endif
+
        an = pool_get(&an_pool, PR_NOWAIT | PR_ZERO);
        if (an == NULL)
                return (ENOBUFS);
@@ -754,48 +772,6 @@ rtable_mpath_match(unsigned int rtableid
        rtfree(rt0);
 
        return (rt);
-}
-
-int
-rtable_mpath_conflict(unsigned int rtableid, struct sockaddr *dst,
-    struct sockaddr *mask, struct sockaddr *gateway, uint8_t prio, int mpathok)
-{
-       struct art_root                 *ar;
-       struct art_node                 *an;
-       struct rtentry                  *rt;
-       uint8_t                         *addr;
-       int                              plen;
-
-       ar = rtable_get(rtableid, dst->sa_family);
-       if (ar == NULL)
-               return (EAFNOSUPPORT);
-
-       addr = satoaddr(ar, dst);
-       plen = satoplen(ar, mask);
-       if (plen == -1)
-               return (EINVAL);
-
-       an = art_lookup(ar, addr, plen);
-       /* Make sure we've got a perfect match. */
-       if (an == NULL || an->an_plen != plen ||
-           memcmp(an->an_dst, dst, dst->sa_len))
-               return (0);
-
-       LIST_FOREACH(rt, &an->an_rtlist, rt_next) {
-               if (prio != RTP_ANY &&
-                   (rt->rt_priority & RTP_MASK) != (prio & RTP_MASK))
-                       continue;
-
-               if (!mpathok)
-                       return (EEXIST);
-
-               if (rt->rt_gateway->sa_len == gateway->sa_len &&
-                   memcmp(rt->rt_gateway, gateway, gateway->sa_len) == 0)
-                       return (EEXIST);
-       }
-
-
-       return (0);
 }
 
 /* Gateway selection by Hash-Threshold (RFC 2992) */
Index: net/rtable.h
===================================================================
RCS file: /cvs/src/sys/net/rtable.h,v
retrieving revision 1.7
diff -u -p -r1.7 rtable.h
--- net/rtable.h        22 Oct 2015 17:19:38 -0000      1.7
+++ net/rtable.h        25 Oct 2015 14:13:46 -0000
@@ -57,7 +57,8 @@ struct rtentry        *rtable_lookup(unsigned i
                     struct sockaddr *);
 struct rtentry *rtable_match(unsigned int, struct sockaddr *);
 int             rtable_insert(unsigned int, struct sockaddr *,
-                    struct sockaddr *, uint8_t, struct rtentry *);
+                    struct sockaddr *, struct sockaddr *, uint8_t,
+                    struct rtentry *);
 int             rtable_delete(unsigned int, struct sockaddr *,
                     struct sockaddr *, uint8_t, struct rtentry *);
 int             rtable_walk(unsigned int, sa_family_t,
@@ -66,8 +67,6 @@ int            rtable_walk(unsigned int, sa_famil
 int             rtable_mpath_capable(unsigned int, sa_family_t);
 struct rtentry *rtable_mpath_match(unsigned int, struct rtentry *,
                     struct sockaddr *, uint8_t);
-int             rtable_mpath_conflict(unsigned int, struct sockaddr *,
-                    struct sockaddr *, struct sockaddr *, uint8_t, int);
 struct rtentry *rtable_mpath_select(struct rtentry *, uint32_t);
 void            rtable_mpath_reprio(struct rtentry *, uint8_t);
 #endif /* _NET_RTABLE_H_ */

Reply via email to