[ovs-dev,v2,04/14] tnl-arp-cache: Add a command to add or modify an ARP cache entry.
diff mbox

Message ID 1441237451-17940-4-git-send-email-blp@nicira.com
State Accepted
Headers show

Commit Message

Ben Pfaff Sept. 2, 2015, 11:44 p.m. UTC
This allows the ARP cache to be prepopulated for testing purposes, so
that tests don't lose the first packet to each destination.  (I guess
this feature could have other uses too.)

Signed-off-by: Ben Pfaff <blp@nicira.com>
---
 lib/tnl-arp-cache.c             | 67 +++++++++++++++++++++++++++++------------
 ofproto/ofproto-tnl-unixctl.man |  4 +++
 2 files changed, 52 insertions(+), 19 deletions(-)

Comments

Andy Zhou Sept. 9, 2015, 5:29 p.m. UTC | #1
Acked-by: Andy Zhou <azhou@nicira.com>

On Wed, Sep 2, 2015 at 4:44 PM, Ben Pfaff <blp@nicira.com> wrote:
> This allows the ARP cache to be prepopulated for testing purposes, so
> that tests don't lose the first packet to each destination.  (I guess
> this feature could have other uses too.)
>
> Signed-off-by: Ben Pfaff <blp@nicira.com>
> ---
>  lib/tnl-arp-cache.c             | 67 +++++++++++++++++++++++++++++------------
>  ofproto/ofproto-tnl-unixctl.man |  4 +++
>  2 files changed, 52 insertions(+), 19 deletions(-)
>
> diff --git a/lib/tnl-arp-cache.c b/lib/tnl-arp-cache.c
> index 3107631..ddfd26f 100644
> --- a/lib/tnl-arp-cache.c
> +++ b/lib/tnl-arp-cache.c
> @@ -30,6 +30,7 @@
>  #include "packets.h"
>  #include "poll-loop.h"
>  #include "seq.h"
> +#include "socket-util.h"
>  #include "timeval.h"
>  #include "tnl-arp-cache.h"
>  #include "unaligned.h"
> @@ -95,28 +96,16 @@ tnl_arp_delete(struct tnl_arp_entry *arp)
>      ovsrcu_postpone(arp_entry_free, arp);
>  }
>
> -int
> -tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
> -              const char name[IFNAMSIZ])
> +static void
> +tnl_arp_set(const char name[IFNAMSIZ], ovs_be32 dst, const struct eth_addr mac)
>  {
> -    struct tnl_arp_entry *arp;
> -
> -    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
> -        return EINVAL;
> -    }
> -
> -    /* Exact Match on all ARP flows. */
> -    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> -    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
> -    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
> -
>      ovs_mutex_lock(&mutex);
> -    arp = tnl_arp_lookup__(name, flow->nw_src);
> +    struct tnl_arp_entry *arp = tnl_arp_lookup__(name, dst);
>      if (arp) {
> -        if (eth_addr_equals(arp->mac, flow->arp_sha)) {
> +        if (eth_addr_equals(arp->mac, mac)) {
>              arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
>              ovs_mutex_unlock(&mutex);
> -            return 0;
> +            return;
>          }
>          tnl_arp_delete(arp);
>          seq_change(tnl_conf_seq);
> @@ -124,12 +113,29 @@ tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
>
>      arp = xmalloc(sizeof *arp);
>
> -    arp->ip = flow->nw_src;
> -    arp->mac = flow->arp_sha;
> +    arp->ip = dst;
> +    arp->mac = mac;
>      arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
>      ovs_strlcpy(arp->br_name, name, sizeof arp->br_name);
>      cmap_insert(&table, &arp->cmap_node, (OVS_FORCE uint32_t) arp->ip);
>      ovs_mutex_unlock(&mutex);
> +}
> +
> +int
> +tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
> +              const char name[IFNAMSIZ])
> +{
> +    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
> +        return EINVAL;
> +    }
> +
> +    /* Exact Match on all ARP flows. */
> +    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> +    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
> +    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
> +
> +    tnl_arp_set(name, flow->nw_src, flow->arp_sha);
> +
>      return 0;
>  }
>
> @@ -172,6 +178,28 @@ tnl_arp_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED,
>      unixctl_command_reply(conn, "OK");
>  }
>
> +static void
> +tnl_arp_cache_add(struct unixctl_conn *conn, int argc OVS_UNUSED,
> +                  const char *argv[], void *aux OVS_UNUSED)
> +{
> +    const char *br_name = argv[1];
> +    struct eth_addr mac;
> +    struct in_addr ip;
> +
> +    if (lookup_ip(argv[2], &ip)) {
> +        unixctl_command_reply_error(conn, "bad IP address");
> +        return;
> +    }
> +
> +    if (!eth_addr_from_string(argv[3], &mac)) {
> +        unixctl_command_reply_error(conn, "bad MAC address");
> +        return;
> +    }
> +
> +    tnl_arp_set(br_name, ip.s_addr, mac);
> +    unixctl_command_reply(conn, "OK");
> +}
> +
>  #define MAX_IP_ADDR_LEN 17
>
>  static void
> @@ -208,5 +236,6 @@ tnl_arp_cache_init(void)
>      cmap_init(&table);
>
>      unixctl_command_register("tnl/arp/show", "", 0, 0, tnl_arp_cache_show, NULL);
> +    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, tnl_arp_cache_add, NULL);
>      unixctl_command_register("tnl/arp/flush", "", 0, 0, tnl_arp_cache_flush, NULL);
>  }
> diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man
> index 853b3f0..f9eb354 100644
> --- a/ofproto/ofproto-tnl-unixctl.man
> +++ b/ofproto/ofproto-tnl-unixctl.man
> @@ -18,6 +18,10 @@ Delete ipv4_address/plen route from OVS routing table.
>  OVS builds ARP cache by snooping are messages. This command shows
>  ARP cache table.
>  .
> +.IP "\fBtnl/arp/set \fIbridge ip mac\fR"
> +Adds or modifies an ARP cache entry in \fIbridge\fR, mapping \fIip\fR
> +to \fImac\fR.
> +.
>  .IP "\fBtnl/arp/flush\fR"
>  Flush ARP table.
>  .
> --
> 2.1.3
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
Ben Pfaff Sept. 9, 2015, 5:41 p.m. UTC | #2
Thanks Andy, applied to master.

