Skip to content

Commit

Permalink
datapath: compat: Refactor egress tunnel info
Browse files Browse the repository at this point in the history
upstream tunnel egress info is retrieved using ndo_fill_metadata_dst.
Since we do not have it on older kernel we need to keep vport operation
to do same on these kernels.
Following patch try to merge these to operations into one to avoid code
duplication.
This commit backports fc4099f1 ("openvswitch:
Fix egress tunnel info.")

Signed-off-by: Pravin B Shelar <pshelar@ovn.org>
Acked-by: Jesse Gross <jesse@kernel.org>
  • Loading branch information
pshelar committed Jul 9, 2016
1 parent 9dede5c commit aad7cb9
Show file tree
Hide file tree
Showing 26 changed files with 345 additions and 216 deletions.
1 change: 1 addition & 0 deletions acinclude.m4
Expand Up @@ -436,6 +436,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/linux/net.h], [sock_create_kern.*net],
[OVS_DEFINE([HAVE_SOCK_CREATE_KERN_NET])])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [ndo_fill_metadata_dst])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_disable_lro])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_get_stats])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_get_by_index_rcu])
Expand Down
17 changes: 9 additions & 8 deletions datapath/actions.c
Expand Up @@ -775,20 +775,21 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
kfree_skb(skb);
}
}

static int output_userspace(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key, const struct nlattr *attr,
const struct nlattr *actions, int actions_len,
uint32_t cutlen)
{
struct ip_tunnel_info info;
struct dp_upcall_info upcall;
const struct nlattr *a;
int rem;
int rem, err;

memset(&upcall, 0, sizeof(upcall));
upcall.cmd = OVS_PACKET_CMD_ACTION;
upcall.mru = OVS_CB(skb)->mru;

SKB_INIT_FILL_METADATA_DST(skb);
for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
a = nla_next(a, &rem)) {
switch (nla_type(a)) {
Expand All @@ -808,11 +809,9 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
if (vport) {
int err;

upcall.egress_tun_info = &info;
err = ovs_vport_get_egress_tun_info(vport, skb,
&upcall);
if (err)
upcall.egress_tun_info = NULL;
err = dev_fill_metadata_dst(vport->dev, skb);
if (!err)
upcall.egress_tun_info = skb_tunnel_info(skb);
}

break;
Expand All @@ -828,7 +827,9 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
} /* End of switch. */
}

return ovs_dp_upcall(dp, skb, key, &upcall, cutlen);
err = ovs_dp_upcall(dp, skb, key, &upcall, cutlen);
SKB_RESTORE_FILL_METADATA_DST(skb);
return err;
}

static int sample(struct datapath *dp, struct sk_buff *skb,
Expand Down
5 changes: 2 additions & 3 deletions datapath/datapath.c
Expand Up @@ -503,9 +503,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,

if (upcall_info->egress_tun_info) {
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
err = ovs_nla_put_egress_tunnel_key(user_skb,
upcall_info->egress_tun_info,
upcall_info->egress_tun_opts);
err = ovs_nla_put_tunnel_info(user_skb,
upcall_info->egress_tun_info);
BUG_ON(err);
nla_nest_end(user_skb, nla);
}
Expand Down
1 change: 0 additions & 1 deletion datapath/datapath.h
Expand Up @@ -120,7 +120,6 @@ struct ovs_skb_cb {
*/
struct dp_upcall_info {
struct ip_tunnel_info *egress_tun_info;
const void *egress_tun_opts;
const struct nlattr *userdata;
const struct nlattr *actions;
int actions_len;
Expand Down
18 changes: 7 additions & 11 deletions datapath/flow_netlink.c
Expand Up @@ -719,7 +719,7 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
if ((output->tun_flags & TUNNEL_OAM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
return -EMSGSIZE;
if (tun_opts) {
if (swkey_tun_opts_len) {
if (output->tun_flags & TUNNEL_GENEVE_OPT &&
nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
swkey_tun_opts_len, tun_opts))
Expand Down Expand Up @@ -751,13 +751,12 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
return 0;
}

int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
const struct ip_tunnel_info *egress_tun_info,
const void *egress_tun_opts)
int ovs_nla_put_tunnel_info(struct sk_buff *skb,
struct ip_tunnel_info *tun_info)
{
return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key,
egress_tun_opts,
egress_tun_info->options_len);
return __ipv4_tun_to_nlattr(skb, &tun_info->key,
ip_tunnel_info_opts(tun_info),
tun_info->options_len);
}

static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
Expand Down Expand Up @@ -2399,10 +2398,7 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
if (!start)
return -EMSGSIZE;

err = ipv4_tun_to_nlattr(skb, &tun_info->key,
tun_info->options_len ?
ip_tunnel_info_opts(tun_info) : NULL,
tun_info->options_len);
err = ovs_nla_put_tunnel_info(skb, tun_info);
if (err)
return err;
nla_nest_end(skb, start);
Expand Down
5 changes: 2 additions & 3 deletions datapath/flow_netlink.h
Expand Up @@ -55,9 +55,8 @@ int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb);
int ovs_nla_get_match(struct net *, struct sw_flow_match *,
const struct nlattr *key, const struct nlattr *mask,
bool log);
int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
const struct ip_tunnel_info *egress_tun_info,
const void *egress_tun_opts);
int ovs_nla_put_tunnel_info(struct sk_buff *skb,
struct ip_tunnel_info *tun_info);

bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log);
int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
Expand Down
32 changes: 32 additions & 0 deletions datapath/linux/compat/dev-openvswitch.c
Expand Up @@ -3,6 +3,11 @@
#include <linux/version.h>
#include <net/rtnetlink.h>

