-static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
-{
- return (struct genevehdr *)(udp_hdr(skb) + 1);
-}
-
-/* Convert 64 bit tunnel ID to 24 bit VNI. */
-static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
-{
-#ifdef __BIG_ENDIAN
- vni[0] = (__force __u8)(tun_id >> 16);
- vni[1] = (__force __u8)(tun_id >> 8);
- vni[2] = (__force __u8)tun_id;
-#else
- vni[0] = (__force __u8)((__force u64)tun_id >> 40);
- vni[1] = (__force __u8)((__force u64)tun_id >> 48);
- vni[2] = (__force __u8)((__force u64)tun_id >> 56);
-#endif
-}
-
-/* Convert 24 bit VNI to 64 bit tunnel ID. */
-static __be64 vni_to_tunnel_id(__u8 *vni)
-{
-#ifdef __BIG_ENDIAN
- return (vni[0] << 16) | (vni[1] << 8) | vni[2];
-#else
- return (__force __be64)(((__force u64)vni[0] << 40) |
- ((__force u64)vni[1] << 48) |
- ((__force u64)vni[2] << 56));
-#endif
-}
-
-static void geneve_build_header(const struct vport *vport,
- struct sk_buff *skb)
-{
- struct geneve_port *geneve_port = geneve_vport(vport);
- struct udphdr *udph = udp_hdr(skb);
- struct genevehdr *geneveh = (struct genevehdr *)(udph + 1);
- const struct ovs_tunnel_info *tun_info = OVS_CB(skb)->tun_info;
-
- udph->dest = inet_sport(geneve_port->sock->sk);
- udph->source = vxlan_src_port(1, USHRT_MAX, skb);
- udph->check = 0;
- udph->len = htons(skb->len - skb_transport_offset(skb));
-
- geneveh->ver = GENEVE_VER;
- geneveh->opt_len = tun_info->options_len / 4;
- geneveh->oam = !!(tun_info->tunnel.tun_flags & TUNNEL_OAM);
- geneveh->critical = !!(tun_info->tunnel.tun_flags & TUNNEL_CRIT_OPT);
- geneveh->rsvd1 = 0;
- geneveh->proto_type = htons(ETH_P_TEB);
- tunnel_id_to_vni(tun_info->tunnel.tun_id, geneveh->vni);
- geneveh->rsvd2 = 0;
-
- memcpy(geneveh->options, tun_info->options, tun_info->options_len);
-}
-
-static int geneve_rcv(struct sock *sk, struct sk_buff *skb)
-{
- struct geneve_port *geneve_port;
- struct genevehdr *geneveh;
- int opts_len;
- struct ovs_tunnel_info tun_info;
- __be64 key;
- __be16 flags;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
- if (unlikely(udp_lib_checksum_complete(skb)))
- goto error;
-#endif
-
- if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
- goto error;
-
- geneveh = geneve_hdr(skb);
-
- if (unlikely(geneveh->ver != GENEVE_VER))
- goto error;
-
- if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
- goto error;
-
- geneve_port = rcu_dereference_sk_user_data(sk);
- if (unlikely(!geneve_port))
- goto error;
-
- opts_len = geneveh->opt_len * 4;
- if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
- htons(ETH_P_TEB)))
- goto error;
-
- geneveh = geneve_hdr(skb);
-
- flags = TUNNEL_KEY | TUNNEL_OPTIONS_PRESENT |
- (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) |
- (geneveh->oam ? TUNNEL_OAM : 0) |
- (geneveh->critical ? TUNNEL_CRIT_OPT : 0);
-
- key = vni_to_tunnel_id(geneveh->vni);
- ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags,
- geneveh->options, opts_len);
-
- ovs_vport_receive(vport_from_priv(geneve_port), skb, &tun_info);
- goto out;
-
-error:
- kfree_skb(skb);
-out:
- return 0;
-}
-
-/* Arbitrary value. Irrelevant as long as it's not 0 since we set the handler. */
-#define UDP_ENCAP_GENEVE 1
-static int geneve_socket_init(struct geneve_port *geneve_port, struct net *net,
- __be16 dst_port)
-{
- struct sockaddr_in sin;
- int err;
-
- err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
- &geneve_port->sock);
- if (err)
- goto error;
-
- /* release net ref. */
- sk_change_net(geneve_port->sock->sk, net);
-
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = dst_port;
-
- err = kernel_bind(geneve_port->sock,
- (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
- if (err)
- goto error_sock;
-
- rcu_assign_sk_user_data(geneve_port->sock->sk, geneve_port);
- udp_sk(geneve_port->sock->sk)->encap_type = UDP_ENCAP_GENEVE;
- udp_sk(geneve_port->sock->sk)->encap_rcv = geneve_rcv;
-
- udp_encap_enable();
-
- return 0;
-
-error_sock:
- sk_release_kernel(geneve_port->sock->sk);
-error:
- pr_warn("cannot register geneve protocol handler: %d\n", err);
- return err;
-}
-