This follows the pattern I see elsewhere for other "set" actions, but I am
uncertain about some parts:

    * I am not sure that set_arp() is called in a context where there is
      guaranteed to be a full Ethernet+IP ARP header present in the packet,
      given megaflows.

    * set_arp() as written here allows an arp_op >=0x100 to be set even
      though flow_extract() only parses arp_op <0x100.  This is probably
      not right, but I'm not sure of the correct fix.

    * The tree now has two (struct arp_eth_header *)skb_network_header(skb)
      casts, perhaps I should add an arp_eth_hdr() helper.

Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 datapath/actions.c  |   24 ++++++++++++++++++++++++
 datapath/datapath.c |    9 +++++++++
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 0a2def6..d483283 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -360,6 +360,26 @@ static int set_tcp(struct sk_buff *skb, const struct 
ovs_key_tcp *tcp_port_key)
        return 0;
 }
 
+static int set_arp(struct sk_buff *skb, const struct ovs_key_arp *arp_key)
+{
+       struct arp_eth_header *ah;
+       int err;
+
+       err = make_writable(skb, skb_network_offset(skb) +
+                                sizeof(struct arp_eth_header));
+       if (unlikely(err))
+               return err;
+
+       ah = (struct arp_eth_header *)skb_network_header(skb);
+       ah->ar_op = arp_key->arp_op;
+       memcpy(ah->ar_sha, arp_key->arp_sha, ETH_ALEN);
+       memcpy(ah->ar_sip, &arp_key->arp_sip, 4);
+       memcpy(ah->ar_tha, arp_key->arp_tha, ETH_ALEN);
+       memcpy(ah->ar_tip, &arp_key->arp_tip, 4);
+
+       return 0;
+}
+
 static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
 {
        struct vport *vport;
@@ -469,6 +489,10 @@ static int execute_set_action(struct sk_buff *skb,
        case OVS_KEY_ATTR_UDP:
                err = set_udp(skb, nla_data(nested_attr));
                break;
+
+       case OVS_KEY_ATTR_ARP:
+               err = set_arp(skb, nla_data(nested_attr));
+               break;
        }
 
        return err;
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 2f02f71..0786379 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -726,6 +726,15 @@ static int validate_set(const struct nlattr *a,
 
                return validate_tp_port(flow_key);
 
+       case OVS_KEY_ATTR_ARP:
+               if (flow_key->eth.type != htons(ETH_P_ARP))
+                       return -EINVAL;
+
+               if (!flow_key->ip.proto)
+                       return -EINVAL;
+
+               return 0;
+
        default:
                return -EINVAL;
        }
-- 
1.7.2.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to