Also Paul, I think this takes care of one of the requirements for VMs to send traffic on the wrong lswitch in <a href="http://redmine.nicira.com/issues/3273">3273</a>, so we don&#39;t have to worry about that anymore =)<br>

<br><div class="gmail_quote">On Thu, Aug 12, 2010 at 2:07 PM, Martin Casado <span dir="ltr">&lt;<a href="mailto:casado@nicira.com">casado@nicira.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

This is great Ben, and sorely needed.  Thanks for getting that patch in. ovs security ++.<div><div></div><div class="h5"><br>
<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
&quot;ARP spoofing&quot; is when a host claims an incorrect association between an<br>
IP address and a MAC address for deceptive purposes.  OpenFlow by itself<br>
can prevent a host from sending out ARP replies from an incorrect MAC<br>
address in the Ethernet L2 header, but it cannot control the MAC addresses<br>
inside the ARP L3 packet.  This commit adds a new action that can be used<br>
to drop these spoofed packets.<br>
<br>
CC: Paul Ingram &lt;<a href="mailto:paul@nicira.com" target="_blank">paul@nicira.com</a>&gt;<br>
---<br>
I&#39;m sending this out partly as an RFC, to check with Paul that this<br>
solves the problem that he has, and to make sure that this type of<br>
solution is OK with the other developers.<br>
<br>
I have not tested this code yet.<br>
<br>
 datapath/actions.c                      |   27 +++++++++++++++++++++++++++<br>
 datapath/flow.c                         |   15 ---------------<br>
 datapath/flow.h                         |   16 ++++++++++++++++<br>
 include/openflow/nicira-ext.h           |   13 ++++++++++++-<br>
 include/openvswitch/datapath-protocol.h |    3 ++-<br>
 ofproto/ofproto.c                       |    6 ++++++<br>
 6 files changed, 63 insertions(+), 17 deletions(-)<br>
<br>
diff --git a/datapath/actions.c b/datapath/actions.c<br>
index a6771b6..81e1c84 100644<br>
--- a/datapath/actions.c<br>
+++ b/datapath/actions.c<br>
@@ -14,6 +14,7 @@<br>
 #include &lt;linux/tcp.h&gt;<br>
 #include &lt;linux/udp.h&gt;<br>
 #include &lt;linux/in6.h&gt;<br>
+#include &lt;linux/if_arp.h&gt;<br>
 #include &lt;linux/if_vlan.h&gt;<br>
 #include &lt;net/inet_ecn.h&gt;<br>
 #include &lt;net/ip.h&gt;<br>
@@ -318,6 +319,26 @@ static struct sk_buff *set_tp_port(struct sk_buff *skb,<br>
        return skb;<br>
 }<br>
 +/* Returns true if &#39;skb&#39; is an Ethernet+IPv4 ARP packet whose inner and outer<br>
+ * Ethernet address differ. */<br>
+static bool is_spoofed_arp(struct sk_buff *skb, const struct odp_flow_key *key)<br>
+{<br>
+       struct arp_eth_header *arp;<br>
+<br>
+       if (key-&gt;dl_type != htons(ETH_P_ARP))<br>
+               return false;<br>
+<br>
+       if (skb_network_offset(skb) + sizeof(struct arp_eth_header) &gt; skb-&gt;len)<br>
+               return false;<br>
+<br>
+       arp = (struct arp_eth_header *)skb_network_header(skb);<br>
+       return (arp-&gt;ar_hrd == htons(ARPHRD_ETHER) &amp;&amp;<br>
+               arp-&gt;ar_pro == htons(ETH_P_IP) &amp;&amp;<br>
+               arp-&gt;ar_hln == ETH_ALEN &amp;&amp;<br>
+               arp-&gt;ar_pln == 4 &amp;&amp;<br>
+               compare_ether_addr(arp-&gt;ar_sha, eth_hdr(skb)-&gt;h_source));<br>
+}<br>
+<br>
 static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)<br>
 {<br>
        struct dp_port *p;<br>
@@ -484,10 +505,16 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,<br>
                case ODPAT_POP_PRIORITY:<br>
                        skb-&gt;priority = priority;<br>
                        break;<br>
+<br>
+               case ODPAT_DROP_SPOOFED_ARP:<br>
+                       if (is_spoofed_arp(skb, key))<br>
+                               goto exit;<br>
+                       break;<br>
                }<br>
                if (!skb)<br>
                        return -ENOMEM;<br>
        }<br>
+exit:<br>
        if (prev_port != -1)<br>
                do_output(dp, skb, prev_port);<br>
        else<br>
diff --git a/datapath/flow.c b/datapath/flow.c<br>
index f769b14..8074b20 100644<br>
--- a/datapath/flow.c<br>
+++ b/datapath/flow.c<br>
@@ -34,21 +34,6 @@<br>
 struct kmem_cache *flow_cache;<br>
 static unsigned int hash_seed;<br>
 -struct arp_eth_header<br>
