On Mon, Nov 3, 2014 at 1:36 PM, Lorand Jakab <loja...@cisco.com> wrote: > 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 | 85 > ++++++++++++++++++++++++++++++++++++------- > datapath/flow.c | 44 ++++++++++++---------- > datapath/flow.h | 4 +- > datapath/flow_netlink.c | 79 +++++++++++++++++++++++++++++++++++++--- > datapath/vport-geneve.c | 2 +- > datapath/vport-gre.c | 2 +- > datapath/vport-internal_dev.c | 2 +- > datapath/vport-lisp.c | 28 +++----------- > datapath/vport-netdev.c | 2 +- > datapath/vport-vxlan.c | 2 +- > datapath/vport.c | 6 ++- > datapath/vport.h | 2 +- > 12 files changed, 187 insertions(+), 71 deletions(-) > > diff --git a/datapath/actions.c b/datapath/actions.c > index a42ad1e..f4d79e0 100644 > --- a/datapath/actions.c > +++ b/datapath/actions.c > @@ -257,6 +257,27 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 > *current_tci) > return 0; > } > > +/* De-accelerate any hardware accelerated VLAN tag present in skb. */ > +static int deaccel_vlan_tx_tag(struct sk_buff *skb) > +{ > + u16 current_tag; > + > + /* push down current VLAN tag */ > + current_tag = vlan_tx_tag_get(skb); > + > + if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag)) > + return -ENOMEM; > + > + /* Update mac_len for subsequent MPLS actions */ > + skb->mac_len += VLAN_HLEN; > + > + if (skb->ip_summed == CHECKSUM_COMPLETE) > + skb->csum = csum_add(skb->csum, csum_partial(skb->data > + + (2 * ETH_ALEN), VLAN_HLEN, 0)); > + > + return 0; > +} > + > static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) > { > __be16 tci; > @@ -293,20 +314,10 @@ static int push_vlan(struct sk_buff *skb, struct > sw_flow_key *key, > const struct ovs_action_push_vlan *vlan) > { > if (unlikely(vlan_tx_tag_present(skb))) { > - u16 current_tag; > - > - /* push down current VLAN tag */ > - current_tag = vlan_tx_tag_get(skb); > - > - if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag)) > - return -ENOMEM; > - > - /* Update mac_len for subsequent MPLS actions */ > - skb->mac_len += VLAN_HLEN; > - > - if (skb->ip_summed == CHECKSUM_COMPLETE) > - skb->csum = csum_add(skb->csum, csum_partial(skb->data > - + (2 * ETH_ALEN), VLAN_HLEN, 0)); > + int err; > + err = deaccel_vlan_tx_tag(skb); > + if (unlikely(err)) > + return err; > > invalidate_flow_key(key); > } else { > @@ -336,6 +347,44 @@ static int set_eth_addr(struct sk_buff *skb, struct > sw_flow_key *key, > return 0; > } > > +static int pop_eth(struct sk_buff *skb) > +{ > + skb_pull_rcsum(skb, ETH_HLEN); > + skb_reset_mac_header(skb); > + skb->mac_len -= ETH_HLEN; > + > + return 0; > +} > + We should pop mac header offset too(skb_pop_mac_header()). So that GSO works for l3 packet.
> +static int push_eth(struct sk_buff *skb, const struct ovs_action_push_eth > *ethh) > +{ > + /* De-accelerate any hardware accelerated VLAN tag added to a previous > + * Ethernet header */ > + if (unlikely(vlan_tx_tag_present(skb))) { > + int err; > + err = deaccel_vlan_tx_tag(skb); > + if (unlikely(err)) > + return err; > + } > + > + /* Add the new Ethernet header */ > + if (skb_cow_head(skb, ETH_HLEN) < 0) > + return -ENOMEM; > + > + skb_push(skb, ETH_HLEN); > + skb_reset_mac_header(skb); > + skb_reset_mac_len(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; > + > + ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); > + > + skb->protocol = ethh->eth_type; > + return 0; > +} > + > static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, > __be32 *addr, __be32 new_addr) > { > @@ -896,6 +945,14 @@ static int do_execute_actions(struct datapath *dp, > struct sk_buff *skb, > err = pop_vlan(skb, key); > break; > > + case OVS_ACTION_ATTR_PUSH_ETH: > + err = push_eth(skb, nla_data(a)); > + break; > + > + case OVS_ACTION_ATTR_POP_ETH: > + err = pop_eth(skb); > + break; > + > case OVS_ACTION_ATTR_RECIRC: > err = execute_recirc(dp, skb, key, a, rem); > if (last_action(a, rem)) { > diff --git a/datapath/flow.c b/datapath/flow.c > index a3c5d2f..f54e361 100644 > --- a/datapath/flow.c > +++ b/datapath/flow.c > @@ -458,28 +458,30 @@ static int key_extract(struct sk_buff *skb, 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); > + /* Link layer. */ > + if (key->phy.is_layer3) { > + key->eth.type = skb->protocol; > + } else { > + 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. > - */ > + __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.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); > @@ -682,7 +684,8 @@ int ovs_flow_key_update(struct sk_buff *skb, struct > sw_flow_key *key) > > int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, > struct sk_buff *skb, > - struct sw_flow_key *key) > + struct sw_flow_key *key, > + bool is_layer3) > { > /* Extract metadata from packet. */ > if (tun_info) { > @@ -706,6 +709,7 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info > *tun_info, > key->phy.priority = skb->priority; > key->phy.in_port = OVS_CB(skb)->input_vport->port_no; > key->phy.skb_mark = skb->mark; > + key->phy.is_layer3 = is_layer3; > key->ovs_flow_hash = 0; > key->recirc_id = 0; > > diff --git a/datapath/flow.h b/datapath/flow.h > index c78b864..fbbc6f1 100644 > --- a/datapath/flow.h > +++ b/datapath/flow.h > @@ -130,6 +130,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 is_layer3; /* 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. */ > @@ -253,7 +254,8 @@ void ovs_flow_stats_clear(struct sw_flow *); > u64 ovs_flow_used_time(unsigned long flow_jiffies); > > int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, > - struct sk_buff *skb, struct sw_flow_key *key); > + struct sk_buff *skb, struct sw_flow_key *key, > + bool is_layer3); > /* Extract key from packet coming from userspace. */ > int ovs_flow_key_extract_userspace(const struct nlattr *attr, > struct sk_buff *skb, > diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c > index 37b0bdd..17e239b 100644 > --- a/datapath/flow_netlink.c > +++ b/datapath/flow_netlink.c > @@ -114,7 +114,7 @@ static void update_range(struct sw_flow_match *match, > static bool match_validate(const struct sw_flow_match *match, > u64 key_attrs, u64 mask_attrs, bool log) > { > - 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 > @@ -137,6 +137,10 @@ static bool match_validate(const struct sw_flow_match > *match, > | (1ULL << OVS_KEY_ATTR_IN_PORT) > | (1ULL << OVS_KEY_ATTR_ETHERTYPE)); > > + /* If Ethertype is present, expect MAC addresses */ > + if (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) > + key_expected |= 1ULL << OVS_KEY_ATTR_ETHERNET; > + > /* Check key attributes. */ > if (match->key->eth.type == htons(ETH_P_ARP) > || match->key->eth.type == htons(ETH_P_RARP)) { > @@ -685,6 +689,15 @@ static int metadata_from_nlattrs(struct sw_flow_match > *match, u64 *attrs, > return -EINVAL; > *attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL); > } > + if (is_mask) > + /* Always exact match is_layer3 */ > + SW_FLOW_KEY_PUT(match, phy.is_layer3, true, is_mask); > + else { > + if (*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) > + SW_FLOW_KEY_PUT(match, phy.is_layer3, false, is_mask); > + else > + SW_FLOW_KEY_PUT(match, phy.is_layer3, true, is_mask); > + } > return 0; > } > > @@ -751,6 +764,17 @@ 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(log, > @@ -776,6 +800,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(log, > @@ -1151,7 +1187,7 @@ int ovs_nla_put_flow(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)) > @@ -1190,6 +1226,9 @@ int ovs_nla_put_flow(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.is_layer3) > + goto noethernet; > + > nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); > if (!nla) > goto nla_put_failure; > @@ -1207,8 +1246,7 @@ int ovs_nla_put_flow(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)) { > /* > @@ -1227,6 +1265,7 @@ int ovs_nla_put_flow(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; > > @@ -1640,7 +1679,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 log) > + bool *set_tun, __be16 eth_type, bool log, > + bool is_layer3) > { > const struct nlattr *ovs_key = nla_data(a); > int key_type = nla_type(ovs_key); > @@ -1661,7 +1701,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 (is_layer3) > + return -EINVAL; > break; > Why similar checks are not done for MPLS actions? > case OVS_KEY_ATTR_TUNNEL: > @@ -1779,6 +1823,7 @@ static int __ovs_nla_copy_actions(const struct nlattr > *attr, > { > const struct nlattr *a; > int rem, err; > + bool is_layer3 = key->phy.is_layer3; > > if (depth >= SAMPLE_ACTION_DEPTH) > return -EOVERFLOW; > @@ -1789,6 +1834,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), > @@ -1835,11 +1882,31 @@ static int __ovs_nla_copy_actions(const struct nlattr > *attr, > break; > } > > + case OVS_ACTION_ATTR_POP_ETH: > + if (is_layer3) > + return -EINVAL; > + if (vlan_tci & htons(VLAN_TAG_PRESENT)) > + return -EINVAL; > + is_layer3 = true; > + break; > + > + case OVS_ACTION_ATTR_PUSH_ETH: > + /* For now disallow pushing an Ethernet header if one > + * is already present */ > + if (!is_layer3) > + return -EINVAL; > + is_layer3 = false; > + break; > + > case OVS_ACTION_ATTR_POP_VLAN: > + if (is_layer3) > + return -EINVAL; > vlan_tci = htons(0); > break; > > case OVS_ACTION_ATTR_PUSH_VLAN: > + if (is_layer3) > + return -EINVAL; > vlan = nla_data(a); > if (vlan->vlan_tpid != htons(ETH_P_8021Q)) > return -EINVAL; > @@ -1889,7 +1956,7 @@ static int __ovs_nla_copy_actions(const struct nlattr > *attr, > > case OVS_ACTION_ATTR_SET: > err = validate_set(a, key, sfa, &skip_copy, eth_type, > - log); > + log, is_layer3); > if (err) > return err; > break; > diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c > index 7c08577..75248cc 100644 > --- a/datapath/vport-geneve.c > +++ b/datapath/vport-geneve.c > @@ -200,7 +200,7 @@ static int geneve_rcv(struct sock *sk, struct sk_buff > *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: > diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c > index 41c025d..ffb69d1 100644 > --- a/datapath/vport-gre.c > +++ b/datapath/vport-gre.c > @@ -114,7 +114,7 @@ static int gre_rcv(struct sk_buff *skb, > ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, 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; > } > > diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c > index a1c4949..faf8378 100644 > --- a/datapath/vport-internal_dev.c > +++ b/datapath/vport-internal_dev.c > @@ -77,7 +77,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; > } > diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c > index f3d450f..4f35c33 100644 > --- a/datapath/vport-lisp.c > +++ b/datapath/vport-lisp.c > @@ -232,8 +232,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)) > @@ -259,26 +257,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: > @@ -452,8 +440,9 @@ static int lisp_send(struct vport *vport, struct sk_buff > *skb) > > tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; > > - if (skb->protocol != htons(ETH_P_IP) && > - skb->protocol != htons(ETH_P_IPV6)) { > + if ((skb->protocol != htons(ETH_P_IP) && > + skb->protocol != htons(ETH_P_IPV6)) || > + vlan_tx_tag_present(skb)) { > kfree_skb(skb); > return 0; > } > @@ -483,11 +472,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 9c0908a..72bba4e 100644 > --- a/datapath/vport-netdev.c > +++ b/datapath/vport-netdev.c > @@ -211,7 +211,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: > diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c > index 8689853..ad67835 100644 > --- a/datapath/vport-vxlan.c > +++ b/datapath/vport-vxlan.c > @@ -72,7 +72,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff > *skb, __be32 vx_vni) > udp_hdr(skb)->source, udp_hdr(skb)->dest, > 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) > diff --git a/datapath/vport.c b/datapath/vport.c > index 274e47f..7b588bd 100644 > --- a/datapath/vport.c > +++ b/datapath/vport.c > @@ -438,13 +438,15 @@ u32 ovs_vport_find_upcall_portid(const struct vport > *vport, 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, > - const struct ovs_tunnel_info *tun_info) > + const struct ovs_tunnel_info *tun_info, > + bool is_layer3) > { > struct pcpu_sw_netstats *stats; > struct sw_flow_key key; > @@ -459,7 +461,7 @@ void ovs_vport_receive(struct vport *vport, struct > sk_buff *skb, > ovs_skb_init_inner_protocol(skb); > OVS_CB(skb)->input_vport = vport; > OVS_CB(skb)->egress_tun_info = NULL; > - error = ovs_flow_key_extract(tun_info, skb, &key); > + error = ovs_flow_key_extract(tun_info, skb, &key, is_layer3); > if (unlikely(error)) { > kfree_skb(skb); > return; > diff --git a/datapath/vport.h b/datapath/vport.h > index c0ab88a..aeebc9a 100644 > --- a/datapath/vport.h > +++ b/datapath/vport.h > @@ -218,7 +218,7 @@ static inline struct vport *vport_from_priv(void *priv) > } > > void ovs_vport_receive(struct vport *, struct sk_buff *, > - const struct ovs_tunnel_info *); > + const struct ovs_tunnel_info *, bool is_layer3); > > /* List of statically compiled vport implementations. Don't forget to also > * add yours to the list at the top of vport.c. > -- Have you tried running GSO traffic over lisp using OVS compat GSO code and upstream GSO code? > 1.9.3 (Apple Git-50) > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev