diff options
| author | David S. Miller <davem@davemloft.net> | 2014-10-06 00:32:25 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-10-06 00:32:25 -0400 |
| commit | 45d9cc7c609680e921060d3eb4e399043eb5e4be (patch) | |
| tree | a4906c8cba2b6c2d116e7b72a71f9e1020b476cb /net | |
| parent | c259c132ad284576ab44308d5d17ea6a16c971b5 (diff) | |
| parent | f5796684069e0c71c65bce6a6d4766114aec1396 (diff) | |
Merge branch 'geneve'
Andy Zhou says:
====================
Add Geneve tunnel protocol support
This patch series adds kernel support for Geneve (Generic Network
Virtualization Encapsulation) based on Geneve IETF draft:
http://www.ietf.org/id/draft-gross-geneve-01.txt
Patch 1 implements Geneve tunneling protocol driver
Patch 2-6 adds openvswitch support for creating and using
Geneve tunnels by OVS user space.
v1->v2: Style fixes: use tab instead space for Kconfig
Patch 2-6 are reviewed by Pravin Shetty, add him to acked-by
Patch 6 was reviewed by Thomas Graf when commiting
to openvswitch.org, add him to acked-by.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/Kconfig | 14 | ||||
| -rw-r--r-- | net/ipv4/Makefile | 1 | ||||
| -rw-r--r-- | net/ipv4/geneve.c | 373 | ||||
| -rw-r--r-- | net/openvswitch/Kconfig | 11 | ||||
| -rw-r--r-- | net/openvswitch/Makefile | 4 | ||||
| -rw-r--r-- | net/openvswitch/actions.c | 5 | ||||
| -rw-r--r-- | net/openvswitch/datapath.c | 44 | ||||
| -rw-r--r-- | net/openvswitch/datapath.h | 2 | ||||
| -rw-r--r-- | net/openvswitch/flow.c | 76 | ||||
| -rw-r--r-- | net/openvswitch/flow.h | 48 | ||||
| -rw-r--r-- | net/openvswitch/flow_netlink.c | 227 | ||||
| -rw-r--r-- | net/openvswitch/vport-geneve.c | 236 | ||||
| -rw-r--r-- | net/openvswitch/vport-gre.c | 16 | ||||
| -rw-r--r-- | net/openvswitch/vport-vxlan.c | 10 | ||||
| -rw-r--r-- | net/openvswitch/vport.c | 9 | ||||
| -rw-r--r-- | net/openvswitch/vport.h | 3 |
16 files changed, 987 insertions, 92 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 69fb37854449..c2035447e649 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
| @@ -453,6 +453,20 @@ config TCP_CONG_BIC | |||
| 453 | increase provides TCP friendliness. | 453 | increase provides TCP friendliness. |
| 454 | See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ | 454 | See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ |
| 455 | 455 | ||
| 456 | config GENEVE | ||
| 457 | tristate "Generic Network Virtualization Encapsulation (Geneve)" | ||
| 458 | depends on INET | ||
| 459 | select NET_IP_TUNNEL | ||
| 460 | select NET_UDP_TUNNEL | ||
| 461 | ---help--- | ||
| 462 | This allows one to create Geneve virtual interfaces that provide | ||
| 463 | Layer 2 Networks over Layer 3 Networks. Geneve is often used | ||
| 464 | to tunnel virtual network infrastructure in virtualized environments. | ||
| 465 | For more information see: | ||
| 466 | http://tools.ietf.org/html/draft-gross-geneve-01 | ||
| 467 | |||
| 468 | To compile this driver as a module, choose M here: the module | ||
| 469 | |||
| 456 | config TCP_CONG_CUBIC | 470 | config TCP_CONG_CUBIC |
| 457 | tristate "CUBIC TCP" | 471 | tristate "CUBIC TCP" |
| 458 | default y | 472 | default y |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index d8105787c199..518c04ed666e 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -56,6 +56,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o | |||
| 56 | obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o | 56 | obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o |
| 57 | obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o | 57 | obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o |
| 58 | obj-$(CONFIG_NETLABEL) += cipso_ipv4.o | 58 | obj-$(CONFIG_NETLABEL) += cipso_ipv4.o |
| 59 | obj-$(CONFIG_GENEVE) += geneve.o | ||
| 59 | 60 | ||
| 60 | obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ | 61 | obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ |
| 61 | xfrm4_output.o xfrm4_protocol.o | 62 | xfrm4_output.o xfrm4_protocol.o |
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c new file mode 100644 index 000000000000..f008c5515f48 --- /dev/null +++ b/net/ipv4/geneve.c | |||
| @@ -0,0 +1,373 @@ | |||
| 1 | /* | ||
| 2 | * Geneve: Generic Network Virtualization Encapsulation | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014 Nicira, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/skbuff.h> | ||
| 20 | #include <linux/rculist.h> | ||
| 21 | #include <linux/netdevice.h> | ||
| 22 | #include <linux/in.h> | ||
| 23 | #include <linux/ip.h> | ||
| 24 | #include <linux/udp.h> | ||
| 25 | #include <linux/igmp.h> | ||
| 26 | #include <linux/etherdevice.h> | ||
| 27 | #include <linux/if_ether.h> | ||
| 28 | #include <linux/if_vlan.h> | ||
| 29 | #include <linux/hash.h> | ||
| 30 | #include <linux/ethtool.h> | ||
| 31 | #include <net/arp.h> | ||
| 32 | #include <net/ndisc.h> | ||
| 33 | #include <net/ip.h> | ||
| 34 | #include <net/ip_tunnels.h> | ||
| 35 | #include <net/icmp.h> | ||
| 36 | #include <net/udp.h> | ||
| 37 | #include <net/rtnetlink.h> | ||
| 38 | #include <net/route.h> | ||
| 39 | #include <net/dsfield.h> | ||
| 40 | #include <net/inet_ecn.h> | ||
| 41 | #include <net/net_namespace.h> | ||
| 42 | #include <net/netns/generic.h> | ||
| 43 | #include <net/geneve.h> | ||
| 44 | #include <net/protocol.h> | ||
| 45 | #include <net/udp_tunnel.h> | ||
| 46 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 47 | #include <net/ipv6.h> | ||
| 48 | #include <net/addrconf.h> | ||
| 49 | #include <net/ip6_tunnel.h> | ||
| 50 | #include <net/ip6_checksum.h> | ||
| 51 | #endif | ||
| 52 | |||
| 53 | #define PORT_HASH_BITS 8 | ||
| 54 | #define PORT_HASH_SIZE (1<<PORT_HASH_BITS) | ||
| 55 | |||
| 56 | /* per-network namespace private data for this module */ | ||
| 57 | struct geneve_net { | ||
| 58 | struct hlist_head sock_list[PORT_HASH_SIZE]; | ||
| 59 | spinlock_t sock_lock; /* Protects sock_list */ | ||
| 60 | }; | ||
| 61 | |||
| 62 | static int geneve_net_id; | ||
| 63 | |||
| 64 | static struct workqueue_struct *geneve_wq; | ||
| 65 | |||
| 66 | static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) | ||
| 67 | { | ||
| 68 | return (struct genevehdr *)(udp_hdr(skb) + 1); | ||
| 69 | } | ||
| 70 | |||
| 71 | static struct hlist_head *gs_head(struct net *net, __be16 port) | ||
| 72 | { | ||
| 73 | struct geneve_net *gn = net_generic(net, geneve_net_id); | ||
| 74 | |||
| 75 | return &gn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)]; | ||
| 76 | } | ||
| 77 | |||
| 78 | /* Find geneve socket based on network namespace and UDP port */ | ||
| 79 | static struct geneve_sock *geneve_find_sock(struct net *net, __be16 port) | ||
| 80 | { | ||
| 81 | struct geneve_sock *gs; | ||
| 82 | |||
| 83 | hlist_for_each_entry_rcu(gs, gs_head(net, port), hlist) { | ||
| 84 | if (inet_sk(gs->sock->sk)->inet_sport == port) | ||
| 85 | return gs; | ||
| 86 | } | ||
| 87 | |||
| 88 | return NULL; | ||
| 89 | } | ||
| 90 | |||
| 91 | static void geneve_build_header(struct genevehdr *geneveh, | ||
| 92 | __be16 tun_flags, u8 vni[3], | ||
| 93 | u8 options_len, u8 *options) | ||
| 94 | { | ||
| 95 | geneveh->ver = GENEVE_VER; | ||
| 96 | geneveh->opt_len = options_len / 4; | ||
| 97 | geneveh->oam = !!(tun_flags & TUNNEL_OAM); | ||
| 98 | geneveh->critical = !!(tun_flags & TUNNEL_CRIT_OPT); | ||
| 99 | geneveh->rsvd1 = 0; | ||
| 100 | memcpy(geneveh->vni, vni, 3); | ||
| 101 | geneveh->proto_type = htons(ETH_P_TEB); | ||
| 102 | geneveh->rsvd2 = 0; | ||
| 103 | |||
| 104 | memcpy(geneveh->options, options, options_len); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* Transmit a fully formated Geneve frame. | ||
| 108 | * | ||
| 109 | * When calling this function. The skb->data should point | ||
| 110 | * to the geneve header which is fully formed. | ||
| 111 | * | ||
| 112 | * This function will add other UDP tunnel headers. | ||
| 113 | */ | ||
| 114 | int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, | ||
| 115 | struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, | ||
| 116 | __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, | ||
| 117 | __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt, | ||
| 118 | bool xnet) | ||
| 119 | { | ||
| 120 | struct genevehdr *gnvh; | ||
| 121 | int min_headroom; | ||
| 122 | int err; | ||
| 123 | |||
| 124 | skb = udp_tunnel_handle_offloads(skb, !gs->sock->sk->sk_no_check_tx); | ||
| 125 | |||
| 126 | min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len | ||
| 127 | + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr) | ||
| 128 | + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); | ||
| 129 | |||
| 130 | err = skb_cow_head(skb, min_headroom); | ||
| 131 | if (unlikely(err)) | ||
| 132 | return err; | ||
| 133 | |||
| 134 | if (vlan_tx_tag_present(skb)) { | ||
| 135 | if (unlikely(!__vlan_put_tag(skb, | ||
| 136 | skb->vlan_proto, | ||
| 137 | vlan_tx_tag_get(skb)))) { | ||
| 138 | err = -ENOMEM; | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | skb->vlan_tci = 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); | ||
| 145 | geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); | ||
| 146 | |||
| 147 | return udp_tunnel_xmit_skb(gs->sock, rt, skb, src, dst, | ||
| 148 | tos, ttl, df, src_port, dst_port, xnet); | ||
| 149 | } | ||
| 150 | EXPORT_SYMBOL_GPL(geneve_xmit_skb); | ||
| 151 | |||
| 152 | static void geneve_notify_add_rx_port(struct geneve_sock *gs) | ||
| 153 | { | ||
| 154 | struct sock *sk = gs->sock->sk; | ||
| 155 | sa_family_t sa_family = sk->sk_family; | ||
| 156 | int err; | ||
| 157 | |||
| 158 | if (sa_family == AF_INET) { | ||
| 159 | err = udp_add_offload(&gs->udp_offloads); | ||
| 160 | if (err) | ||
| 161 | pr_warn("geneve: udp_add_offload failed with status %d\n", | ||
| 162 | err); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | /* Callback from net/ipv4/udp.c to receive packets */ | ||
| 167 | static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) | ||
| 168 | { | ||
| 169 | struct genevehdr *geneveh; | ||
| 170 | struct geneve_sock *gs; | ||
| 171 | int opts_len; | ||
| 172 | |||
| 173 | /* Need Geneve and inner Ethernet header to be present */ | ||
| 174 | if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) | ||
| 175 | goto error; | ||
| 176 | |||
| 177 | /* Return packets with reserved bits set */ | ||
| 178 | geneveh = geneve_hdr(skb); | ||
| 179 | |||
| 180 | if (unlikely(geneveh->ver != GENEVE_VER)) | ||
| 181 | goto error; | ||
| 182 | |||
| 183 | if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) | ||
| 184 | goto error; | ||
| 185 | |||
| 186 | opts_len = geneveh->opt_len * 4; | ||
| 187 | if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, | ||
| 188 | htons(ETH_P_TEB))) | ||
| 189 | goto drop; | ||
| 190 | |||
| 191 | gs = rcu_dereference_sk_user_data(sk); | ||
| 192 | if (!gs) | ||
| 193 | goto drop; | ||
| 194 | |||
| 195 | gs->rcv(gs, skb); | ||
| 196 | return 0; | ||
| 197 | |||
| 198 | drop: | ||
| 199 | /* Consume bad packet */ | ||
| 200 | kfree_skb(skb); | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | error: | ||
| 204 | /* Let the UDP layer deal with the skb */ | ||
| 205 | return 1; | ||
| 206 | } | ||
| 207 | |||
| 208 | static void geneve_del_work(struct work_struct *work) | ||
| 209 | { | ||
| 210 | struct geneve_sock *gs = container_of(work, struct geneve_sock, | ||
| 211 | del_work); | ||
| 212 | |||
| 213 | udp_tunnel_sock_release(gs->sock); | ||
| 214 | kfree_rcu(gs, rcu); | ||
| 215 | } | ||
| 216 | |||
| 217 | static struct socket *geneve_create_sock(struct net *net, bool ipv6, | ||
| 218 | __be16 port) | ||
| 219 | { | ||
| 220 | struct socket *sock; | ||
| 221 | struct udp_port_cfg udp_conf; | ||
| 222 | int err; | ||
| 223 | |||
| 224 | memset(&udp_conf, 0, sizeof(udp_conf)); | ||
| 225 | |||
| 226 | if (ipv6) { | ||
| 227 | udp_conf.family = AF_INET6; | ||
| 228 | } else { | ||
| 229 | udp_conf.family = AF_INET; | ||
| 230 | udp_conf.local_ip.s_addr = INADDR_ANY; | ||
| 231 | } | ||
| 232 | |||
| 233 | udp_conf.local_udp_port = port; | ||
| 234 | |||
| 235 | /* Open UDP socket */ | ||
| 236 | err = udp_sock_create(net, &udp_conf, &sock); | ||
| 237 | if (err < 0) | ||
| 238 | return ERR_PTR(err); | ||
| 239 | |||
| 240 | return sock; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* Create new listen socket if needed */ | ||
| 244 | static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, | ||
| 245 | geneve_rcv_t *rcv, void *data, | ||
| 246 | bool ipv6) | ||
| 247 | { | ||
| 248 | struct geneve_net *gn = net_generic(net, geneve_net_id); | ||
| 249 | struct geneve_sock *gs; | ||
| 250 | struct socket *sock; | ||
| 251 | struct udp_tunnel_sock_cfg tunnel_cfg; | ||
| 252 | |||
| 253 | gs = kzalloc(sizeof(*gs), GFP_KERNEL); | ||
| 254 | if (!gs) | ||
| 255 | return ERR_PTR(-ENOMEM); | ||
| 256 | |||
| 257 | INIT_WORK(&gs->del_work, geneve_del_work); | ||
| 258 | |||
| 259 | sock = geneve_create_sock(net, ipv6, port); | ||
| 260 | if (IS_ERR(sock)) { | ||
| 261 | kfree(gs); | ||
| 262 | return ERR_CAST(sock); | ||
| 263 | } | ||
| 264 | |||
| 265 | gs->sock = sock; | ||
| 266 | atomic_set(&gs->refcnt, 1); | ||
| 267 | gs->rcv = rcv; | ||
| 268 | gs->rcv_data = data; | ||
| 269 | |||
| 270 | /* Initialize the geneve udp offloads structure */ | ||
| 271 | gs->udp_offloads.port = port; | ||
| 272 | gs->udp_offloads.callbacks.gro_receive = NULL; | ||
| 273 | gs->udp_offloads.callbacks.gro_complete = NULL; | ||
| 274 | |||
| 275 | spin_lock(&gn->sock_lock); | ||
| 276 | hlist_add_head_rcu(&gs->hlist, gs_head(net, port)); | ||
| 277 | geneve_notify_add_rx_port(gs); | ||
| 278 | spin_unlock(&gn->sock_lock); | ||
| 279 | |||
| 280 | /* Mark socket as an encapsulation socket */ | ||
| 281 | tunnel_cfg.sk_user_data = gs; | ||
| 282 | tunnel_cfg.encap_type = 1; | ||
| 283 | tunnel_cfg.encap_rcv = geneve_udp_encap_recv; | ||
| 284 | tunnel_cfg.encap_destroy = NULL; | ||
| 285 | setup_udp_tunnel_sock(net, sock, &tunnel_cfg); | ||
| 286 | |||
| 287 | return gs; | ||
| 288 | } | ||
| 289 | |||
| 290 | struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, | ||
| 291 | geneve_rcv_t *rcv, void *data, | ||
| 292 | bool no_share, bool ipv6) | ||
| 293 | { | ||
| 294 | struct geneve_sock *gs; | ||
| 295 | |||
| 296 | gs = geneve_socket_create(net, port, rcv, data, ipv6); | ||
| 297 | if (!IS_ERR(gs)) | ||
| 298 | return gs; | ||
| 299 | |||
| 300 | if (no_share) /* Return error if sharing is not allowed. */ | ||
| 301 | return ERR_PTR(-EINVAL); | ||
| 302 | |||
| 303 | gs = geneve_find_sock(net, port); | ||
| 304 | if (gs) { | ||
| 305 | if (gs->rcv == rcv) | ||
| 306 | atomic_inc(&gs->refcnt); | ||
| 307 | else | ||
| 308 | gs = ERR_PTR(-EBUSY); | ||
| 309 | } else { | ||
| 310 | gs = ERR_PTR(-EINVAL); | ||
| 311 | } | ||
| 312 | |||
| 313 | return gs; | ||
| 314 | } | ||
| 315 | EXPORT_SYMBOL_GPL(geneve_sock_add); | ||
| 316 | |||
| 317 | void geneve_sock_release(struct geneve_sock *gs) | ||
| 318 | { | ||
| 319 | if (!atomic_dec_and_test(&gs->refcnt)) | ||
| 320 | return; | ||
| 321 | |||
| 322 | queue_work(geneve_wq, &gs->del_work); | ||
| 323 | } | ||
| 324 | EXPORT_SYMBOL_GPL(geneve_sock_release); | ||
| 325 | |||
| 326 | static __net_init int geneve_init_net(struct net *net) | ||
| 327 | { | ||
| 328 | struct geneve_net *gn = net_generic(net, geneve_net_id); | ||
| 329 | unsigned int h; | ||
| 330 | |||
| 331 | spin_lock_init(&gn->sock_lock); | ||
| 332 | |||
| 333 | for (h = 0; h < PORT_HASH_SIZE; ++h) | ||
| 334 | INIT_HLIST_HEAD(&gn->sock_list[h]); | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | static struct pernet_operations geneve_net_ops = { | ||
| 340 | .init = geneve_init_net, | ||
| 341 | .exit = NULL, | ||
| 342 | .id = &geneve_net_id, | ||
| 343 | .size = sizeof(struct geneve_net), | ||
| 344 | }; | ||
| 345 | |||
| 346 | static int __init geneve_init_module(void) | ||
| 347 | { | ||
| 348 | int rc; | ||
| 349 | |||
| 350 | geneve_wq = alloc_workqueue("geneve", 0, 0); | ||
| 351 | if (!geneve_wq) | ||
| 352 | return -ENOMEM; | ||
| 353 | |||
| 354 | rc = register_pernet_subsys(&geneve_net_ops); | ||
| 355 | if (rc) | ||
| 356 | return rc; | ||
| 357 | |||
| 358 | pr_info("Geneve driver\n"); | ||
| 359 | |||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | late_initcall(geneve_init_module); | ||
| 363 | |||
| 364 | static void __exit geneve_cleanup_module(void) | ||
| 365 | { | ||
| 366 | destroy_workqueue(geneve_wq); | ||
| 367 | } | ||
| 368 | module_exit(geneve_cleanup_module); | ||
| 369 | |||
| 370 | MODULE_LICENSE("GPL"); | ||
| 371 | MODULE_AUTHOR("Jesse Gross <jesse@nicira.com>"); | ||
| 372 | MODULE_DESCRIPTION("Driver for GENEVE encapsulated traffic"); | ||
| 373 | MODULE_ALIAS_RTNL_LINK("geneve"); | ||
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 6ecf491ad509..ba3bb8203b99 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig | |||
| @@ -54,3 +54,14 @@ config OPENVSWITCH_VXLAN | |||
| 54 | Say N to exclude this support and reduce the binary size. | 54 | Say N to exclude this support and reduce the binary size. |
| 55 | 55 | ||
| 56 | If unsure, say Y. | 56 | If unsure, say Y. |
| 57 | |||
| 58 | config OPENVSWITCH_GENEVE | ||
| 59 | bool "Open vSwitch Geneve tunneling support" | ||
| 60 | depends on INET | ||
| 61 | depends on OPENVSWITCH | ||
| 62 | depends on GENEVE && !(OPENVSWITCH=y && GENEVE=m) | ||
| 63 | default y | ||
| 64 | ---help--- | ||
| 65 | If you say Y here, then the Open vSwitch will be able create geneve vport. | ||
| 66 | |||
| 67 | Say N to exclude this support and reduce the binary size. | ||
diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 3591cb5dae91..9a33a273c375 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile | |||
| @@ -15,6 +15,10 @@ openvswitch-y := \ | |||
| 15 | vport-internal_dev.o \ | 15 | vport-internal_dev.o \ |
| 16 | vport-netdev.o | 16 | vport-netdev.o |
| 17 | 17 | ||
| 18 | ifneq ($(CONFIG_OPENVSWITCH_GENEVE),) | ||
| 19 | openvswitch-y += vport-geneve.o | ||
| 20 | endif | ||
| 21 | |||
| 18 | ifneq ($(CONFIG_OPENVSWITCH_VXLAN),) | 22 | ifneq ($(CONFIG_OPENVSWITCH_VXLAN),) |
| 19 | openvswitch-y += vport-vxlan.o | 23 | openvswitch-y += vport-vxlan.o |
| 20 | endif | 24 | endif |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 6932a42e41a2..006886dbee36 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -590,8 +590,8 @@ static int execute_set_action(struct sk_buff *skb, | |||
| 590 | skb->mark = nla_get_u32(nested_attr); | 590 | skb->mark = nla_get_u32(nested_attr); |
| 591 | break; | 591 | break; |
| 592 | 592 | ||
| 593 | case OVS_KEY_ATTR_IPV4_TUNNEL: | 593 | case OVS_KEY_ATTR_TUNNEL_INFO: |
| 594 | OVS_CB(skb)->egress_tun_key = nla_data(nested_attr); | 594 | OVS_CB(skb)->egress_tun_info = nla_data(nested_attr); |
| 595 | break; | 595 | break; |
| 596 | 596 | ||
| 597 | case OVS_KEY_ATTR_ETHERNET: | 597 | case OVS_KEY_ATTR_ETHERNET: |
| @@ -778,6 +778,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
| 778 | acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); | 778 | acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); |
| 779 | 779 | ||
| 780 | this_cpu_inc(exec_actions_level); | 780 | this_cpu_inc(exec_actions_level); |
| 781 | OVS_CB(skb)->egress_tun_info = NULL; | ||
| 781 | err = do_execute_actions(dp, skb, key, | 782 | err = do_execute_actions(dp, skb, key, |
| 782 | acts->actions, acts->actions_len); | 783 | acts->actions, acts->actions_len); |
| 783 | 784 | ||
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9e3a2fae6a8f..2e31d9e7f4dc 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -369,6 +369,8 @@ static size_t key_attr_size(void) | |||
| 369 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ | 369 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ |
| 370 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ | 370 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ |
| 371 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ | 371 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ |
| 372 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */ | ||
| 373 | + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */ | ||
| 372 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ | 374 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ |
| 373 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ | 375 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ |
| 374 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ | 376 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ |
| @@ -555,10 +557,12 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
| 555 | 557 | ||
| 556 | err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS], | 558 | err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS], |
| 557 | &flow->key, 0, &acts); | 559 | &flow->key, 0, &acts); |
| 558 | rcu_assign_pointer(flow->sf_acts, acts); | ||
| 559 | if (err) | 560 | if (err) |
| 560 | goto err_flow_free; | 561 | goto err_flow_free; |
| 561 | 562 | ||
| 563 | rcu_assign_pointer(flow->sf_acts, acts); | ||
| 564 | |||
| 565 | OVS_CB(packet)->egress_tun_info = NULL; | ||
| 562 | OVS_CB(packet)->flow = flow; | 566 | OVS_CB(packet)->flow = flow; |
| 563 | packet->priority = flow->key.phy.priority; | 567 | packet->priority = flow->key.phy.priority; |
| 564 | packet->mark = flow->key.phy.skb_mark; | 568 | packet->mark = flow->key.phy.skb_mark; |
| @@ -932,11 +936,34 @@ error: | |||
| 932 | return error; | 936 | return error; |
| 933 | } | 937 | } |
| 934 | 938 | ||
| 939 | static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, | ||
| 940 | const struct sw_flow_key *key, | ||
| 941 | const struct sw_flow_mask *mask) | ||
| 942 | { | ||
| 943 | struct sw_flow_actions *acts; | ||
| 944 | struct sw_flow_key masked_key; | ||
| 945 | int error; | ||
| 946 | |||
| 947 | acts = ovs_nla_alloc_flow_actions(nla_len(a)); | ||
| 948 | if (IS_ERR(acts)) | ||
| 949 | return acts; | ||
| 950 | |||
| 951 | ovs_flow_mask_key(&masked_key, key, mask); | ||
| 952 | error = ovs_nla_copy_actions(a, &masked_key, 0, &acts); | ||
| 953 | if (error) { | ||
| 954 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
| 955 | kfree(acts); | ||
| 956 | return ERR_PTR(error); | ||
| 957 | } | ||
| 958 | |||
| 959 | return acts; | ||
| 960 | } | ||
| 961 | |||
| 935 | static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | 962 | static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) |
| 936 | { | 963 | { |
| 937 | struct nlattr **a = info->attrs; | 964 | struct nlattr **a = info->attrs; |
| 938 | struct ovs_header *ovs_header = info->userhdr; | 965 | struct ovs_header *ovs_header = info->userhdr; |
| 939 | struct sw_flow_key key, masked_key; | 966 | struct sw_flow_key key; |
| 940 | struct sw_flow *flow; | 967 | struct sw_flow *flow; |
| 941 | struct sw_flow_mask mask; | 968 | struct sw_flow_mask mask; |
| 942 | struct sk_buff *reply = NULL; | 969 | struct sk_buff *reply = NULL; |
| @@ -958,17 +985,10 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
| 958 | 985 | ||
| 959 | /* Validate actions. */ | 986 | /* Validate actions. */ |
| 960 | if (a[OVS_FLOW_ATTR_ACTIONS]) { | 987 | if (a[OVS_FLOW_ATTR_ACTIONS]) { |
| 961 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); | 988 | acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask); |
| 962 | error = PTR_ERR(acts); | 989 | if (IS_ERR(acts)) { |
| 963 | if (IS_ERR(acts)) | 990 | error = PTR_ERR(acts); |
| 964 | goto error; | 991 | goto error; |
| 965 | |||
| 966 | ovs_flow_mask_key(&masked_key, &key, &mask); | ||
| 967 | error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], | ||
| 968 | &masked_key, 0, &acts); | ||
| 969 | if (error) { | ||
| 970 | OVS_NLERR("Flow actions may not be safe on all matching packets.\n"); | ||
| 971 | goto err_kfree_acts; | ||
| 972 | } | 992 | } |
| 973 | } | 993 | } |
| 974 | 994 | ||
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index ac3f3df96961..974135439c5c 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
| @@ -102,8 +102,8 @@ struct datapath { | |||
| 102 | */ | 102 | */ |
| 103 | struct ovs_skb_cb { | 103 | struct ovs_skb_cb { |
| 104 | struct sw_flow *flow; | 104 | struct sw_flow *flow; |
| 105 | struct ovs_tunnel_info *egress_tun_info; | ||
| 105 | struct vport *input_vport; | 106 | struct vport *input_vport; |
| 106 | struct ovs_key_ipv4_tunnel *egress_tun_key; | ||
| 107 | }; | 107 | }; |
| 108 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) | 108 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) |
| 109 | 109 | ||
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 4010423f2831..62db02ba36bc 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -448,6 +448,9 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 448 | int error; | 448 | int error; |
| 449 | struct ethhdr *eth; | 449 | struct ethhdr *eth; |
| 450 | 450 | ||
| 451 | /* Flags are always used as part of stats */ | ||
| 452 | key->tp.flags = 0; | ||
| 453 | |||
| 451 | skb_reset_mac_header(skb); | 454 | skb_reset_mac_header(skb); |
| 452 | 455 | ||
| 453 | /* Link layer. We are guaranteed to have at least the 14 byte Ethernet | 456 | /* Link layer. We are guaranteed to have at least the 14 byte Ethernet |
| @@ -462,6 +465,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 462 | * update skb->csum here. | 465 | * update skb->csum here. |
| 463 | */ | 466 | */ |
| 464 | 467 | ||
| 468 | key->eth.tci = 0; | ||
| 465 | if (vlan_tx_tag_present(skb)) | 469 | if (vlan_tx_tag_present(skb)) |
| 466 | key->eth.tci = htons(skb->vlan_tci); | 470 | key->eth.tci = htons(skb->vlan_tci); |
| 467 | else if (eth->h_proto == htons(ETH_P_8021Q)) | 471 | else if (eth->h_proto == htons(ETH_P_8021Q)) |
| @@ -482,6 +486,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 482 | 486 | ||
| 483 | error = check_iphdr(skb); | 487 | error = check_iphdr(skb); |
| 484 | if (unlikely(error)) { | 488 | if (unlikely(error)) { |
| 489 | memset(&key->ip, 0, sizeof(key->ip)); | ||
| 490 | memset(&key->ipv4, 0, sizeof(key->ipv4)); | ||
| 485 | if (error == -EINVAL) { | 491 | if (error == -EINVAL) { |
| 486 | skb->transport_header = skb->network_header; | 492 | skb->transport_header = skb->network_header; |
| 487 | error = 0; | 493 | error = 0; |
| @@ -503,8 +509,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 503 | return 0; | 509 | return 0; |
| 504 | } | 510 | } |
| 505 | if (nh->frag_off & htons(IP_MF) || | 511 | if (nh->frag_off & htons(IP_MF) || |
| 506 | skb_shinfo(skb)->gso_type & SKB_GSO_UDP) | 512 | skb_shinfo(skb)->gso_type & SKB_GSO_UDP) |
| 507 | key->ip.frag = OVS_FRAG_TYPE_FIRST; | 513 | key->ip.frag = OVS_FRAG_TYPE_FIRST; |
| 514 | else | ||
| 515 | key->ip.frag = OVS_FRAG_TYPE_NONE; | ||
| 508 | 516 | ||
| 509 | /* Transport layer. */ | 517 | /* Transport layer. */ |
| 510 | if (key->ip.proto == IPPROTO_TCP) { | 518 | if (key->ip.proto == IPPROTO_TCP) { |
| @@ -513,18 +521,25 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 513 | key->tp.src = tcp->source; | 521 | key->tp.src = tcp->source; |
| 514 | key->tp.dst = tcp->dest; | 522 | key->tp.dst = tcp->dest; |
| 515 | key->tp.flags = TCP_FLAGS_BE16(tcp); | 523 | key->tp.flags = TCP_FLAGS_BE16(tcp); |
| 524 | } else { | ||
| 525 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 516 | } | 526 | } |
| 527 | |||
| 517 | } else if (key->ip.proto == IPPROTO_UDP) { | 528 | } else if (key->ip.proto == IPPROTO_UDP) { |
| 518 | if (udphdr_ok(skb)) { | 529 | if (udphdr_ok(skb)) { |
| 519 | struct udphdr *udp = udp_hdr(skb); | 530 | struct udphdr *udp = udp_hdr(skb); |
| 520 | key->tp.src = udp->source; | 531 | key->tp.src = udp->source; |
| 521 | key->tp.dst = udp->dest; | 532 | key->tp.dst = udp->dest; |
| 533 | } else { | ||
| 534 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 522 | } | 535 | } |
| 523 | } else if (key->ip.proto == IPPROTO_SCTP) { | 536 | } else if (key->ip.proto == IPPROTO_SCTP) { |
| 524 | if (sctphdr_ok(skb)) { | 537 | if (sctphdr_ok(skb)) { |
| 525 | struct sctphdr *sctp = sctp_hdr(skb); | 538 | struct sctphdr *sctp = sctp_hdr(skb); |
| 526 | key->tp.src = sctp->source; | 539 | key->tp.src = sctp->source; |
| 527 | key->tp.dst = sctp->dest; | 540 | key->tp.dst = sctp->dest; |
| 541 | } else { | ||
| 542 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 528 | } | 543 | } |
| 529 | } else if (key->ip.proto == IPPROTO_ICMP) { | 544 | } else if (key->ip.proto == IPPROTO_ICMP) { |
| 530 | if (icmphdr_ok(skb)) { | 545 | if (icmphdr_ok(skb)) { |
| @@ -534,33 +549,44 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 534 | * them in 16-bit network byte order. */ | 549 | * them in 16-bit network byte order. */ |
| 535 | key->tp.src = htons(icmp->type); | 550 | key->tp.src = htons(icmp->type); |
| 536 | key->tp.dst = htons(icmp->code); | 551 | key->tp.dst = htons(icmp->code); |
| 552 | } else { | ||
| 553 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 537 | } | 554 | } |
| 538 | } | 555 | } |
| 539 | 556 | ||
| 540 | } else if ((key->eth.type == htons(ETH_P_ARP) || | 557 | } else if (key->eth.type == htons(ETH_P_ARP) || |
| 541 | key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) { | 558 | key->eth.type == htons(ETH_P_RARP)) { |
| 542 | struct arp_eth_header *arp; | 559 | struct arp_eth_header *arp; |
| 543 | 560 | ||
| 544 | arp = (struct arp_eth_header *)skb_network_header(skb); | 561 | arp = (struct arp_eth_header *)skb_network_header(skb); |
| 545 | 562 | ||
| 546 | if (arp->ar_hrd == htons(ARPHRD_ETHER) | 563 | if (arphdr_ok(skb) && |
| 547 | && arp->ar_pro == htons(ETH_P_IP) | 564 | arp->ar_hrd == htons(ARPHRD_ETHER) && |
| 548 | && arp->ar_hln == ETH_ALEN | 565 | arp->ar_pro == htons(ETH_P_IP) && |
| 549 | && arp->ar_pln == 4) { | 566 | arp->ar_hln == ETH_ALEN && |
| 567 | arp->ar_pln == 4) { | ||
| 550 | 568 | ||
| 551 | /* We only match on the lower 8 bits of the opcode. */ | 569 | /* We only match on the lower 8 bits of the opcode. */ |
| 552 | if (ntohs(arp->ar_op) <= 0xff) | 570 | if (ntohs(arp->ar_op) <= 0xff) |
| 553 | key->ip.proto = ntohs(arp->ar_op); | 571 | key->ip.proto = ntohs(arp->ar_op); |
| 572 | else | ||
| 573 | key->ip.proto = 0; | ||
| 574 | |||
| 554 | memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); | 575 | memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); |
| 555 | memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); | 576 | memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); |
| 556 | ether_addr_copy(key->ipv4.arp.sha, arp->ar_sha); | 577 | ether_addr_copy(key->ipv4.arp.sha, arp->ar_sha); |
| 557 | ether_addr_copy(key->ipv4.arp.tha, arp->ar_tha); | 578 | ether_addr_copy(key->ipv4.arp.tha, arp->ar_tha); |
| 579 | } else { | ||
| 580 | memset(&key->ip, 0, sizeof(key->ip)); | ||
| 581 | memset(&key->ipv4, 0, sizeof(key->ipv4)); | ||
| 558 | } | 582 | } |
| 559 | } else if (key->eth.type == htons(ETH_P_IPV6)) { | 583 | } else if (key->eth.type == htons(ETH_P_IPV6)) { |
| 560 | int nh_len; /* IPv6 Header + Extensions */ | 584 | int nh_len; /* IPv6 Header + Extensions */ |
| 561 | 585 | ||
| 562 | nh_len = parse_ipv6hdr(skb, key); | 586 | nh_len = parse_ipv6hdr(skb, key); |
| 563 | if (unlikely(nh_len < 0)) { | 587 | if (unlikely(nh_len < 0)) { |
| 588 | memset(&key->ip, 0, sizeof(key->ip)); | ||
| 589 | memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr)); | ||
| 564 | if (nh_len == -EINVAL) { | 590 | if (nh_len == -EINVAL) { |
| 565 | skb->transport_header = skb->network_header; | 591 | skb->transport_header = skb->network_header; |
| 566 | error = 0; | 592 | error = 0; |
| @@ -582,24 +608,32 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 582 | key->tp.src = tcp->source; | 608 | key->tp.src = tcp->source; |
| 583 | key->tp.dst = tcp->dest; | 609 | key->tp.dst = tcp->dest; |
| 584 | key->tp.flags = TCP_FLAGS_BE16(tcp); | 610 | key->tp.flags = TCP_FLAGS_BE16(tcp); |
| 611 | } else { | ||
| 612 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 585 | } | 613 | } |
| 586 | } else if (key->ip.proto == NEXTHDR_UDP) { | 614 | } else if (key->ip.proto == NEXTHDR_UDP) { |
| 587 | if (udphdr_ok(skb)) { | 615 | if (udphdr_ok(skb)) { |
| 588 | struct udphdr *udp = udp_hdr(skb); | 616 | struct udphdr *udp = udp_hdr(skb); |
| 589 | key->tp.src = udp->source; | 617 | key->tp.src = udp->source; |
| 590 | key->tp.dst = udp->dest; | 618 | key->tp.dst = udp->dest; |
| 619 | } else { | ||
| 620 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 591 | } | 621 | } |
| 592 | } else if (key->ip.proto == NEXTHDR_SCTP) { | 622 | } else if (key->ip.proto == NEXTHDR_SCTP) { |
| 593 | if (sctphdr_ok(skb)) { | 623 | if (sctphdr_ok(skb)) { |
| 594 | struct sctphdr *sctp = sctp_hdr(skb); | 624 | struct sctphdr *sctp = sctp_hdr(skb); |
| 595 | key->tp.src = sctp->source; | 625 | key->tp.src = sctp->source; |
| 596 | key->tp.dst = sctp->dest; | 626 | key->tp.dst = sctp->dest; |
| 627 | } else { | ||
| 628 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 597 | } | 629 | } |
| 598 | } else if (key->ip.proto == NEXTHDR_ICMP) { | 630 | } else if (key->ip.proto == NEXTHDR_ICMP) { |
| 599 | if (icmp6hdr_ok(skb)) { | 631 | if (icmp6hdr_ok(skb)) { |
| 600 | error = parse_icmpv6(skb, key, nh_len); | 632 | error = parse_icmpv6(skb, key, nh_len); |
| 601 | if (error) | 633 | if (error) |
| 602 | return error; | 634 | return error; |
| 635 | } else { | ||
| 636 | memset(&key->tp, 0, sizeof(key->tp)); | ||
| 603 | } | 637 | } |
| 604 | } | 638 | } |
| 605 | } | 639 | } |
| @@ -611,17 +645,36 @@ int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) | |||
| 611 | return key_extract(skb, key); | 645 | return key_extract(skb, key); |
| 612 | } | 646 | } |
| 613 | 647 | ||
| 614 | int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key, | 648 | int ovs_flow_key_extract(struct ovs_tunnel_info *tun_info, |
| 615 | struct sk_buff *skb, struct sw_flow_key *key) | 649 | struct sk_buff *skb, struct sw_flow_key *key) |
| 616 | { | 650 | { |
| 617 | /* Extract metadata from packet. */ | 651 | /* Extract metadata from packet. */ |
| 618 | memset(key, 0, sizeof(*key)); | 652 | if (tun_info) { |
| 619 | if (tun_key) | 653 | memcpy(&key->tun_key, &tun_info->tunnel, sizeof(key->tun_key)); |
| 620 | memcpy(&key->tun_key, tun_key, sizeof(key->tun_key)); | 654 | |
| 655 | if (tun_info->options) { | ||
| 656 | BUILD_BUG_ON((1 << (sizeof(tun_info->options_len) * | ||
| 657 | 8)) - 1 | ||
| 658 | > sizeof(key->tun_opts)); | ||
| 659 | memcpy(GENEVE_OPTS(key, tun_info->options_len), | ||
| 660 | tun_info->options, tun_info->options_len); | ||
| 661 | key->tun_opts_len = tun_info->options_len; | ||
| 662 | } else { | ||
| 663 | key->tun_opts_len = 0; | ||
| 664 | } | ||
| 665 | } else { | ||
| 666 | key->tun_opts_len = 0; | ||
| 667 | memset(&key->tun_key, 0, sizeof(key->tun_key)); | ||
| 668 | } | ||
| 621 | 669 | ||
| 622 | key->phy.priority = skb->priority; | 670 | key->phy.priority = skb->priority; |
| 623 | key->phy.in_port = OVS_CB(skb)->input_vport->port_no; | 671 | key->phy.in_port = OVS_CB(skb)->input_vport->port_no; |
| 624 | key->phy.skb_mark = skb->mark; | 672 | key->phy.skb_mark = skb->mark; |
| 673 | key->ovs_flow_hash = 0; | ||
| 674 | key->recirc_id = 0; | ||
| 675 | |||
| 676 | /* Flags are always used as part of stats */ | ||
| 677 | key->tp.flags = 0; | ||
| 625 | 678 | ||
| 626 | return key_extract(skb, key); | 679 | return key_extract(skb, key); |
| 627 | } | 680 | } |
| @@ -632,7 +685,6 @@ int ovs_flow_key_extract_userspace(const struct nlattr *attr, | |||
| 632 | { | 685 | { |
| 633 | int err; | 686 | int err; |
| 634 | 687 | ||
| 635 | memset(key, 0, sizeof(*key)); | ||
| 636 | /* Extract metadata from netlink attributes. */ | 688 | /* Extract metadata from netlink attributes. */ |
| 637 | err = ovs_nla_get_flow_metadata(attr, key); | 689 | err = ovs_nla_get_flow_metadata(attr, key); |
| 638 | if (err) | 690 | if (err) |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 0f5db4ec565d..71813318c8c7 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
| @@ -49,23 +49,45 @@ struct ovs_key_ipv4_tunnel { | |||
| 49 | u8 ipv4_ttl; | 49 | u8 ipv4_ttl; |
| 50 | } __packed __aligned(4); /* Minimize padding. */ | 50 | } __packed __aligned(4); /* Minimize padding. */ |
| 51 | 51 | ||
| 52 | static inline void ovs_flow_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key, | 52 | struct ovs_tunnel_info { |
| 53 | const struct iphdr *iph, __be64 tun_id, | 53 | struct ovs_key_ipv4_tunnel tunnel; |
| 54 | __be16 tun_flags) | 54 | struct geneve_opt *options; |
| 55 | u8 options_len; | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* Store options at the end of the array if they are less than the | ||
| 59 | * maximum size. This allows us to get the benefits of variable length | ||
| 60 | * matching for small options. | ||
| 61 | */ | ||
| 62 | #define GENEVE_OPTS(flow_key, opt_len) \ | ||
| 63 | ((struct geneve_opt *)((flow_key)->tun_opts + \ | ||
| 64 | FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \ | ||
| 65 | opt_len)) | ||
| 66 | |||
| 67 | static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, | ||
| 68 | const struct iphdr *iph, | ||
| 69 | __be64 tun_id, __be16 tun_flags, | ||
| 70 | struct geneve_opt *opts, | ||
| 71 | u8 opts_len) | ||
| 55 | { | 72 | { |
| 56 | tun_key->tun_id = tun_id; | 73 | tun_info->tunnel.tun_id = tun_id; |
| 57 | tun_key->ipv4_src = iph->saddr; | 74 | tun_info->tunnel.ipv4_src = iph->saddr; |
| 58 | tun_key->ipv4_dst = iph->daddr; | 75 | tun_info->tunnel.ipv4_dst = iph->daddr; |
| 59 | tun_key->ipv4_tos = iph->tos; | 76 | tun_info->tunnel.ipv4_tos = iph->tos; |
| 60 | tun_key->ipv4_ttl = iph->ttl; | 77 | tun_info->tunnel.ipv4_ttl = iph->ttl; |
| 61 | tun_key->tun_flags = tun_flags; | 78 | tun_info->tunnel.tun_flags = tun_flags; |
| 62 | 79 | ||
| 63 | /* clear struct padding. */ | 80 | /* clear struct padding. */ |
| 64 | memset((unsigned char *) tun_key + OVS_TUNNEL_KEY_SIZE, 0, | 81 | memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, 0, |
| 65 | sizeof(*tun_key) - OVS_TUNNEL_KEY_SIZE); | 82 | sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE); |
| 83 | |||
| 84 | tun_info->options = opts; | ||
| 85 | tun_info->options_len = opts_len; | ||
| 66 | } | 86 | } |
| 67 | 87 | ||
| 68 | struct sw_flow_key { | 88 | struct sw_flow_key { |
| 89 | u8 tun_opts[255]; | ||
| 90 | u8 tun_opts_len; | ||
| 69 | struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ | 91 | struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ |
| 70 | struct { | 92 | struct { |
| 71 | u32 priority; /* Packet QoS priority. */ | 93 | u32 priority; /* Packet QoS priority. */ |
| @@ -190,8 +212,8 @@ void ovs_flow_stats_clear(struct sw_flow *); | |||
| 190 | u64 ovs_flow_used_time(unsigned long flow_jiffies); | 212 | u64 ovs_flow_used_time(unsigned long flow_jiffies); |
| 191 | 213 | ||
| 192 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key); | 214 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key); |
| 193 | int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key, | 215 | int ovs_flow_key_extract(struct ovs_tunnel_info *tun_info, struct sk_buff *skb, |
| 194 | struct sk_buff *skb, struct sw_flow_key *key); | 216 | struct sw_flow_key *key); |
| 195 | /* Extract key from packet coming from userspace. */ | 217 | /* Extract key from packet coming from userspace. */ |
| 196 | int ovs_flow_key_extract_userspace(const struct nlattr *attr, | 218 | int ovs_flow_key_extract_userspace(const struct nlattr *attr, |
| 197 | struct sk_buff *skb, | 219 | struct sk_buff *skb, |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index f4c8daa73965..368f23307911 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/icmp.h> | 42 | #include <linux/icmp.h> |
| 43 | #include <linux/icmpv6.h> | 43 | #include <linux/icmpv6.h> |
| 44 | #include <linux/rculist.h> | 44 | #include <linux/rculist.h> |
| 45 | #include <net/geneve.h> | ||
| 45 | #include <net/ip.h> | 46 | #include <net/ip.h> |
| 46 | #include <net/ipv6.h> | 47 | #include <net/ipv6.h> |
| 47 | #include <net/ndisc.h> | 48 | #include <net/ndisc.h> |
| @@ -88,18 +89,20 @@ static void update_range__(struct sw_flow_match *match, | |||
| 88 | } \ | 89 | } \ |
| 89 | } while (0) | 90 | } while (0) |
| 90 | 91 | ||
| 91 | #define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \ | 92 | #define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \ |
| 92 | do { \ | 93 | do { \ |
| 93 | update_range__(match, offsetof(struct sw_flow_key, field), \ | 94 | update_range__(match, offset, len, is_mask); \ |
| 94 | len, is_mask); \ | 95 | if (is_mask) \ |
| 95 | if (is_mask) { \ | 96 | memcpy((u8 *)&(match)->mask->key + offset, value_p, \ |
| 96 | if ((match)->mask) \ | 97 | len); \ |
| 97 | memcpy(&(match)->mask->key.field, value_p, len);\ | 98 | else \ |
| 98 | } else { \ | 99 | memcpy((u8 *)(match)->key + offset, value_p, len); \ |
| 99 | memcpy(&(match)->key->field, value_p, len); \ | ||
| 100 | } \ | ||
| 101 | } while (0) | 100 | } while (0) |
| 102 | 101 | ||
| 102 | #define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \ | ||
| 103 | SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \ | ||
| 104 | value_p, len, is_mask) | ||
| 105 | |||
| 103 | static u16 range_n_bytes(const struct sw_flow_key_range *range) | 106 | static u16 range_n_bytes(const struct sw_flow_key_range *range) |
| 104 | { | 107 | { |
| 105 | return range->end - range->start; | 108 | return range->end - range->start; |
| @@ -335,6 +338,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
| 335 | int rem; | 338 | int rem; |
| 336 | bool ttl = false; | 339 | bool ttl = false; |
| 337 | __be16 tun_flags = 0; | 340 | __be16 tun_flags = 0; |
| 341 | unsigned long opt_key_offset; | ||
| 338 | 342 | ||
| 339 | nla_for_each_nested(a, attr, rem) { | 343 | nla_for_each_nested(a, attr, rem) { |
| 340 | int type = nla_type(a); | 344 | int type = nla_type(a); |
| @@ -346,6 +350,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
| 346 | [OVS_TUNNEL_KEY_ATTR_TTL] = 1, | 350 | [OVS_TUNNEL_KEY_ATTR_TTL] = 1, |
| 347 | [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0, | 351 | [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0, |
| 348 | [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, | 352 | [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, |
| 353 | [OVS_TUNNEL_KEY_ATTR_OAM] = 0, | ||
| 354 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1, | ||
| 349 | }; | 355 | }; |
| 350 | 356 | ||
| 351 | if (type > OVS_TUNNEL_KEY_ATTR_MAX) { | 357 | if (type > OVS_TUNNEL_KEY_ATTR_MAX) { |
| @@ -354,7 +360,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
| 354 | return -EINVAL; | 360 | return -EINVAL; |
| 355 | } | 361 | } |
| 356 | 362 | ||
| 357 | if (ovs_tunnel_key_lens[type] != nla_len(a)) { | 363 | if (ovs_tunnel_key_lens[type] != nla_len(a) && |
| 364 | ovs_tunnel_key_lens[type] != -1) { | ||
| 358 | OVS_NLERR("IPv4 tunnel attribute type has unexpected " | 365 | OVS_NLERR("IPv4 tunnel attribute type has unexpected " |
| 359 | " length (type=%d, length=%d, expected=%d).\n", | 366 | " length (type=%d, length=%d, expected=%d).\n", |
| 360 | type, nla_len(a), ovs_tunnel_key_lens[type]); | 367 | type, nla_len(a), ovs_tunnel_key_lens[type]); |
| @@ -390,7 +397,63 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
| 390 | case OVS_TUNNEL_KEY_ATTR_CSUM: | 397 | case OVS_TUNNEL_KEY_ATTR_CSUM: |
| 391 | tun_flags |= TUNNEL_CSUM; | 398 | tun_flags |= TUNNEL_CSUM; |
| 392 | break; | 399 | break; |
| 400 | case OVS_TUNNEL_KEY_ATTR_OAM: | ||
| 401 | tun_flags |= TUNNEL_OAM; | ||
| 402 | break; | ||
| 403 | case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: | ||
| 404 | tun_flags |= TUNNEL_OPTIONS_PRESENT; | ||
| 405 | if (nla_len(a) > sizeof(match->key->tun_opts)) { | ||
| 406 | OVS_NLERR("Geneve option length exceeds maximum size (len %d, max %zu).\n", | ||
| 407 | nla_len(a), | ||
| 408 | sizeof(match->key->tun_opts)); | ||
| 409 | return -EINVAL; | ||
| 410 | } | ||
| 411 | |||
| 412 | if (nla_len(a) % 4 != 0) { | ||
| 413 | OVS_NLERR("Geneve option length is not a multiple of 4 (len %d).\n", | ||
| 414 | nla_len(a)); | ||
| 415 | return -EINVAL; | ||
| 416 | } | ||
| 417 | |||
| 418 | /* We need to record the length of the options passed | ||
| 419 | * down, otherwise packets with the same format but | ||
| 420 | * additional options will be silently matched. | ||
| 421 | */ | ||
| 422 | if (!is_mask) { | ||
| 423 | SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a), | ||
| 424 | false); | ||
| 425 | } else { | ||
| 426 | /* This is somewhat unusual because it looks at | ||
| 427 | * both the key and mask while parsing the | ||
| 428 | * attributes (and by extension assumes the key | ||
| 429 | * is parsed first). Normally, we would verify | ||
| 430 | * that each is the correct length and that the | ||
| 431 | * attributes line up in the validate function. | ||
| 432 | * However, that is difficult because this is | ||
| 433 | * variable length and we won't have the | ||
| 434 | * information later. | ||
| 435 | */ | ||
| 436 | if (match->key->tun_opts_len != nla_len(a)) { | ||
| 437 | OVS_NLERR("Geneve option key length (%d) is different from mask length (%d).", | ||
| 438 | match->key->tun_opts_len, | ||
| 439 | nla_len(a)); | ||
| 440 | return -EINVAL; | ||
| 441 | } | ||
| 442 | |||
| 443 | SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, | ||
| 444 | true); | ||
| 445 | } | ||
| 446 | |||
| 447 | opt_key_offset = (unsigned long)GENEVE_OPTS( | ||
| 448 | (struct sw_flow_key *)0, | ||
| 449 | nla_len(a)); | ||
| 450 | SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, | ||
| 451 | nla_data(a), nla_len(a), | ||
| 452 | is_mask); | ||
| 453 | break; | ||
| 393 | default: | 454 | default: |
| 455 | OVS_NLERR("Unknown IPv4 tunnel attribute (%d).\n", | ||
| 456 | type); | ||
| 394 | return -EINVAL; | 457 | return -EINVAL; |
| 395 | } | 458 | } |
| 396 | } | 459 | } |
| @@ -417,42 +480,63 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
| 417 | return 0; | 480 | return 0; |
| 418 | } | 481 | } |
| 419 | 482 | ||
| 420 | static int ipv4_tun_to_nlattr(struct sk_buff *skb, | 483 | static int __ipv4_tun_to_nlattr(struct sk_buff *skb, |
| 421 | const struct ovs_key_ipv4_tunnel *tun_key, | 484 | const struct ovs_key_ipv4_tunnel *output, |
| 422 | const struct ovs_key_ipv4_tunnel *output) | 485 | const struct geneve_opt *tun_opts, |
| 486 | int swkey_tun_opts_len) | ||
| 423 | { | 487 | { |
| 424 | struct nlattr *nla; | ||
| 425 | |||
| 426 | nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL); | ||
| 427 | if (!nla) | ||
| 428 | return -EMSGSIZE; | ||
| 429 | |||
| 430 | if (output->tun_flags & TUNNEL_KEY && | 488 | if (output->tun_flags & TUNNEL_KEY && |
| 431 | nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) | 489 | nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) |
| 432 | return -EMSGSIZE; | 490 | return -EMSGSIZE; |
| 433 | if (output->ipv4_src && | 491 | if (output->ipv4_src && |
| 434 | nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, output->ipv4_src)) | 492 | nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, output->ipv4_src)) |
| 435 | return -EMSGSIZE; | 493 | return -EMSGSIZE; |
| 436 | if (output->ipv4_dst && | 494 | if (output->ipv4_dst && |
| 437 | nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst)) | 495 | nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst)) |
| 438 | return -EMSGSIZE; | 496 | return -EMSGSIZE; |
| 439 | if (output->ipv4_tos && | 497 | if (output->ipv4_tos && |
| 440 | nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos)) | 498 | nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos)) |
| 441 | return -EMSGSIZE; | 499 | return -EMSGSIZE; |
| 442 | if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ipv4_ttl)) | 500 | if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ipv4_ttl)) |
| 443 | return -EMSGSIZE; | 501 | return -EMSGSIZE; |
| 444 | if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) && | 502 | if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) && |
| 445 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)) | 503 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)) |
| 446 | return -EMSGSIZE; | 504 | return -EMSGSIZE; |
| 447 | if ((output->tun_flags & TUNNEL_CSUM) && | 505 | if ((output->tun_flags & TUNNEL_CSUM) && |
| 448 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) | 506 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) |
| 507 | return -EMSGSIZE; | ||
| 508 | if ((output->tun_flags & TUNNEL_OAM) && | ||
| 509 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) | ||
| 510 | return -EMSGSIZE; | ||
| 511 | if (tun_opts && | ||
| 512 | nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, | ||
| 513 | swkey_tun_opts_len, tun_opts)) | ||
| 449 | return -EMSGSIZE; | 514 | return -EMSGSIZE; |
| 450 | 515 | ||
| 451 | nla_nest_end(skb, nla); | ||
| 452 | return 0; | 516 | return 0; |
| 453 | } | 517 | } |
| 454 | 518 | ||
| 455 | 519 | ||
| 520 | static int ipv4_tun_to_nlattr(struct sk_buff *skb, | ||
| 521 | const struct ovs_key_ipv4_tunnel *output, | ||
| 522 | const struct geneve_opt *tun_opts, | ||
| 523 | int swkey_tun_opts_len) | ||
| 524 | { | ||
| 525 | struct nlattr *nla; | ||
| 526 | int err; | ||
| 527 | |||
| 528 | nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL); | ||
| 529 | if (!nla) | ||
| 530 | return -EMSGSIZE; | ||
| 531 | |||
| 532 | err = __ipv4_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len); | ||
| 533 | if (err) | ||
| 534 | return err; | ||
| 535 | |||
| 536 | nla_nest_end(skb, nla); | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 456 | static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, | 540 | static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, |
| 457 | const struct nlattr **a, bool is_mask) | 541 | const struct nlattr **a, bool is_mask) |
| 458 | { | 542 | { |
| @@ -898,9 +982,16 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey, | |||
| 898 | if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) | 982 | if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) |
| 899 | goto nla_put_failure; | 983 | goto nla_put_failure; |
| 900 | 984 | ||
| 901 | if ((swkey->tun_key.ipv4_dst || is_mask) && | 985 | if ((swkey->tun_key.ipv4_dst || is_mask)) { |
| 902 | ipv4_tun_to_nlattr(skb, &swkey->tun_key, &output->tun_key)) | 986 | const struct geneve_opt *opts = NULL; |
| 903 | goto nla_put_failure; | 987 | |
| 988 | if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) | ||
| 989 | opts = GENEVE_OPTS(output, swkey->tun_opts_len); | ||
| 990 | |||
| 991 | if (ipv4_tun_to_nlattr(skb, &output->tun_key, opts, | ||
| 992 | swkey->tun_opts_len)) | ||
| 993 | goto nla_put_failure; | ||
| 994 | } | ||
| 904 | 995 | ||
| 905 | if (swkey->phy.in_port == DP_MAX_PORTS) { | 996 | if (swkey->phy.in_port == DP_MAX_PORTS) { |
| 906 | if (is_mask && (output->phy.in_port == 0xffff)) | 997 | if (is_mask && (output->phy.in_port == 0xffff)) |
| @@ -1141,13 +1232,14 @@ out: | |||
| 1141 | return (struct nlattr *) ((unsigned char *)(*sfa) + next_offset); | 1232 | return (struct nlattr *) ((unsigned char *)(*sfa) + next_offset); |
| 1142 | } | 1233 | } |
| 1143 | 1234 | ||
| 1144 | static int add_action(struct sw_flow_actions **sfa, int attrtype, void *data, int len) | 1235 | static struct nlattr *__add_action(struct sw_flow_actions **sfa, |
| 1236 | int attrtype, void *data, int len) | ||
| 1145 | { | 1237 | { |
| 1146 | struct nlattr *a; | 1238 | struct nlattr *a; |
| 1147 | 1239 | ||
| 1148 | a = reserve_sfa_size(sfa, nla_attr_size(len)); | 1240 | a = reserve_sfa_size(sfa, nla_attr_size(len)); |
| 1149 | if (IS_ERR(a)) | 1241 | if (IS_ERR(a)) |
| 1150 | return PTR_ERR(a); | 1242 | return a; |
| 1151 | 1243 | ||
| 1152 | a->nla_type = attrtype; | 1244 | a->nla_type = attrtype; |
| 1153 | a->nla_len = nla_attr_size(len); | 1245 | a->nla_len = nla_attr_size(len); |
| @@ -1156,6 +1248,18 @@ static int add_action(struct sw_flow_actions **sfa, int attrtype, void *data, in | |||
| 1156 | memcpy(nla_data(a), data, len); | 1248 | memcpy(nla_data(a), data, len); |
| 1157 | memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len)); | 1249 | memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len)); |
| 1158 | 1250 | ||
| 1251 | return a; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | static int add_action(struct sw_flow_actions **sfa, int attrtype, | ||
| 1255 | void *data, int len) | ||
| 1256 | { | ||
| 1257 | struct nlattr *a; | ||
| 1258 | |||
| 1259 | a = __add_action(sfa, attrtype, data, len); | ||
| 1260 | if (IS_ERR(a)) | ||
| 1261 | return PTR_ERR(a); | ||
| 1262 | |||
| 1159 | return 0; | 1263 | return 0; |
| 1160 | } | 1264 | } |
| 1161 | 1265 | ||
| @@ -1261,6 +1365,8 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, | |||
| 1261 | { | 1365 | { |
| 1262 | struct sw_flow_match match; | 1366 | struct sw_flow_match match; |
| 1263 | struct sw_flow_key key; | 1367 | struct sw_flow_key key; |
| 1368 | struct ovs_tunnel_info *tun_info; | ||
| 1369 | struct nlattr *a; | ||
| 1264 | int err, start; | 1370 | int err, start; |
| 1265 | 1371 | ||
| 1266 | ovs_match_init(&match, &key, NULL); | 1372 | ovs_match_init(&match, &key, NULL); |
| @@ -1268,12 +1374,56 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, | |||
| 1268 | if (err) | 1374 | if (err) |
| 1269 | return err; | 1375 | return err; |
| 1270 | 1376 | ||
| 1377 | if (key.tun_opts_len) { | ||
| 1378 | struct geneve_opt *option = GENEVE_OPTS(&key, | ||
| 1379 | key.tun_opts_len); | ||
| 1380 | int opts_len = key.tun_opts_len; | ||
| 1381 | bool crit_opt = false; | ||
| 1382 | |||
| 1383 | while (opts_len > 0) { | ||
| 1384 | int len; | ||
| 1385 | |||
| 1386 | if (opts_len < sizeof(*option)) | ||
| 1387 | return -EINVAL; | ||
| 1388 | |||
| 1389 | len = sizeof(*option) + option->length * 4; | ||
| 1390 | if (len > opts_len) | ||
| 1391 | return -EINVAL; | ||
| 1392 | |||
| 1393 | crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE); | ||
| 1394 | |||
| 1395 | option = (struct geneve_opt *)((u8 *)option + len); | ||
| 1396 | opts_len -= len; | ||
| 1397 | }; | ||
| 1398 | |||
| 1399 | key.tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0; | ||
| 1400 | }; | ||
| 1401 | |||
| 1271 | start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET); | 1402 | start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET); |
| 1272 | if (start < 0) | 1403 | if (start < 0) |
| 1273 | return start; | 1404 | return start; |
| 1274 | 1405 | ||
| 1275 | err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &match.key->tun_key, | 1406 | a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL, |
| 1276 | sizeof(match.key->tun_key)); | 1407 | sizeof(*tun_info) + key.tun_opts_len); |
| 1408 | if (IS_ERR(a)) | ||
| 1409 | return PTR_ERR(a); | ||
| 1410 | |||
| 1411 | tun_info = nla_data(a); | ||
| 1412 | tun_info->tunnel = key.tun_key; | ||
| 1413 | tun_info->options_len = key.tun_opts_len; | ||
| 1414 | |||
| 1415 | if (tun_info->options_len) { | ||
| 1416 | /* We need to store the options in the action itself since | ||
| 1417 | * everything else will go away after flow setup. We can append | ||
| 1418 | * it to tun_info and then point there. | ||
| 1419 | */ | ||
| 1420 | memcpy((tun_info + 1), GENEVE_OPTS(&key, key.tun_opts_len), | ||
| 1421 | key.tun_opts_len); | ||
| 1422 | tun_info->options = (struct geneve_opt *)(tun_info + 1); | ||
| 1423 | } else { | ||
| 1424 | tun_info->options = NULL; | ||
| 1425 | } | ||
| 1426 | |||
| 1277 | add_nested_action_end(*sfa, start); | 1427 | add_nested_action_end(*sfa, start); |
| 1278 | 1428 | ||
| 1279 | return err; | 1429 | return err; |
| @@ -1556,17 +1706,22 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | |||
| 1556 | int err; | 1706 | int err; |
| 1557 | 1707 | ||
| 1558 | switch (key_type) { | 1708 | switch (key_type) { |
| 1559 | case OVS_KEY_ATTR_IPV4_TUNNEL: | 1709 | case OVS_KEY_ATTR_TUNNEL_INFO: { |
| 1710 | struct ovs_tunnel_info *tun_info = nla_data(ovs_key); | ||
| 1711 | |||
| 1560 | start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); | 1712 | start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); |
| 1561 | if (!start) | 1713 | if (!start) |
| 1562 | return -EMSGSIZE; | 1714 | return -EMSGSIZE; |
| 1563 | 1715 | ||
| 1564 | err = ipv4_tun_to_nlattr(skb, nla_data(ovs_key), | 1716 | err = ipv4_tun_to_nlattr(skb, &tun_info->tunnel, |
| 1565 | nla_data(ovs_key)); | 1717 | tun_info->options_len ? |
| 1718 | tun_info->options : NULL, | ||
| 1719 | tun_info->options_len); | ||
| 1566 | if (err) | 1720 | if (err) |
| 1567 | return err; | 1721 | return err; |
| 1568 | nla_nest_end(skb, start); | 1722 | nla_nest_end(skb, start); |
| 1569 | break; | 1723 | break; |
| 1724 | } | ||
| 1570 | default: | 1725 | default: |
| 1571 | if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key)) | 1726 | if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key)) |
| 1572 | return -EMSGSIZE; | 1727 | return -EMSGSIZE; |
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c new file mode 100644 index 000000000000..5572d482f285 --- /dev/null +++ b/net/openvswitch/vport-geneve.c | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Nicira, Inc. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 11 | |||
| 12 | #include <linux/version.h> | ||
| 13 | |||
| 14 | #include <linux/in.h> | ||
| 15 | #include <linux/ip.h> | ||
| 16 | #include <linux/net.h> | ||
| 17 | #include <linux/rculist.h> | ||
| 18 | #include <linux/udp.h> | ||
| 19 | #include <linux/if_vlan.h> | ||
| 20 | |||
| 21 | #include <net/geneve.h> | ||
| 22 | #include <net/icmp.h> | ||
| 23 | #include <net/ip.h> | ||
| 24 | #include <net/route.h> | ||
| 25 | #include <net/udp.h> | ||
| 26 | #include <net/xfrm.h> | ||
| 27 | |||
| 28 | #include "datapath.h" | ||
| 29 | #include "vport.h" | ||
| 30 | |||
| 31 | /** | ||
| 32 | * struct geneve_port - Keeps track of open UDP ports | ||
| 33 | * @sock: The socket created for this port number. | ||
| 34 | * @name: vport name. | ||
| 35 | */ | ||
| 36 | struct geneve_port { | ||
| 37 | struct geneve_sock *gs; | ||
| 38 | char name[IFNAMSIZ]; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static LIST_HEAD(geneve_ports); | ||
| 42 | |||
| 43 | static inline struct geneve_port *geneve_vport(const struct vport *vport) | ||
| 44 | { | ||
| 45 | return vport_priv(vport); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) | ||
| 49 | { | ||
| 50 | return (struct genevehdr *)(udp_hdr(skb) + 1); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Convert 64 bit tunnel ID to 24 bit VNI. */ | ||
| 54 | static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni) | ||
| 55 | { | ||
| 56 | #ifdef __BIG_ENDIAN | ||
| 57 | vni[0] = (__force __u8)(tun_id >> 16); | ||
| 58 | vni[1] = (__force __u8)(tun_id >> 8); | ||
| 59 | vni[2] = (__force __u8)tun_id; | ||
| 60 | #else | ||
| 61 | vni[0] = (__force __u8)((__force u64)tun_id >> 40); | ||
| 62 | vni[1] = (__force __u8)((__force u64)tun_id >> 48); | ||
| 63 | vni[2] = (__force __u8)((__force u64)tun_id >> 56); | ||
| 64 | #endif | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Convert 24 bit VNI to 64 bit tunnel ID. */ | ||
| 68 | static __be64 vni_to_tunnel_id(__u8 *vni) | ||
| 69 | { | ||
| 70 | #ifdef __BIG_ENDIAN | ||
| 71 | return (vni[0] << 16) | (vni[1] << 8) | vni[2]; | ||
| 72 | #else | ||
| 73 | return (__force __be64)(((__force u64)vni[0] << 40) | | ||
| 74 | ((__force u64)vni[1] << 48) | | ||
| 75 | ((__force u64)vni[2] << 56)); | ||
| 76 | #endif | ||
| 77 | } | ||
| 78 | |||
| 79 | static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb) | ||
| 80 | { | ||
| 81 | struct vport *vport = gs->rcv_data; | ||
| 82 | struct genevehdr *geneveh = geneve_hdr(skb); | ||
| 83 | int opts_len; | ||
| 84 | struct ovs_tunnel_info tun_info; | ||
| 85 | __be64 key; | ||
| 86 | __be16 flags; | ||
| 87 | |||
| 88 | opts_len = geneveh->opt_len * 4; | ||
| 89 | |||
| 90 | flags = TUNNEL_KEY | TUNNEL_OPTIONS_PRESENT | | ||
| 91 | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) | | ||
| 92 | (geneveh->oam ? TUNNEL_OAM : 0) | | ||
| 93 | (geneveh->critical ? TUNNEL_CRIT_OPT : 0); | ||
| 94 | |||
| 95 | key = vni_to_tunnel_id(geneveh->vni); | ||
| 96 | |||
| 97 | ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags, | ||
| 98 | geneveh->options, opts_len); | ||
| 99 | |||
| 100 | ovs_vport_receive(vport, skb, &tun_info); | ||
| 101 | } | ||
| 102 | |||
| 103 | static int geneve_get_options(const struct vport *vport, | ||
| 104 | struct sk_buff *skb) | ||
| 105 | { | ||
| 106 | struct geneve_port *geneve_port = geneve_vport(vport); | ||
| 107 | __be16 sport; | ||
| 108 | |||
| 109 | sport = ntohs(inet_sk(geneve_port->gs->sock->sk)->inet_sport); | ||
| 110 | if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, sport)) | ||
| 111 | return -EMSGSIZE; | ||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static void geneve_tnl_destroy(struct vport *vport) | ||
| 116 | { | ||
| 117 | struct geneve_port *geneve_port = geneve_vport(vport); | ||
| 118 | |||
| 119 | geneve_sock_release(geneve_port->gs); | ||
| 120 | |||
| 121 | ovs_vport_deferred_free(vport); | ||
| 122 | } | ||
| 123 | |||
| 124 | static struct vport *geneve_tnl_create(const struct vport_parms *parms) | ||
| 125 | { | ||
| 126 | struct net *net = ovs_dp_get_net(parms->dp); | ||
| 127 | struct nlattr *options = parms->options; | ||
| 128 | struct geneve_port *geneve_port; | ||
| 129 | struct geneve_sock *gs; | ||
| 130 | struct vport *vport; | ||
| 131 | struct nlattr *a; | ||
| 132 | int err; | ||
| 133 | u16 dst_port; | ||
| 134 | |||
| 135 | if (!options) { | ||
| 136 | err = -EINVAL; | ||
| 137 | goto error; | ||
| 138 | } | ||
| 139 | |||
| 140 | a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); | ||
| 141 | if (a && nla_len(a) == sizeof(u16)) { | ||
| 142 | dst_port = nla_get_u16(a); | ||
| 143 | } else { | ||
| 144 | /* Require destination port from userspace. */ | ||
| 145 | err = -EINVAL; | ||
| 146 | goto error; | ||
| 147 | } | ||
| 148 | |||
| 149 | vport = ovs_vport_alloc(sizeof(struct geneve_port), | ||
| 150 | &ovs_geneve_vport_ops, parms); | ||
| 151 | if (IS_ERR(vport)) | ||
| 152 | return vport; | ||
| 153 | |||
| 154 | geneve_port = geneve_vport(vport); | ||
| 155 | strncpy(geneve_port->name, parms->name, IFNAMSIZ); | ||
| 156 | |||
| 157 | gs = geneve_sock_add(net, htons(dst_port), geneve_rcv, vport, true, 0); | ||
| 158 | if (IS_ERR(gs)) { | ||
| 159 | ovs_vport_free(vport); | ||
| 160 | return (void *)gs; | ||
| 161 | } | ||
| 162 | geneve_port->gs = gs; | ||
| 163 | |||
| 164 | return vport; | ||
| 165 | error: | ||
| 166 | return ERR_PTR(err); | ||
| 167 | } | ||
| 168 | |||
| 169 | static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) | ||
| 170 | { | ||
| 171 | struct ovs_key_ipv4_tunnel *tun_key; | ||
| 172 | struct ovs_tunnel_info *tun_info; | ||
| 173 | struct net *net = ovs_dp_get_net(vport->dp); | ||
| 174 | struct geneve_port *geneve_port = geneve_vport(vport); | ||
| 175 | __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport; | ||
| 176 | __be16 sport; | ||
| 177 | struct rtable *rt; | ||
| 178 | struct flowi4 fl; | ||
| 179 | u8 vni[3]; | ||
| 180 | __be16 df; | ||
| 181 | int err; | ||
| 182 | |||
| 183 | tun_info = OVS_CB(skb)->egress_tun_info; | ||
| 184 | if (unlikely(!tun_info)) { | ||
| 185 | err = -EINVAL; | ||
| 186 | goto error; | ||
| 187 | } | ||
| 188 | |||
| 189 | tun_key = &tun_info->tunnel; | ||
| 190 | |||
| 191 | /* Route lookup */ | ||
| 192 | memset(&fl, 0, sizeof(fl)); | ||
| 193 | fl.daddr = tun_key->ipv4_dst; | ||
| 194 | fl.saddr = tun_key->ipv4_src; | ||
| 195 | fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos); | ||
| 196 | fl.flowi4_mark = skb->mark; | ||
| 197 | fl.flowi4_proto = IPPROTO_UDP; | ||
| 198 | |||
| 199 | rt = ip_route_output_key(net, &fl); | ||
| 200 | if (IS_ERR(rt)) { | ||
| 201 | err = PTR_ERR(rt); | ||
| 202 | goto error; | ||
| 203 | } | ||
| 204 | |||
| 205 | df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; | ||
| 206 | sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); | ||
| 207 | tunnel_id_to_vni(tun_key->tun_id, vni); | ||
| 208 | skb->ignore_df = 1; | ||
| 209 | |||
| 210 | err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr, | ||
| 211 | tun_key->ipv4_dst, tun_key->ipv4_tos, | ||
| 212 | tun_key->ipv4_ttl, df, sport, dport, | ||
| 213 | tun_key->tun_flags, vni, | ||
| 214 | tun_info->options_len, (u8 *)tun_info->options, | ||
| 215 | false); | ||
| 216 | if (err < 0) | ||
| 217 | ip_rt_put(rt); | ||
| 218 | error: | ||
| 219 | return err; | ||
| 220 | } | ||
| 221 | |||
| 222 | static const char *geneve_get_name(const struct vport *vport) | ||
| 223 | { | ||
| 224 | struct geneve_port *geneve_port = geneve_vport(vport); | ||
| 225 | |||
| 226 | return geneve_port->name; | ||
| 227 | } | ||
| 228 | |||
| 229 | const struct vport_ops ovs_geneve_vport_ops = { | ||
| 230 | .type = OVS_VPORT_TYPE_GENEVE, | ||
| 231 | .create = geneve_tnl_create, | ||
| 232 | .destroy = geneve_tnl_destroy, | ||
| 233 | .get_name = geneve_get_name, | ||
| 234 | .get_options = geneve_get_options, | ||
| 235 | .send = geneve_tnl_send, | ||
| 236 | }; | ||
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 309cca6e816f..108b82da2fd9 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c | |||
| @@ -63,8 +63,10 @@ static __be16 filter_tnl_flags(__be16 flags) | |||
| 63 | static struct sk_buff *__build_header(struct sk_buff *skb, | 63 | static struct sk_buff *__build_header(struct sk_buff *skb, |
| 64 | int tunnel_hlen) | 64 | int tunnel_hlen) |
| 65 | { | 65 | { |
| 66 | const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->egress_tun_key; | ||
| 67 | struct tnl_ptk_info tpi; | 66 | struct tnl_ptk_info tpi; |
| 67 | const struct ovs_key_ipv4_tunnel *tun_key; | ||
| 68 | |||
| 69 | tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; | ||
| 68 | 70 | ||
| 69 | skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); | 71 | skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); |
| 70 | if (IS_ERR(skb)) | 72 | if (IS_ERR(skb)) |
| @@ -92,7 +94,7 @@ static __be64 key_to_tunnel_id(__be32 key, __be32 seq) | |||
| 92 | static int gre_rcv(struct sk_buff *skb, | 94 | static int gre_rcv(struct sk_buff *skb, |
| 93 | const struct tnl_ptk_info *tpi) | 95 | const struct tnl_ptk_info *tpi) |
| 94 | { | 96 | { |
| 95 | struct ovs_key_ipv4_tunnel tun_key; | 97 | struct ovs_tunnel_info tun_info; |
| 96 | struct ovs_net *ovs_net; | 98 | struct ovs_net *ovs_net; |
| 97 | struct vport *vport; | 99 | struct vport *vport; |
| 98 | __be64 key; | 100 | __be64 key; |
| @@ -103,10 +105,10 @@ static int gre_rcv(struct sk_buff *skb, | |||
| 103 | return PACKET_REJECT; | 105 | return PACKET_REJECT; |
| 104 | 106 | ||
| 105 | key = key_to_tunnel_id(tpi->key, tpi->seq); | 107 | key = key_to_tunnel_id(tpi->key, tpi->seq); |
| 106 | ovs_flow_tun_key_init(&tun_key, ip_hdr(skb), key, | 108 | ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, |
| 107 | filter_tnl_flags(tpi->flags)); | 109 | filter_tnl_flags(tpi->flags), NULL, 0); |
| 108 | 110 | ||
| 109 | ovs_vport_receive(vport, skb, &tun_key); | 111 | ovs_vport_receive(vport, skb, &tun_info); |
| 110 | return PACKET_RCVD; | 112 | return PACKET_RCVD; |
| 111 | } | 113 | } |
| 112 | 114 | ||
| @@ -137,12 +139,12 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
| 137 | __be16 df; | 139 | __be16 df; |
| 138 | int err; | 140 | int err; |
| 139 | 141 | ||
| 140 | if (unlikely(!OVS_CB(skb)->egress_tun_key)) { | 142 | if (unlikely(!OVS_CB(skb)->egress_tun_info)) { |
| 141 | err = -EINVAL; | 143 | err = -EINVAL; |
| 142 | goto error; | 144 | goto error; |
| 143 | } | 145 | } |
| 144 | 146 | ||
| 145 | tun_key = OVS_CB(skb)->egress_tun_key; | 147 | tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; |
| 146 | /* Route lookup */ | 148 | /* Route lookup */ |
| 147 | memset(&fl, 0, sizeof(fl)); | 149 | memset(&fl, 0, sizeof(fl)); |
| 148 | fl.daddr = tun_key->ipv4_dst; | 150 | fl.daddr = tun_key->ipv4_dst; |
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index f19539bb8adc..2735e01dca73 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c | |||
| @@ -58,7 +58,7 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport) | |||
| 58 | /* Called with rcu_read_lock and BH disabled. */ | 58 | /* Called with rcu_read_lock and BH disabled. */ |
| 59 | static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni) | 59 | static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni) |
| 60 | { | 60 | { |
| 61 | struct ovs_key_ipv4_tunnel tun_key; | 61 | struct ovs_tunnel_info tun_info; |
| 62 | struct vport *vport = vs->data; | 62 | struct vport *vport = vs->data; |
| 63 | struct iphdr *iph; | 63 | struct iphdr *iph; |
| 64 | __be64 key; | 64 | __be64 key; |
| @@ -66,9 +66,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni) | |||
| 66 | /* Save outer tunnel values */ | 66 | /* Save outer tunnel values */ |
| 67 | iph = ip_hdr(skb); | 67 | iph = ip_hdr(skb); |
| 68 | key = cpu_to_be64(ntohl(vx_vni) >> 8); | 68 | key = cpu_to_be64(ntohl(vx_vni) >> 8); |
| 69 | ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY); | 69 | ovs_flow_tun_info_init(&tun_info, iph, key, TUNNEL_KEY, NULL, 0); |
| 70 | 70 | ||
| 71 | ovs_vport_receive(vport, skb, &tun_key); | 71 | ovs_vport_receive(vport, skb, &tun_info); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) | 74 | static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) |
| @@ -147,12 +147,12 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
| 147 | __be16 df; | 147 | __be16 df; |
| 148 | int err; | 148 | int err; |
| 149 | 149 | ||
| 150 | if (unlikely(!OVS_CB(skb)->egress_tun_key)) { | 150 | if (unlikely(!OVS_CB(skb)->egress_tun_info)) { |
| 151 | err = -EINVAL; | 151 | err = -EINVAL; |
| 152 | goto error; | 152 | goto error; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | tun_key = OVS_CB(skb)->egress_tun_key; | 155 | tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; |
| 156 | /* Route lookup */ | 156 | /* Route lookup */ |
| 157 | memset(&fl, 0, sizeof(fl)); | 157 | memset(&fl, 0, sizeof(fl)); |
| 158 | fl.daddr = tun_key->ipv4_dst; | 158 | fl.daddr = tun_key->ipv4_dst; |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 5df8377fcfb1..53001b020ca7 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
| @@ -48,6 +48,9 @@ static const struct vport_ops *vport_ops_list[] = { | |||
| 48 | #ifdef CONFIG_OPENVSWITCH_VXLAN | 48 | #ifdef CONFIG_OPENVSWITCH_VXLAN |
| 49 | &ovs_vxlan_vport_ops, | 49 | &ovs_vxlan_vport_ops, |
| 50 | #endif | 50 | #endif |
| 51 | #ifdef CONFIG_OPENVSWITCH_GENEVE | ||
| 52 | &ovs_geneve_vport_ops, | ||
| 53 | #endif | ||
| 51 | }; | 54 | }; |
| 52 | 55 | ||
| 53 | /* Protected by RCU read lock for reading, ovs_mutex for writing. */ | 56 | /* Protected by RCU read lock for reading, ovs_mutex for writing. */ |
| @@ -432,7 +435,7 @@ u32 ovs_vport_find_upcall_portid(const struct vport *p, struct sk_buff *skb) | |||
| 432 | * skb->data should point to the Ethernet header. | 435 | * skb->data should point to the Ethernet header. |
| 433 | */ | 436 | */ |
| 434 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | 437 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, |
| 435 | struct ovs_key_ipv4_tunnel *tun_key) | 438 | struct ovs_tunnel_info *tun_info) |
| 436 | { | 439 | { |
| 437 | struct pcpu_sw_netstats *stats; | 440 | struct pcpu_sw_netstats *stats; |
| 438 | struct sw_flow_key key; | 441 | struct sw_flow_key key; |
| @@ -445,9 +448,9 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | |||
| 445 | u64_stats_update_end(&stats->syncp); | 448 | u64_stats_update_end(&stats->syncp); |
| 446 | 449 | ||
| 447 | OVS_CB(skb)->input_vport = vport; | 450 | OVS_CB(skb)->input_vport = vport; |
| 448 | OVS_CB(skb)->egress_tun_key = NULL; | 451 | OVS_CB(skb)->egress_tun_info = NULL; |
| 449 | /* Extract flow from 'skb' into 'key'. */ | 452 | /* Extract flow from 'skb' into 'key'. */ |
| 450 | error = ovs_flow_key_extract(tun_key, skb, &key); | 453 | error = ovs_flow_key_extract(tun_info, skb, &key); |
| 451 | if (unlikely(error)) { | 454 | if (unlikely(error)) { |
| 452 | kfree_skb(skb); | 455 | kfree_skb(skb); |
| 453 | return; | 456 | return; |
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 0efd62fef1e8..8942125de3a6 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
| @@ -207,7 +207,7 @@ static inline struct vport *vport_from_priv(void *priv) | |||
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | void ovs_vport_receive(struct vport *, struct sk_buff *, | 209 | void ovs_vport_receive(struct vport *, struct sk_buff *, |
| 210 | struct ovs_key_ipv4_tunnel *); | 210 | struct ovs_tunnel_info *); |
| 211 | 211 | ||
| 212 | /* List of statically compiled vport implementations. Don't forget to also | 212 | /* List of statically compiled vport implementations. Don't forget to also |
| 213 | * add yours to the list at the top of vport.c. */ | 213 | * add yours to the list at the top of vport.c. */ |
| @@ -215,6 +215,7 @@ extern const struct vport_ops ovs_netdev_vport_ops; | |||
| 215 | extern const struct vport_ops ovs_internal_vport_ops; | 215 | extern const struct vport_ops ovs_internal_vport_ops; |
| 216 | extern const struct vport_ops ovs_gre_vport_ops; | 216 | extern const struct vport_ops ovs_gre_vport_ops; |
| 217 | extern const struct vport_ops ovs_vxlan_vport_ops; | 217 | extern const struct vport_ops ovs_vxlan_vport_ops; |
| 218 | extern const struct vport_ops ovs_geneve_vport_ops; | ||
| 218 | 219 | ||
| 219 | static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, | 220 | static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, |
| 220 | const void *start, unsigned int len) | 221 | const void *start, unsigned int len) |