-{<br>
-       __be16      ar_hrd;     /* format of hardware address   */<br>
-       __be16      ar_pro;     /* format of protocol address   */<br>
-       unsigned char   ar_hln; /* length of hardware address   */<br>
-       unsigned char   ar_pln; /* length of protocol address   */<br>
-       __be16      ar_op;      /* ARP opcode (command)     */<br>
-<br>
-       /* Ethernet+IPv4 specific members. */<br>
-       unsigned char       ar_sha[ETH_ALEN];   /* sender hardware address  */<br>
-       unsigned char       ar_sip[4];          /* sender IP address        */<br>
-       unsigned char       ar_tha[ETH_ALEN];   /* target hardware address  */<br>
-       unsigned char       ar_tip[4];          /* target IP address        */<br>
-} __attribute__((packed));<br>
-<br>
 static inline int arphdr_ok(struct sk_buff *skb)<br>
 {<br>
        int nh_ofs = skb_network_offset(skb);<br>
diff --git a/datapath/flow.h b/datapath/flow.h<br>
index 534c7af..80a5b66 100644<br>
--- a/datapath/flow.h<br>
+++ b/datapath/flow.h<br>
@@ -14,6 +14,7 @@<br>
 #include &lt;linux/types.h&gt;<br>
 #include &lt;linux/rcupdate.h&gt;<br>
 #include &lt;linux/gfp.h&gt;<br>
+#include &lt;linux/if_ether.h&gt;<br>
 #include &lt;linux/jiffies.h&gt;<br>
 #include &lt;linux/time.h&gt;<br>
 @@ -42,6 +43,21 @@ struct sw_flow {<br>
        u8 tcp_flags;           /* Union of seen TCP flags. */<br>
 };<br>
 +struct arp_eth_header<br>
+{<br>
+       __be16      ar_hrd;     /* format of hardware address   */<br>
+       __be16      ar_pro;     /* format of protocol address   */<br>
+       unsigned char   ar_hln; /* length of hardware address   */<br>
+       unsigned char   ar_pln; /* length of protocol address   */<br>
+       __be16      ar_op;      /* ARP opcode (command)     */<br>
+<br>
+       /* Ethernet+IPv4 specific members. */<br>
+       unsigned char       ar_sha[ETH_ALEN];   /* sender hardware address  */<br>
+       unsigned char       ar_sip[4];          /* sender IP address        */<br>
+       unsigned char       ar_tha[ETH_ALEN];   /* target hardware address  */<br>
+       unsigned char       ar_tip[4];          /* target IP address        */<br>
+} __attribute__((packed));<br>
+<br>
 extern struct kmem_cache *flow_cache;<br>
  struct sw_flow_actions *flow_actions_alloc(size_t n_actions);<br>
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h<br>
index e6f34ba..f2c5b73 100644<br>
--- a/include/openflow/nicira-ext.h<br>
+++ b/include/openflow/nicira-ext.h<br>
@@ -129,7 +129,18 @@ enum nx_action_subtype {<br>
      */<br>
     NXAST_RESUBMIT,<br>
 -    NXAST_SET_TUNNEL                /* Set encapsulating tunnel ID. */<br>
+    /* Set encapsulating tunnel ID. */<br>
+    NXAST_SET_TUNNEL,<br>
+<br>
+    /* Stops processing further actions, if the packet being processed is an<br>
+     * Ethernet+IPv4 ARP packet for which the source Ethernet address inside<br>
+     * the ARP packet differs from the source Ethernet address in the Ethernet<br>
+     * header.<br>
+     *<br>
+     * This is useful because OpenFlow does not provide a way to match on the<br>
+     * Ethernet addresses inside ARP packets, so there is no other way to drop<br>
+     * spoofed ARPs other than sending every packet up to the controller. */<br>
+    NXAST_DROP_SPOOFED_ARP<br>
 };<br>
  /* Action structure for NXAST_RESUBMIT. */<br>
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h<br>
index c3ec4dc..839c484 100644<br>
--- a/include/openvswitch/datapath-protocol.h<br>
+++ b/include/openvswitch/datapath-protocol.h<br>
@@ -281,7 +281,8 @@ struct odp_flowvec {<br>
 #define ODPAT_SET_TUNNEL        13   /* Set the encapsulating tunnel ID. */<br>
 #define ODPAT_SET_PRIORITY      14   /* Set skb-&gt;priority. */<br>
 #define ODPAT_POP_PRIORITY      15   /* Restore original skb-&gt;priority. */<br>
-#define ODPAT_N_ACTIONS         16<br>
+#define ODPAT_DROP_SPOOFED_ARP  16   /* Drop ARPs with spoofed source MAC. */<br>
+#define ODPAT_N_ACTIONS         17<br>
  struct odp_action_output {<br>
     uint16_t type;              /* ODPAT_OUTPUT. */<br>
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c<br>
index a466c9c..c0d4acc 100644<br>
--- a/ofproto/ofproto.c<br>
+++ b/ofproto/ofproto.c<br>
@@ -2635,6 +2635,12 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,<br>
         ctx-&gt;flow.tun_id = oa-&gt;tunnel.tun_id = nast-&gt;tun_id;<br>
         break;<br>
 +    case NXAST_DROP_SPOOFED_ARP:<br>
+        if (ctx-&gt;flow.dl_type == htons(ETH_TYPE_ARP)) {<br>
+            odp_actions_add(ctx-&gt;out, ODPAT_DROP_SPOOFED_ARP);<br>
+        }<br>
+        break;<br>
+<br>
     /* If you add a new action here that modifies flow data, don&#39;t forget to<br>
      * update the flow key in ctx-&gt;flow at the same time. */<br>
   <br>
</blockquote>
<br>
<br></div></div><div><div></div><div class="h5">
_______________________________________________<br>
dev mailing list<br>
<a href="mailto:dev@openvswitch.org" target="_blank">dev@openvswitch.org</a><br>
<a href="http://openvswitch.org/mailman/listinfo/dev_openvswitch.org" target="_blank">http://openvswitch.org/mailman/listinfo/dev_openvswitch.org</a><br>
</div></div></blockquote></div><br>