#include "gso.h"
#include "vport.h"
#include "vport-internal_dev.h"
#include "vport-netdev.h"

#ifndef HAVE_DEV_DISABLE_LRO

#ifdef NETIF_F_LRO
Expand Down Expand Up @@ -54,3 +59,30 @@ int rpl_rtnl_delete_link(struct net_device *dev)
#endif
return 0;
}

#ifndef HAVE_NDO_FILL_METADATA_DST
int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info;
struct vport *vport;

if (!SKB_SETUP_FILL_METADATA_DST(skb))
return -ENOMEM;

vport = ovs_netdev_get_vport(dev);
if (!vport)
return -EINVAL;

if (!vport->ops->fill_metadata_dst)
return -EINVAL;

info = skb_tunnel_info(skb);
if (!info)
return -ENOMEM;
if (unlikely(!(info->mode & IP_TUNNEL_INFO_TX)))
return -EINVAL;

return vport->ops->fill_metadata_dst(dev, skb);
}
EXPORT_SYMBOL_GPL(ovs_dev_fill_metadata_dst);
#endif
43 changes: 36 additions & 7 deletions datapath/linux/compat/geneve.c
Expand Up @@ -615,14 +615,12 @@ static struct rtable *geneve_get_rt(struct sk_buff *skb,
rt = ip_route_output_key(geneve->net, fl4);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr);
dev->stats.tx_carrier_errors++;
return rt;
return ERR_PTR(-ENETUNREACH);
}
if (rt->dst.dev == dev) { /* is this necessary? */
netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
dev->stats.collisions++;
ip_rt_put(rt);
return ERR_PTR(-EINVAL);
return ERR_PTR(-ELOOP);
}
return rt;
}
Expand All @@ -649,12 +647,12 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb)
struct ip_tunnel_info *info = NULL;
struct rtable *rt = NULL;
const struct iphdr *iip; /* interior IP header */
int err = -EINVAL;
struct flowi4 fl4;
__u8 tos, ttl;
__be16 sport;
bool udp_csum;
__be16 df;
int err;

if (geneve->collect_md) {
info = skb_tunnel_info(skb);
Expand All @@ -669,7 +667,7 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb)
rt = geneve_get_rt(skb, dev, &fl4, info);
if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr);
dev->stats.tx_carrier_errors++;
err = PTR_ERR(rt);
goto tx_error;
}

Expand Down Expand Up @@ -721,7 +719,12 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb)
tx_error:
dev_kfree_skb(skb);
err:
dev->stats.tx_errors++;
if (err == -ELOOP)
dev->stats.collisions++;
else if (err == -ENETUNREACH)
dev->stats.tx_carrier_errors++;
else
dev->stats.tx_errors++;
return NETDEV_TX_OK;
}
EXPORT_SYMBOL(rpl_geneve_xmit);
Expand Down Expand Up @@ -765,6 +768,29 @@ static int geneve_change_mtu(struct net_device *dev, int new_mtu)
return __geneve_change_mtu(dev, new_mtu, true);
}

int ovs_geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info = skb_tunnel_info(skb);
struct geneve_dev *geneve = netdev_priv(dev);
struct rtable *rt;
struct flowi4 fl4;

if (ip_tunnel_info_af(info) != AF_INET)
return -EINVAL;

rt = geneve_get_rt(skb, dev, &fl4, info);
if (IS_ERR(rt))
return PTR_ERR(rt);

ip_rt_put(rt);
info->key.u.ipv4.src = fl4.saddr;
info->key.tp_src = udp_flow_src_port(geneve->net, skb,
1, USHRT_MAX, true);
info->key.tp_dst = geneve->dst_port;
return 0;
}
EXPORT_SYMBOL_GPL(ovs_geneve_fill_metadata_dst);

