Implementation of the pop_eth and push_eth actions in the kernel, and
layer 3 flow support.

Signed-off-by: Lorand Jakab <loja...@cisco.com>
---
 datapath/actions.c            | 35 +++++++++++++++++++++
 datapath/datapath.h           |  1 +
 datapath/flow.c               | 47 ++++++++++++++++------------
 datapath/flow.h               |  1 +
 datapath/flow_netlink.c       | 72 ++++++++++++++++++++++++++++++++++++-------
 datapath/vport-geneve.c       |  6 +++-
 datapath/vport-gre.c          |  5 ++-
 datapath/vport-internal_dev.c |  5 ++-
 datapath/vport-lisp.c         | 26 ++++------------
 datapath/vport-netdev.c       |  5 ++-
 datapath/vport-vxlan.c        |  7 ++++-
 datapath/vport.c              |  5 ++-
 datapath/vport.h              |  2 +-
 13 files changed, 159 insertions(+), 58 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index cb26ad5..20c66f5 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -241,6 +241,33 @@ static int set_eth_addr(struct sk_buff *skb,
        return 0;
 }
 
+static int pop_eth(struct sk_buff *skb)
+{
+       skb_pull_rcsum(skb, skb_network_offset(skb));
+       skb_reset_mac_header(skb);
+       vlan_set_tci(skb, 0);
+
+       OVS_CB(skb)->is_layer3 = true;
+
+       return 0;
+}
+
+static void push_eth(struct sk_buff *skb, const struct ovs_action_push_eth 
*ethh)
+{
+       skb_push(skb, ETH_HLEN);
+       skb_reset_mac_header(skb);
+
+       ether_addr_copy(eth_hdr(skb)->h_source, ethh->addresses.eth_src);
+       ether_addr_copy(eth_hdr(skb)->h_dest, ethh->addresses.eth_dst);
+
+       eth_hdr(skb)->h_proto = ethh->eth_type;
+       skb->protocol = ethh->eth_type;
+
+       ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
+
+       OVS_CB(skb)->is_layer3 = false;
+}
+
 static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
                                __be32 *addr, __be32 new_addr)
 {
@@ -726,6 +753,14 @@ static int do_execute_actions(struct datapath *dp, struct 
sk_buff *skb,
                        err = pop_vlan(skb);
                        break;
 
+               case OVS_ACTION_ATTR_PUSH_ETH:
+                       push_eth(skb, nla_data(a));
+                       break;
+
+               case OVS_ACTION_ATTR_POP_ETH:
+                       err = pop_eth(skb);
+                       break;
+
                case OVS_ACTION_ATTR_RECIRC: {
                        struct sk_buff *recirc_skb;
 
diff --git a/datapath/datapath.h b/datapath/datapath.h
index fcd8e86..07ae0c8 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -107,6 +107,7 @@ struct ovs_skb_cb {
        struct sw_flow_key      *pkt_key;
        struct ovs_tunnel_info  *tun_info;
        struct vport    *input_vport;
+       bool is_layer3;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
diff --git a/datapath/flow.c b/datapath/flow.c
index e234796..9357e89 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -481,27 +481,34 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, 
struct sw_flow_key *key)
 
        skb_reset_mac_header(skb);
 
-       /* Link layer.  We are guaranteed to have at least the 14 byte Ethernet
-        * header in the linear data area.
-        */
-       eth = eth_hdr(skb);
-       ether_addr_copy(key->eth.src, eth->h_source);
-       ether_addr_copy(key->eth.dst, eth->h_dest);
-
-       __skb_pull(skb, 2 * ETH_ALEN);
-       /* We are going to push all headers that we pull, so no need to
-        * update skb->csum here. */
-
-       key->eth.tci = 0;
-       if (vlan_tx_tag_present(skb))
-               key->eth.tci = htons(vlan_get_tci(skb));
-       else if (eth->h_proto == htons(ETH_P_8021Q))
-               if (unlikely(parse_vlan(skb, key)))
+       /* Link layer. */
+       if (OVS_CB(skb)->is_layer3) {
+               /* The receiving L3 vport should set the inner packet protocol
+                * on the skb.  We use that here to set eth.type */
+               key->phy.noeth = true;
+               key->eth.tci = 0;
+               key->eth.type = skb->protocol;
+       } else {
+               key->phy.noeth = false;
+               eth = eth_hdr(skb);
+               ether_addr_copy(key->eth.src, eth->h_source);
+               ether_addr_copy(key->eth.dst, eth->h_dest);
+
+               __skb_pull(skb, 2 * ETH_ALEN);
+               /* We are going to push all headers that we pull, so no need to
+                * update skb->csum here. */
+
+               key->eth.tci = 0;
+               if (vlan_tx_tag_present(skb))
+                       key->eth.tci = htons(vlan_get_tci(skb));
+               else if (eth->h_proto == htons(ETH_P_8021Q))
+                       if (unlikely(parse_vlan(skb, key)))
+                               return -ENOMEM;
+
+               key->eth.type = parse_ethertype(skb);
+               if (unlikely(key->eth.type == htons(0)))
                        return -ENOMEM;
-
-       key->eth.type = parse_ethertype(skb);
-       if (unlikely(key->eth.type == htons(0)))
-               return -ENOMEM;
+       }
 
        skb_reset_network_header(skb);
        skb_reset_mac_len(skb);
diff --git a/datapath/flow.h b/datapath/flow.h
index f6afa48..20215a4 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -95,6 +95,7 @@ struct sw_flow_key {
                u32     priority;       /* Packet QoS priority. */
                u32     skb_mark;       /* SKB mark. */
                u16     in_port;        /* Input switch port (or DP_MAX_PORTS). 
*/
+               bool    noeth;          /* Packet has no Ethernet header */
        } __packed phy; /* Safe when right after 'tun_key'. */
        u32 ovs_flow_hash;              /* Datapath computed hash value.  */
        u32 recirc_id;                  /* Recirculation ID.  */
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 5a1a487..347142b 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -114,14 +114,12 @@ static u16 range_n_bytes(const struct sw_flow_key_range 
*range)
 static bool match_validate(const struct sw_flow_match *match,
                           u64 key_attrs, u64 mask_attrs)
 {
-       u64 key_expected = 1ULL << OVS_KEY_ATTR_ETHERNET;
+       u64 key_expected = 0;
        u64 mask_allowed = key_attrs;  /* At most allow all key attributes */
 
        /* The following mask attributes allowed only if they
         * pass the validation tests. */
-       mask_allowed &= ~((1ULL << OVS_KEY_ATTR_IPV4)
-                       | (1ULL << OVS_KEY_ATTR_IPV6)
-                       | (1ULL << OVS_KEY_ATTR_TCP)
+       mask_allowed &= ~((1ULL << OVS_KEY_ATTR_TCP)
                        | (1ULL << OVS_KEY_ATTR_TCP_FLAGS)
                        | (1ULL << OVS_KEY_ATTR_UDP)
                        | (1ULL << OVS_KEY_ATTR_SCTP)
@@ -134,7 +132,10 @@ static bool match_validate(const struct sw_flow_match 
*match,
        /* Always allowed mask fields. */
        mask_allowed |= ((1ULL << OVS_KEY_ATTR_TUNNEL)
                       | (1ULL << OVS_KEY_ATTR_IN_PORT)
-                      | (1ULL << OVS_KEY_ATTR_ETHERTYPE));
+                      | (1ULL << OVS_KEY_ATTR_ETHERNET)
+                      | (1ULL << OVS_KEY_ATTR_ETHERTYPE)
+                      | (1ULL << OVS_KEY_ATTR_IPV4)
+                      | (1ULL << OVS_KEY_ATTR_IPV6));
 
        /* Check key attributes. */
        if (match->key->eth.type == htons(ETH_P_ARP)
@@ -600,8 +601,10 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
                                eth_key->eth_src, ETH_ALEN, is_mask);
                SW_FLOW_KEY_MEMCPY(match, eth.dst,
                                eth_key->eth_dst, ETH_ALEN, is_mask);
+               SW_FLOW_KEY_PUT(match, phy.noeth, false, is_mask);
                attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERNET);
-       }
+       } else if (!is_mask)
+               SW_FLOW_KEY_PUT(match, phy.noeth, true, is_mask);
 
        if (attrs & (1ULL << OVS_KEY_ATTR_VLAN)) {
                __be16 tci;
@@ -643,6 +646,18 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
        if (attrs & (1ULL << OVS_KEY_ATTR_IPV4)) {
                const struct ovs_key_ipv4 *ipv4_key;
 
+               /* Add eth.type value for layer 3 flows */
+               if (!(attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE))) {
+                       __be16 eth_type;
+
+                       if (is_mask) {
+                               eth_type = htons(0xffff);
+                       } else {
+                               eth_type = htons(ETH_P_IP);
+                       }
+                       SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
+               }
+
                ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
                if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
                        OVS_NLERR("Unknown IPv4 fragment type (value=%d, 
max=%d).\n",
@@ -667,6 +682,18 @@ static int ovs_key_from_nlattrs(struct sw_flow_match 
*match, u64 attrs,
        if (attrs & (1ULL << OVS_KEY_ATTR_IPV6)) {
                const struct ovs_key_ipv6 *ipv6_key;
 
+               /* Add eth.type value for layer 3 flows */
+               if (!(attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE))) {
+                       __be16 eth_type;
+
+                       if (is_mask) {
+                               eth_type = htons(0xffff);
+                       } else {
+                               eth_type = htons(ETH_P_IPV6);
+                       }
+                       SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
+               }
+
                ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
                if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
                        OVS_NLERR("Unknown IPv6 fragment type (value=%d, 
max=%d).\n",
@@ -977,7 +1004,7 @@ int ovs_nla_put_flow(struct datapath *dp, const struct 
sw_flow_key *swkey,
                     const struct sw_flow_key *output, struct sk_buff *skb)
 {
        struct ovs_key_ethernet *eth_key;
-       struct nlattr *nla, *encap;
+       struct nlattr *nla, *encap = NULL;
        bool is_mask = (swkey != output);
 
        if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
@@ -1024,6 +1051,9 @@ int ovs_nla_put_flow(struct datapath *dp, const struct 
sw_flow_key *swkey,
        if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
                goto nla_put_failure;
 
+       if (swkey->phy.noeth)
+               goto noethernet;
+
        nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
        if (!nla)
                goto nla_put_failure;
@@ -1041,8 +1071,7 @@ int ovs_nla_put_flow(struct datapath *dp, const struct 
sw_flow_key *swkey,
                encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP);
                if (!swkey->eth.tci)
                        goto unencap;
-       } else
-               encap = NULL;
+       }
 
        if (swkey->eth.type == htons(ETH_P_802_2)) {
                /*
@@ -1061,6 +1090,7 @@ int ovs_nla_put_flow(struct datapath *dp, const struct 
sw_flow_key *swkey,
        if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
                goto nla_put_failure;
 
+noethernet:
        if (swkey->eth.type == htons(ETH_P_IP)) {
                struct ovs_key_ipv4 *ipv4_key;
 
@@ -1470,7 +1500,8 @@ static int validate_and_copy_set_tun(const struct nlattr 
*attr,
 static int validate_set(const struct nlattr *a,
                        const struct sw_flow_key *flow_key,
                        struct sw_flow_actions **sfa,
-                       bool *set_tun, __be16 eth_type)
+                       bool *set_tun, __be16 eth_type,
+                       bool noeth)
 {
        const struct nlattr *ovs_key = nla_data(a);
        int key_type = nla_type(ovs_key);
@@ -1491,7 +1522,11 @@ static int validate_set(const struct nlattr *a,
 
        case OVS_KEY_ATTR_PRIORITY:
        case OVS_KEY_ATTR_SKB_MARK:
+               break;
+
        case OVS_KEY_ATTR_ETHERNET:
+               if (noeth)
+                       return -EINVAL;
                break;
 
        case OVS_KEY_ATTR_TUNNEL:
@@ -1608,6 +1643,7 @@ static int ovs_nla_copy_actions__(const struct nlattr 
*attr,
 {
        const struct nlattr *a;
        int rem, err;
+       bool noeth = key->phy.noeth;
 
        if (depth >= SAMPLE_ACTION_DEPTH)
                return -EOVERFLOW;
@@ -1618,6 +1654,8 @@ static int ovs_nla_copy_actions__(const struct nlattr 
*attr,
                        [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
                        [OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
                        [OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
+                       [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct 
ovs_action_push_eth),
+                       [OVS_ACTION_ATTR_POP_ETH] = 0,
                        [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct 
ovs_action_push_mpls),
                        [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
                        [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct 
ovs_action_push_vlan),
@@ -1664,10 +1702,22 @@ static int ovs_nla_copy_actions__(const struct nlattr 
*attr,
                        break;
                }
 
+               case OVS_ACTION_ATTR_POP_ETH:
+                       if (noeth)
+                               return -EINVAL;
+                       noeth = true;
+                       break;
+
+               case OVS_ACTION_ATTR_PUSH_ETH:
+                       noeth = false;
+                       break;
+
                case OVS_ACTION_ATTR_POP_VLAN:
                        break;
 
                case OVS_ACTION_ATTR_PUSH_VLAN:
+                       if (noeth)
+                               return -EINVAL;
                        vlan = nla_data(a);
                        if (vlan->vlan_tpid != htons(ETH_P_8021Q))
                                return -EINVAL;
@@ -1722,7 +1772,7 @@ static int ovs_nla_copy_actions__(const struct nlattr 
*attr,
                        break;
 
                case OVS_ACTION_ATTR_SET:
-                       err = validate_set(a, key, sfa, &skip_copy, eth_type);
+                       err = validate_set(a, key, sfa, &skip_copy, eth_type, 
noeth);
                        if (err)
                                return err;
                        break;
diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c
index 33047f2..7e21de7 100644
--- a/datapath/vport-geneve.c
+++ b/datapath/vport-geneve.c
@@ -198,7 +198,7 @@ static int geneve_rcv(struct sock *sk, struct sk_buff *skb)
        ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags,
                                geneveh->options, opts_len);
 
-       ovs_vport_receive(vport_from_priv(geneve_port), skb, &tun_info);
+       ovs_vport_receive(vport_from_priv(geneve_port), skb, &tun_info, false);
        goto out;
 
 error:
@@ -358,6 +358,10 @@ static int geneve_send(struct vport *vport, struct sk_buff 
*skb)
        int sent_len;
        int err;
 
+       if (unlikely(OVS_CB(skb)->is_layer3)) {
+               return -EINVAL;
+       }
+
        if (unlikely(!OVS_CB(skb)->tun_info))
                return -EINVAL;
 
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index d2a2602..84a9047 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -113,7 +113,7 @@ static int gre_rcv(struct sk_buff *skb,
        ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key,
                               filter_tnl_flags(tpi->flags), NULL, 0);
 
-       ovs_vport_receive(vport, skb, &tun_info);
+       ovs_vport_receive(vport, skb, &tun_info, false);
        return PACKET_RCVD;
 }
 
@@ -284,6 +284,9 @@ static int gre_send(struct vport *vport, struct sk_buff 
*skb)
 {
        int hlen;
 
+       if (unlikely(OVS_CB(skb)->is_layer3))
+               return -EINVAL;
+
        if (unlikely(!OVS_CB(skb)->tun_info))
                return -EINVAL;
 
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 637d712..afb9a67 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -76,7 +76,7 @@ static struct net_device_stats *internal_dev_sys_stats(struct 
net_device *netdev
 static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        rcu_read_lock();
-       ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL);
+       ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL, false);
        rcu_read_unlock();
        return 0;
 }
@@ -236,6 +236,9 @@ static int internal_dev_recv(struct vport *vport, struct 
sk_buff *skb)
        struct net_device *netdev = netdev_vport_priv(vport)->dev;
        int len;
 
+       if (unlikely(OVS_CB(skb)->is_layer3))
+               return -EINVAL;
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
        if (vlan_tx_tag_present(skb)) {
                if (unlikely(!__vlan_put_tag(skb,
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index c41e09e..0497d98 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -226,8 +226,6 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
        struct iphdr *iph, *inner_iph;
        struct ovs_tunnel_info tun_info;
        __be64 key;
-       struct ethhdr *ethh;
-       __be16 protocol;
 
        lisp_port = lisp_find_port(dev_net(skb->dev), udp_hdr(skb)->dest);
        if (unlikely(!lisp_port))
@@ -251,26 +249,16 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
        inner_iph = (struct iphdr *)(lisph + 1);
        switch (inner_iph->version) {
        case 4:
-               protocol = htons(ETH_P_IP);
+               skb->protocol = htons(ETH_P_IP);
                break;
        case 6:
-               protocol = htons(ETH_P_IPV6);
+               skb->protocol = htons(ETH_P_IPV6);
                break;
        default:
                goto error;
        }
-       skb->protocol = protocol;
 
-       /* Add Ethernet header */
-       ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
-       memset(ethh, 0, ETH_HLEN);
-       ethh->h_dest[0] = 0x02;
-       ethh->h_source[0] = 0x02;
-       ethh->h_proto = protocol;
-
-       ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
-
-       ovs_vport_receive(vport_from_priv(lisp_port), skb, &tun_info);
+       ovs_vport_receive(vport_from_priv(lisp_port), skb, &tun_info, true);
        goto out;
 
 error:
@@ -434,6 +422,9 @@ static int lisp_send(struct vport *vport, struct sk_buff 
*skb)
        int sent_len;
        int err;
 
+       if (unlikely(!OVS_CB(skb)->is_layer3))
+               return -EINVAL;
+
        if (unlikely(!OVS_CB(skb)->tun_info))
                return -EINVAL;
 
@@ -470,11 +461,6 @@ static int lisp_send(struct vport *vport, struct sk_buff 
*skb)
                        goto err_free_rt;
        }
 
-       /* Reset l2 headers. */
-       skb_pull(skb, network_offset);
-       skb_reset_mac_header(skb);
-       vlan_set_tci(skb, 0);
-
        skb_reset_inner_headers(skb);
 
        __skb_push(skb, LISP_HLEN);
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index c15923b..1afef3f 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -209,7 +209,7 @@ static void netdev_port_receive(struct vport *vport, struct 
sk_buff *skb)
        skb_push(skb, ETH_HLEN);
        ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
 
-       ovs_vport_receive(vport, skb, NULL);
+       ovs_vport_receive(vport, skb, NULL, false);
        return;
 
 error:
@@ -232,6 +232,9 @@ static int netdev_send(struct vport *vport, struct sk_buff 
*skb)
        int mtu = netdev_vport->dev->mtu;
        int len;
 
+       if (unlikely(OVS_CB(skb)->is_layer3))
+               return -EINVAL;
+
        if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
                net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
                                     netdev_vport->dev->name,
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index d93a844..d616aa7 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -70,7 +70,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff 
*skb, __be32 vx_vni)
        key = cpu_to_be64(ntohl(vx_vni) >> 8);
        ovs_flow_tun_info_init(&tun_info, iph, key, TUNNEL_KEY, NULL, 0);
 
-       ovs_vport_receive(vport, skb, &tun_info);
+       ovs_vport_receive(vport, skb, &tun_info, false);
 }
 
 static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
@@ -151,6 +151,11 @@ static int vxlan_tnl_send(struct vport *vport, struct 
sk_buff *skb)
        int port_max;
        int err;
 
+       if (unlikely(OVS_CB(skb)->is_layer3)) {
+               err = -EINVAL;
+               goto error;
+       }
+
        if (unlikely(!OVS_CB(skb)->tun_info)) {
                err = -EINVAL;
                goto error;
diff --git a/datapath/vport.c b/datapath/vport.c
index 02ccc89..c15b77f 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -462,13 +462,15 @@ u32 ovs_vport_find_upcall_portid(const struct vport *p, 
struct sk_buff *skb)
  * @vport: vport that received the packet
  * @skb: skb that was received
  * @tun_info: tunnel (if any) that carried packet
+ * @is_layer3: packet is layer 3
  *
  * Must be called with rcu_read_lock.  The packet cannot be shared and
  * skb->data should point to the Ethernet header.  The caller must have already
  * called compute_ip_summed() to initialize the checksumming fields.
  */
 void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
-                      struct ovs_tunnel_info *tun_info)
+                      struct ovs_tunnel_info *tun_info,
+                      bool is_layer3)
 {
        struct pcpu_sw_netstats *stats;
 
@@ -479,6 +481,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff 
*skb,
        u64_stats_update_end(&stats->syncp);
 
        OVS_CB(skb)->tun_info = tun_info;
+       OVS_CB(skb)->is_layer3 = is_layer3;
        ovs_dp_process_received_packet(vport, skb);
 }
 
diff --git a/datapath/vport.h b/datapath/vport.h
index bdd9a89..20eca8b 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -211,7 +211,7 @@ static inline struct vport *vport_from_priv(void *priv)
 }
 
 void ovs_vport_receive(struct vport *, struct sk_buff *,
-                      struct ovs_tunnel_info *);
+                      struct ovs_tunnel_info *, bool);
 
 /* List of statically compiled vport implementations.  Don't forget to also
  * add yours to the list at the top of vport.c. */
-- 
1.8.5.2 (Apple Git-48)

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

Reply via email to