On Wed, Sep 09, 2015 at 10:29:56AM -0700, Andy Zhou wrote:
> Acked-by: Andy Zhou <azhou@nicira.com>
> 
> On Wed, Sep 2, 2015 at 4:44 PM, Ben Pfaff <blp@nicira.com> wrote:
> > This allows the ARP cache to be prepopulated for testing purposes, so
> > that tests don't lose the first packet to each destination.  (I guess
> > this feature could have other uses too.)
> >
> > Signed-off-by: Ben Pfaff <blp@nicira.com>
> > ---
> >  lib/tnl-arp-cache.c             | 67 +++++++++++++++++++++++++++++------------
> >  ofproto/ofproto-tnl-unixctl.man |  4 +++
> >  2 files changed, 52 insertions(+), 19 deletions(-)
> >
> > diff --git a/lib/tnl-arp-cache.c b/lib/tnl-arp-cache.c
> > index 3107631..ddfd26f 100644
> > --- a/lib/tnl-arp-cache.c
> > +++ b/lib/tnl-arp-cache.c
> > @@ -30,6 +30,7 @@
> >  #include "packets.h"
> >  #include "poll-loop.h"
> >  #include "seq.h"
> > +#include "socket-util.h"
> >  #include "timeval.h"
> >  #include "tnl-arp-cache.h"
> >  #include "unaligned.h"
> > @@ -95,28 +96,16 @@ tnl_arp_delete(struct tnl_arp_entry *arp)
> >      ovsrcu_postpone(arp_entry_free, arp);
> >  }
> >
> > -int
> > -tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
> > -              const char name[IFNAMSIZ])
> > +static void
> > +tnl_arp_set(const char name[IFNAMSIZ], ovs_be32 dst, const struct eth_addr mac)
> >  {
> > -    struct tnl_arp_entry *arp;
> > -
> > -    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
> > -        return EINVAL;
> > -    }
> > -
> > -    /* Exact Match on all ARP flows. */
> > -    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> > -    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
> > -    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
> > -
> >      ovs_mutex_lock(&mutex);
> > -    arp = tnl_arp_lookup__(name, flow->nw_src);
> > +    struct tnl_arp_entry *arp = tnl_arp_lookup__(name, dst);
> >      if (arp) {
> > -        if (eth_addr_equals(arp->mac, flow->arp_sha)) {
> > +        if (eth_addr_equals(arp->mac, mac)) {
> >              arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
> >              ovs_mutex_unlock(&mutex);
> > -            return 0;
> > +            return;
> >          }
> >          tnl_arp_delete(arp);
> >          seq_change(tnl_conf_seq);
> > @@ -124,12 +113,29 @@ tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
> >
> >      arp = xmalloc(sizeof *arp);
> >
> > -    arp->ip = flow->nw_src;
> > -    arp->mac = flow->arp_sha;
> > +    arp->ip = dst;
> > +    arp->mac = mac;
> >      arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
> >      ovs_strlcpy(arp->br_name, name, sizeof arp->br_name);
> >      cmap_insert(&table, &arp->cmap_node, (OVS_FORCE uint32_t) arp->ip);
> >      ovs_mutex_unlock(&mutex);
> > +}
> > +
> > +int
> > +tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
> > +              const char name[IFNAMSIZ])
> > +{
> > +    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
> > +        return EINVAL;
> > +    }
> > +
> > +    /* Exact Match on all ARP flows. */
> > +    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> > +    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
> > +    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
> > +
> > +    tnl_arp_set(name, flow->nw_src, flow->arp_sha);
> > +
> >      return 0;
> >  }
> >
> > @@ -172,6 +178,28 @@ tnl_arp_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED,
> >      unixctl_command_reply(conn, "OK");
> >  }
> >
> > +static void
> > +tnl_arp_cache_add(struct unixctl_conn *conn, int argc OVS_UNUSED,
> > +                  const char *argv[], void *aux OVS_UNUSED)
> > +{
> > +    const char *br_name = argv[1];
> > +    struct eth_addr mac;
> > +    struct in_addr ip;
> > +
> > +    if (lookup_ip(argv[2], &ip)) {
> > +        unixctl_command_reply_error(conn, "bad IP address");
> > +        return;
> > +    }
> > +
> > +    if (!eth_addr_from_string(argv[3], &mac)) {
> > +        unixctl_command_reply_error(conn, "bad MAC address");
> > +        return;
> > +    }
> > +
> > +    tnl_arp_set(br_name, ip.s_addr, mac);
> > +    unixctl_command_reply(conn, "OK");
> > +}
> > +
> >  #define MAX_IP_ADDR_LEN 17
> >
> >  static void
> > @@ -208,5 +236,6 @@ tnl_arp_cache_init(void)
> >      cmap_init(&table);
> >
> >      unixctl_command_register("tnl/arp/show", "", 0, 0, tnl_arp_cache_show, NULL);
> > +    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, tnl_arp_cache_add, NULL);
> >      unixctl_command_register("tnl/arp/flush", "", 0, 0, tnl_arp_cache_flush, NULL);
> >  }
> > diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man
> > index 853b3f0..f9eb354 100644
> > --- a/ofproto/ofproto-tnl-unixctl.man
> > +++ b/ofproto/ofproto-tnl-unixctl.man
> > @@ -18,6 +18,10 @@ Delete ipv4_address/plen route from OVS routing table.
> >  OVS builds ARP cache by snooping are messages. This command shows
> >  ARP cache table.
> >  .
> > +.IP "\fBtnl/arp/set \fIbridge ip mac\fR"
> > +Adds or modifies an ARP cache entry in \fIbridge\fR, mapping \fIip\fR
> > +to \fImac\fR.
> > +.
> >  .IP "\fBtnl/arp/flush\fR"
> >  Flush ARP table.
> >  .
> > --
> > 2.1.3
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > http://openvswitch.org/mailman/listinfo/dev