static const struct net_device_ops geneve_netdev_ops = {
.ndo_init = geneve_init,
.ndo_uninit = geneve_uninit,
Expand All @@ -775,6 +801,9 @@ static const struct net_device_ops geneve_netdev_ops = {
.ndo_change_mtu = geneve_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
#ifdef HAVE_NDO_FILL_METADATA_DST
.ndo_fill_metadata_dst = geneve_fill_metadata_dst,
#endif
};

static void geneve_get_drvinfo(struct net_device *dev,
Expand Down
45 changes: 45 additions & 0 deletions datapath/linux/compat/gso.h
Expand Up @@ -23,6 +23,11 @@ struct ovs_gso_cb {
#ifndef HAVE_INNER_NETWORK_HEADER
unsigned int inner_network_header;
#endif
#ifndef HAVE_NDO_FILL_METADATA_DST
/* Keep original tunnel info during userspace action execution. */
struct metadata_dst *fill_md_dst;
#endif

};
#define OVS_GSO_CB(skb) ((struct ovs_gso_cb *)(skb)->cb)

Expand Down Expand Up @@ -197,4 +202,44 @@ static inline void ovs_dst_release(struct dst_entry *dst)
#define ovs_dst_release dst_release
#endif

#ifndef HAVE_NDO_FILL_METADATA_DST
#define SKB_INIT_FILL_METADATA_DST(skb) OVS_GSO_CB(skb)->fill_md_dst = NULL;

#define SKB_RESTORE_FILL_METADATA_DST(skb) do { \
if (OVS_GSO_CB(skb)->fill_md_dst) { \
kfree(OVS_GSO_CB(skb)->tun_dst); \
OVS_GSO_CB(skb)->tun_dst = OVS_GSO_CB(skb)->fill_md_dst; \
} \
} while (0)


#define SKB_SETUP_FILL_METADATA_DST(skb) ({ \
struct metadata_dst *new_md_dst; \
struct metadata_dst *md_dst; \
int md_size; \
int ret = 1; \
\
SKB_RESTORE_FILL_METADATA_DST(skb); \
new_md_dst = kmalloc(sizeof(struct metadata_dst) + 256, GFP_ATOMIC); \
if (new_md_dst) { \
md_dst = OVS_GSO_CB(skb)->tun_dst; \
md_size = new_md_dst->u.tun_info.options_len; \
memcpy(&new_md_dst->u.tun_info, &md_dst->u.tun_info, \
sizeof(struct ip_tunnel_info) + md_size); \
\
OVS_GSO_CB(skb)->fill_md_dst = md_dst; \
OVS_GSO_CB(skb)->tun_dst = new_md_dst; \
ret = 1; \
} else { \
ret = 0; \
} \
ret; \
})

#else
#define SKB_INIT_FILL_METADATA_DST(skb) do {} while(0)
#define SKB_SETUP_FILL_METADATA_DST(skb) (true)
#define SKB_RESTORE_FILL_METADATA_DST(skb) do {} while(0)
#endif

#endif
4 changes: 4 additions & 0 deletions datapath/linux/compat/include/linux/netdevice.h
Expand Up @@ -249,4 +249,8 @@ do { \

#endif

#ifndef HAVE_NDO_FILL_METADATA_DST
#define dev_fill_metadata_dst ovs_dev_fill_metadata_dst
int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
#endif
#endif /* __LINUX_NETDEVICE_WRAPPER_H */
3 changes: 3 additions & 0 deletions datapath/linux/compat/include/net/geneve.h
Expand Up @@ -91,4 +91,7 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb);
#define geneve_init_module rpl_geneve_init_module
#define geneve_cleanup_module rpl_geneve_cleanup_module

#define geneve_fill_metadata_dst ovs_geneve_fill_metadata_dst
int ovs_geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);

#endif /*ifdef__NET_GENEVE_H */
3 changes: 3 additions & 0 deletions datapath/linux/compat/include/net/gre.h
Expand Up @@ -66,4 +66,7 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb);
#define ipgre_init rpl_ipgre_init
#define ipgre_fini rpl_ipgre_fini

#define gre_fill_metadata_dst ovs_gre_fill_metadata_dst
int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);

#endif
3 changes: 3 additions & 0 deletions datapath/linux/compat/include/net/lisp.h
Expand Up @@ -21,4 +21,7 @@ void rpl_lisp_cleanup_module(void);
#define lisp_xmit rpl_lisp_xmit
netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb);

#define lisp_fill_metadata_dst ovs_lisp_fill_metadata_dst
int ovs_lisp_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);

#endif /*ifdef__NET_LISP_H */
3 changes: 3 additions & 0 deletions datapath/linux/compat/include/net/stt.h
Expand Up @@ -64,4 +64,7 @@ static inline netdev_tx_t ovs_stt_xmit(struct sk_buff *skb)
#define stt_init_module ovs_stt_init_module
#define stt_cleanup_module ovs_stt_cleanup_module

#define stt_fill_metadata_dst ovs_stt_fill_metadata_dst
int ovs_stt_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);

#endif /*ifdef__NET_STT_H */
2 changes: 2 additions & 0 deletions datapath/linux/compat/include/net/vxlan.h
Expand Up @@ -274,4 +274,6 @@ netdev_tx_t rpl_vxlan_xmit(struct sk_buff *skb);
#define vxlan_init_module rpl_vxlan_init_module
#define vxlan_cleanup_module rpl_vxlan_cleanup_module

#define vxlan_fill_metadata_dst ovs_vxlan_fill_metadata_dst
int ovs_vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
#endif

0 comments on commit aad7cb9

Please sign in to comment.