Re: proxy ARP for ART

2016-03-29 Thread Alexander Bluhm
On Tue, Mar 29, 2016 at 12:59:46PM +0200, Martin Pieuchot wrote:
> @@ -600,6 +601,10 @@ route_output(struct mbuf *m, ...)
> + if (route_arp_conflict(, tableid)) {
> + error = EEXIST;
> + goto flush;
> + }

I don't like a function that returns a boolean when its name does
not clearly say so.  And this function has side effects.
What about returning EEXIST and using this check?

if ((error = route_arp_conflict(, tableid)))
goto flush;

> +route_arp_conflict(struct rt_addrinfo *info, unsigned int tableid)
> +{
> +#ifdef ART
...
> + (rtable_mpath_next(rt) != NULL)) {
...
> +#endif /* ART */

rtable_mpath_next() is not defined with SMALL_KERNEL.  You need
another #ifndef here or RAMDISK kernel will break when we enable
ART there.


> @@ -698,8 +698,20 @@ arplookup(u_int32_t addr, int create, in
> +#ifdef ART
...
> + while ((mrt = rtable_mpath_next(mrt)) != NULL) {
...
> +#endif /* ART */

same here

with that OK bluhm@



proxy ARP for ART

2016-03-29 Thread Martin Pieuchot
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 -  1.133
+++ net/route.h 29 Mar 2016 09:52:29 -
@@ -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 0x1 /* this is a cloned route */
 #define RTF_MPATH  0x4 /* 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.c26 Mar 2016 21:56:04 -  1.187
+++ net/rtsock.c29 Mar 2016 10:07:53 -
@@ -98,6 +98,7 @@ struct walkarg {
 
 introute_ctloutput(int, struct socket *, int, int, struct mbuf **);
 void   route_input(struct mbuf *m0, ...);
+introute_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(, tableid)) {
+   error = EEXIST;
+   goto flush;
+   }
error = rtrequest(RTM_ADD, , prio, _nrt, tableid);
if (error == 0) {
rt_setmetrics(rtm->rtm_inits, >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 -  1.203
+++ netinet/if_ether.c  29 Mar 2016 10:07:12 -
@@ -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