Patch
diff mbox

diff --git a/lib/tnl-arp-cache.c b/lib/tnl-arp-cache.c
index 3107631..ddfd26f 100644
--- a/lib/tnl-arp-cache.c
+++ b/lib/tnl-arp-cache.c
@@ -30,6 +30,7 @@ 
 #include "packets.h"
 #include "poll-loop.h"
 #include "seq.h"
+#include "socket-util.h"
 #include "timeval.h"
 #include "tnl-arp-cache.h"
 #include "unaligned.h"
@@ -95,28 +96,16 @@  tnl_arp_delete(struct tnl_arp_entry *arp)
     ovsrcu_postpone(arp_entry_free, arp);
 }
 
-int
-tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
-              const char name[IFNAMSIZ])
+static void
+tnl_arp_set(const char name[IFNAMSIZ], ovs_be32 dst, const struct eth_addr mac)
 {
-    struct tnl_arp_entry *arp;
-
-    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
-        return EINVAL;
-    }
-
-    /* Exact Match on all ARP flows. */
-    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
-    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
-    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
-
     ovs_mutex_lock(&mutex);
-    arp = tnl_arp_lookup__(name, flow->nw_src);
+    struct tnl_arp_entry *arp = tnl_arp_lookup__(name, dst);
     if (arp) {
-        if (eth_addr_equals(arp->mac, flow->arp_sha)) {
+        if (eth_addr_equals(arp->mac, mac)) {
             arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
             ovs_mutex_unlock(&mutex);
-            return 0;
+            return;
         }
         tnl_arp_delete(arp);
         seq_change(tnl_conf_seq);
@@ -124,12 +113,29 @@  tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
 
     arp = xmalloc(sizeof *arp);
 
-    arp->ip = flow->nw_src;
-    arp->mac = flow->arp_sha;
+    arp->ip = dst;
+    arp->mac = mac;
     arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
     ovs_strlcpy(arp->br_name, name, sizeof arp->br_name);
     cmap_insert(&table, &arp->cmap_node, (OVS_FORCE uint32_t) arp->ip);
     ovs_mutex_unlock(&mutex);
+}
+
+int
+tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
+              const char name[IFNAMSIZ])
+{
+    if (flow->dl_type != htons(ETH_TYPE_ARP)) {
+        return EINVAL;
+    }
+
+    /* Exact Match on all ARP flows. */
+    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+    memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
+
+    tnl_arp_set(name, flow->nw_src, flow->arp_sha);
+
     return 0;
 }
 
