Diff below implements proxy ARP using the mpath property of our routing
table.  This solution is not limited to ART and could be used for
different purposes, like putting multicast addresses in the routing
table.  However I'm keeping it under "#ifdef ART" as long as we are not
totally committed to this new routing table.

The new function in net/rtsock.c enforces that at most one private and
one public ARP entry are inserted in a routing table.  I didn't put it
in netinet/if_ether.c because I don't want to spread more "rt_addrinfo"
than we already have.

I'll work on removing the KERNEL_LOCK() around rtable_mpath_next() soon.

With this all ARP and arp(8) regression tests pass.

ok?

Index: net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.133
diff -u -p -r1.133 route.h
--- net/route.h 26 Mar 2016 21:56:04 -0000      1.133
+++ net/route.h 29 Mar 2016 09:52:29 -0000
@@ -136,6 +136,7 @@ struct rtentry {
 #define RTF_BLACKHOLE  0x1000          /* just discard pkts (during updates) */
 #define RTF_PROTO3     0x2000          /* protocol specific routing flag */
 #define RTF_PROTO2     0x4000          /* protocol specific routing flag */
+#define RTF_ANNOUNCE   RTF_PROTO2      /* announce L2 entry */
 #define RTF_PROTO1     0x8000          /* protocol specific routing flag */
 #define RTF_CLONED     0x10000         /* this is a cloned route */
 #define RTF_MPATH      0x40000         /* multipath route or operation */
Index: net/rtsock.c
===================================================================
RCS file: /cvs/src/sys/net/rtsock.c,v
retrieving revision 1.187
diff -u -p -r1.187 rtsock.c
--- net/rtsock.c        26 Mar 2016 21:56:04 -0000      1.187
+++ net/rtsock.c        29 Mar 2016 10:07:53 -0000
@@ -98,6 +98,7 @@ struct walkarg {
 
 int    route_ctloutput(int, struct socket *, int, int, struct mbuf **);
 void   route_input(struct mbuf *m0, ...);
+int    route_arp_conflict(struct rt_addrinfo *, unsigned int);
 
 struct mbuf    *rt_msg1(int, struct rt_addrinfo *);
 int             rt_msg2(int, int, struct rt_addrinfo *, caddr_t,
@@ -600,6 +601,10 @@ route_output(struct mbuf *m, ...)
                        error = EINVAL;
                        goto flush;
                }
+               if (route_arp_conflict(&info, tableid)) {
+                       error = EEXIST;
+                       goto flush;
+               }
                error = rtrequest(RTM_ADD, &info, prio, &saved_nrt, tableid);
                if (error == 0) {
                        rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
@@ -884,6 +889,47 @@ fail:
                rp->rcb_proto.sp_family = PF_ROUTE;
 
        return (error);
+}
+
+/*
+ * Check if the user request to insert an ARP entry does not conflict
+ * with existing ones.
+ *
+ * Only two entries are allowed for a given IP address: a private one
+ * (priv) and a public one (pub).
+ */
+int
+route_arp_conflict(struct rt_addrinfo *info, unsigned int tableid)
+{
+#ifdef ART
+       struct rtentry  *rt;
+       int              proxy = (info->rti_flags & RTF_ANNOUNCE);
+
+       if ((info->rti_flags & RTF_LLINFO) == 0 ||
+           (info->rti_info[RTAX_DST]->sa_family != AF_INET))
+               return (0);
+
+       rt = rtalloc(info->rti_info[RTAX_DST], 0, tableid);
+       if (rt == NULL || !ISSET(rt->rt_flags, RTF_LLINFO)) {
+               rtfree(rt);
+               return (0);
+       }
+
+       /*
+        * Same destination and both "priv" or "pub" conflict.
+        * If a second entry exists, it always conflict.
+        */
+       if ((ISSET(rt->rt_flags, RTF_ANNOUNCE) == proxy) ||
+           (rtable_mpath_next(rt) != NULL)) {
+               rtfree(rt);
+               return (1);
+       }
+
+       /* No conflict but an entry exist so we need to force mpath. */
+       info->rti_flags |= RTF_MPATH;
+       rtfree(rt);
+#endif /* ART */
+       return (0);
 }
 
 void
Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.203
diff -u -p -r1.203 if_ether.c
--- netinet/if_ether.c  24 Mar 2016 07:15:10 -0000      1.203
+++ netinet/if_ether.c  29 Mar 2016 10:07:12 -0000
@@ -698,8 +698,20 @@ arplookup(u_int32_t addr, int create, in
        }
 
        if (proxy && !ISSET(rt->rt_flags, RTF_ANNOUNCE)) {
+               struct rtentry *mrt = NULL;
+#ifdef ART
+               mrt = rt;
+               KERNEL_LOCK();
+               while ((mrt = rtable_mpath_next(mrt)) != NULL) {
+                       if (ISSET(mrt->rt_flags, RTF_ANNOUNCE)) {
+                               rtref(mrt);
+                               break;
+                       }
+               }
+               KERNEL_UNLOCK();
+#endif /* ART */
                rtfree(rt);
-               return (NULL);
+               return (mrt);
        }
 
        return (rt);
Index: netinet/if_ether.h
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.h,v
retrieving revision 1.69
diff -u -p -r1.69 if_ether.h
--- netinet/if_ether.h  16 Mar 2016 11:48:27 -0000      1.69
+++ netinet/if_ether.h  29 Mar 2016 09:54:24 -0000
@@ -148,7 +148,6 @@ struct sockaddr_inarp {
  * IP and ethernet specific routing flags
  */
 #define        RTF_USETRAILERS   RTF_PROTO1    /* use trailers */
-#define        RTF_ANNOUNCE      RTF_PROTO2    /* announce new arp entry */
 #define        RTF_PERMANENT_ARP RTF_PROTO3    /* only manual overwrite of 
entry */
 
 #ifdef _KERNEL
Index: netinet6/nd6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.57
diff -u -p -r1.57 nd6.h
--- netinet6/nd6.h      3 Mar 2016 12:57:15 -0000       1.57
+++ netinet6/nd6.h      29 Mar 2016 09:52:29 -0000
@@ -35,11 +35,6 @@
 
 #include <sys/task.h>
 
-/* see net/route.h, or net/if_inarp.h */
-#ifndef RTF_ANNOUNCE
-#define RTF_ANNOUNCE   RTF_PROTO2
-#endif
-
 #define ND6_LLINFO_PURGE       -3
 #define ND6_LLINFO_NOSTATE     -2
 #define ND6_LLINFO_INCOMPLETE  0

Reply via email to