1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22d07dc79SJohn W. Linville /*
32d07dc79SJohn W. Linville * GENEVE: Generic Network Virtualization Encapsulation
42d07dc79SJohn W. Linville *
52d07dc79SJohn W. Linville * Copyright (c) 2015 Red Hat, Inc.
62d07dc79SJohn W. Linville */
72d07dc79SJohn W. Linville
82d07dc79SJohn W. Linville #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
92d07dc79SJohn W. Linville
10cc69837fSJakub Kicinski #include <linux/ethtool.h>
112d07dc79SJohn W. Linville #include <linux/kernel.h>
122d07dc79SJohn W. Linville #include <linux/module.h>
132d07dc79SJohn W. Linville #include <linux/etherdevice.h>
142d07dc79SJohn W. Linville #include <linux/hash.h>
153616d08bSDavid Ahern #include <net/ipv6_stubs.h>
16e305ac6cSPravin B Shelar #include <net/dst_metadata.h>
178e816df8SJesse Gross #include <net/gro_cells.h>
182d07dc79SJohn W. Linville #include <net/rtnetlink.h>
192d07dc79SJohn W. Linville #include <net/geneve.h>
204721031cSEric Dumazet #include <net/gro.h>
21371bd106SPravin B Shelar #include <net/protocol.h>
222d07dc79SJohn W. Linville
232d07dc79SJohn W. Linville #define GENEVE_NETDEV_VER "0.6"
242d07dc79SJohn W. Linville
252d07dc79SJohn W. Linville #define GENEVE_N_VID (1u << 24)
262d07dc79SJohn W. Linville #define GENEVE_VID_MASK (GENEVE_N_VID - 1)
272d07dc79SJohn W. Linville
282d07dc79SJohn W. Linville #define VNI_HASH_BITS 10
292d07dc79SJohn W. Linville #define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
302d07dc79SJohn W. Linville
312d07dc79SJohn W. Linville static bool log_ecn_error = true;
322d07dc79SJohn W. Linville module_param(log_ecn_error, bool, 0644);
332d07dc79SJohn W. Linville MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
342d07dc79SJohn W. Linville
35371bd106SPravin B Shelar #define GENEVE_VER 0
36371bd106SPravin B Shelar #define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr))
375edbea69SAlexey Kodanev #define GENEVE_IPV4_HLEN (ETH_HLEN + sizeof(struct iphdr) + GENEVE_BASE_HLEN)
385edbea69SAlexey Kodanev #define GENEVE_IPV6_HLEN (ETH_HLEN + sizeof(struct ipv6hdr) + GENEVE_BASE_HLEN)
39371bd106SPravin B Shelar
402d07dc79SJohn W. Linville /* per-network namespace private data for this module */
412d07dc79SJohn W. Linville struct geneve_net {
422d07dc79SJohn W. Linville struct list_head geneve_list;
43371bd106SPravin B Shelar struct list_head sock_list;
442d07dc79SJohn W. Linville };
452d07dc79SJohn W. Linville
46c7d03a00SAlexey Dobriyan static unsigned int geneve_net_id;
47371bd106SPravin B Shelar
484b4c21faSJiri Benc struct geneve_dev_node {
494b4c21faSJiri Benc struct hlist_node hlist;
504b4c21faSJiri Benc struct geneve_dev *geneve;
514b4c21faSJiri Benc };
524b4c21faSJiri Benc
539e06e859SSabrina Dubroca struct geneve_config {
549e06e859SSabrina Dubroca struct ip_tunnel_info info;
559e06e859SSabrina Dubroca bool collect_md;
569e06e859SSabrina Dubroca bool use_udp6_rx_checksums;
579e06e859SSabrina Dubroca bool ttl_inherit;
589e06e859SSabrina Dubroca enum ifla_geneve_df df;
59435fe1c0SEyal Birger bool inner_proto_inherit;
609e06e859SSabrina Dubroca };
619e06e859SSabrina Dubroca
622d07dc79SJohn W. Linville /* Pseudo network device */
632d07dc79SJohn W. Linville struct geneve_dev {
644b4c21faSJiri Benc struct geneve_dev_node hlist4; /* vni hash table for IPv4 socket */
654b4c21faSJiri Benc #if IS_ENABLED(CONFIG_IPV6)
664b4c21faSJiri Benc struct geneve_dev_node hlist6; /* vni hash table for IPv6 socket */
674b4c21faSJiri Benc #endif
682d07dc79SJohn W. Linville struct net *net; /* netns for packet i/o */
692d07dc79SJohn W. Linville struct net_device *dev; /* netdev for geneve tunnel */
70fceb9c3eSpravin shelar struct geneve_sock __rcu *sock4; /* IPv4 socket used for geneve tunnel */
718ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
72fceb9c3eSpravin shelar struct geneve_sock __rcu *sock6; /* IPv6 socket used for geneve tunnel */
738ed66f0eSJohn W. Linville #endif
742d07dc79SJohn W. Linville struct list_head next; /* geneve's per namespace list */
758e816df8SJesse Gross struct gro_cells gro_cells;
769e06e859SSabrina Dubroca struct geneve_config cfg;
772d07dc79SJohn W. Linville };
782d07dc79SJohn W. Linville
79371bd106SPravin B Shelar struct geneve_sock {
80371bd106SPravin B Shelar bool collect_md;
81371bd106SPravin B Shelar struct list_head list;
82371bd106SPravin B Shelar struct socket *sock;
83371bd106SPravin B Shelar struct rcu_head rcu;
84371bd106SPravin B Shelar int refcnt;
8566d47003SPravin B Shelar struct hlist_head vni_list[VNI_HASH_SIZE];
86371bd106SPravin B Shelar };
872d07dc79SJohn W. Linville
geneve_net_vni_hash(u8 vni[3])882d07dc79SJohn W. Linville static inline __u32 geneve_net_vni_hash(u8 vni[3])
892d07dc79SJohn W. Linville {
902d07dc79SJohn W. Linville __u32 vnid;
912d07dc79SJohn W. Linville
922d07dc79SJohn W. Linville vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
932d07dc79SJohn W. Linville return hash_32(vnid, VNI_HASH_BITS);
942d07dc79SJohn W. Linville }
952d07dc79SJohn W. Linville
vni_to_tunnel_id(const __u8 * vni)96e305ac6cSPravin B Shelar static __be64 vni_to_tunnel_id(const __u8 *vni)
97e305ac6cSPravin B Shelar {
98e305ac6cSPravin B Shelar #ifdef __BIG_ENDIAN
99e305ac6cSPravin B Shelar return (vni[0] << 16) | (vni[1] << 8) | vni[2];
100e305ac6cSPravin B Shelar #else
101e305ac6cSPravin B Shelar return (__force __be64)(((__force u64)vni[0] << 40) |
102e305ac6cSPravin B Shelar ((__force u64)vni[1] << 48) |
103e305ac6cSPravin B Shelar ((__force u64)vni[2] << 56));
104e305ac6cSPravin B Shelar #endif
105e305ac6cSPravin B Shelar }
106e305ac6cSPravin B Shelar
1079b4437a5Spravin shelar /* Convert 64 bit tunnel ID to 24 bit VNI. */
tunnel_id_to_vni(__be64 tun_id,__u8 * vni)1089b4437a5Spravin shelar static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
1099b4437a5Spravin shelar {
1109b4437a5Spravin shelar #ifdef __BIG_ENDIAN
1119b4437a5Spravin shelar vni[0] = (__force __u8)(tun_id >> 16);
1129b4437a5Spravin shelar vni[1] = (__force __u8)(tun_id >> 8);
1139b4437a5Spravin shelar vni[2] = (__force __u8)tun_id;
1149b4437a5Spravin shelar #else
1159b4437a5Spravin shelar vni[0] = (__force __u8)((__force u64)tun_id >> 40);
1169b4437a5Spravin shelar vni[1] = (__force __u8)((__force u64)tun_id >> 48);
1179b4437a5Spravin shelar vni[2] = (__force __u8)((__force u64)tun_id >> 56);
1189b4437a5Spravin shelar #endif
1199b4437a5Spravin shelar }
1209b4437a5Spravin shelar
eq_tun_id_and_vni(u8 * tun_id,u8 * vni)1212e0b26e1Spravin shelar static bool eq_tun_id_and_vni(u8 *tun_id, u8 *vni)
1222e0b26e1Spravin shelar {
1232e0b26e1Spravin shelar return !memcmp(vni, &tun_id[5], 3);
1242e0b26e1Spravin shelar }
1252e0b26e1Spravin shelar
geneve_get_sk_family(struct geneve_sock * gs)1261e9f12ecSJiri Benc static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
1271e9f12ecSJiri Benc {
1281e9f12ecSJiri Benc return gs->sock->sk->sk_family;
1291e9f12ecSJiri Benc }
1301e9f12ecSJiri Benc
geneve_lookup(struct geneve_sock * gs,__be32 addr,u8 vni[])13166d47003SPravin B Shelar static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
132371bd106SPravin B Shelar __be32 addr, u8 vni[])
1332d07dc79SJohn W. Linville {
1342d07dc79SJohn W. Linville struct hlist_head *vni_list_head;
1354b4c21faSJiri Benc struct geneve_dev_node *node;
1362d07dc79SJohn W. Linville __u32 hash;
1372d07dc79SJohn W. Linville
1382d07dc79SJohn W. Linville /* Find the device for this VNI */
139371bd106SPravin B Shelar hash = geneve_net_vni_hash(vni);
14066d47003SPravin B Shelar vni_list_head = &gs->vni_list[hash];
1414b4c21faSJiri Benc hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1429e06e859SSabrina Dubroca if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1439e06e859SSabrina Dubroca addr == node->geneve->cfg.info.key.u.ipv4.dst)
1444b4c21faSJiri Benc return node->geneve;
1452d07dc79SJohn W. Linville }
146e305ac6cSPravin B Shelar return NULL;
147e305ac6cSPravin B Shelar }
148e305ac6cSPravin B Shelar
1498ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve6_lookup(struct geneve_sock * gs,struct in6_addr addr6,u8 vni[])1508ed66f0eSJohn W. Linville static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
1518ed66f0eSJohn W. Linville struct in6_addr addr6, u8 vni[])
1528ed66f0eSJohn W. Linville {
1538ed66f0eSJohn W. Linville struct hlist_head *vni_list_head;
1544b4c21faSJiri Benc struct geneve_dev_node *node;
1558ed66f0eSJohn W. Linville __u32 hash;
1568ed66f0eSJohn W. Linville
1578ed66f0eSJohn W. Linville /* Find the device for this VNI */
1588ed66f0eSJohn W. Linville hash = geneve_net_vni_hash(vni);
1598ed66f0eSJohn W. Linville vni_list_head = &gs->vni_list[hash];
1604b4c21faSJiri Benc hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
1619e06e859SSabrina Dubroca if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
1629e06e859SSabrina Dubroca ipv6_addr_equal(&addr6, &node->geneve->cfg.info.key.u.ipv6.dst))
1634b4c21faSJiri Benc return node->geneve;
1648ed66f0eSJohn W. Linville }
1658ed66f0eSJohn W. Linville return NULL;
1668ed66f0eSJohn W. Linville }
1678ed66f0eSJohn W. Linville #endif
1688ed66f0eSJohn W. Linville
geneve_hdr(const struct sk_buff * skb)169371bd106SPravin B Shelar static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
170371bd106SPravin B Shelar {
171371bd106SPravin B Shelar return (struct genevehdr *)(udp_hdr(skb) + 1);
172371bd106SPravin B Shelar }
173371bd106SPravin B Shelar
geneve_lookup_skb(struct geneve_sock * gs,struct sk_buff * skb)1749fc47545SJiri Benc static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
1759fc47545SJiri Benc struct sk_buff *skb)
176e305ac6cSPravin B Shelar {
1778ed66f0eSJohn W. Linville static u8 zero_vni[3];
1789b4437a5Spravin shelar u8 *vni;
179e305ac6cSPravin B Shelar
1801e9f12ecSJiri Benc if (geneve_get_sk_family(gs) == AF_INET) {
1819fc47545SJiri Benc struct iphdr *iph;
1829b4437a5Spravin shelar __be32 addr;
1839fc47545SJiri Benc
18408399efcSJohn W. Linville iph = ip_hdr(skb); /* outer IP header... */
18508399efcSJohn W. Linville
186371bd106SPravin B Shelar if (gs->collect_md) {
187371bd106SPravin B Shelar vni = zero_vni;
188371bd106SPravin B Shelar addr = 0;
189371bd106SPravin B Shelar } else {
1909fc47545SJiri Benc vni = geneve_hdr(skb)->vni;
191371bd106SPravin B Shelar addr = iph->saddr;
192371bd106SPravin B Shelar }
193371bd106SPravin B Shelar
1949fc47545SJiri Benc return geneve_lookup(gs, addr, vni);
1958ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1961e9f12ecSJiri Benc } else if (geneve_get_sk_family(gs) == AF_INET6) {
1979b4437a5Spravin shelar static struct in6_addr zero_addr6;
1989fc47545SJiri Benc struct ipv6hdr *ip6h;
1999fc47545SJiri Benc struct in6_addr addr6;
2009fc47545SJiri Benc
2018ed66f0eSJohn W. Linville ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
2028ed66f0eSJohn W. Linville
2038ed66f0eSJohn W. Linville if (gs->collect_md) {
2048ed66f0eSJohn W. Linville vni = zero_vni;
2058ed66f0eSJohn W. Linville addr6 = zero_addr6;
2068ed66f0eSJohn W. Linville } else {
2079fc47545SJiri Benc vni = geneve_hdr(skb)->vni;
2088ed66f0eSJohn W. Linville addr6 = ip6h->saddr;
2098ed66f0eSJohn W. Linville }
2108ed66f0eSJohn W. Linville
2119fc47545SJiri Benc return geneve6_lookup(gs, addr6, vni);
2128ed66f0eSJohn W. Linville #endif
2138ed66f0eSJohn W. Linville }
2149fc47545SJiri Benc return NULL;
2159fc47545SJiri Benc }
2169fc47545SJiri Benc
2179fc47545SJiri Benc /* geneve receive/decap routine */
geneve_rx(struct geneve_dev * geneve,struct geneve_sock * gs,struct sk_buff * skb)2189fc47545SJiri Benc static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
2199fc47545SJiri Benc struct sk_buff *skb)
2209fc47545SJiri Benc {
2219fc47545SJiri Benc struct genevehdr *gnvh = geneve_hdr(skb);
2229fc47545SJiri Benc struct metadata_dst *tun_dst = NULL;
223fe741e23SGirish Moodalbail unsigned int len;
2240ece581dSEric Dumazet int nh, err = 0;
2259fc47545SJiri Benc void *oiph;
2262d07dc79SJohn W. Linville
227371bd106SPravin B Shelar if (ip_tunnel_collect_metadata() || gs->collect_md) {
228e305ac6cSPravin B Shelar __be16 flags;
229e305ac6cSPravin B Shelar
2309c2e14b4SYi-Hung Wei flags = TUNNEL_KEY | (gnvh->oam ? TUNNEL_OAM : 0) |
231e305ac6cSPravin B Shelar (gnvh->critical ? TUNNEL_CRIT_OPT : 0);
232e305ac6cSPravin B Shelar
2331e9f12ecSJiri Benc tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
234e305ac6cSPravin B Shelar vni_to_tunnel_id(gnvh->vni),
235e305ac6cSPravin B Shelar gnvh->opt_len * 4);
236fe741e23SGirish Moodalbail if (!tun_dst) {
237fe741e23SGirish Moodalbail geneve->dev->stats.rx_dropped++;
238e305ac6cSPravin B Shelar goto drop;
239fe741e23SGirish Moodalbail }
240e305ac6cSPravin B Shelar /* Update tunnel dst according to Geneve options. */
2414c222798SPravin B Shelar ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
242256c87c1SPieter Jansen van Vuuren gnvh->options, gnvh->opt_len * 4,
243256c87c1SPieter Jansen van Vuuren TUNNEL_GENEVE_OPT);
244e305ac6cSPravin B Shelar } else {
2452d07dc79SJohn W. Linville /* Drop packets w/ critical options,
2462d07dc79SJohn W. Linville * since we don't support any...
2472d07dc79SJohn W. Linville */
248fe741e23SGirish Moodalbail if (gnvh->critical) {
249fe741e23SGirish Moodalbail geneve->dev->stats.rx_frame_errors++;
250fe741e23SGirish Moodalbail geneve->dev->stats.rx_errors++;
2512d07dc79SJohn W. Linville goto drop;
252e305ac6cSPravin B Shelar }
253fe741e23SGirish Moodalbail }
2542d07dc79SJohn W. Linville
255435fe1c0SEyal Birger if (tun_dst)
256435fe1c0SEyal Birger skb_dst_set(skb, &tun_dst->dst);
257435fe1c0SEyal Birger
258435fe1c0SEyal Birger if (gnvh->proto_type == htons(ETH_P_TEB)) {
2592d07dc79SJohn W. Linville skb_reset_mac_header(skb);
2602d07dc79SJohn W. Linville skb->protocol = eth_type_trans(skb, geneve->dev);
2612d07dc79SJohn W. Linville skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
2622d07dc79SJohn W. Linville
2632d07dc79SJohn W. Linville /* Ignore packet loops (and multicast echo) */
264435fe1c0SEyal Birger if (ether_addr_equal(eth_hdr(skb)->h_source,
265435fe1c0SEyal Birger geneve->dev->dev_addr)) {
266c02bd115SJakub Kicinski geneve->dev->stats.rx_errors++;
267c02bd115SJakub Kicinski goto drop;
2684179b00cSEric Dumazet }
269435fe1c0SEyal Birger } else {
270435fe1c0SEyal Birger skb_reset_mac_header(skb);
271435fe1c0SEyal Birger skb->dev = geneve->dev;
272435fe1c0SEyal Birger skb->pkt_type = PACKET_HOST;
273435fe1c0SEyal Birger }
274c02bd115SJakub Kicinski
2750ece581dSEric Dumazet /* Save offset of outer header relative to skb->head,
2760ece581dSEric Dumazet * because we are going to reset the network header to the inner header
2770ece581dSEric Dumazet * and might change skb->head.
2780ece581dSEric Dumazet */
2790ece581dSEric Dumazet nh = skb_network_header(skb) - skb->head;
2800ece581dSEric Dumazet
2812d07dc79SJohn W. Linville skb_reset_network_header(skb);
2822d07dc79SJohn W. Linville
2830ece581dSEric Dumazet if (!pskb_inet_may_pull(skb)) {
2840ece581dSEric Dumazet DEV_STATS_INC(geneve->dev, rx_length_errors);
2850ece581dSEric Dumazet DEV_STATS_INC(geneve->dev, rx_errors);
2860ece581dSEric Dumazet goto drop;
2870ece581dSEric Dumazet }
2880ece581dSEric Dumazet
2890ece581dSEric Dumazet /* Get the outer header. */
2900ece581dSEric Dumazet oiph = skb->head + nh;
2910ece581dSEric Dumazet
2929fc47545SJiri Benc if (geneve_get_sk_family(gs) == AF_INET)
2939fc47545SJiri Benc err = IP_ECN_decapsulate(oiph, skb);
2948ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
2959fc47545SJiri Benc else
2969fc47545SJiri Benc err = IP6_ECN_decapsulate(oiph, skb);
2978ed66f0eSJohn W. Linville #endif
2982d07dc79SJohn W. Linville
2992d07dc79SJohn W. Linville if (unlikely(err)) {
3008ed66f0eSJohn W. Linville if (log_ecn_error) {
3019fc47545SJiri Benc if (geneve_get_sk_family(gs) == AF_INET)
3028ed66f0eSJohn W. Linville net_info_ratelimited("non-ECT from %pI4 "
3038ed66f0eSJohn W. Linville "with TOS=%#x\n",
3049fc47545SJiri Benc &((struct iphdr *)oiph)->saddr,
3059fc47545SJiri Benc ((struct iphdr *)oiph)->tos);
3068ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
3079fc47545SJiri Benc else
3088ed66f0eSJohn W. Linville net_info_ratelimited("non-ECT from %pI6\n",
3099fc47545SJiri Benc &((struct ipv6hdr *)oiph)->saddr);
3108ed66f0eSJohn W. Linville #endif
3118ed66f0eSJohn W. Linville }
3122d07dc79SJohn W. Linville if (err > 1) {
3132d07dc79SJohn W. Linville ++geneve->dev->stats.rx_frame_errors;
3142d07dc79SJohn W. Linville ++geneve->dev->stats.rx_errors;
3152d07dc79SJohn W. Linville goto drop;
3162d07dc79SJohn W. Linville }
3172d07dc79SJohn W. Linville }
3182d07dc79SJohn W. Linville
319fe741e23SGirish Moodalbail len = skb->len;
320fe741e23SGirish Moodalbail err = gro_cells_receive(&geneve->gro_cells, skb);
3211e84527bSFabian Frederick if (likely(err == NET_RX_SUCCESS))
3221e84527bSFabian Frederick dev_sw_netstats_rx_add(geneve->dev, len);
3231e84527bSFabian Frederick
3242d07dc79SJohn W. Linville return;
3252d07dc79SJohn W. Linville drop:
3262d07dc79SJohn W. Linville /* Consume bad packet */
3272d07dc79SJohn W. Linville kfree_skb(skb);
3282d07dc79SJohn W. Linville }
3292d07dc79SJohn W. Linville
3302d07dc79SJohn W. Linville /* Setup stats when device is created */
geneve_init(struct net_device * dev)3312d07dc79SJohn W. Linville static int geneve_init(struct net_device *dev)
3322d07dc79SJohn W. Linville {
3338e816df8SJesse Gross struct geneve_dev *geneve = netdev_priv(dev);
3348e816df8SJesse Gross int err;
3358e816df8SJesse Gross
3362d07dc79SJohn W. Linville dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
3372d07dc79SJohn W. Linville if (!dev->tstats)
3382d07dc79SJohn W. Linville return -ENOMEM;
3398e816df8SJesse Gross
3408e816df8SJesse Gross err = gro_cells_init(&geneve->gro_cells, dev);
3418e816df8SJesse Gross if (err) {
3428e816df8SJesse Gross free_percpu(dev->tstats);
3438e816df8SJesse Gross return err;
3448e816df8SJesse Gross }
3458e816df8SJesse Gross
3469e06e859SSabrina Dubroca err = dst_cache_init(&geneve->cfg.info.dst_cache, GFP_KERNEL);
347468dfffcSPaolo Abeni if (err) {
348468dfffcSPaolo Abeni free_percpu(dev->tstats);
349468dfffcSPaolo Abeni gro_cells_destroy(&geneve->gro_cells);
350468dfffcSPaolo Abeni return err;
351468dfffcSPaolo Abeni }
352a7b862abSEric Dumazet netdev_lockdep_set_classes(dev);
3532d07dc79SJohn W. Linville return 0;
3542d07dc79SJohn W. Linville }
3552d07dc79SJohn W. Linville
geneve_uninit(struct net_device * dev)3562d07dc79SJohn W. Linville static void geneve_uninit(struct net_device *dev)
3572d07dc79SJohn W. Linville {
3588e816df8SJesse Gross struct geneve_dev *geneve = netdev_priv(dev);
3598e816df8SJesse Gross
3609e06e859SSabrina Dubroca dst_cache_destroy(&geneve->cfg.info.dst_cache);
3618e816df8SJesse Gross gro_cells_destroy(&geneve->gro_cells);
3622d07dc79SJohn W. Linville free_percpu(dev->tstats);
3632d07dc79SJohn W. Linville }
3642d07dc79SJohn W. Linville
365371bd106SPravin B Shelar /* Callback from net/ipv4/udp.c to receive packets */
geneve_udp_encap_recv(struct sock * sk,struct sk_buff * skb)366371bd106SPravin B Shelar static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
367371bd106SPravin B Shelar {
368371bd106SPravin B Shelar struct genevehdr *geneveh;
3699fc47545SJiri Benc struct geneve_dev *geneve;
370371bd106SPravin B Shelar struct geneve_sock *gs;
371435fe1c0SEyal Birger __be16 inner_proto;
372371bd106SPravin B Shelar int opts_len;
373371bd106SPravin B Shelar
374fe741e23SGirish Moodalbail /* Need UDP and Geneve header to be present */
375371bd106SPravin B Shelar if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
376e5aed006SHannes Frederic Sowa goto drop;
377371bd106SPravin B Shelar
378371bd106SPravin B Shelar /* Return packets with reserved bits set */
379371bd106SPravin B Shelar geneveh = geneve_hdr(skb);
380371bd106SPravin B Shelar if (unlikely(geneveh->ver != GENEVE_VER))
381e5aed006SHannes Frederic Sowa goto drop;
382371bd106SPravin B Shelar
3839fc47545SJiri Benc gs = rcu_dereference_sk_user_data(sk);
3849fc47545SJiri Benc if (!gs)
3859fc47545SJiri Benc goto drop;
3869fc47545SJiri Benc
3879fc47545SJiri Benc geneve = geneve_lookup_skb(gs, skb);
3889fc47545SJiri Benc if (!geneve)
3899fc47545SJiri Benc goto drop;
3909fc47545SJiri Benc
391251d5a28SJosef Miegl inner_proto = geneveh->proto_type;
392251d5a28SJosef Miegl
393435fe1c0SEyal Birger if (unlikely((!geneve->cfg.inner_proto_inherit &&
394435fe1c0SEyal Birger inner_proto != htons(ETH_P_TEB)))) {
395435fe1c0SEyal Birger geneve->dev->stats.rx_dropped++;
396435fe1c0SEyal Birger goto drop;
397435fe1c0SEyal Birger }
398435fe1c0SEyal Birger
399371bd106SPravin B Shelar opts_len = geneveh->opt_len * 4;
400435fe1c0SEyal Birger if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
401fe741e23SGirish Moodalbail !net_eq(geneve->net, dev_net(geneve->dev)))) {
402fe741e23SGirish Moodalbail geneve->dev->stats.rx_dropped++;
403371bd106SPravin B Shelar goto drop;
404fe741e23SGirish Moodalbail }
405371bd106SPravin B Shelar
4069fc47545SJiri Benc geneve_rx(geneve, gs, skb);
407371bd106SPravin B Shelar return 0;
408371bd106SPravin B Shelar
409371bd106SPravin B Shelar drop:
410371bd106SPravin B Shelar /* Consume bad packet */
411371bd106SPravin B Shelar kfree_skb(skb);
412371bd106SPravin B Shelar return 0;
413371bd106SPravin B Shelar }
414371bd106SPravin B Shelar
415a0796644SStefano Brivio /* Callback from net/ipv{4,6}/udp.c to check that we have a tunnel for errors */
geneve_udp_encap_err_lookup(struct sock * sk,struct sk_buff * skb)416a0796644SStefano Brivio static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
417a0796644SStefano Brivio {
418a0796644SStefano Brivio struct genevehdr *geneveh;
419a0796644SStefano Brivio struct geneve_sock *gs;
420a0796644SStefano Brivio u8 zero_vni[3] = { 0 };
421a0796644SStefano Brivio u8 *vni = zero_vni;
422a0796644SStefano Brivio
423eccc73a6SStefano Brivio if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
424a0796644SStefano Brivio return -EINVAL;
425a0796644SStefano Brivio
426a0796644SStefano Brivio geneveh = geneve_hdr(skb);
427a0796644SStefano Brivio if (geneveh->ver != GENEVE_VER)
428a0796644SStefano Brivio return -EINVAL;
429a0796644SStefano Brivio
430a0796644SStefano Brivio if (geneveh->proto_type != htons(ETH_P_TEB))
431a0796644SStefano Brivio return -EINVAL;
432a0796644SStefano Brivio
433a0796644SStefano Brivio gs = rcu_dereference_sk_user_data(sk);
434a0796644SStefano Brivio if (!gs)
435a0796644SStefano Brivio return -ENOENT;
436a0796644SStefano Brivio
437a0796644SStefano Brivio if (geneve_get_sk_family(gs) == AF_INET) {
438a0796644SStefano Brivio struct iphdr *iph = ip_hdr(skb);
439a0796644SStefano Brivio __be32 addr4 = 0;
440a0796644SStefano Brivio
441a0796644SStefano Brivio if (!gs->collect_md) {
442a0796644SStefano Brivio vni = geneve_hdr(skb)->vni;
443a0796644SStefano Brivio addr4 = iph->daddr;
444a0796644SStefano Brivio }
445a0796644SStefano Brivio
446a0796644SStefano Brivio return geneve_lookup(gs, addr4, vni) ? 0 : -ENOENT;
447a0796644SStefano Brivio }
448a0796644SStefano Brivio
449a0796644SStefano Brivio #if IS_ENABLED(CONFIG_IPV6)
450a0796644SStefano Brivio if (geneve_get_sk_family(gs) == AF_INET6) {
451a0796644SStefano Brivio struct ipv6hdr *ip6h = ipv6_hdr(skb);
4528a962c4aSNathan Chancellor struct in6_addr addr6;
4538a962c4aSNathan Chancellor
4548a962c4aSNathan Chancellor memset(&addr6, 0, sizeof(struct in6_addr));
455a0796644SStefano Brivio
456a0796644SStefano Brivio if (!gs->collect_md) {
457a0796644SStefano Brivio vni = geneve_hdr(skb)->vni;
458a0796644SStefano Brivio addr6 = ip6h->daddr;
459a0796644SStefano Brivio }
460a0796644SStefano Brivio
461a0796644SStefano Brivio return geneve6_lookup(gs, addr6, vni) ? 0 : -ENOENT;
462a0796644SStefano Brivio }
463a0796644SStefano Brivio #endif
464a0796644SStefano Brivio
465a0796644SStefano Brivio return -EPFNOSUPPORT;
466a0796644SStefano Brivio }
467a0796644SStefano Brivio
geneve_create_sock(struct net * net,bool ipv6,__be16 port,bool ipv6_rx_csum)468371bd106SPravin B Shelar static struct socket *geneve_create_sock(struct net *net, bool ipv6,
4699b4437a5Spravin shelar __be16 port, bool ipv6_rx_csum)
470371bd106SPravin B Shelar {
471371bd106SPravin B Shelar struct socket *sock;
472371bd106SPravin B Shelar struct udp_port_cfg udp_conf;
473371bd106SPravin B Shelar int err;
474371bd106SPravin B Shelar
475371bd106SPravin B Shelar memset(&udp_conf, 0, sizeof(udp_conf));
476371bd106SPravin B Shelar
477371bd106SPravin B Shelar if (ipv6) {
478371bd106SPravin B Shelar udp_conf.family = AF_INET6;
4798ed66f0eSJohn W. Linville udp_conf.ipv6_v6only = 1;
4809b4437a5Spravin shelar udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
481371bd106SPravin B Shelar } else {
482371bd106SPravin B Shelar udp_conf.family = AF_INET;
483371bd106SPravin B Shelar udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
484371bd106SPravin B Shelar }
485371bd106SPravin B Shelar
486371bd106SPravin B Shelar udp_conf.local_udp_port = port;
487371bd106SPravin B Shelar
488371bd106SPravin B Shelar /* Open UDP socket */
489371bd106SPravin B Shelar err = udp_sock_create(net, &udp_conf, &sock);
490371bd106SPravin B Shelar if (err < 0)
491371bd106SPravin B Shelar return ERR_PTR(err);
492371bd106SPravin B Shelar
49361630c4fSPaolo Abeni udp_allow_gso(sock->sk);
494371bd106SPravin B Shelar return sock;
495371bd106SPravin B Shelar }
496371bd106SPravin B Shelar
geneve_hlen(struct genevehdr * gh)497371bd106SPravin B Shelar static int geneve_hlen(struct genevehdr *gh)
498371bd106SPravin B Shelar {
499371bd106SPravin B Shelar return sizeof(*gh) + gh->opt_len * 4;
500371bd106SPravin B Shelar }
501371bd106SPravin B Shelar
geneve_gro_receive(struct sock * sk,struct list_head * head,struct sk_buff * skb)502d4546c25SDavid Miller static struct sk_buff *geneve_gro_receive(struct sock *sk,
503d4546c25SDavid Miller struct list_head *head,
5044a0090a9STom Herbert struct sk_buff *skb)
505371bd106SPravin B Shelar {
506d4546c25SDavid Miller struct sk_buff *pp = NULL;
507d4546c25SDavid Miller struct sk_buff *p;
508371bd106SPravin B Shelar struct genevehdr *gh, *gh2;
509371bd106SPravin B Shelar unsigned int hlen, gh_len, off_gnv;
510371bd106SPravin B Shelar const struct packet_offload *ptype;
511371bd106SPravin B Shelar __be16 type;
512371bd106SPravin B Shelar int flush = 1;
513371bd106SPravin B Shelar
514371bd106SPravin B Shelar off_gnv = skb_gro_offset(skb);
515371bd106SPravin B Shelar hlen = off_gnv + sizeof(*gh);
51635ffb665SRichard Gobert gh = skb_gro_header(skb, hlen, off_gnv);
517371bd106SPravin B Shelar if (unlikely(!gh))
518371bd106SPravin B Shelar goto out;
519371bd106SPravin B Shelar
520371bd106SPravin B Shelar if (gh->ver != GENEVE_VER || gh->oam)
521371bd106SPravin B Shelar goto out;
522371bd106SPravin B Shelar gh_len = geneve_hlen(gh);
523371bd106SPravin B Shelar
524371bd106SPravin B Shelar hlen = off_gnv + gh_len;
525371bd106SPravin B Shelar if (skb_gro_header_hard(skb, hlen)) {
526371bd106SPravin B Shelar gh = skb_gro_header_slow(skb, hlen, off_gnv);
527371bd106SPravin B Shelar if (unlikely(!gh))
528371bd106SPravin B Shelar goto out;
529371bd106SPravin B Shelar }
530371bd106SPravin B Shelar
531d4546c25SDavid Miller list_for_each_entry(p, head, list) {
532371bd106SPravin B Shelar if (!NAPI_GRO_CB(p)->same_flow)
533371bd106SPravin B Shelar continue;
534371bd106SPravin B Shelar
535371bd106SPravin B Shelar gh2 = (struct genevehdr *)(p->data + off_gnv);
536371bd106SPravin B Shelar if (gh->opt_len != gh2->opt_len ||
537371bd106SPravin B Shelar memcmp(gh, gh2, gh_len)) {
538371bd106SPravin B Shelar NAPI_GRO_CB(p)->same_flow = 0;
539371bd106SPravin B Shelar continue;
540371bd106SPravin B Shelar }
541371bd106SPravin B Shelar }
542371bd106SPravin B Shelar
543f623f83aSPaolo Abeni skb_gro_pull(skb, gh_len);
544f623f83aSPaolo Abeni skb_gro_postpull_rcsum(skb, gh, gh_len);
545371bd106SPravin B Shelar type = gh->proto_type;
546f623f83aSPaolo Abeni if (likely(type == htons(ETH_P_TEB)))
547f623f83aSPaolo Abeni return call_gro_receive(eth_gro_receive, head, skb);
548371bd106SPravin B Shelar
549371bd106SPravin B Shelar ptype = gro_find_receive_by_type(type);
550c194cf93SAlexander Duyck if (!ptype)
551fc1ca334SEric Dumazet goto out;
552371bd106SPravin B Shelar
553fcd91dd4SSabrina Dubroca pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
554c194cf93SAlexander Duyck flush = 0;
555371bd106SPravin B Shelar
556371bd106SPravin B Shelar out:
557603d4cf8SSabrina Dubroca skb_gro_flush_final(skb, pp, flush);
558371bd106SPravin B Shelar
559371bd106SPravin B Shelar return pp;
560371bd106SPravin B Shelar }
561371bd106SPravin B Shelar
geneve_gro_complete(struct sock * sk,struct sk_buff * skb,int nhoff)5624a0090a9STom Herbert static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
5634a0090a9STom Herbert int nhoff)
564371bd106SPravin B Shelar {
565371bd106SPravin B Shelar struct genevehdr *gh;
566371bd106SPravin B Shelar struct packet_offload *ptype;
567371bd106SPravin B Shelar __be16 type;
568371bd106SPravin B Shelar int gh_len;
569371bd106SPravin B Shelar int err = -ENOSYS;
570371bd106SPravin B Shelar
571371bd106SPravin B Shelar gh = (struct genevehdr *)(skb->data + nhoff);
572371bd106SPravin B Shelar gh_len = geneve_hlen(gh);
573371bd106SPravin B Shelar type = gh->proto_type;
574371bd106SPravin B Shelar
575f623f83aSPaolo Abeni /* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */
576f623f83aSPaolo Abeni if (likely(type == htons(ETH_P_TEB)))
577f623f83aSPaolo Abeni return eth_gro_complete(skb, nhoff + gh_len);
578f623f83aSPaolo Abeni
579371bd106SPravin B Shelar ptype = gro_find_complete_by_type(type);
580371bd106SPravin B Shelar if (ptype)
581371bd106SPravin B Shelar err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
582371bd106SPravin B Shelar
583229740c6SJarno Rajahalme skb_set_inner_mac_header(skb, nhoff + gh_len);
584229740c6SJarno Rajahalme
585371bd106SPravin B Shelar return err;
586371bd106SPravin B Shelar }
587371bd106SPravin B Shelar
588371bd106SPravin B Shelar /* Create new listen socket if needed */
geneve_socket_create(struct net * net,__be16 port,bool ipv6,bool ipv6_rx_csum)589371bd106SPravin B Shelar static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
5909b4437a5Spravin shelar bool ipv6, bool ipv6_rx_csum)
591371bd106SPravin B Shelar {
592371bd106SPravin B Shelar struct geneve_net *gn = net_generic(net, geneve_net_id);
593371bd106SPravin B Shelar struct geneve_sock *gs;
594371bd106SPravin B Shelar struct socket *sock;
595371bd106SPravin B Shelar struct udp_tunnel_sock_cfg tunnel_cfg;
59666d47003SPravin B Shelar int h;
597371bd106SPravin B Shelar
598371bd106SPravin B Shelar gs = kzalloc(sizeof(*gs), GFP_KERNEL);
599371bd106SPravin B Shelar if (!gs)
600371bd106SPravin B Shelar return ERR_PTR(-ENOMEM);
601371bd106SPravin B Shelar
6029b4437a5Spravin shelar sock = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
603371bd106SPravin B Shelar if (IS_ERR(sock)) {
604371bd106SPravin B Shelar kfree(gs);
605371bd106SPravin B Shelar return ERR_CAST(sock);
606371bd106SPravin B Shelar }
607371bd106SPravin B Shelar
608371bd106SPravin B Shelar gs->sock = sock;
609371bd106SPravin B Shelar gs->refcnt = 1;
61066d47003SPravin B Shelar for (h = 0; h < VNI_HASH_SIZE; ++h)
61166d47003SPravin B Shelar INIT_HLIST_HEAD(&gs->vni_list[h]);
612371bd106SPravin B Shelar
613371bd106SPravin B Shelar /* Initialize the geneve udp offloads structure */
614e7b3db5eSAlexander Duyck udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
615371bd106SPravin B Shelar
616371bd106SPravin B Shelar /* Mark socket as an encapsulation socket */
6174a0090a9STom Herbert memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
618371bd106SPravin B Shelar tunnel_cfg.sk_user_data = gs;
619371bd106SPravin B Shelar tunnel_cfg.encap_type = 1;
6204a0090a9STom Herbert tunnel_cfg.gro_receive = geneve_gro_receive;
6214a0090a9STom Herbert tunnel_cfg.gro_complete = geneve_gro_complete;
622371bd106SPravin B Shelar tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
623a0796644SStefano Brivio tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup;
624371bd106SPravin B Shelar tunnel_cfg.encap_destroy = NULL;
625371bd106SPravin B Shelar setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
626371bd106SPravin B Shelar list_add(&gs->list, &gn->sock_list);
627371bd106SPravin B Shelar return gs;
628371bd106SPravin B Shelar }
629371bd106SPravin B Shelar
__geneve_sock_release(struct geneve_sock * gs)6308ed66f0eSJohn W. Linville static void __geneve_sock_release(struct geneve_sock *gs)
631371bd106SPravin B Shelar {
6328ed66f0eSJohn W. Linville if (!gs || --gs->refcnt)
633371bd106SPravin B Shelar return;
634371bd106SPravin B Shelar
635371bd106SPravin B Shelar list_del(&gs->list);
636e7b3db5eSAlexander Duyck udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
637371bd106SPravin B Shelar udp_tunnel_sock_release(gs->sock);
638371bd106SPravin B Shelar kfree_rcu(gs, rcu);
639371bd106SPravin B Shelar }
640371bd106SPravin B Shelar
geneve_sock_release(struct geneve_dev * geneve)6418ed66f0eSJohn W. Linville static void geneve_sock_release(struct geneve_dev *geneve)
6428ed66f0eSJohn W. Linville {
643fceb9c3eSpravin shelar struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
6448ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
645fceb9c3eSpravin shelar struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
646fceb9c3eSpravin shelar
647fceb9c3eSpravin shelar rcu_assign_pointer(geneve->sock6, NULL);
648fceb9c3eSpravin shelar #endif
649fceb9c3eSpravin shelar
650fceb9c3eSpravin shelar rcu_assign_pointer(geneve->sock4, NULL);
651fceb9c3eSpravin shelar synchronize_net();
652fceb9c3eSpravin shelar
653fceb9c3eSpravin shelar __geneve_sock_release(gs4);
654fceb9c3eSpravin shelar #if IS_ENABLED(CONFIG_IPV6)
655fceb9c3eSpravin shelar __geneve_sock_release(gs6);
6568ed66f0eSJohn W. Linville #endif
6578ed66f0eSJohn W. Linville }
6588ed66f0eSJohn W. Linville
geneve_find_sock(struct geneve_net * gn,sa_family_t family,__be16 dst_port)659371bd106SPravin B Shelar static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
6608ed66f0eSJohn W. Linville sa_family_t family,
661371bd106SPravin B Shelar __be16 dst_port)
662371bd106SPravin B Shelar {
663371bd106SPravin B Shelar struct geneve_sock *gs;
664371bd106SPravin B Shelar
665371bd106SPravin B Shelar list_for_each_entry(gs, &gn->sock_list, list) {
666371bd106SPravin B Shelar if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
6671e9f12ecSJiri Benc geneve_get_sk_family(gs) == family) {
668371bd106SPravin B Shelar return gs;
669371bd106SPravin B Shelar }
670371bd106SPravin B Shelar }
671371bd106SPravin B Shelar return NULL;
672371bd106SPravin B Shelar }
673371bd106SPravin B Shelar
geneve_sock_add(struct geneve_dev * geneve,bool ipv6)6748ed66f0eSJohn W. Linville static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
6752d07dc79SJohn W. Linville {
6762d07dc79SJohn W. Linville struct net *net = geneve->net;
677371bd106SPravin B Shelar struct geneve_net *gn = net_generic(net, geneve_net_id);
6784b4c21faSJiri Benc struct geneve_dev_node *node;
6792d07dc79SJohn W. Linville struct geneve_sock *gs;
6809b4437a5Spravin shelar __u8 vni[3];
68166d47003SPravin B Shelar __u32 hash;
6822d07dc79SJohn W. Linville
6839e06e859SSabrina Dubroca gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->cfg.info.key.tp_dst);
684371bd106SPravin B Shelar if (gs) {
685371bd106SPravin B Shelar gs->refcnt++;
686371bd106SPravin B Shelar goto out;
687371bd106SPravin B Shelar }
688371bd106SPravin B Shelar
6899e06e859SSabrina Dubroca gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6,
6909e06e859SSabrina Dubroca geneve->cfg.use_udp6_rx_checksums);
6912d07dc79SJohn W. Linville if (IS_ERR(gs))
6922d07dc79SJohn W. Linville return PTR_ERR(gs);
6932d07dc79SJohn W. Linville
694371bd106SPravin B Shelar out:
6959e06e859SSabrina Dubroca gs->collect_md = geneve->cfg.collect_md;
6968ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
6974b4c21faSJiri Benc if (ipv6) {
698fceb9c3eSpravin shelar rcu_assign_pointer(geneve->sock6, gs);
6994b4c21faSJiri Benc node = &geneve->hlist6;
7004b4c21faSJiri Benc } else
7018ed66f0eSJohn W. Linville #endif
7024b4c21faSJiri Benc {
703fceb9c3eSpravin shelar rcu_assign_pointer(geneve->sock4, gs);
7044b4c21faSJiri Benc node = &geneve->hlist4;
7054b4c21faSJiri Benc }
7064b4c21faSJiri Benc node->geneve = geneve;
70766d47003SPravin B Shelar
7089e06e859SSabrina Dubroca tunnel_id_to_vni(geneve->cfg.info.key.tun_id, vni);
7099b4437a5Spravin shelar hash = geneve_net_vni_hash(vni);
7104b4c21faSJiri Benc hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]);
7112d07dc79SJohn W. Linville return 0;
7122d07dc79SJohn W. Linville }
7132d07dc79SJohn W. Linville
geneve_open(struct net_device * dev)7148ed66f0eSJohn W. Linville static int geneve_open(struct net_device *dev)
7158ed66f0eSJohn W. Linville {
7168ed66f0eSJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
7179e06e859SSabrina Dubroca bool metadata = geneve->cfg.collect_md;
718cf1c9ccbSJiri Benc bool ipv4, ipv6;
7198ed66f0eSJohn W. Linville int ret = 0;
7208ed66f0eSJohn W. Linville
7219e06e859SSabrina Dubroca ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
722cf1c9ccbSJiri Benc ipv4 = !ipv6 || metadata;
7238ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
724cf1c9ccbSJiri Benc if (ipv6) {
7258ed66f0eSJohn W. Linville ret = geneve_sock_add(geneve, true);
726cf1c9ccbSJiri Benc if (ret < 0 && ret != -EAFNOSUPPORT)
727cf1c9ccbSJiri Benc ipv4 = false;
728cf1c9ccbSJiri Benc }
7298ed66f0eSJohn W. Linville #endif
730cf1c9ccbSJiri Benc if (ipv4)
7318ed66f0eSJohn W. Linville ret = geneve_sock_add(geneve, false);
7328ed66f0eSJohn W. Linville if (ret < 0)
7338ed66f0eSJohn W. Linville geneve_sock_release(geneve);
7348ed66f0eSJohn W. Linville
7358ed66f0eSJohn W. Linville return ret;
7368ed66f0eSJohn W. Linville }
7378ed66f0eSJohn W. Linville
geneve_stop(struct net_device * dev)7382d07dc79SJohn W. Linville static int geneve_stop(struct net_device *dev)
7392d07dc79SJohn W. Linville {
7402d07dc79SJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
7412d07dc79SJohn W. Linville
7424b4c21faSJiri Benc hlist_del_init_rcu(&geneve->hlist4.hlist);
7434b4c21faSJiri Benc #if IS_ENABLED(CONFIG_IPV6)
7444b4c21faSJiri Benc hlist_del_init_rcu(&geneve->hlist6.hlist);
7454b4c21faSJiri Benc #endif
7468ed66f0eSJohn W. Linville geneve_sock_release(geneve);
7472d07dc79SJohn W. Linville return 0;
7482d07dc79SJohn W. Linville }
7492d07dc79SJohn W. Linville
geneve_build_header(struct genevehdr * geneveh,const struct ip_tunnel_info * info,__be16 inner_proto)7508ed66f0eSJohn W. Linville static void geneve_build_header(struct genevehdr *geneveh,
751435fe1c0SEyal Birger const struct ip_tunnel_info *info,
752435fe1c0SEyal Birger __be16 inner_proto)
7538ed66f0eSJohn W. Linville {
7548ed66f0eSJohn W. Linville geneveh->ver = GENEVE_VER;
755c3ef5aa5Spravin shelar geneveh->opt_len = info->options_len / 4;
756c3ef5aa5Spravin shelar geneveh->oam = !!(info->key.tun_flags & TUNNEL_OAM);
757c3ef5aa5Spravin shelar geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT);
7588ed66f0eSJohn W. Linville geneveh->rsvd1 = 0;
759c3ef5aa5Spravin shelar tunnel_id_to_vni(info->key.tun_id, geneveh->vni);
760435fe1c0SEyal Birger geneveh->proto_type = inner_proto;
7618ed66f0eSJohn W. Linville geneveh->rsvd2 = 0;
7628ed66f0eSJohn W. Linville
763256c87c1SPieter Jansen van Vuuren if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
764c3ef5aa5Spravin shelar ip_tunnel_info_opts_get(geneveh->options, info);
7658ed66f0eSJohn W. Linville }
7668ed66f0eSJohn W. Linville
geneve_build_skb(struct dst_entry * dst,struct sk_buff * skb,const struct ip_tunnel_info * info,bool xnet,int ip_hdr_len,bool inner_proto_inherit)767c3ef5aa5Spravin shelar static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
768c3ef5aa5Spravin shelar const struct ip_tunnel_info *info,
769435fe1c0SEyal Birger bool xnet, int ip_hdr_len,
770435fe1c0SEyal Birger bool inner_proto_inherit)
771371bd106SPravin B Shelar {
772c3ef5aa5Spravin shelar bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
773371bd106SPravin B Shelar struct genevehdr *gnvh;
774435fe1c0SEyal Birger __be16 inner_proto;
775371bd106SPravin B Shelar int min_headroom;
776371bd106SPravin B Shelar int err;
777371bd106SPravin B Shelar
778c3ef5aa5Spravin shelar skb_reset_mac_header(skb);
7798ed66f0eSJohn W. Linville skb_scrub_packet(skb, xnet);
7808ed66f0eSJohn W. Linville
781c3ef5aa5Spravin shelar min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +
782c3ef5aa5Spravin shelar GENEVE_BASE_HLEN + info->options_len + ip_hdr_len;
7838ed66f0eSJohn W. Linville err = skb_cow_head(skb, min_headroom);
784aed069dfSAlexander Duyck if (unlikely(err))
7858ed66f0eSJohn W. Linville goto free_dst;
7868ed66f0eSJohn W. Linville
787aed069dfSAlexander Duyck err = udp_tunnel_handle_offloads(skb, udp_sum);
7881ba64facSDan Carpenter if (err)
7898ed66f0eSJohn W. Linville goto free_dst;
7908ed66f0eSJohn W. Linville
791d58ff351SJohannes Berg gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len);
792435fe1c0SEyal Birger inner_proto = inner_proto_inherit ? skb->protocol : htons(ETH_P_TEB);
793435fe1c0SEyal Birger geneve_build_header(gnvh, info, inner_proto);
794435fe1c0SEyal Birger skb_set_inner_protocol(skb, inner_proto);
7958ed66f0eSJohn W. Linville return 0;
7968ed66f0eSJohn W. Linville
7978ed66f0eSJohn W. Linville free_dst:
7988ed66f0eSJohn W. Linville dst_release(dst);
7998ed66f0eSJohn W. Linville return err;
8008ed66f0eSJohn W. Linville }
8018ed66f0eSJohn W. Linville
geneve_get_v4_rt(struct sk_buff * skb,struct net_device * dev,struct geneve_sock * gs4,struct flowi4 * fl4,const struct ip_tunnel_info * info,__be16 dport,__be16 sport,__u8 * full_tos)8028ed66f0eSJohn W. Linville static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
803e305ac6cSPravin B Shelar struct net_device *dev,
8045b861f6bSGirish Moodalbail struct geneve_sock *gs4,
805e305ac6cSPravin B Shelar struct flowi4 *fl4,
80634beb215SMark Gray const struct ip_tunnel_info *info,
807b4ab94d6SMatthias May __be16 dport, __be16 sport,
808b4ab94d6SMatthias May __u8 *full_tos)
809e305ac6cSPravin B Shelar {
810db3c6139SDaniel Borkmann bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
811e305ac6cSPravin B Shelar struct geneve_dev *geneve = netdev_priv(dev);
812468dfffcSPaolo Abeni struct dst_cache *dst_cache;
813e305ac6cSPravin B Shelar struct rtable *rt = NULL;
814e305ac6cSPravin B Shelar __u8 tos;
815e305ac6cSPravin B Shelar
8165b861f6bSGirish Moodalbail if (!gs4)
817fceb9c3eSpravin shelar return ERR_PTR(-EIO);
818fceb9c3eSpravin shelar
819e305ac6cSPravin B Shelar memset(fl4, 0, sizeof(*fl4));
820e305ac6cSPravin B Shelar fl4->flowi4_mark = skb->mark;
821e305ac6cSPravin B Shelar fl4->flowi4_proto = IPPROTO_UDP;
822e305ac6cSPravin B Shelar fl4->daddr = info->key.u.ipv4.dst;
823e305ac6cSPravin B Shelar fl4->saddr = info->key.u.ipv4.src;
82434beb215SMark Gray fl4->fl4_dport = dport;
82534beb215SMark Gray fl4->fl4_sport = sport;
826861396acSPaul Chaignon fl4->flowi4_flags = info->key.flow_flags;
827e305ac6cSPravin B Shelar
8289b4437a5Spravin shelar tos = info->key.tos;
8299e06e859SSabrina Dubroca if ((tos == 1) && !geneve->cfg.collect_md) {
8309b4437a5Spravin shelar tos = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
831468dfffcSPaolo Abeni use_cache = false;
832e305ac6cSPravin B Shelar }
833e305ac6cSPravin B Shelar fl4->flowi4_tos = RT_TOS(tos);
834b4ab94d6SMatthias May if (full_tos)
835b4ab94d6SMatthias May *full_tos = tos;
836468dfffcSPaolo Abeni
837c3ef5aa5Spravin shelar dst_cache = (struct dst_cache *)&info->dst_cache;
838468dfffcSPaolo Abeni if (use_cache) {
839468dfffcSPaolo Abeni rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
840468dfffcSPaolo Abeni if (rt)
841468dfffcSPaolo Abeni return rt;
842e305ac6cSPravin B Shelar }
843e305ac6cSPravin B Shelar rt = ip_route_output_key(geneve->net, fl4);
844e305ac6cSPravin B Shelar if (IS_ERR(rt)) {
845e305ac6cSPravin B Shelar netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr);
846fc4099f1SPravin B Shelar return ERR_PTR(-ENETUNREACH);
847e305ac6cSPravin B Shelar }
848e305ac6cSPravin B Shelar if (rt->dst.dev == dev) { /* is this necessary? */
849e305ac6cSPravin B Shelar netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
850e305ac6cSPravin B Shelar ip_rt_put(rt);
851fc4099f1SPravin B Shelar return ERR_PTR(-ELOOP);
852e305ac6cSPravin B Shelar }
853468dfffcSPaolo Abeni if (use_cache)
854468dfffcSPaolo Abeni dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
855e305ac6cSPravin B Shelar return rt;
856e305ac6cSPravin B Shelar }
857e305ac6cSPravin B Shelar
8588ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve_get_v6_dst(struct sk_buff * skb,struct net_device * dev,struct geneve_sock * gs6,struct flowi6 * fl6,const struct ip_tunnel_info * info,__be16 dport,__be16 sport)8598ed66f0eSJohn W. Linville static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
8608ed66f0eSJohn W. Linville struct net_device *dev,
8615b861f6bSGirish Moodalbail struct geneve_sock *gs6,
8628ed66f0eSJohn W. Linville struct flowi6 *fl6,
86334beb215SMark Gray const struct ip_tunnel_info *info,
86434beb215SMark Gray __be16 dport, __be16 sport)
8658ed66f0eSJohn W. Linville {
866db3c6139SDaniel Borkmann bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
8678ed66f0eSJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
8688ed66f0eSJohn W. Linville struct dst_entry *dst = NULL;
869468dfffcSPaolo Abeni struct dst_cache *dst_cache;
8703a56f86fSJohn W. Linville __u8 prio;
8718ed66f0eSJohn W. Linville
872fceb9c3eSpravin shelar if (!gs6)
873fceb9c3eSpravin shelar return ERR_PTR(-EIO);
874fceb9c3eSpravin shelar
8758ed66f0eSJohn W. Linville memset(fl6, 0, sizeof(*fl6));
8768ed66f0eSJohn W. Linville fl6->flowi6_mark = skb->mark;
8778ed66f0eSJohn W. Linville fl6->flowi6_proto = IPPROTO_UDP;
8788ed66f0eSJohn W. Linville fl6->daddr = info->key.u.ipv6.dst;
8798ed66f0eSJohn W. Linville fl6->saddr = info->key.u.ipv6.src;
88034beb215SMark Gray fl6->fl6_dport = dport;
88134beb215SMark Gray fl6->fl6_sport = sport;
88234beb215SMark Gray
8839b4437a5Spravin shelar prio = info->key.tos;
8849e06e859SSabrina Dubroca if ((prio == 1) && !geneve->cfg.collect_md) {
8859b4437a5Spravin shelar prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
886468dfffcSPaolo Abeni use_cache = false;
8873a56f86fSJohn W. Linville }
8883a56f86fSJohn W. Linville
889ca2bb695SMatthias May fl6->flowlabel = ip6_make_flowinfo(prio, info->key.label);
890c3ef5aa5Spravin shelar dst_cache = (struct dst_cache *)&info->dst_cache;
891468dfffcSPaolo Abeni if (use_cache) {
892468dfffcSPaolo Abeni dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
893468dfffcSPaolo Abeni if (dst)
894468dfffcSPaolo Abeni return dst;
8958ed66f0eSJohn W. Linville }
8966c8991f4SSabrina Dubroca dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
8976c8991f4SSabrina Dubroca NULL);
8986c8991f4SSabrina Dubroca if (IS_ERR(dst)) {
8998ed66f0eSJohn W. Linville netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr);
9008ed66f0eSJohn W. Linville return ERR_PTR(-ENETUNREACH);
9018ed66f0eSJohn W. Linville }
9028ed66f0eSJohn W. Linville if (dst->dev == dev) { /* is this necessary? */
9038ed66f0eSJohn W. Linville netdev_dbg(dev, "circular route to %pI6\n", &fl6->daddr);
9048ed66f0eSJohn W. Linville dst_release(dst);
9058ed66f0eSJohn W. Linville return ERR_PTR(-ELOOP);
9068ed66f0eSJohn W. Linville }
9078ed66f0eSJohn W. Linville
908468dfffcSPaolo Abeni if (use_cache)
909468dfffcSPaolo Abeni dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
9108ed66f0eSJohn W. Linville return dst;
9118ed66f0eSJohn W. Linville }
9128ed66f0eSJohn W. Linville #endif
9138ed66f0eSJohn W. Linville
geneve_xmit_skb(struct sk_buff * skb,struct net_device * dev,struct geneve_dev * geneve,const struct ip_tunnel_info * info)9149b4437a5Spravin shelar static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
915c3ef5aa5Spravin shelar struct geneve_dev *geneve,
916c3ef5aa5Spravin shelar const struct ip_tunnel_info *info)
917e305ac6cSPravin B Shelar {
918bb5c1b0fSGal Pressman bool inner_proto_inherit = geneve->cfg.inner_proto_inherit;
9199b4437a5Spravin shelar bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
9209b4437a5Spravin shelar struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
9219b4437a5Spravin shelar const struct ip_tunnel_key *key = &info->key;
9229b4437a5Spravin shelar struct rtable *rt;
9232d07dc79SJohn W. Linville struct flowi4 fl4;
924b4ab94d6SMatthias May __u8 full_tos;
9258760ce58SJohn W. Linville __u8 tos, ttl;
926a025fb5fSStefano Brivio __be16 df = 0;
927e305ac6cSPravin B Shelar __be16 sport;
928bcceeec3Spravin shelar int err;
9292d07dc79SJohn W. Linville
930bb5c1b0fSGal Pressman if (!skb_vlan_inet_prepare(skb, inner_proto_inherit))
9316628ddfeSPhillip Potter return -EINVAL;
9326628ddfeSPhillip Potter
93334beb215SMark Gray sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
93434beb215SMark Gray rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
935b4ab94d6SMatthias May geneve->cfg.info.key.tp_dst, sport, &full_tos);
9369b4437a5Spravin shelar if (IS_ERR(rt))
9379b4437a5Spravin shelar return PTR_ERR(rt);
938371bd106SPravin B Shelar
939c1a800e8SStefano Brivio err = skb_tunnel_check_pmtu(skb, &rt->dst,
940c1a800e8SStefano Brivio GENEVE_IPV4_HLEN + info->options_len,
941c1a800e8SStefano Brivio netif_is_any_bridge_port(dev));
942c1a800e8SStefano Brivio if (err < 0) {
943c1a800e8SStefano Brivio dst_release(&rt->dst);
944c1a800e8SStefano Brivio return err;
945c1a800e8SStefano Brivio } else if (err) {
946c1a800e8SStefano Brivio struct ip_tunnel_info *info;
947c1a800e8SStefano Brivio
948c1a800e8SStefano Brivio info = skb_tunnel_info(skb);
949c1a800e8SStefano Brivio if (info) {
95068c1a943SAntoine Tenart struct ip_tunnel_info *unclone;
95168c1a943SAntoine Tenart
95268c1a943SAntoine Tenart unclone = skb_tunnel_info_unclone(skb);
95368c1a943SAntoine Tenart if (unlikely(!unclone)) {
95468c1a943SAntoine Tenart dst_release(&rt->dst);
95568c1a943SAntoine Tenart return -ENOMEM;
95668c1a943SAntoine Tenart }
95768c1a943SAntoine Tenart
95868c1a943SAntoine Tenart unclone->key.u.ipv4.dst = fl4.saddr;
95968c1a943SAntoine Tenart unclone->key.u.ipv4.src = fl4.daddr;
960c1a800e8SStefano Brivio }
961c1a800e8SStefano Brivio
962c1a800e8SStefano Brivio if (!pskb_may_pull(skb, ETH_HLEN)) {
963c1a800e8SStefano Brivio dst_release(&rt->dst);
964c1a800e8SStefano Brivio return -EINVAL;
965c1a800e8SStefano Brivio }
966c1a800e8SStefano Brivio
967c1a800e8SStefano Brivio skb->protocol = eth_type_trans(skb, geneve->dev);
968baebdf48SSebastian Andrzej Siewior __netif_rx(skb);
969c1a800e8SStefano Brivio dst_release(&rt->dst);
970c1a800e8SStefano Brivio return -EMSGSIZE;
971c1a800e8SStefano Brivio }
97252a589d5SXin Long
9739e06e859SSabrina Dubroca if (geneve->cfg.collect_md) {
9749b4437a5Spravin shelar tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
9759b4437a5Spravin shelar ttl = key->ttl;
976a025fb5fSStefano Brivio
977a025fb5fSStefano Brivio df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
9789b4437a5Spravin shelar } else {
979b4ab94d6SMatthias May tos = ip_tunnel_ecn_encap(full_tos, ip_hdr(skb), skb);
9809e06e859SSabrina Dubroca if (geneve->cfg.ttl_inherit)
98152d0d404SHangbin Liu ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
98252d0d404SHangbin Liu else
98352d0d404SHangbin Liu ttl = key->ttl;
98452d0d404SHangbin Liu ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
985a025fb5fSStefano Brivio
9869e06e859SSabrina Dubroca if (geneve->cfg.df == GENEVE_DF_SET) {
987a025fb5fSStefano Brivio df = htons(IP_DF);
9889e06e859SSabrina Dubroca } else if (geneve->cfg.df == GENEVE_DF_INHERIT) {
98997ce3a4eSEric Dumazet struct ethhdr *eth = skb_eth_hdr(skb);
990a025fb5fSStefano Brivio
991a025fb5fSStefano Brivio if (ntohs(eth->h_proto) == ETH_P_IPV6) {
992a025fb5fSStefano Brivio df = htons(IP_DF);
993a025fb5fSStefano Brivio } else if (ntohs(eth->h_proto) == ETH_P_IP) {
994a025fb5fSStefano Brivio struct iphdr *iph = ip_hdr(skb);
995a025fb5fSStefano Brivio
996a025fb5fSStefano Brivio if (iph->frag_off & htons(IP_DF))
997a025fb5fSStefano Brivio df = htons(IP_DF);
9989b4437a5Spravin shelar }
999a025fb5fSStefano Brivio }
1000a025fb5fSStefano Brivio }
1001e305ac6cSPravin B Shelar
1002435fe1c0SEyal Birger err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr),
1003bb5c1b0fSGal Pressman inner_proto_inherit);
1004371bd106SPravin B Shelar if (unlikely(err))
10059b4437a5Spravin shelar return err;
1006371bd106SPravin B Shelar
1007039f5062SPravin B Shelar udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
10089e06e859SSabrina Dubroca tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
1009371bd106SPravin B Shelar !net_eq(geneve->net, dev_net(geneve->dev)),
10109b4437a5Spravin shelar !(info->key.tun_flags & TUNNEL_CSUM));
10119b4437a5Spravin shelar return 0;
10122d07dc79SJohn W. Linville }
10132d07dc79SJohn W. Linville
10148ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
geneve6_xmit_skb(struct sk_buff * skb,struct net_device * dev,struct geneve_dev * geneve,const struct ip_tunnel_info * info)10159b4437a5Spravin shelar static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
1016c3ef5aa5Spravin shelar struct geneve_dev *geneve,
1017c3ef5aa5Spravin shelar const struct ip_tunnel_info *info)
10188ed66f0eSJohn W. Linville {
1019bb5c1b0fSGal Pressman bool inner_proto_inherit = geneve->cfg.inner_proto_inherit;
10209b4437a5Spravin shelar bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
10219b4437a5Spravin shelar struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
10229b4437a5Spravin shelar const struct ip_tunnel_key *key = &info->key;
10238ed66f0eSJohn W. Linville struct dst_entry *dst = NULL;
10248ed66f0eSJohn W. Linville struct flowi6 fl6;
10253a56f86fSJohn W. Linville __u8 prio, ttl;
10268ed66f0eSJohn W. Linville __be16 sport;
1027bcceeec3Spravin shelar int err;
10289b4437a5Spravin shelar
1029bb5c1b0fSGal Pressman if (!skb_vlan_inet_prepare(skb, inner_proto_inherit))
10306628ddfeSPhillip Potter return -EINVAL;
10316628ddfeSPhillip Potter
103234beb215SMark Gray sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
103334beb215SMark Gray dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
103434beb215SMark Gray geneve->cfg.info.key.tp_dst, sport);
10359b4437a5Spravin shelar if (IS_ERR(dst))
10369b4437a5Spravin shelar return PTR_ERR(dst);
10379b4437a5Spravin shelar
1038c1a800e8SStefano Brivio err = skb_tunnel_check_pmtu(skb, dst,
1039c1a800e8SStefano Brivio GENEVE_IPV6_HLEN + info->options_len,
1040c1a800e8SStefano Brivio netif_is_any_bridge_port(dev));
1041c1a800e8SStefano Brivio if (err < 0) {
1042c1a800e8SStefano Brivio dst_release(dst);
1043c1a800e8SStefano Brivio return err;
1044c1a800e8SStefano Brivio } else if (err) {
1045c1a800e8SStefano Brivio struct ip_tunnel_info *info = skb_tunnel_info(skb);
1046c1a800e8SStefano Brivio
1047c1a800e8SStefano Brivio if (info) {
104868c1a943SAntoine Tenart struct ip_tunnel_info *unclone;
104968c1a943SAntoine Tenart
105068c1a943SAntoine Tenart unclone = skb_tunnel_info_unclone(skb);
105168c1a943SAntoine Tenart if (unlikely(!unclone)) {
105268c1a943SAntoine Tenart dst_release(dst);
105368c1a943SAntoine Tenart return -ENOMEM;
105468c1a943SAntoine Tenart }
105568c1a943SAntoine Tenart
105668c1a943SAntoine Tenart unclone->key.u.ipv6.dst = fl6.saddr;
105768c1a943SAntoine Tenart unclone->key.u.ipv6.src = fl6.daddr;
1058c1a800e8SStefano Brivio }
1059c1a800e8SStefano Brivio
1060c1a800e8SStefano Brivio if (!pskb_may_pull(skb, ETH_HLEN)) {
1061c1a800e8SStefano Brivio dst_release(dst);
1062c1a800e8SStefano Brivio return -EINVAL;
1063c1a800e8SStefano Brivio }
1064c1a800e8SStefano Brivio
1065c1a800e8SStefano Brivio skb->protocol = eth_type_trans(skb, geneve->dev);
1066baebdf48SSebastian Andrzej Siewior __netif_rx(skb);
1067c1a800e8SStefano Brivio dst_release(dst);
1068c1a800e8SStefano Brivio return -EMSGSIZE;
1069c1a800e8SStefano Brivio }
107052a589d5SXin Long
10719e06e859SSabrina Dubroca if (geneve->cfg.collect_md) {
10729b4437a5Spravin shelar prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
10739b4437a5Spravin shelar ttl = key->ttl;
10749b4437a5Spravin shelar } else {
10759b4437a5Spravin shelar prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
10769b4437a5Spravin shelar ip_hdr(skb), skb);
10779e06e859SSabrina Dubroca if (geneve->cfg.ttl_inherit)
107852d0d404SHangbin Liu ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
107952d0d404SHangbin Liu else
108052d0d404SHangbin Liu ttl = key->ttl;
108152d0d404SHangbin Liu ttl = ttl ? : ip6_dst_hoplimit(dst);
10829b4437a5Spravin shelar }
1083435fe1c0SEyal Birger err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr),
1084bb5c1b0fSGal Pressman inner_proto_inherit);
10858ed66f0eSJohn W. Linville if (unlikely(err))
10869b4437a5Spravin shelar return err;
10878eb3b995SDaniel Borkmann
1088039f5062SPravin B Shelar udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
10899b4437a5Spravin shelar &fl6.saddr, &fl6.daddr, prio, ttl,
10909e06e859SSabrina Dubroca info->key.label, sport, geneve->cfg.info.key.tp_dst,
10919b4437a5Spravin shelar !(info->key.tun_flags & TUNNEL_CSUM));
10929b4437a5Spravin shelar return 0;
10938ed66f0eSJohn W. Linville }
10948ed66f0eSJohn W. Linville #endif
10958ed66f0eSJohn W. Linville
geneve_xmit(struct sk_buff * skb,struct net_device * dev)10968ed66f0eSJohn W. Linville static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
10978ed66f0eSJohn W. Linville {
10988ed66f0eSJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
10998ed66f0eSJohn W. Linville struct ip_tunnel_info *info = NULL;
11009b4437a5Spravin shelar int err;
11018ed66f0eSJohn W. Linville
11029e06e859SSabrina Dubroca if (geneve->cfg.collect_md) {
11038ed66f0eSJohn W. Linville info = skb_tunnel_info(skb);
11049b4437a5Spravin shelar if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
11059b4437a5Spravin shelar netdev_dbg(dev, "no tunnel metadata\n");
11069d149045SJiri Benc dev_kfree_skb(skb);
11079d149045SJiri Benc dev->stats.tx_dropped++;
11089d149045SJiri Benc return NETDEV_TX_OK;
11099b4437a5Spravin shelar }
11109b4437a5Spravin shelar } else {
11119e06e859SSabrina Dubroca info = &geneve->cfg.info;
11129b4437a5Spravin shelar }
11138ed66f0eSJohn W. Linville
1114a717e3f7SJakub Kicinski rcu_read_lock();
11158ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
11169b4437a5Spravin shelar if (info->mode & IP_TUNNEL_INFO_IPV6)
11179b4437a5Spravin shelar err = geneve6_xmit_skb(skb, dev, geneve, info);
11189b4437a5Spravin shelar else
11198ed66f0eSJohn W. Linville #endif
11209b4437a5Spravin shelar err = geneve_xmit_skb(skb, dev, geneve, info);
1121a717e3f7SJakub Kicinski rcu_read_unlock();
11229b4437a5Spravin shelar
11239b4437a5Spravin shelar if (likely(!err))
11249b4437a5Spravin shelar return NETDEV_TX_OK;
11259d149045SJiri Benc
1126c1a800e8SStefano Brivio if (err != -EMSGSIZE)
11279b4437a5Spravin shelar dev_kfree_skb(skb);
11289b4437a5Spravin shelar
11299b4437a5Spravin shelar if (err == -ELOOP)
11309b4437a5Spravin shelar dev->stats.collisions++;
11319b4437a5Spravin shelar else if (err == -ENETUNREACH)
11329b4437a5Spravin shelar dev->stats.tx_carrier_errors++;
11339b4437a5Spravin shelar
11349b4437a5Spravin shelar dev->stats.tx_errors++;
11359b4437a5Spravin shelar return NETDEV_TX_OK;
11368ed66f0eSJohn W. Linville }
11378ed66f0eSJohn W. Linville
geneve_change_mtu(struct net_device * dev,int new_mtu)113891572088SJarod Wilson static int geneve_change_mtu(struct net_device *dev, int new_mtu)
113955e5bfb5SDavid Wragg {
114091572088SJarod Wilson if (new_mtu > dev->max_mtu)
114191572088SJarod Wilson new_mtu = dev->max_mtu;
1142321acc1cSAlexey Kodanev else if (new_mtu < dev->min_mtu)
1143321acc1cSAlexey Kodanev new_mtu = dev->min_mtu;
1144aeee0e66SDavid Wragg
114555e5bfb5SDavid Wragg dev->mtu = new_mtu;
114655e5bfb5SDavid Wragg return 0;
114755e5bfb5SDavid Wragg }
114855e5bfb5SDavid Wragg
geneve_fill_metadata_dst(struct net_device * dev,struct sk_buff * skb)1149fc4099f1SPravin B Shelar static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
1150fc4099f1SPravin B Shelar {
1151fc4099f1SPravin B Shelar struct ip_tunnel_info *info = skb_tunnel_info(skb);
1152fc4099f1SPravin B Shelar struct geneve_dev *geneve = netdev_priv(dev);
115334beb215SMark Gray __be16 sport;
1154fc4099f1SPravin B Shelar
1155b8812fa8SJohn W. Linville if (ip_tunnel_info_af(info) == AF_INET) {
11569b4437a5Spravin shelar struct rtable *rt;
11579b4437a5Spravin shelar struct flowi4 fl4;
11589b4437a5Spravin shelar
115934beb215SMark Gray struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
116034beb215SMark Gray sport = udp_flow_src_port(geneve->net, skb,
116134beb215SMark Gray 1, USHRT_MAX, true);
116234beb215SMark Gray
116334beb215SMark Gray rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
1164b4ab94d6SMatthias May geneve->cfg.info.key.tp_dst, sport, NULL);
1165fc4099f1SPravin B Shelar if (IS_ERR(rt))
1166fc4099f1SPravin B Shelar return PTR_ERR(rt);
1167fc4099f1SPravin B Shelar
1168fc4099f1SPravin B Shelar ip_rt_put(rt);
1169fc4099f1SPravin B Shelar info->key.u.ipv4.src = fl4.saddr;
1170b8812fa8SJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1171b8812fa8SJohn W. Linville } else if (ip_tunnel_info_af(info) == AF_INET6) {
11729b4437a5Spravin shelar struct dst_entry *dst;
11739b4437a5Spravin shelar struct flowi6 fl6;
11749b4437a5Spravin shelar
117534beb215SMark Gray struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
117634beb215SMark Gray sport = udp_flow_src_port(geneve->net, skb,
117734beb215SMark Gray 1, USHRT_MAX, true);
117834beb215SMark Gray
117934beb215SMark Gray dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
118034beb215SMark Gray geneve->cfg.info.key.tp_dst, sport);
1181b8812fa8SJohn W. Linville if (IS_ERR(dst))
1182b8812fa8SJohn W. Linville return PTR_ERR(dst);
1183b8812fa8SJohn W. Linville
1184b8812fa8SJohn W. Linville dst_release(dst);
1185b8812fa8SJohn W. Linville info->key.u.ipv6.src = fl6.saddr;
1186b8812fa8SJohn W. Linville #endif
1187b8812fa8SJohn W. Linville } else {
1188b8812fa8SJohn W. Linville return -EINVAL;
1189b8812fa8SJohn W. Linville }
1190b8812fa8SJohn W. Linville
119134beb215SMark Gray info->key.tp_src = sport;
11929e06e859SSabrina Dubroca info->key.tp_dst = geneve->cfg.info.key.tp_dst;
1193fc4099f1SPravin B Shelar return 0;
1194fc4099f1SPravin B Shelar }
1195fc4099f1SPravin B Shelar
11962d07dc79SJohn W. Linville static const struct net_device_ops geneve_netdev_ops = {
11972d07dc79SJohn W. Linville .ndo_init = geneve_init,
11982d07dc79SJohn W. Linville .ndo_uninit = geneve_uninit,
11992d07dc79SJohn W. Linville .ndo_open = geneve_open,
12002d07dc79SJohn W. Linville .ndo_stop = geneve_stop,
12012d07dc79SJohn W. Linville .ndo_start_xmit = geneve_xmit,
1202b220a4a7SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
120355e5bfb5SDavid Wragg .ndo_change_mtu = geneve_change_mtu,
12042d07dc79SJohn W. Linville .ndo_validate_addr = eth_validate_addr,
12052d07dc79SJohn W. Linville .ndo_set_mac_address = eth_mac_addr,
1206fc4099f1SPravin B Shelar .ndo_fill_metadata_dst = geneve_fill_metadata_dst,
12072d07dc79SJohn W. Linville };
12082d07dc79SJohn W. Linville
geneve_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * drvinfo)12092d07dc79SJohn W. Linville static void geneve_get_drvinfo(struct net_device *dev,
12102d07dc79SJohn W. Linville struct ethtool_drvinfo *drvinfo)
12112d07dc79SJohn W. Linville {
1212fb3ceec1SWolfram Sang strscpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
1213fb3ceec1SWolfram Sang strscpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
12142d07dc79SJohn W. Linville }
12152d07dc79SJohn W. Linville
12162d07dc79SJohn W. Linville static const struct ethtool_ops geneve_ethtool_ops = {
12172d07dc79SJohn W. Linville .get_drvinfo = geneve_get_drvinfo,
12182d07dc79SJohn W. Linville .get_link = ethtool_op_get_link,
12192d07dc79SJohn W. Linville };
12202d07dc79SJohn W. Linville
12212d07dc79SJohn W. Linville /* Info for udev, that this is a virtual tunnel endpoint */
12222d07dc79SJohn W. Linville static struct device_type geneve_type = {
12232d07dc79SJohn W. Linville .name = "geneve",
12242d07dc79SJohn W. Linville };
12252d07dc79SJohn W. Linville
1226e5de25dcSSabrina Dubroca /* Calls the ndo_udp_tunnel_add of the caller in order to
122705ca4029SSinghai, Anjali * supply the listening GENEVE udp ports. Callers are expected
1228e5de25dcSSabrina Dubroca * to implement the ndo_udp_tunnel_add.
122905ca4029SSinghai, Anjali */
geneve_offload_rx_ports(struct net_device * dev,bool push)12302d2b13fcSSabrina Dubroca static void geneve_offload_rx_ports(struct net_device *dev, bool push)
123105ca4029SSinghai, Anjali {
123205ca4029SSinghai, Anjali struct net *net = dev_net(dev);
123305ca4029SSinghai, Anjali struct geneve_net *gn = net_generic(net, geneve_net_id);
123405ca4029SSinghai, Anjali struct geneve_sock *gs;
1235681e683fSHannes Frederic Sowa
123605ca4029SSinghai, Anjali rcu_read_lock();
12372d2b13fcSSabrina Dubroca list_for_each_entry_rcu(gs, &gn->sock_list, list) {
12382d2b13fcSSabrina Dubroca if (push) {
1239e7b3db5eSAlexander Duyck udp_tunnel_push_rx_port(dev, gs->sock,
1240e7b3db5eSAlexander Duyck UDP_TUNNEL_TYPE_GENEVE);
12412d2b13fcSSabrina Dubroca } else {
12422d2b13fcSSabrina Dubroca udp_tunnel_drop_rx_port(dev, gs->sock,
12432d2b13fcSSabrina Dubroca UDP_TUNNEL_TYPE_GENEVE);
12442d2b13fcSSabrina Dubroca }
12452d2b13fcSSabrina Dubroca }
124605ca4029SSinghai, Anjali rcu_read_unlock();
124705ca4029SSinghai, Anjali }
124805ca4029SSinghai, Anjali
12492d07dc79SJohn W. Linville /* Initialize the device structure. */
geneve_setup(struct net_device * dev)12502d07dc79SJohn W. Linville static void geneve_setup(struct net_device *dev)
12512d07dc79SJohn W. Linville {
12522d07dc79SJohn W. Linville ether_setup(dev);
12532d07dc79SJohn W. Linville
12542d07dc79SJohn W. Linville dev->netdev_ops = &geneve_netdev_ops;
12552d07dc79SJohn W. Linville dev->ethtool_ops = &geneve_ethtool_ops;
1256cf124db5SDavid S. Miller dev->needs_free_netdev = true;
12572d07dc79SJohn W. Linville
12582d07dc79SJohn W. Linville SET_NETDEV_DEVTYPE(dev, &geneve_type);
12592d07dc79SJohn W. Linville
12602d07dc79SJohn W. Linville dev->features |= NETIF_F_LLTX;
126118423e1aSXin Long dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_FRAGLIST;
12622d07dc79SJohn W. Linville dev->features |= NETIF_F_RXCSUM;
12632d07dc79SJohn W. Linville dev->features |= NETIF_F_GSO_SOFTWARE;
12642d07dc79SJohn W. Linville
126518423e1aSXin Long dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_FRAGLIST;
126618423e1aSXin Long dev->hw_features |= NETIF_F_RXCSUM;
12672d07dc79SJohn W. Linville dev->hw_features |= NETIF_F_GSO_SOFTWARE;
12682d07dc79SJohn W. Linville
126991572088SJarod Wilson /* MTU range: 68 - (something less than 65535) */
127091572088SJarod Wilson dev->min_mtu = ETH_MIN_MTU;
127191572088SJarod Wilson /* The max_mtu calculation does not take account of GENEVE
127291572088SJarod Wilson * options, to avoid excluding potentially valid
127391572088SJarod Wilson * configurations. This will be further reduced by IPvX hdr size.
127491572088SJarod Wilson */
127591572088SJarod Wilson dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
127691572088SJarod Wilson
12772d07dc79SJohn W. Linville netif_keep_dst(dev);
1278fc41cdb3SJiri Benc dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1279ed961ac2SPhil Sutter dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
128087cd3dcaSPravin B Shelar eth_hw_addr_random(dev);
12812d07dc79SJohn W. Linville }
12822d07dc79SJohn W. Linville
12832d07dc79SJohn W. Linville static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
128436c2e31aSEyal Birger [IFLA_GENEVE_UNSPEC] = { .strict_start_type = IFLA_GENEVE_INNER_PROTO_INHERIT },
12852d07dc79SJohn W. Linville [IFLA_GENEVE_ID] = { .type = NLA_U32 },
1286c593642cSPankaj Bharadiya [IFLA_GENEVE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) },
12878ed66f0eSJohn W. Linville [IFLA_GENEVE_REMOTE6] = { .len = sizeof(struct in6_addr) },
12888760ce58SJohn W. Linville [IFLA_GENEVE_TTL] = { .type = NLA_U8 },
1289d8951125SJohn W. Linville [IFLA_GENEVE_TOS] = { .type = NLA_U8 },
12908eb3b995SDaniel Borkmann [IFLA_GENEVE_LABEL] = { .type = NLA_U32 },
1291cd7918b3SPravin B Shelar [IFLA_GENEVE_PORT] = { .type = NLA_U16 },
1292e305ac6cSPravin B Shelar [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG },
1293abe492b4STom Herbert [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 },
1294abe492b4STom Herbert [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
1295abe492b4STom Herbert [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
129652d0d404SHangbin Liu [IFLA_GENEVE_TTL_INHERIT] = { .type = NLA_U8 },
1297a025fb5fSStefano Brivio [IFLA_GENEVE_DF] = { .type = NLA_U8 },
129836c2e31aSEyal Birger [IFLA_GENEVE_INNER_PROTO_INHERIT] = { .type = NLA_FLAG },
12992d07dc79SJohn W. Linville };
13002d07dc79SJohn W. Linville
geneve_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1301a8b8a889SMatthias Schiffer static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
1302a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
13032d07dc79SJohn W. Linville {
13042d07dc79SJohn W. Linville if (tb[IFLA_ADDRESS]) {
1305c5ebc440SGirish Moodalbail if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
1306c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
1307c5ebc440SGirish Moodalbail "Provided link layer address is not Ethernet");
13082d07dc79SJohn W. Linville return -EINVAL;
13092d07dc79SJohn W. Linville }
13102d07dc79SJohn W. Linville
1311c5ebc440SGirish Moodalbail if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
1312c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
1313c5ebc440SGirish Moodalbail "Provided Ethernet address is not unicast");
1314c5ebc440SGirish Moodalbail return -EADDRNOTAVAIL;
1315c5ebc440SGirish Moodalbail }
1316c5ebc440SGirish Moodalbail }
1317c5ebc440SGirish Moodalbail
1318c5ebc440SGirish Moodalbail if (!data) {
1319c5ebc440SGirish Moodalbail NL_SET_ERR_MSG(extack,
1320c5ebc440SGirish Moodalbail "Not enough attributes provided to perform the operation");
13212d07dc79SJohn W. Linville return -EINVAL;
1322c5ebc440SGirish Moodalbail }
13232d07dc79SJohn W. Linville
13242d07dc79SJohn W. Linville if (data[IFLA_GENEVE_ID]) {
13252d07dc79SJohn W. Linville __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]);
13262d07dc79SJohn W. Linville
1327c5ebc440SGirish Moodalbail if (vni >= GENEVE_N_VID) {
1328c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID],
1329c5ebc440SGirish Moodalbail "Geneve ID must be lower than 16777216");
13302d07dc79SJohn W. Linville return -ERANGE;
13312d07dc79SJohn W. Linville }
1332c5ebc440SGirish Moodalbail }
13332d07dc79SJohn W. Linville
1334a025fb5fSStefano Brivio if (data[IFLA_GENEVE_DF]) {
1335a025fb5fSStefano Brivio enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
1336a025fb5fSStefano Brivio
1337a025fb5fSStefano Brivio if (df < 0 || df > GENEVE_DF_MAX) {
13389a7b5b50SSabrina Dubroca NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_DF],
1339a025fb5fSStefano Brivio "Invalid DF attribute");
1340a025fb5fSStefano Brivio return -EINVAL;
1341a025fb5fSStefano Brivio }
1342a025fb5fSStefano Brivio }
1343a025fb5fSStefano Brivio
13442d07dc79SJohn W. Linville return 0;
13452d07dc79SJohn W. Linville }
13462d07dc79SJohn W. Linville
geneve_find_dev(struct geneve_net * gn,const struct ip_tunnel_info * info,bool * tun_on_same_port,bool * tun_collect_md)1347371bd106SPravin B Shelar static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
13489b4437a5Spravin shelar const struct ip_tunnel_info *info,
1349371bd106SPravin B Shelar bool *tun_on_same_port,
1350371bd106SPravin B Shelar bool *tun_collect_md)
1351371bd106SPravin B Shelar {
13529b4437a5Spravin shelar struct geneve_dev *geneve, *t = NULL;
1353371bd106SPravin B Shelar
1354371bd106SPravin B Shelar *tun_on_same_port = false;
1355371bd106SPravin B Shelar *tun_collect_md = false;
1356371bd106SPravin B Shelar list_for_each_entry(geneve, &gn->geneve_list, next) {
13579e06e859SSabrina Dubroca if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) {
13589e06e859SSabrina Dubroca *tun_collect_md = geneve->cfg.collect_md;
1359371bd106SPravin B Shelar *tun_on_same_port = true;
1360371bd106SPravin B Shelar }
13619e06e859SSabrina Dubroca if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
13629e06e859SSabrina Dubroca info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
13639e06e859SSabrina Dubroca !memcmp(&info->key.u, &geneve->cfg.info.key.u, sizeof(info->key.u)))
1364371bd106SPravin B Shelar t = geneve;
1365371bd106SPravin B Shelar }
1366371bd106SPravin B Shelar return t;
1367371bd106SPravin B Shelar }
1368371bd106SPravin B Shelar
is_tnl_info_zero(const struct ip_tunnel_info * info)13699b4437a5Spravin shelar static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
13709b4437a5Spravin shelar {
13713fa5f11dSStefano Brivio return !(info->key.tun_id || info->key.tun_flags || info->key.tos ||
13729b4437a5Spravin shelar info->key.ttl || info->key.label || info->key.tp_src ||
13733fa5f11dSStefano Brivio memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
13749b4437a5Spravin shelar }
13759b4437a5Spravin shelar
geneve_dst_addr_equal(struct ip_tunnel_info * a,struct ip_tunnel_info * b)13765b861f6bSGirish Moodalbail static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
13775b861f6bSGirish Moodalbail struct ip_tunnel_info *b)
13785b861f6bSGirish Moodalbail {
13795b861f6bSGirish Moodalbail if (ip_tunnel_info_af(a) == AF_INET)
13805b861f6bSGirish Moodalbail return a->key.u.ipv4.dst == b->key.u.ipv4.dst;
13815b861f6bSGirish Moodalbail else
13825b861f6bSGirish Moodalbail return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst);
13835b861f6bSGirish Moodalbail }
13845b861f6bSGirish Moodalbail
geneve_configure(struct net * net,struct net_device * dev,struct netlink_ext_ack * extack,const struct geneve_config * cfg)1385e305ac6cSPravin B Shelar static int geneve_configure(struct net *net, struct net_device *dev,
1386c5ebc440SGirish Moodalbail struct netlink_ext_ack *extack,
13879e06e859SSabrina Dubroca const struct geneve_config *cfg)
13882d07dc79SJohn W. Linville {
13892d07dc79SJohn W. Linville struct geneve_net *gn = net_generic(net, geneve_net_id);
1390371bd106SPravin B Shelar struct geneve_dev *t, *geneve = netdev_priv(dev);
13919e06e859SSabrina Dubroca const struct ip_tunnel_info *info = &cfg->info;
1392371bd106SPravin B Shelar bool tun_collect_md, tun_on_same_port;
1393184fc8b5SPaolo Abeni int err, encap_len;
13942d07dc79SJohn W. Linville
13959e06e859SSabrina Dubroca if (cfg->collect_md && !is_tnl_info_zero(info)) {
1396c5ebc440SGirish Moodalbail NL_SET_ERR_MSG(extack,
1397c5ebc440SGirish Moodalbail "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified");
13988ed66f0eSJohn W. Linville return -EINVAL;
1399c5ebc440SGirish Moodalbail }
14002d07dc79SJohn W. Linville
14012d07dc79SJohn W. Linville geneve->net = net;
14022d07dc79SJohn W. Linville geneve->dev = dev;
14032d07dc79SJohn W. Linville
14049b4437a5Spravin shelar t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
1405371bd106SPravin B Shelar if (t)
1406371bd106SPravin B Shelar return -EBUSY;
1407371bd106SPravin B Shelar
1408184fc8b5SPaolo Abeni /* make enough headroom for basic scenario */
1409184fc8b5SPaolo Abeni encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
14109e06e859SSabrina Dubroca if (!cfg->collect_md && ip_tunnel_info_af(info) == AF_INET) {
1411184fc8b5SPaolo Abeni encap_len += sizeof(struct iphdr);
141291572088SJarod Wilson dev->max_mtu -= sizeof(struct iphdr);
141391572088SJarod Wilson } else {
1414184fc8b5SPaolo Abeni encap_len += sizeof(struct ipv6hdr);
141591572088SJarod Wilson dev->max_mtu -= sizeof(struct ipv6hdr);
141691572088SJarod Wilson }
1417184fc8b5SPaolo Abeni dev->needed_headroom = encap_len + ETH_HLEN;
1418184fc8b5SPaolo Abeni
14199e06e859SSabrina Dubroca if (cfg->collect_md) {
1420c5ebc440SGirish Moodalbail if (tun_on_same_port) {
1421c5ebc440SGirish Moodalbail NL_SET_ERR_MSG(extack,
1422c5ebc440SGirish Moodalbail "There can be only one externally controlled device on a destination port");
1423371bd106SPravin B Shelar return -EPERM;
1424c5ebc440SGirish Moodalbail }
1425371bd106SPravin B Shelar } else {
1426c5ebc440SGirish Moodalbail if (tun_collect_md) {
1427c5ebc440SGirish Moodalbail NL_SET_ERR_MSG(extack,
1428c5ebc440SGirish Moodalbail "There already exists an externally controlled device on this destination port");
1429371bd106SPravin B Shelar return -EPERM;
1430371bd106SPravin B Shelar }
1431c5ebc440SGirish Moodalbail }
1432371bd106SPravin B Shelar
14339e06e859SSabrina Dubroca dst_cache_reset(&geneve->cfg.info.dst_cache);
14349e06e859SSabrina Dubroca memcpy(&geneve->cfg, cfg, sizeof(*cfg));
1435468dfffcSPaolo Abeni
1436435fe1c0SEyal Birger if (geneve->cfg.inner_proto_inherit) {
1437435fe1c0SEyal Birger dev->header_ops = NULL;
1438435fe1c0SEyal Birger dev->type = ARPHRD_NONE;
1439435fe1c0SEyal Birger dev->hard_header_len = 0;
1440435fe1c0SEyal Birger dev->addr_len = 0;
144145ef71d1SJosef Miegl dev->flags = IFF_POINTOPOINT | IFF_NOARP;
1442435fe1c0SEyal Birger }
1443435fe1c0SEyal Birger
14442d07dc79SJohn W. Linville err = register_netdevice(dev);
14452d07dc79SJohn W. Linville if (err)
14462d07dc79SJohn W. Linville return err;
14472d07dc79SJohn W. Linville
14482d07dc79SJohn W. Linville list_add(&geneve->next, &gn->geneve_list);
14492d07dc79SJohn W. Linville return 0;
14502d07dc79SJohn W. Linville }
14512d07dc79SJohn W. Linville
init_tnl_info(struct ip_tunnel_info * info,__u16 dst_port)14529b4437a5Spravin shelar static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
14539b4437a5Spravin shelar {
14549b4437a5Spravin shelar memset(info, 0, sizeof(*info));
14559b4437a5Spravin shelar info->key.tp_dst = htons(dst_port);
14569b4437a5Spravin shelar }
14579b4437a5Spravin shelar
geneve_nl2info(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack,struct geneve_config * cfg,bool changelink)1458c5ebc440SGirish Moodalbail static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
1459c5ebc440SGirish Moodalbail struct netlink_ext_ack *extack,
14609e06e859SSabrina Dubroca struct geneve_config *cfg, bool changelink)
1461e305ac6cSPravin B Shelar {
14629e06e859SSabrina Dubroca struct ip_tunnel_info *info = &cfg->info;
1463c5ebc440SGirish Moodalbail int attrtype;
1464c5ebc440SGirish Moodalbail
1465c5ebc440SGirish Moodalbail if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
1466c5ebc440SGirish Moodalbail NL_SET_ERR_MSG(extack,
1467c5ebc440SGirish Moodalbail "Cannot specify both IPv4 and IPv6 Remote addresses");
14688ed66f0eSJohn W. Linville return -EINVAL;
1469c5ebc440SGirish Moodalbail }
14708ed66f0eSJohn W. Linville
14718ed66f0eSJohn W. Linville if (data[IFLA_GENEVE_REMOTE]) {
1472c5ebc440SGirish Moodalbail if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
1473c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_REMOTE;
1474c5ebc440SGirish Moodalbail goto change_notsup;
1475c5ebc440SGirish Moodalbail }
14765b861f6bSGirish Moodalbail
14775b861f6bSGirish Moodalbail info->key.u.ipv4.dst =
14788ed66f0eSJohn W. Linville nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
14798ed66f0eSJohn W. Linville
1480842841ecSDave Taht if (ipv4_is_multicast(info->key.u.ipv4.dst)) {
1481c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE],
1482c5ebc440SGirish Moodalbail "Remote IPv4 address cannot be Multicast");
14838ed66f0eSJohn W. Linville return -EINVAL;
14848ed66f0eSJohn W. Linville }
14858ed66f0eSJohn W. Linville }
14868ed66f0eSJohn W. Linville
14879b4437a5Spravin shelar if (data[IFLA_GENEVE_REMOTE6]) {
14889b4437a5Spravin shelar #if IS_ENABLED(CONFIG_IPV6)
1489c5ebc440SGirish Moodalbail if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
1490c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_REMOTE6;
1491c5ebc440SGirish Moodalbail goto change_notsup;
1492c5ebc440SGirish Moodalbail }
14935b861f6bSGirish Moodalbail
14945b861f6bSGirish Moodalbail info->mode = IP_TUNNEL_INFO_IPV6;
14955b861f6bSGirish Moodalbail info->key.u.ipv6.dst =
14969b4437a5Spravin shelar nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
1497e277de5fSJesse Gross
14985b861f6bSGirish Moodalbail if (ipv6_addr_type(&info->key.u.ipv6.dst) &
14999b4437a5Spravin shelar IPV6_ADDR_LINKLOCAL) {
1500c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1501c5ebc440SGirish Moodalbail "Remote IPv6 address cannot be link-local");
15029b4437a5Spravin shelar return -EINVAL;
15039b4437a5Spravin shelar }
15045b861f6bSGirish Moodalbail if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
1505c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1506c5ebc440SGirish Moodalbail "Remote IPv6 address cannot be Multicast");
15079b4437a5Spravin shelar return -EINVAL;
15089b4437a5Spravin shelar }
15095b861f6bSGirish Moodalbail info->key.tun_flags |= TUNNEL_CSUM;
15109e06e859SSabrina Dubroca cfg->use_udp6_rx_checksums = true;
15119b4437a5Spravin shelar #else
1512c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
1513c5ebc440SGirish Moodalbail "IPv6 support not enabled in the kernel");
15149b4437a5Spravin shelar return -EPFNOSUPPORT;
15159b4437a5Spravin shelar #endif
15169b4437a5Spravin shelar }
15179b4437a5Spravin shelar
15189b4437a5Spravin shelar if (data[IFLA_GENEVE_ID]) {
15199b4437a5Spravin shelar __u32 vni;
15209b4437a5Spravin shelar __u8 tvni[3];
15215b861f6bSGirish Moodalbail __be64 tunid;
15229b4437a5Spravin shelar
15239b4437a5Spravin shelar vni = nla_get_u32(data[IFLA_GENEVE_ID]);
15249b4437a5Spravin shelar tvni[0] = (vni & 0x00ff0000) >> 16;
15259b4437a5Spravin shelar tvni[1] = (vni & 0x0000ff00) >> 8;
15269b4437a5Spravin shelar tvni[2] = vni & 0x000000ff;
15279b4437a5Spravin shelar
15285b861f6bSGirish Moodalbail tunid = vni_to_tunnel_id(tvni);
1529c5ebc440SGirish Moodalbail if (changelink && (tunid != info->key.tun_id)) {
1530c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_ID;
1531c5ebc440SGirish Moodalbail goto change_notsup;
1532c5ebc440SGirish Moodalbail }
15335b861f6bSGirish Moodalbail info->key.tun_id = tunid;
15349b4437a5Spravin shelar }
15355b861f6bSGirish Moodalbail
1536a97d97baSHangbin Liu if (data[IFLA_GENEVE_TTL_INHERIT]) {
1537a97d97baSHangbin Liu if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT]))
15389e06e859SSabrina Dubroca cfg->ttl_inherit = true;
1539a97d97baSHangbin Liu else
15409e06e859SSabrina Dubroca cfg->ttl_inherit = false;
1541a97d97baSHangbin Liu } else if (data[IFLA_GENEVE_TTL]) {
1542a97d97baSHangbin Liu info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
15439e06e859SSabrina Dubroca cfg->ttl_inherit = false;
1544a97d97baSHangbin Liu }
154552d0d404SHangbin Liu
1546e305ac6cSPravin B Shelar if (data[IFLA_GENEVE_TOS])
15475b861f6bSGirish Moodalbail info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
1548e305ac6cSPravin B Shelar
1549a025fb5fSStefano Brivio if (data[IFLA_GENEVE_DF])
15509e06e859SSabrina Dubroca cfg->df = nla_get_u8(data[IFLA_GENEVE_DF]);
1551a025fb5fSStefano Brivio
15529b4437a5Spravin shelar if (data[IFLA_GENEVE_LABEL]) {
15535b861f6bSGirish Moodalbail info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
15548eb3b995SDaniel Borkmann IPV6_FLOWLABEL_MASK;
1555c5ebc440SGirish Moodalbail if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) {
1556c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL],
1557c5ebc440SGirish Moodalbail "Label attribute only applies for IPv6 Geneve devices");
15589b4437a5Spravin shelar return -EINVAL;
15599b4437a5Spravin shelar }
1560c5ebc440SGirish Moodalbail }
15618eb3b995SDaniel Borkmann
15625b861f6bSGirish Moodalbail if (data[IFLA_GENEVE_PORT]) {
1563c5ebc440SGirish Moodalbail if (changelink) {
1564c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_PORT;
1565c5ebc440SGirish Moodalbail goto change_notsup;
1566c5ebc440SGirish Moodalbail }
15675b861f6bSGirish Moodalbail info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]);
15685b861f6bSGirish Moodalbail }
1569e305ac6cSPravin B Shelar
15705b861f6bSGirish Moodalbail if (data[IFLA_GENEVE_COLLECT_METADATA]) {
1571c5ebc440SGirish Moodalbail if (changelink) {
1572c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_COLLECT_METADATA;
1573c5ebc440SGirish Moodalbail goto change_notsup;
1574c5ebc440SGirish Moodalbail }
15759e06e859SSabrina Dubroca cfg->collect_md = true;
15765b861f6bSGirish Moodalbail }
1577e305ac6cSPravin B Shelar
15785b861f6bSGirish Moodalbail if (data[IFLA_GENEVE_UDP_CSUM]) {
1579c5ebc440SGirish Moodalbail if (changelink) {
1580c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_UDP_CSUM;
1581c5ebc440SGirish Moodalbail goto change_notsup;
1582c5ebc440SGirish Moodalbail }
15835b861f6bSGirish Moodalbail if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
15845b861f6bSGirish Moodalbail info->key.tun_flags |= TUNNEL_CSUM;
15855b861f6bSGirish Moodalbail }
1586abe492b4STom Herbert
15875b861f6bSGirish Moodalbail if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
1588f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1589c5ebc440SGirish Moodalbail if (changelink) {
1590c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX;
1591c5ebc440SGirish Moodalbail goto change_notsup;
1592c5ebc440SGirish Moodalbail }
15935b861f6bSGirish Moodalbail if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
15945b861f6bSGirish Moodalbail info->key.tun_flags &= ~TUNNEL_CSUM;
1595f9094b76SHangbin Liu #else
1596f9094b76SHangbin Liu NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX],
1597f9094b76SHangbin Liu "IPv6 support not enabled in the kernel");
1598f9094b76SHangbin Liu return -EPFNOSUPPORT;
1599f9094b76SHangbin Liu #endif
16005b861f6bSGirish Moodalbail }
1601abe492b4STom Herbert
16025b861f6bSGirish Moodalbail if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
1603f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1604c5ebc440SGirish Moodalbail if (changelink) {
1605c5ebc440SGirish Moodalbail attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX;
1606c5ebc440SGirish Moodalbail goto change_notsup;
1607c5ebc440SGirish Moodalbail }
16085b861f6bSGirish Moodalbail if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
16099e06e859SSabrina Dubroca cfg->use_udp6_rx_checksums = false;
1610f9094b76SHangbin Liu #else
1611f9094b76SHangbin Liu NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX],
1612f9094b76SHangbin Liu "IPv6 support not enabled in the kernel");
1613f9094b76SHangbin Liu return -EPFNOSUPPORT;
1614f9094b76SHangbin Liu #endif
16155b861f6bSGirish Moodalbail }
16165b861f6bSGirish Moodalbail
1617435fe1c0SEyal Birger if (data[IFLA_GENEVE_INNER_PROTO_INHERIT]) {
1618435fe1c0SEyal Birger if (changelink) {
1619435fe1c0SEyal Birger attrtype = IFLA_GENEVE_INNER_PROTO_INHERIT;
1620435fe1c0SEyal Birger goto change_notsup;
1621435fe1c0SEyal Birger }
1622435fe1c0SEyal Birger cfg->inner_proto_inherit = true;
1623435fe1c0SEyal Birger }
1624435fe1c0SEyal Birger
16255b861f6bSGirish Moodalbail return 0;
1626c5ebc440SGirish Moodalbail change_notsup:
1627c5ebc440SGirish Moodalbail NL_SET_ERR_MSG_ATTR(extack, data[attrtype],
1628435fe1c0SEyal Birger "Changing VNI, Port, endpoint IP address family, external, inner_proto_inherit, and UDP checksum attributes are not supported");
1629c5ebc440SGirish Moodalbail return -EOPNOTSUPP;
16305b861f6bSGirish Moodalbail }
16315b861f6bSGirish Moodalbail
geneve_link_config(struct net_device * dev,struct ip_tunnel_info * info,struct nlattr * tb[])1632c40e89fdSAlexey Kodanev static void geneve_link_config(struct net_device *dev,
1633c40e89fdSAlexey Kodanev struct ip_tunnel_info *info, struct nlattr *tb[])
1634c40e89fdSAlexey Kodanev {
1635c40e89fdSAlexey Kodanev struct geneve_dev *geneve = netdev_priv(dev);
1636c40e89fdSAlexey Kodanev int ldev_mtu = 0;
1637c40e89fdSAlexey Kodanev
1638c40e89fdSAlexey Kodanev if (tb[IFLA_MTU]) {
1639c40e89fdSAlexey Kodanev geneve_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
1640c40e89fdSAlexey Kodanev return;
1641c40e89fdSAlexey Kodanev }
1642c40e89fdSAlexey Kodanev
1643c40e89fdSAlexey Kodanev switch (ip_tunnel_info_af(info)) {
1644c40e89fdSAlexey Kodanev case AF_INET: {
1645c40e89fdSAlexey Kodanev struct flowi4 fl4 = { .daddr = info->key.u.ipv4.dst };
1646c40e89fdSAlexey Kodanev struct rtable *rt = ip_route_output_key(geneve->net, &fl4);
1647c40e89fdSAlexey Kodanev
1648c40e89fdSAlexey Kodanev if (!IS_ERR(rt) && rt->dst.dev) {
1649c40e89fdSAlexey Kodanev ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV4_HLEN;
1650c40e89fdSAlexey Kodanev ip_rt_put(rt);
1651c40e89fdSAlexey Kodanev }
1652c40e89fdSAlexey Kodanev break;
1653c40e89fdSAlexey Kodanev }
1654c40e89fdSAlexey Kodanev #if IS_ENABLED(CONFIG_IPV6)
1655c40e89fdSAlexey Kodanev case AF_INET6: {
1656c0a47e44SHangbin Liu struct rt6_info *rt;
1657c0a47e44SHangbin Liu
1658c0a47e44SHangbin Liu if (!__in6_dev_get(dev))
1659c0a47e44SHangbin Liu break;
1660c0a47e44SHangbin Liu
1661c0a47e44SHangbin Liu rt = rt6_lookup(geneve->net, &info->key.u.ipv6.dst, NULL, 0,
1662c40e89fdSAlexey Kodanev NULL, 0);
1663c40e89fdSAlexey Kodanev
1664c40e89fdSAlexey Kodanev if (rt && rt->dst.dev)
1665c40e89fdSAlexey Kodanev ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV6_HLEN;
1666c40e89fdSAlexey Kodanev ip6_rt_put(rt);
1667c40e89fdSAlexey Kodanev break;
1668c40e89fdSAlexey Kodanev }
1669c40e89fdSAlexey Kodanev #endif
1670c40e89fdSAlexey Kodanev }
1671c40e89fdSAlexey Kodanev
1672c40e89fdSAlexey Kodanev if (ldev_mtu <= 0)
1673c40e89fdSAlexey Kodanev return;
1674c40e89fdSAlexey Kodanev
1675c40e89fdSAlexey Kodanev geneve_change_mtu(dev, ldev_mtu - info->options_len);
1676c40e89fdSAlexey Kodanev }
1677c40e89fdSAlexey Kodanev
geneve_newlink(struct net * net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)16785b861f6bSGirish Moodalbail static int geneve_newlink(struct net *net, struct net_device *dev,
16795b861f6bSGirish Moodalbail struct nlattr *tb[], struct nlattr *data[],
16805b861f6bSGirish Moodalbail struct netlink_ext_ack *extack)
16815b861f6bSGirish Moodalbail {
16829e06e859SSabrina Dubroca struct geneve_config cfg = {
16839e06e859SSabrina Dubroca .df = GENEVE_DF_UNSET,
16849e06e859SSabrina Dubroca .use_udp6_rx_checksums = false,
16859e06e859SSabrina Dubroca .ttl_inherit = false,
16869e06e859SSabrina Dubroca .collect_md = false,
16879e06e859SSabrina Dubroca };
16885b861f6bSGirish Moodalbail int err;
16895b861f6bSGirish Moodalbail
16909e06e859SSabrina Dubroca init_tnl_info(&cfg.info, GENEVE_UDP_PORT);
16919e06e859SSabrina Dubroca err = geneve_nl2info(tb, data, extack, &cfg, false);
16925b861f6bSGirish Moodalbail if (err)
16935b861f6bSGirish Moodalbail return err;
1694abe492b4STom Herbert
16959e06e859SSabrina Dubroca err = geneve_configure(net, dev, extack, &cfg);
1696c40e89fdSAlexey Kodanev if (err)
1697c40e89fdSAlexey Kodanev return err;
1698c40e89fdSAlexey Kodanev
16999e06e859SSabrina Dubroca geneve_link_config(dev, &cfg.info, tb);
1700c40e89fdSAlexey Kodanev
1701c40e89fdSAlexey Kodanev return 0;
1702e305ac6cSPravin B Shelar }
1703e305ac6cSPravin B Shelar
17045b861f6bSGirish Moodalbail /* Quiesces the geneve device data path for both TX and RX.
17055b861f6bSGirish Moodalbail *
17065b861f6bSGirish Moodalbail * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
17075b861f6bSGirish Moodalbail * So, if we set that socket to NULL under RCU and wait for synchronize_net()
17085b861f6bSGirish Moodalbail * to complete for the existing set of in-flight packets to be transmitted,
17095b861f6bSGirish Moodalbail * then we would have quiesced the transmit data path. All the future packets
17105b861f6bSGirish Moodalbail * will get dropped until we unquiesce the data path.
17115b861f6bSGirish Moodalbail *
17125b861f6bSGirish Moodalbail * On receive geneve dereference the geneve_sock stashed in the socket. So,
17135b861f6bSGirish Moodalbail * if we set that to NULL under RCU and wait for synchronize_net() to
17145b861f6bSGirish Moodalbail * complete, then we would have quiesced the receive data path.
17155b861f6bSGirish Moodalbail */
geneve_quiesce(struct geneve_dev * geneve,struct geneve_sock ** gs4,struct geneve_sock ** gs6)17165b861f6bSGirish Moodalbail static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
17175b861f6bSGirish Moodalbail struct geneve_sock **gs6)
17185b861f6bSGirish Moodalbail {
17195b861f6bSGirish Moodalbail *gs4 = rtnl_dereference(geneve->sock4);
17205b861f6bSGirish Moodalbail rcu_assign_pointer(geneve->sock4, NULL);
17215b861f6bSGirish Moodalbail if (*gs4)
17225b861f6bSGirish Moodalbail rcu_assign_sk_user_data((*gs4)->sock->sk, NULL);
17235b861f6bSGirish Moodalbail #if IS_ENABLED(CONFIG_IPV6)
17245b861f6bSGirish Moodalbail *gs6 = rtnl_dereference(geneve->sock6);
17255b861f6bSGirish Moodalbail rcu_assign_pointer(geneve->sock6, NULL);
17265b861f6bSGirish Moodalbail if (*gs6)
17275b861f6bSGirish Moodalbail rcu_assign_sk_user_data((*gs6)->sock->sk, NULL);
17285b861f6bSGirish Moodalbail #else
17295b861f6bSGirish Moodalbail *gs6 = NULL;
17305b861f6bSGirish Moodalbail #endif
17315b861f6bSGirish Moodalbail synchronize_net();
17325b861f6bSGirish Moodalbail }
17335b861f6bSGirish Moodalbail
17345b861f6bSGirish Moodalbail /* Resumes the geneve device data path for both TX and RX. */
geneve_unquiesce(struct geneve_dev * geneve,struct geneve_sock * gs4,struct geneve_sock __maybe_unused * gs6)17355b861f6bSGirish Moodalbail static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
17365b861f6bSGirish Moodalbail struct geneve_sock __maybe_unused *gs6)
17375b861f6bSGirish Moodalbail {
17385b861f6bSGirish Moodalbail rcu_assign_pointer(geneve->sock4, gs4);
17395b861f6bSGirish Moodalbail if (gs4)
17405b861f6bSGirish Moodalbail rcu_assign_sk_user_data(gs4->sock->sk, gs4);
17415b861f6bSGirish Moodalbail #if IS_ENABLED(CONFIG_IPV6)
17425b861f6bSGirish Moodalbail rcu_assign_pointer(geneve->sock6, gs6);
17435b861f6bSGirish Moodalbail if (gs6)
17445b861f6bSGirish Moodalbail rcu_assign_sk_user_data(gs6->sock->sk, gs6);
17455b861f6bSGirish Moodalbail #endif
17465b861f6bSGirish Moodalbail synchronize_net();
17475b861f6bSGirish Moodalbail }
17485b861f6bSGirish Moodalbail
geneve_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)17495b861f6bSGirish Moodalbail static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
17505b861f6bSGirish Moodalbail struct nlattr *data[],
17515b861f6bSGirish Moodalbail struct netlink_ext_ack *extack)
17525b861f6bSGirish Moodalbail {
17535b861f6bSGirish Moodalbail struct geneve_dev *geneve = netdev_priv(dev);
17545b861f6bSGirish Moodalbail struct geneve_sock *gs4, *gs6;
17559e06e859SSabrina Dubroca struct geneve_config cfg;
17565b861f6bSGirish Moodalbail int err;
17575b861f6bSGirish Moodalbail
17585b861f6bSGirish Moodalbail /* If the geneve device is configured for metadata (or externally
17595b861f6bSGirish Moodalbail * controlled, for example, OVS), then nothing can be changed.
17605b861f6bSGirish Moodalbail */
17619e06e859SSabrina Dubroca if (geneve->cfg.collect_md)
17625b861f6bSGirish Moodalbail return -EOPNOTSUPP;
17635b861f6bSGirish Moodalbail
17645b861f6bSGirish Moodalbail /* Start with the existing info. */
17659e06e859SSabrina Dubroca memcpy(&cfg, &geneve->cfg, sizeof(cfg));
17669e06e859SSabrina Dubroca err = geneve_nl2info(tb, data, extack, &cfg, true);
17675b861f6bSGirish Moodalbail if (err)
17685b861f6bSGirish Moodalbail return err;
17695b861f6bSGirish Moodalbail
17709e06e859SSabrina Dubroca if (!geneve_dst_addr_equal(&geneve->cfg.info, &cfg.info)) {
17719e06e859SSabrina Dubroca dst_cache_reset(&cfg.info.dst_cache);
17729e06e859SSabrina Dubroca geneve_link_config(dev, &cfg.info, tb);
1773c40e89fdSAlexey Kodanev }
17745b861f6bSGirish Moodalbail
17755b861f6bSGirish Moodalbail geneve_quiesce(geneve, &gs4, &gs6);
17769e06e859SSabrina Dubroca memcpy(&geneve->cfg, &cfg, sizeof(cfg));
17775b861f6bSGirish Moodalbail geneve_unquiesce(geneve, gs4, gs6);
17785b861f6bSGirish Moodalbail
17795b861f6bSGirish Moodalbail return 0;
17805b861f6bSGirish Moodalbail }
17815b861f6bSGirish Moodalbail
geneve_dellink(struct net_device * dev,struct list_head * head)17822d07dc79SJohn W. Linville static void geneve_dellink(struct net_device *dev, struct list_head *head)
17832d07dc79SJohn W. Linville {
17842d07dc79SJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
17852d07dc79SJohn W. Linville
17862d07dc79SJohn W. Linville list_del(&geneve->next);
17872d07dc79SJohn W. Linville unregister_netdevice_queue(dev, head);
17882d07dc79SJohn W. Linville }
17892d07dc79SJohn W. Linville
geneve_get_size(const struct net_device * dev)17902d07dc79SJohn W. Linville static size_t geneve_get_size(const struct net_device *dev)
17912d07dc79SJohn W. Linville {
17922d07dc79SJohn W. Linville return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */
17938ed66f0eSJohn W. Linville nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
17948760ce58SJohn W. Linville nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
1795d8951125SJohn W. Linville nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
1796a025fb5fSStefano Brivio nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_DF */
17978eb3b995SDaniel Borkmann nla_total_size(sizeof(__be32)) + /* IFLA_GENEVE_LABEL */
17987bbe33ffSJohn W. Linville nla_total_size(sizeof(__be16)) + /* IFLA_GENEVE_PORT */
1799e305ac6cSPravin B Shelar nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */
1800abe492b4STom Herbert nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
1801abe492b4STom Herbert nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
1802abe492b4STom Herbert nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
180352d0d404SHangbin Liu nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */
180436c2e31aSEyal Birger nla_total_size(0) + /* IFLA_GENEVE_INNER_PROTO_INHERIT */
18052d07dc79SJohn W. Linville 0;
18062d07dc79SJohn W. Linville }
18072d07dc79SJohn W. Linville
geneve_fill_info(struct sk_buff * skb,const struct net_device * dev)18082d07dc79SJohn W. Linville static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
18092d07dc79SJohn W. Linville {
18102d07dc79SJohn W. Linville struct geneve_dev *geneve = netdev_priv(dev);
18119e06e859SSabrina Dubroca struct ip_tunnel_info *info = &geneve->cfg.info;
18129e06e859SSabrina Dubroca bool ttl_inherit = geneve->cfg.ttl_inherit;
18139e06e859SSabrina Dubroca bool metadata = geneve->cfg.collect_md;
18149b4437a5Spravin shelar __u8 tmp_vni[3];
18152d07dc79SJohn W. Linville __u32 vni;
18162d07dc79SJohn W. Linville
18179b4437a5Spravin shelar tunnel_id_to_vni(info->key.tun_id, tmp_vni);
18189b4437a5Spravin shelar vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2];
18192d07dc79SJohn W. Linville if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
18202d07dc79SJohn W. Linville goto nla_put_failure;
18212d07dc79SJohn W. Linville
1822fd7eafd0SHangbin Liu if (!metadata && ip_tunnel_info_af(info) == AF_INET) {
18232d07dc79SJohn W. Linville if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
18249b4437a5Spravin shelar info->key.u.ipv4.dst))
18252d07dc79SJohn W. Linville goto nla_put_failure;
18269b4437a5Spravin shelar if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
18279b4437a5Spravin shelar !!(info->key.tun_flags & TUNNEL_CSUM)))
18289b4437a5Spravin shelar goto nla_put_failure;
18299b4437a5Spravin shelar
18308ed66f0eSJohn W. Linville #if IS_ENABLED(CONFIG_IPV6)
1831fd7eafd0SHangbin Liu } else if (!metadata) {
18328ed66f0eSJohn W. Linville if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
18339b4437a5Spravin shelar &info->key.u.ipv6.dst))
18349b4437a5Spravin shelar goto nla_put_failure;
18359b4437a5Spravin shelar if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
18369b4437a5Spravin shelar !(info->key.tun_flags & TUNNEL_CSUM)))
18379b4437a5Spravin shelar goto nla_put_failure;
183811387fe4SEric Garver #endif
1839fd7eafd0SHangbin Liu }
18402d07dc79SJohn W. Linville
18419b4437a5Spravin shelar if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
18429b4437a5Spravin shelar nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
18439b4437a5Spravin shelar nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
18448760ce58SJohn W. Linville goto nla_put_failure;
18458760ce58SJohn W. Linville
18469e06e859SSabrina Dubroca if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->cfg.df))
1847a025fb5fSStefano Brivio goto nla_put_failure;
1848a025fb5fSStefano Brivio
18499b4437a5Spravin shelar if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
1850cd7918b3SPravin B Shelar goto nla_put_failure;
1851cd7918b3SPravin B Shelar
1852fd7eafd0SHangbin Liu if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA))
1853e305ac6cSPravin B Shelar goto nla_put_failure;
1854fd7eafd0SHangbin Liu
1855f9094b76SHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
1856fd7eafd0SHangbin Liu if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
18579e06e859SSabrina Dubroca !geneve->cfg.use_udp6_rx_checksums))
1858fd7eafd0SHangbin Liu goto nla_put_failure;
1859f9094b76SHangbin Liu #endif
1860fd7eafd0SHangbin Liu
186152d0d404SHangbin Liu if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
186252d0d404SHangbin Liu goto nla_put_failure;
186352d0d404SHangbin Liu
1864435fe1c0SEyal Birger if (geneve->cfg.inner_proto_inherit &&
1865435fe1c0SEyal Birger nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT))
1866435fe1c0SEyal Birger goto nla_put_failure;
1867435fe1c0SEyal Birger
18682d07dc79SJohn W. Linville return 0;
18692d07dc79SJohn W. Linville
18702d07dc79SJohn W. Linville nla_put_failure:
18712d07dc79SJohn W. Linville return -EMSGSIZE;
18722d07dc79SJohn W. Linville }
18732d07dc79SJohn W. Linville
18742d07dc79SJohn W. Linville static struct rtnl_link_ops geneve_link_ops __read_mostly = {
18752d07dc79SJohn W. Linville .kind = "geneve",
18762d07dc79SJohn W. Linville .maxtype = IFLA_GENEVE_MAX,
18772d07dc79SJohn W. Linville .policy = geneve_policy,
18782d07dc79SJohn W. Linville .priv_size = sizeof(struct geneve_dev),
18792d07dc79SJohn W. Linville .setup = geneve_setup,
18802d07dc79SJohn W. Linville .validate = geneve_validate,
18812d07dc79SJohn W. Linville .newlink = geneve_newlink,
18825b861f6bSGirish Moodalbail .changelink = geneve_changelink,
18832d07dc79SJohn W. Linville .dellink = geneve_dellink,
18842d07dc79SJohn W. Linville .get_size = geneve_get_size,
18852d07dc79SJohn W. Linville .fill_info = geneve_fill_info,
18862d07dc79SJohn W. Linville };
18872d07dc79SJohn W. Linville
geneve_dev_create_fb(struct net * net,const char * name,u8 name_assign_type,u16 dst_port)1888e305ac6cSPravin B Shelar struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
1889e305ac6cSPravin B Shelar u8 name_assign_type, u16 dst_port)
1890e305ac6cSPravin B Shelar {
1891e305ac6cSPravin B Shelar struct nlattr *tb[IFLA_MAX + 1];
1892e305ac6cSPravin B Shelar struct net_device *dev;
1893106da663SNicolas Dichtel LIST_HEAD(list_kill);
1894e305ac6cSPravin B Shelar int err;
18959e06e859SSabrina Dubroca struct geneve_config cfg = {
18969e06e859SSabrina Dubroca .df = GENEVE_DF_UNSET,
18979e06e859SSabrina Dubroca .use_udp6_rx_checksums = true,
18989e06e859SSabrina Dubroca .ttl_inherit = false,
18999e06e859SSabrina Dubroca .collect_md = true,
19009e06e859SSabrina Dubroca };
1901e305ac6cSPravin B Shelar
1902e305ac6cSPravin B Shelar memset(tb, 0, sizeof(tb));
1903e305ac6cSPravin B Shelar dev = rtnl_create_link(net, name, name_assign_type,
1904d0522f1cSDavid Ahern &geneve_link_ops, tb, NULL);
1905e305ac6cSPravin B Shelar if (IS_ERR(dev))
1906e305ac6cSPravin B Shelar return dev;
1907e305ac6cSPravin B Shelar
19089e06e859SSabrina Dubroca init_tnl_info(&cfg.info, dst_port);
19099e06e859SSabrina Dubroca err = geneve_configure(net, dev, NULL, &cfg);
1910106da663SNicolas Dichtel if (err) {
1911106da663SNicolas Dichtel free_netdev(dev);
1912106da663SNicolas Dichtel return ERR_PTR(err);
1913106da663SNicolas Dichtel }
19147e059158SDavid Wragg
19157e059158SDavid Wragg /* openvswitch users expect packet sizes to be unrestricted,
19167e059158SDavid Wragg * so set the largest MTU we can.
19177e059158SDavid Wragg */
191891572088SJarod Wilson err = geneve_change_mtu(dev, IP_MAX_MTU);
19197e059158SDavid Wragg if (err)
19207e059158SDavid Wragg goto err;
19217e059158SDavid Wragg
19221d997f10SHangbin Liu err = rtnl_configure_link(dev, NULL, 0, NULL);
192341009481SNicolas Dichtel if (err < 0)
192441009481SNicolas Dichtel goto err;
192541009481SNicolas Dichtel
19267e059158SDavid Wragg return dev;
19277e059158SDavid Wragg err:
1928106da663SNicolas Dichtel geneve_dellink(dev, &list_kill);
1929106da663SNicolas Dichtel unregister_netdevice_many(&list_kill);
1930e305ac6cSPravin B Shelar return ERR_PTR(err);
1931e305ac6cSPravin B Shelar }
1932e305ac6cSPravin B Shelar EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
1933e305ac6cSPravin B Shelar
geneve_netdevice_event(struct notifier_block * unused,unsigned long event,void * ptr)1934681e683fSHannes Frederic Sowa static int geneve_netdevice_event(struct notifier_block *unused,
1935681e683fSHannes Frederic Sowa unsigned long event, void *ptr)
1936681e683fSHannes Frederic Sowa {
1937681e683fSHannes Frederic Sowa struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1938681e683fSHannes Frederic Sowa
1939dedc33e7SJakub Kicinski if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
194004584957SSabrina Dubroca geneve_offload_rx_ports(dev, true);
1941dedc33e7SJakub Kicinski else if (event == NETDEV_UDP_TUNNEL_DROP_INFO)
1942dedc33e7SJakub Kicinski geneve_offload_rx_ports(dev, false);
1943681e683fSHannes Frederic Sowa
1944681e683fSHannes Frederic Sowa return NOTIFY_DONE;
1945681e683fSHannes Frederic Sowa }
1946681e683fSHannes Frederic Sowa
1947681e683fSHannes Frederic Sowa static struct notifier_block geneve_notifier_block __read_mostly = {
1948681e683fSHannes Frederic Sowa .notifier_call = geneve_netdevice_event,
1949681e683fSHannes Frederic Sowa };
1950681e683fSHannes Frederic Sowa
geneve_init_net(struct net * net)19512d07dc79SJohn W. Linville static __net_init int geneve_init_net(struct net *net)
19522d07dc79SJohn W. Linville {
19532d07dc79SJohn W. Linville struct geneve_net *gn = net_generic(net, geneve_net_id);
19542d07dc79SJohn W. Linville
19552d07dc79SJohn W. Linville INIT_LIST_HEAD(&gn->geneve_list);
1956371bd106SPravin B Shelar INIT_LIST_HEAD(&gn->sock_list);
19572d07dc79SJohn W. Linville return 0;
19582d07dc79SJohn W. Linville }
19592d07dc79SJohn W. Linville
geneve_destroy_tunnels(struct net * net,struct list_head * head)19602843a253SHaishuang Yan static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
19612d07dc79SJohn W. Linville {
19622d07dc79SJohn W. Linville struct geneve_net *gn = net_generic(net, geneve_net_id);
19632d07dc79SJohn W. Linville struct geneve_dev *geneve, *next;
19642d07dc79SJohn W. Linville
1965*3ce92ca9SKuniyuki Iwashima list_for_each_entry_safe(geneve, next, &gn->geneve_list, next)
1966*3ce92ca9SKuniyuki Iwashima geneve_dellink(geneve->dev, head);
19672843a253SHaishuang Yan }
19682843a253SHaishuang Yan
geneve_exit_batch_net(struct list_head * net_list)19692843a253SHaishuang Yan static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
19702843a253SHaishuang Yan {
19712843a253SHaishuang Yan struct net *net;
19722843a253SHaishuang Yan LIST_HEAD(list);
19732843a253SHaishuang Yan
19742843a253SHaishuang Yan rtnl_lock();
19752843a253SHaishuang Yan list_for_each_entry(net, net_list, exit_list)
19762843a253SHaishuang Yan geneve_destroy_tunnels(net, &list);
19772843a253SHaishuang Yan
19782d07dc79SJohn W. Linville /* unregister the devices gathered above */
19792d07dc79SJohn W. Linville unregister_netdevice_many(&list);
19802d07dc79SJohn W. Linville rtnl_unlock();
19810fda7600SFlorian Westphal
19820fda7600SFlorian Westphal list_for_each_entry(net, net_list, exit_list) {
19830fda7600SFlorian Westphal const struct geneve_net *gn = net_generic(net, geneve_net_id);
19840fda7600SFlorian Westphal
19850fda7600SFlorian Westphal WARN_ON_ONCE(!list_empty(&gn->sock_list));
19860fda7600SFlorian Westphal }
19872d07dc79SJohn W. Linville }
19882d07dc79SJohn W. Linville
19892d07dc79SJohn W. Linville static struct pernet_operations geneve_net_ops = {
19902d07dc79SJohn W. Linville .init = geneve_init_net,
19912843a253SHaishuang Yan .exit_batch = geneve_exit_batch_net,
19922d07dc79SJohn W. Linville .id = &geneve_net_id,
19932d07dc79SJohn W. Linville .size = sizeof(struct geneve_net),
19942d07dc79SJohn W. Linville };
19952d07dc79SJohn W. Linville
geneve_init_module(void)19962d07dc79SJohn W. Linville static int __init geneve_init_module(void)
19972d07dc79SJohn W. Linville {
19982d07dc79SJohn W. Linville int rc;
19992d07dc79SJohn W. Linville
20002d07dc79SJohn W. Linville rc = register_pernet_subsys(&geneve_net_ops);
20012d07dc79SJohn W. Linville if (rc)
20022d07dc79SJohn W. Linville goto out1;
20032d07dc79SJohn W. Linville
2004681e683fSHannes Frederic Sowa rc = register_netdevice_notifier(&geneve_notifier_block);
20052d07dc79SJohn W. Linville if (rc)
20062d07dc79SJohn W. Linville goto out2;
20072d07dc79SJohn W. Linville
2008681e683fSHannes Frederic Sowa rc = rtnl_link_register(&geneve_link_ops);
2009681e683fSHannes Frederic Sowa if (rc)
2010681e683fSHannes Frederic Sowa goto out3;
2011681e683fSHannes Frederic Sowa
20122d07dc79SJohn W. Linville return 0;
2013681e683fSHannes Frederic Sowa out3:
2014681e683fSHannes Frederic Sowa unregister_netdevice_notifier(&geneve_notifier_block);
20152d07dc79SJohn W. Linville out2:
20162d07dc79SJohn W. Linville unregister_pernet_subsys(&geneve_net_ops);
20172d07dc79SJohn W. Linville out1:
20182d07dc79SJohn W. Linville return rc;
20192d07dc79SJohn W. Linville }
20202d07dc79SJohn W. Linville late_initcall(geneve_init_module);
20212d07dc79SJohn W. Linville
geneve_cleanup_module(void)20222d07dc79SJohn W. Linville static void __exit geneve_cleanup_module(void)
20232d07dc79SJohn W. Linville {
20242d07dc79SJohn W. Linville rtnl_link_unregister(&geneve_link_ops);
2025681e683fSHannes Frederic Sowa unregister_netdevice_notifier(&geneve_notifier_block);
20262d07dc79SJohn W. Linville unregister_pernet_subsys(&geneve_net_ops);
20272d07dc79SJohn W. Linville }
20282d07dc79SJohn W. Linville module_exit(geneve_cleanup_module);
20292d07dc79SJohn W. Linville
20302d07dc79SJohn W. Linville MODULE_LICENSE("GPL");
20312d07dc79SJohn W. Linville MODULE_VERSION(GENEVE_NETDEV_VER);
20322d07dc79SJohn W. Linville MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
20332d07dc79SJohn W. Linville MODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic");
20342d07dc79SJohn W. Linville MODULE_ALIAS_RTNL_LINK("geneve");
2035