@@ -172,6 +178,28 @@  tnl_arp_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED,
     unixctl_command_reply(conn, "OK");
 }
 
+static void
+tnl_arp_cache_add(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                  const char *argv[], void *aux OVS_UNUSED)
+{
+    const char *br_name = argv[1];
+    struct eth_addr mac;
+    struct in_addr ip;
+
+    if (lookup_ip(argv[2], &ip)) {
+        unixctl_command_reply_error(conn, "bad IP address");
+        return;
+    }
+
+    if (!eth_addr_from_string(argv[3], &mac)) {
+        unixctl_command_reply_error(conn, "bad MAC address");
+        return;
+    }
+
+    tnl_arp_set(br_name, ip.s_addr, mac);
+    unixctl_command_reply(conn, "OK");
+}
+
 #define MAX_IP_ADDR_LEN 17
 
 static void
@@ -208,5 +236,6 @@  tnl_arp_cache_init(void)
     cmap_init(&table);
 
     unixctl_command_register("tnl/arp/show", "", 0, 0, tnl_arp_cache_show, NULL);
+    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, tnl_arp_cache_add, NULL);
     unixctl_command_register("tnl/arp/flush", "", 0, 0, tnl_arp_cache_flush, NULL);
 }
diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man
index 853b3f0..f9eb354 100644
--- a/ofproto/ofproto-tnl-unixctl.man
+++ b/ofproto/ofproto-tnl-unixctl.man
@@ -18,6 +18,10 @@  Delete ipv4_address/plen route from OVS routing table.
 OVS builds ARP cache by snooping are messages. This command shows
 ARP cache table.
 .
+.IP "\fBtnl/arp/set \fIbridge ip mac\fR"
+Adds or modifies an ARP cache entry in \fIbridge\fR, mapping \fIip\fR
+to \fImac\fR.
+.
 .IP "\fBtnl/arp/flush\fR"
 Flush ARP table.
 .