diff options
Diffstat (limited to 'datapath/linux/compat')
-rw-r--r-- | datapath/linux/compat/dev-openvswitch.c | 32 | ||||
-rw-r--r-- | datapath/linux/compat/geneve.c | 43 | ||||
-rw-r--r-- | datapath/linux/compat/gso.h | 45 | ||||
-rw-r--r-- | datapath/linux/compat/include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | datapath/linux/compat/include/net/geneve.h | 3 | ||||
-rw-r--r-- | datapath/linux/compat/include/net/gre.h | 3 | ||||
-rw-r--r-- | datapath/linux/compat/include/net/lisp.h | 3 | ||||
-rw-r--r-- | datapath/linux/compat/include/net/stt.h | 3 | ||||
-rw-r--r-- | datapath/linux/compat/include/net/vxlan.h | 2 | ||||
-rw-r--r-- | datapath/linux/compat/ip_gre.c | 49 | ||||
-rw-r--r-- | datapath/linux/compat/lisp.c | 64 | ||||
-rw-r--r-- | datapath/linux/compat/stt.c | 55 | ||||
-rw-r--r-- | datapath/linux/compat/vxlan.c | 44 |
13 files changed, 318 insertions, 32 deletions
diff --git a/datapath/linux/compat/dev-openvswitch.c b/datapath/linux/compat/dev-openvswitch.c index 0d2088b38..1e870431f 100644 --- a/datapath/linux/compat/dev-openvswitch.c +++ b/datapath/linux/compat/dev-openvswitch.c @@ -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 @@ -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 diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c index 0399de706..054049485 100644 --- a/datapath/linux/compat/geneve.c +++ b/datapath/linux/compat/geneve.c @@ -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; } @@ -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); @@ -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; } @@ -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); @@ -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, @@ -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, diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h index 0f2b09a9a..7a20942a5 100644 --- a/datapath/linux/compat/gso.h +++ b/datapath/linux/compat/gso.h @@ -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) @@ -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 diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index e9fa99579..ac612efee 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -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 */ diff --git a/datapath/linux/compat/include/net/geneve.h b/datapath/linux/compat/include/net/geneve.h index 550f4a77e..a7f22526e 100644 --- a/datapath/linux/compat/include/net/geneve.h +++ b/datapath/linux/compat/include/net/geneve.h @@ -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 */ diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index 60618df9e..8082a9853 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -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 diff --git a/datapath/linux/compat/include/net/lisp.h b/datapath/linux/compat/include/net/lisp.h index b8af17dbb..6b43c77e2 100644 --- a/datapath/linux/compat/include/net/lisp.h +++ b/datapath/linux/compat/include/net/lisp.h @@ -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 */ diff --git a/datapath/linux/compat/include/net/stt.h b/datapath/linux/compat/include/net/stt.h index 28d4dc53c..d2e63d163 100644 --- a/datapath/linux/compat/include/net/stt.h +++ b/datapath/linux/compat/include/net/stt.h @@ -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 */ diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h index 75a5a7acd..589e6f259 100644 --- a/datapath/linux/compat/include/net/vxlan.h +++ b/datapath/linux/compat/include/net/vxlan.h @@ -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 diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 2e1384348..67db9af73 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -256,11 +256,26 @@ static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags, ovs_skb_set_inner_protocol(skb, proto); } +static struct rtable *gre_get_rt(struct sk_buff *skb, + struct net_device *dev, + struct flowi4 *fl, + const struct ip_tunnel_key *key) +{ + struct net *net = dev_net(dev); + + memset(fl, 0, sizeof(*fl)); + fl->daddr = key->u.ipv4.dst; + fl->saddr = key->u.ipv4.src; + fl->flowi4_tos = RT_TOS(key->tos); + fl->flowi4_mark = skb->mark; + fl->flowi4_proto = IPPROTO_GRE; + + return ip_route_output_key(net, fl); +} netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct net *net = dev_net(dev); struct ip_tunnel_info *tun_info; const struct ip_tunnel_key *key; struct flowi4 fl; @@ -276,14 +291,8 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb) goto err_free_skb; key = &tun_info->key; - memset(&fl, 0, sizeof(fl)); - fl.daddr = key->u.ipv4.dst; - fl.saddr = key->u.ipv4.src; - fl.flowi4_tos = RT_TOS(key->tos); - fl.flowi4_mark = skb->mark; - fl.flowi4_proto = IPPROTO_GRE; - - rt = ip_route_output_key(net, &fl); + + rt = gre_get_rt(skb, dev, &fl, key); if (IS_ERR(rt)) goto err_free_skb; @@ -459,6 +468,25 @@ static netdev_tx_t gre_dev_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) +{ + struct ip_tunnel_info *info = skb_tunnel_info(skb); + struct rtable *rt; + struct flowi4 fl4; + + if (ip_tunnel_info_af(info) != AF_INET) + return -EINVAL; + + rt = gre_get_rt(skb, dev, &fl4, &info->key); + if (IS_ERR(rt)) + return PTR_ERR(rt); + + ip_rt_put(rt); + info->key.u.ipv4.src = fl4.saddr; + return 0; +} +EXPORT_SYMBOL_GPL(ovs_gre_fill_metadata_dst); + static const struct net_device_ops gre_tap_netdev_ops = { .ndo_init = gre_tap_init, .ndo_uninit = ip_tunnel_uninit, @@ -472,6 +500,9 @@ static const struct net_device_ops gre_tap_netdev_ops = { #ifdef HAVE_NDO_GET_IFLINK .ndo_get_iflink = ip_tunnel_get_iflink, #endif +#ifdef HAVE_NDO_FILL_METADATA_DST + .ndo_fill_metadata_dst = gre_fill_metadata_dst, +#endif }; static void ipgre_tap_setup(struct net_device *dev) diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c index f1f50aea5..ae3e5f37b 100644 --- a/datapath/linux/compat/lisp.c +++ b/datapath/linux/compat/lisp.c @@ -269,6 +269,24 @@ out: return 0; } +static struct rtable *lisp_get_rt(struct sk_buff *skb, + struct net_device *dev, + struct flowi4 *fl, + const struct ip_tunnel_key *key) +{ + struct net *net = dev_net(dev); + + /* Route lookup */ + memset(fl, 0, sizeof(*fl)); + fl->daddr = key->u.ipv4.dst; + fl->saddr = key->u.ipv4.src; + fl->flowi4_tos = RT_TOS(key->tos); + fl->flowi4_mark = skb->mark; + fl->flowi4_proto = IPPROTO_UDP; + + return ip_route_output_key(net, fl); +} + netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; @@ -298,14 +316,7 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) tun_key = &info->key; - /* Route lookup */ - memset(&fl, 0, sizeof(fl)); - fl.daddr = tun_key->u.ipv4.dst; - fl.saddr = tun_key->u.ipv4.src; - fl.flowi4_tos = RT_TOS(tun_key->tos); - fl.flowi4_mark = skb->mark; - fl.flowi4_proto = IPPROTO_UDP; - rt = ip_route_output_key(net, &fl); + rt = lisp_get_rt(skb, dev, &fl, tun_key); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; @@ -456,6 +467,40 @@ static int lisp_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb, + struct ip_tunnel_info *info, + __be16 sport, __be16 dport) +{ + struct rtable *rt; + struct flowi4 fl4; + + rt = lisp_get_rt(skb, dev, &fl4, &info->key); + if (IS_ERR(rt)) + return PTR_ERR(rt); + ip_rt_put(rt); + + info->key.u.ipv4.src = fl4.saddr; + info->key.tp_src = sport; + info->key.tp_dst = dport; + return 0; +} + +int ovs_lisp_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) +{ + struct lisp_dev *lisp = netdev_priv(dev); + struct net *net = lisp->net; + struct ip_tunnel_info *info = skb_tunnel_info(skb); + __be16 sport, dport; + + sport = htons(get_src_port(net, skb)); + dport = lisp->dst_port; + + if (ip_tunnel_info_af(info) == AF_INET) + return egress_ipv4_tun_info(dev, skb, info, sport, dport); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(ovs_lisp_fill_metadata_dst); + static const struct net_device_ops lisp_netdev_ops = { .ndo_init = lisp_init, .ndo_uninit = lisp_uninit, @@ -466,6 +511,9 @@ static const struct net_device_ops lisp_netdev_ops = { .ndo_change_mtu = lisp_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 = lisp_fill_metadata_dst, +#endif }; static void lisp_get_drvinfo(struct net_device *dev, diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c index 86d225e86..0bdd4db49 100644 --- a/datapath/linux/compat/stt.c +++ b/datapath/linux/compat/stt.c @@ -980,6 +980,24 @@ err_free_rt: return ret; } +static struct rtable *stt_get_rt(struct sk_buff *skb, + struct net_device *dev, + struct flowi4 *fl, + const struct ip_tunnel_key *key) +{ + struct net *net = dev_net(dev); + + /* Route lookup */ + memset(fl, 0, sizeof(*fl)); + fl->daddr = key->u.ipv4.dst; + fl->saddr = key->u.ipv4.src; + fl->flowi4_tos = RT_TOS(key->tos); + fl->flowi4_mark = skb->mark; + fl->flowi4_proto = IPPROTO_TCP; + + return ip_route_output_key(net, fl); +} + netdev_tx_t ovs_stt_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; @@ -1002,14 +1020,7 @@ netdev_tx_t ovs_stt_xmit(struct sk_buff *skb) tun_key = &tun_info->key; - /* Route lookup */ - memset(&fl, 0, sizeof(fl)); - fl.daddr = tun_key->u.ipv4.dst; - fl.saddr = tun_key->u.ipv4.src; - fl.flowi4_tos = RT_TOS(tun_key->tos); - fl.flowi4_mark = skb->mark; - fl.flowi4_proto = IPPROTO_TCP; - rt = ip_route_output_key(net, &fl); + rt = stt_get_rt(skb, dev, &fl, tun_key); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; @@ -1802,6 +1813,31 @@ static int stt_change_mtu(struct net_device *dev, int new_mtu) return __stt_change_mtu(dev, new_mtu, true); } +int ovs_stt_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) +{ + struct ip_tunnel_info *info = skb_tunnel_info(skb); + struct stt_dev *stt_dev = netdev_priv(dev); + struct net *net = stt_dev->net; + __be16 dport = stt_dev->dst_port; + struct flowi4 fl4; + struct rtable *rt; + + if (ip_tunnel_info_af(info) != AF_INET) + return -EINVAL; + + rt = stt_get_rt(skb, dev, &fl4, &info->key); + 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(net, skb, 1, USHRT_MAX, true); + info->key.tp_dst = dport; + return 0; +} +EXPORT_SYMBOL_GPL(ovs_stt_fill_metadata_dst); + static const struct net_device_ops stt_netdev_ops = { .ndo_init = stt_init, .ndo_uninit = stt_uninit, @@ -1812,6 +1848,9 @@ static const struct net_device_ops stt_netdev_ops = { .ndo_change_mtu = stt_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 = stt_fill_metadata_dst, +#endif }; static void stt_get_drvinfo(struct net_device *dev, diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index 4faa18f3e..b92a90259 100644 --- a/datapath/linux/compat/vxlan.c +++ b/datapath/linux/compat/vxlan.c @@ -1648,6 +1648,47 @@ static netdev_tx_t vxlan_dev_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb, + struct ip_tunnel_info *info, + __be16 sport, __be16 dport) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct rtable *rt; + struct flowi4 fl4; + + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_tos = RT_TOS(info->key.tos); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; + fl4.daddr = info->key.u.ipv4.dst; + + rt = ip_route_output_key(vxlan->net, &fl4); + if (IS_ERR(rt)) + return PTR_ERR(rt); + ip_rt_put(rt); + + info->key.u.ipv4.src = fl4.saddr; + info->key.tp_src = sport; + info->key.tp_dst = dport; + return 0; +} + +int ovs_vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct ip_tunnel_info *info = skb_tunnel_info(skb); + __be16 sport, dport; + + sport = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min, + vxlan->cfg.port_max, true); + dport = info->key.tp_dst ? : vxlan->cfg.dst_port; + + if (ip_tunnel_info_af(info) == AF_INET) + return egress_ipv4_tun_info(dev, skb, info, sport, dport); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(ovs_vxlan_fill_metadata_dst); + static const struct net_device_ops vxlan_netdev_ops = { .ndo_init = vxlan_init, .ndo_uninit = vxlan_uninit, @@ -1659,6 +1700,9 @@ static const struct net_device_ops vxlan_netdev_ops = { .ndo_change_mtu = vxlan_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 = vxlan_fill_metadata_dst, +#endif }; /* Info for udev, that this is a virtual tunnel endpoint */ |