18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GENEVE: Generic Network Virtualization Encapsulation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Red Hat, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/hash.h> 148c2ecf20Sopenharmony_ci#include <net/ipv6_stubs.h> 158c2ecf20Sopenharmony_ci#include <net/dst_metadata.h> 168c2ecf20Sopenharmony_ci#include <net/gro_cells.h> 178c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 188c2ecf20Sopenharmony_ci#include <net/geneve.h> 198c2ecf20Sopenharmony_ci#include <net/protocol.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define GENEVE_NETDEV_VER "0.6" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define GENEVE_N_VID (1u << 24) 248c2ecf20Sopenharmony_ci#define GENEVE_VID_MASK (GENEVE_N_VID - 1) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define VNI_HASH_BITS 10 278c2ecf20Sopenharmony_ci#define VNI_HASH_SIZE (1<<VNI_HASH_BITS) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic bool log_ecn_error = true; 308c2ecf20Sopenharmony_cimodule_param(log_ecn_error, bool, 0644); 318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define GENEVE_VER 0 348c2ecf20Sopenharmony_ci#define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr)) 358c2ecf20Sopenharmony_ci#define GENEVE_IPV4_HLEN (ETH_HLEN + sizeof(struct iphdr) + GENEVE_BASE_HLEN) 368c2ecf20Sopenharmony_ci#define GENEVE_IPV6_HLEN (ETH_HLEN + sizeof(struct ipv6hdr) + GENEVE_BASE_HLEN) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* per-network namespace private data for this module */ 398c2ecf20Sopenharmony_cistruct geneve_net { 408c2ecf20Sopenharmony_ci struct list_head geneve_list; 418c2ecf20Sopenharmony_ci struct list_head sock_list; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic unsigned int geneve_net_id; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct geneve_dev_node { 478c2ecf20Sopenharmony_ci struct hlist_node hlist; 488c2ecf20Sopenharmony_ci struct geneve_dev *geneve; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct geneve_config { 528c2ecf20Sopenharmony_ci struct ip_tunnel_info info; 538c2ecf20Sopenharmony_ci bool collect_md; 548c2ecf20Sopenharmony_ci bool use_udp6_rx_checksums; 558c2ecf20Sopenharmony_ci bool ttl_inherit; 568c2ecf20Sopenharmony_ci enum ifla_geneve_df df; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Pseudo network device */ 608c2ecf20Sopenharmony_cistruct geneve_dev { 618c2ecf20Sopenharmony_ci struct geneve_dev_node hlist4; /* vni hash table for IPv4 socket */ 628c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 638c2ecf20Sopenharmony_ci struct geneve_dev_node hlist6; /* vni hash table for IPv6 socket */ 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci struct net *net; /* netns for packet i/o */ 668c2ecf20Sopenharmony_ci struct net_device *dev; /* netdev for geneve tunnel */ 678c2ecf20Sopenharmony_ci struct geneve_sock __rcu *sock4; /* IPv4 socket used for geneve tunnel */ 688c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 698c2ecf20Sopenharmony_ci struct geneve_sock __rcu *sock6; /* IPv6 socket used for geneve tunnel */ 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci struct list_head next; /* geneve's per namespace list */ 728c2ecf20Sopenharmony_ci struct gro_cells gro_cells; 738c2ecf20Sopenharmony_ci struct geneve_config cfg; 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistruct geneve_sock { 778c2ecf20Sopenharmony_ci bool collect_md; 788c2ecf20Sopenharmony_ci struct list_head list; 798c2ecf20Sopenharmony_ci struct socket *sock; 808c2ecf20Sopenharmony_ci struct rcu_head rcu; 818c2ecf20Sopenharmony_ci int refcnt; 828c2ecf20Sopenharmony_ci struct hlist_head vni_list[VNI_HASH_SIZE]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline __u32 geneve_net_vni_hash(u8 vni[3]) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci __u32 vnid; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2]; 908c2ecf20Sopenharmony_ci return hash_32(vnid, VNI_HASH_BITS); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic __be64 vni_to_tunnel_id(const __u8 *vni) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 968c2ecf20Sopenharmony_ci return (vni[0] << 16) | (vni[1] << 8) | vni[2]; 978c2ecf20Sopenharmony_ci#else 988c2ecf20Sopenharmony_ci return (__force __be64)(((__force u64)vni[0] << 40) | 998c2ecf20Sopenharmony_ci ((__force u64)vni[1] << 48) | 1008c2ecf20Sopenharmony_ci ((__force u64)vni[2] << 56)); 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Convert 64 bit tunnel ID to 24 bit VNI. */ 1058c2ecf20Sopenharmony_cistatic void tunnel_id_to_vni(__be64 tun_id, __u8 *vni) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 1088c2ecf20Sopenharmony_ci vni[0] = (__force __u8)(tun_id >> 16); 1098c2ecf20Sopenharmony_ci vni[1] = (__force __u8)(tun_id >> 8); 1108c2ecf20Sopenharmony_ci vni[2] = (__force __u8)tun_id; 1118c2ecf20Sopenharmony_ci#else 1128c2ecf20Sopenharmony_ci vni[0] = (__force __u8)((__force u64)tun_id >> 40); 1138c2ecf20Sopenharmony_ci vni[1] = (__force __u8)((__force u64)tun_id >> 48); 1148c2ecf20Sopenharmony_ci vni[2] = (__force __u8)((__force u64)tun_id >> 56); 1158c2ecf20Sopenharmony_ci#endif 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic bool eq_tun_id_and_vni(u8 *tun_id, u8 *vni) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return !memcmp(vni, &tun_id[5], 3); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic sa_family_t geneve_get_sk_family(struct geneve_sock *gs) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return gs->sock->sk->sk_family; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_lookup(struct geneve_sock *gs, 1298c2ecf20Sopenharmony_ci __be32 addr, u8 vni[]) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct hlist_head *vni_list_head; 1328c2ecf20Sopenharmony_ci struct geneve_dev_node *node; 1338c2ecf20Sopenharmony_ci __u32 hash; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Find the device for this VNI */ 1368c2ecf20Sopenharmony_ci hash = geneve_net_vni_hash(vni); 1378c2ecf20Sopenharmony_ci vni_list_head = &gs->vni_list[hash]; 1388c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(node, vni_list_head, hlist) { 1398c2ecf20Sopenharmony_ci if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) && 1408c2ecf20Sopenharmony_ci addr == node->geneve->cfg.info.key.u.ipv4.dst) 1418c2ecf20Sopenharmony_ci return node->geneve; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1478c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve6_lookup(struct geneve_sock *gs, 1488c2ecf20Sopenharmony_ci struct in6_addr addr6, u8 vni[]) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct hlist_head *vni_list_head; 1518c2ecf20Sopenharmony_ci struct geneve_dev_node *node; 1528c2ecf20Sopenharmony_ci __u32 hash; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Find the device for this VNI */ 1558c2ecf20Sopenharmony_ci hash = geneve_net_vni_hash(vni); 1568c2ecf20Sopenharmony_ci vni_list_head = &gs->vni_list[hash]; 1578c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(node, vni_list_head, hlist) { 1588c2ecf20Sopenharmony_ci if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) && 1598c2ecf20Sopenharmony_ci ipv6_addr_equal(&addr6, &node->geneve->cfg.info.key.u.ipv6.dst)) 1608c2ecf20Sopenharmony_ci return node->geneve; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return NULL; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return (struct genevehdr *)(udp_hdr(skb) + 1); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs, 1728c2ecf20Sopenharmony_ci struct sk_buff *skb) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci static u8 zero_vni[3]; 1758c2ecf20Sopenharmony_ci u8 *vni; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (geneve_get_sk_family(gs) == AF_INET) { 1788c2ecf20Sopenharmony_ci struct iphdr *iph; 1798c2ecf20Sopenharmony_ci __be32 addr; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci iph = ip_hdr(skb); /* outer IP header... */ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (gs->collect_md) { 1848c2ecf20Sopenharmony_ci vni = zero_vni; 1858c2ecf20Sopenharmony_ci addr = 0; 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci vni = geneve_hdr(skb)->vni; 1888c2ecf20Sopenharmony_ci addr = iph->saddr; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return geneve_lookup(gs, addr, vni); 1928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1938c2ecf20Sopenharmony_ci } else if (geneve_get_sk_family(gs) == AF_INET6) { 1948c2ecf20Sopenharmony_ci static struct in6_addr zero_addr6; 1958c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h; 1968c2ecf20Sopenharmony_ci struct in6_addr addr6; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ip6h = ipv6_hdr(skb); /* outer IPv6 header... */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (gs->collect_md) { 2018c2ecf20Sopenharmony_ci vni = zero_vni; 2028c2ecf20Sopenharmony_ci addr6 = zero_addr6; 2038c2ecf20Sopenharmony_ci } else { 2048c2ecf20Sopenharmony_ci vni = geneve_hdr(skb)->vni; 2058c2ecf20Sopenharmony_ci addr6 = ip6h->saddr; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return geneve6_lookup(gs, addr6, vni); 2098c2ecf20Sopenharmony_ci#endif 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci return NULL; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* geneve receive/decap routine */ 2158c2ecf20Sopenharmony_cistatic void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, 2168c2ecf20Sopenharmony_ci struct sk_buff *skb) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct genevehdr *gnvh = geneve_hdr(skb); 2198c2ecf20Sopenharmony_ci struct metadata_dst *tun_dst = NULL; 2208c2ecf20Sopenharmony_ci unsigned int len; 2218c2ecf20Sopenharmony_ci int err = 0; 2228c2ecf20Sopenharmony_ci void *oiph; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (ip_tunnel_collect_metadata() || gs->collect_md) { 2258c2ecf20Sopenharmony_ci __be16 flags; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci flags = TUNNEL_KEY | (gnvh->oam ? TUNNEL_OAM : 0) | 2288c2ecf20Sopenharmony_ci (gnvh->critical ? TUNNEL_CRIT_OPT : 0); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags, 2318c2ecf20Sopenharmony_ci vni_to_tunnel_id(gnvh->vni), 2328c2ecf20Sopenharmony_ci gnvh->opt_len * 4); 2338c2ecf20Sopenharmony_ci if (!tun_dst) { 2348c2ecf20Sopenharmony_ci geneve->dev->stats.rx_dropped++; 2358c2ecf20Sopenharmony_ci goto drop; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci /* Update tunnel dst according to Geneve options. */ 2388c2ecf20Sopenharmony_ci ip_tunnel_info_opts_set(&tun_dst->u.tun_info, 2398c2ecf20Sopenharmony_ci gnvh->options, gnvh->opt_len * 4, 2408c2ecf20Sopenharmony_ci TUNNEL_GENEVE_OPT); 2418c2ecf20Sopenharmony_ci } else { 2428c2ecf20Sopenharmony_ci /* Drop packets w/ critical options, 2438c2ecf20Sopenharmony_ci * since we don't support any... 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (gnvh->critical) { 2468c2ecf20Sopenharmony_ci geneve->dev->stats.rx_frame_errors++; 2478c2ecf20Sopenharmony_ci geneve->dev->stats.rx_errors++; 2488c2ecf20Sopenharmony_ci goto drop; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 2538c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, geneve->dev); 2548c2ecf20Sopenharmony_ci skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (tun_dst) 2578c2ecf20Sopenharmony_ci skb_dst_set(skb, &tun_dst->dst); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Ignore packet loops (and multicast echo) */ 2608c2ecf20Sopenharmony_ci if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) { 2618c2ecf20Sopenharmony_ci geneve->dev->stats.rx_errors++; 2628c2ecf20Sopenharmony_ci goto drop; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci oiph = skb_network_header(skb); 2668c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (geneve_get_sk_family(gs) == AF_INET) 2698c2ecf20Sopenharmony_ci err = IP_ECN_decapsulate(oiph, skb); 2708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci err = IP6_ECN_decapsulate(oiph, skb); 2738c2ecf20Sopenharmony_ci#endif 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (unlikely(err)) { 2768c2ecf20Sopenharmony_ci if (log_ecn_error) { 2778c2ecf20Sopenharmony_ci if (geneve_get_sk_family(gs) == AF_INET) 2788c2ecf20Sopenharmony_ci net_info_ratelimited("non-ECT from %pI4 " 2798c2ecf20Sopenharmony_ci "with TOS=%#x\n", 2808c2ecf20Sopenharmony_ci &((struct iphdr *)oiph)->saddr, 2818c2ecf20Sopenharmony_ci ((struct iphdr *)oiph)->tos); 2828c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2838c2ecf20Sopenharmony_ci else 2848c2ecf20Sopenharmony_ci net_info_ratelimited("non-ECT from %pI6\n", 2858c2ecf20Sopenharmony_ci &((struct ipv6hdr *)oiph)->saddr); 2868c2ecf20Sopenharmony_ci#endif 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci if (err > 1) { 2898c2ecf20Sopenharmony_ci ++geneve->dev->stats.rx_frame_errors; 2908c2ecf20Sopenharmony_ci ++geneve->dev->stats.rx_errors; 2918c2ecf20Sopenharmony_ci goto drop; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci len = skb->len; 2968c2ecf20Sopenharmony_ci err = gro_cells_receive(&geneve->gro_cells, skb); 2978c2ecf20Sopenharmony_ci if (likely(err == NET_RX_SUCCESS)) 2988c2ecf20Sopenharmony_ci dev_sw_netstats_rx_add(geneve->dev, len); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_cidrop: 3028c2ecf20Sopenharmony_ci /* Consume bad packet */ 3038c2ecf20Sopenharmony_ci kfree_skb(skb); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* Setup stats when device is created */ 3078c2ecf20Sopenharmony_cistatic int geneve_init(struct net_device *dev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 3108c2ecf20Sopenharmony_ci int err; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 3138c2ecf20Sopenharmony_ci if (!dev->tstats) 3148c2ecf20Sopenharmony_ci return -ENOMEM; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci err = gro_cells_init(&geneve->gro_cells, dev); 3178c2ecf20Sopenharmony_ci if (err) { 3188c2ecf20Sopenharmony_ci free_percpu(dev->tstats); 3198c2ecf20Sopenharmony_ci return err; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci err = dst_cache_init(&geneve->cfg.info.dst_cache, GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (err) { 3248c2ecf20Sopenharmony_ci free_percpu(dev->tstats); 3258c2ecf20Sopenharmony_ci gro_cells_destroy(&geneve->gro_cells); 3268c2ecf20Sopenharmony_ci return err; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void geneve_uninit(struct net_device *dev) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci dst_cache_destroy(&geneve->cfg.info.dst_cache); 3368c2ecf20Sopenharmony_ci gro_cells_destroy(&geneve->gro_cells); 3378c2ecf20Sopenharmony_ci free_percpu(dev->tstats); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* Callback from net/ipv4/udp.c to receive packets */ 3418c2ecf20Sopenharmony_cistatic int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct genevehdr *geneveh; 3448c2ecf20Sopenharmony_ci struct geneve_dev *geneve; 3458c2ecf20Sopenharmony_ci struct geneve_sock *gs; 3468c2ecf20Sopenharmony_ci int opts_len; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Need UDP and Geneve header to be present */ 3498c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) 3508c2ecf20Sopenharmony_ci goto drop; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* Return packets with reserved bits set */ 3538c2ecf20Sopenharmony_ci geneveh = geneve_hdr(skb); 3548c2ecf20Sopenharmony_ci if (unlikely(geneveh->ver != GENEVE_VER)) 3558c2ecf20Sopenharmony_ci goto drop; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) 3588c2ecf20Sopenharmony_ci goto drop; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci gs = rcu_dereference_sk_user_data(sk); 3618c2ecf20Sopenharmony_ci if (!gs) 3628c2ecf20Sopenharmony_ci goto drop; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci geneve = geneve_lookup_skb(gs, skb); 3658c2ecf20Sopenharmony_ci if (!geneve) 3668c2ecf20Sopenharmony_ci goto drop; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci opts_len = geneveh->opt_len * 4; 3698c2ecf20Sopenharmony_ci if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, 3708c2ecf20Sopenharmony_ci htons(ETH_P_TEB), 3718c2ecf20Sopenharmony_ci !net_eq(geneve->net, dev_net(geneve->dev)))) { 3728c2ecf20Sopenharmony_ci geneve->dev->stats.rx_dropped++; 3738c2ecf20Sopenharmony_ci goto drop; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci geneve_rx(geneve, gs, skb); 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cidrop: 3808c2ecf20Sopenharmony_ci /* Consume bad packet */ 3818c2ecf20Sopenharmony_ci kfree_skb(skb); 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/* Callback from net/ipv{4,6}/udp.c to check that we have a tunnel for errors */ 3868c2ecf20Sopenharmony_cistatic int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct genevehdr *geneveh; 3898c2ecf20Sopenharmony_ci struct geneve_sock *gs; 3908c2ecf20Sopenharmony_ci u8 zero_vni[3] = { 0 }; 3918c2ecf20Sopenharmony_ci u8 *vni = zero_vni; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN)) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci geneveh = geneve_hdr(skb); 3978c2ecf20Sopenharmony_ci if (geneveh->ver != GENEVE_VER) 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (geneveh->proto_type != htons(ETH_P_TEB)) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci gs = rcu_dereference_sk_user_data(sk); 4048c2ecf20Sopenharmony_ci if (!gs) 4058c2ecf20Sopenharmony_ci return -ENOENT; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (geneve_get_sk_family(gs) == AF_INET) { 4088c2ecf20Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 4098c2ecf20Sopenharmony_ci __be32 addr4 = 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!gs->collect_md) { 4128c2ecf20Sopenharmony_ci vni = geneve_hdr(skb)->vni; 4138c2ecf20Sopenharmony_ci addr4 = iph->daddr; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return geneve_lookup(gs, addr4, vni) ? 0 : -ENOENT; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4208c2ecf20Sopenharmony_ci if (geneve_get_sk_family(gs) == AF_INET6) { 4218c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h = ipv6_hdr(skb); 4228c2ecf20Sopenharmony_ci struct in6_addr addr6; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci memset(&addr6, 0, sizeof(struct in6_addr)); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!gs->collect_md) { 4278c2ecf20Sopenharmony_ci vni = geneve_hdr(skb)->vni; 4288c2ecf20Sopenharmony_ci addr6 = ip6h->daddr; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return geneve6_lookup(gs, addr6, vni) ? 0 : -ENOENT; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci#endif 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct socket *geneve_create_sock(struct net *net, bool ipv6, 4398c2ecf20Sopenharmony_ci __be16 port, bool ipv6_rx_csum) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct socket *sock; 4428c2ecf20Sopenharmony_ci struct udp_port_cfg udp_conf; 4438c2ecf20Sopenharmony_ci int err; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci memset(&udp_conf, 0, sizeof(udp_conf)); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (ipv6) { 4488c2ecf20Sopenharmony_ci udp_conf.family = AF_INET6; 4498c2ecf20Sopenharmony_ci udp_conf.ipv6_v6only = 1; 4508c2ecf20Sopenharmony_ci udp_conf.use_udp6_rx_checksums = ipv6_rx_csum; 4518c2ecf20Sopenharmony_ci } else { 4528c2ecf20Sopenharmony_ci udp_conf.family = AF_INET; 4538c2ecf20Sopenharmony_ci udp_conf.local_ip.s_addr = htonl(INADDR_ANY); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci udp_conf.local_udp_port = port; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Open UDP socket */ 4598c2ecf20Sopenharmony_ci err = udp_sock_create(net, &udp_conf, &sock); 4608c2ecf20Sopenharmony_ci if (err < 0) 4618c2ecf20Sopenharmony_ci return ERR_PTR(err); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return sock; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int geneve_hlen(struct genevehdr *gh) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci return sizeof(*gh) + gh->opt_len * 4; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct sk_buff *geneve_gro_receive(struct sock *sk, 4728c2ecf20Sopenharmony_ci struct list_head *head, 4738c2ecf20Sopenharmony_ci struct sk_buff *skb) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct sk_buff *pp = NULL; 4768c2ecf20Sopenharmony_ci struct sk_buff *p; 4778c2ecf20Sopenharmony_ci struct genevehdr *gh, *gh2; 4788c2ecf20Sopenharmony_ci unsigned int hlen, gh_len, off_gnv; 4798c2ecf20Sopenharmony_ci const struct packet_offload *ptype; 4808c2ecf20Sopenharmony_ci __be16 type; 4818c2ecf20Sopenharmony_ci int flush = 1; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci off_gnv = skb_gro_offset(skb); 4848c2ecf20Sopenharmony_ci hlen = off_gnv + sizeof(*gh); 4858c2ecf20Sopenharmony_ci gh = skb_gro_header_fast(skb, off_gnv); 4868c2ecf20Sopenharmony_ci if (skb_gro_header_hard(skb, hlen)) { 4878c2ecf20Sopenharmony_ci gh = skb_gro_header_slow(skb, hlen, off_gnv); 4888c2ecf20Sopenharmony_ci if (unlikely(!gh)) 4898c2ecf20Sopenharmony_ci goto out; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (gh->ver != GENEVE_VER || gh->oam) 4938c2ecf20Sopenharmony_ci goto out; 4948c2ecf20Sopenharmony_ci gh_len = geneve_hlen(gh); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci hlen = off_gnv + gh_len; 4978c2ecf20Sopenharmony_ci if (skb_gro_header_hard(skb, hlen)) { 4988c2ecf20Sopenharmony_ci gh = skb_gro_header_slow(skb, hlen, off_gnv); 4998c2ecf20Sopenharmony_ci if (unlikely(!gh)) 5008c2ecf20Sopenharmony_ci goto out; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci list_for_each_entry(p, head, list) { 5048c2ecf20Sopenharmony_ci if (!NAPI_GRO_CB(p)->same_flow) 5058c2ecf20Sopenharmony_ci continue; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci gh2 = (struct genevehdr *)(p->data + off_gnv); 5088c2ecf20Sopenharmony_ci if (gh->opt_len != gh2->opt_len || 5098c2ecf20Sopenharmony_ci memcmp(gh, gh2, gh_len)) { 5108c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->same_flow = 0; 5118c2ecf20Sopenharmony_ci continue; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci type = gh->proto_type; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci rcu_read_lock(); 5188c2ecf20Sopenharmony_ci ptype = gro_find_receive_by_type(type); 5198c2ecf20Sopenharmony_ci if (!ptype) 5208c2ecf20Sopenharmony_ci goto out_unlock; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci skb_gro_pull(skb, gh_len); 5238c2ecf20Sopenharmony_ci skb_gro_postpull_rcsum(skb, gh, gh_len); 5248c2ecf20Sopenharmony_ci pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); 5258c2ecf20Sopenharmony_ci flush = 0; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciout_unlock: 5288c2ecf20Sopenharmony_ci rcu_read_unlock(); 5298c2ecf20Sopenharmony_ciout: 5308c2ecf20Sopenharmony_ci skb_gro_flush_final(skb, pp, flush); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return pp; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic int geneve_gro_complete(struct sock *sk, struct sk_buff *skb, 5368c2ecf20Sopenharmony_ci int nhoff) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct genevehdr *gh; 5398c2ecf20Sopenharmony_ci struct packet_offload *ptype; 5408c2ecf20Sopenharmony_ci __be16 type; 5418c2ecf20Sopenharmony_ci int gh_len; 5428c2ecf20Sopenharmony_ci int err = -ENOSYS; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci gh = (struct genevehdr *)(skb->data + nhoff); 5458c2ecf20Sopenharmony_ci gh_len = geneve_hlen(gh); 5468c2ecf20Sopenharmony_ci type = gh->proto_type; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci rcu_read_lock(); 5498c2ecf20Sopenharmony_ci ptype = gro_find_complete_by_type(type); 5508c2ecf20Sopenharmony_ci if (ptype) 5518c2ecf20Sopenharmony_ci err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci rcu_read_unlock(); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci skb_set_inner_mac_header(skb, nhoff + gh_len); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return err; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* Create new listen socket if needed */ 5618c2ecf20Sopenharmony_cistatic struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, 5628c2ecf20Sopenharmony_ci bool ipv6, bool ipv6_rx_csum) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 5658c2ecf20Sopenharmony_ci struct geneve_sock *gs; 5668c2ecf20Sopenharmony_ci struct socket *sock; 5678c2ecf20Sopenharmony_ci struct udp_tunnel_sock_cfg tunnel_cfg; 5688c2ecf20Sopenharmony_ci int h; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci gs = kzalloc(sizeof(*gs), GFP_KERNEL); 5718c2ecf20Sopenharmony_ci if (!gs) 5728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci sock = geneve_create_sock(net, ipv6, port, ipv6_rx_csum); 5758c2ecf20Sopenharmony_ci if (IS_ERR(sock)) { 5768c2ecf20Sopenharmony_ci kfree(gs); 5778c2ecf20Sopenharmony_ci return ERR_CAST(sock); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci gs->sock = sock; 5818c2ecf20Sopenharmony_ci gs->refcnt = 1; 5828c2ecf20Sopenharmony_ci for (h = 0; h < VNI_HASH_SIZE; ++h) 5838c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&gs->vni_list[h]); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Initialize the geneve udp offloads structure */ 5868c2ecf20Sopenharmony_ci udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Mark socket as an encapsulation socket */ 5898c2ecf20Sopenharmony_ci memset(&tunnel_cfg, 0, sizeof(tunnel_cfg)); 5908c2ecf20Sopenharmony_ci tunnel_cfg.sk_user_data = gs; 5918c2ecf20Sopenharmony_ci tunnel_cfg.encap_type = 1; 5928c2ecf20Sopenharmony_ci tunnel_cfg.gro_receive = geneve_gro_receive; 5938c2ecf20Sopenharmony_ci tunnel_cfg.gro_complete = geneve_gro_complete; 5948c2ecf20Sopenharmony_ci tunnel_cfg.encap_rcv = geneve_udp_encap_recv; 5958c2ecf20Sopenharmony_ci tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup; 5968c2ecf20Sopenharmony_ci tunnel_cfg.encap_destroy = NULL; 5978c2ecf20Sopenharmony_ci setup_udp_tunnel_sock(net, sock, &tunnel_cfg); 5988c2ecf20Sopenharmony_ci list_add(&gs->list, &gn->sock_list); 5998c2ecf20Sopenharmony_ci return gs; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic void __geneve_sock_release(struct geneve_sock *gs) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci if (!gs || --gs->refcnt) 6058c2ecf20Sopenharmony_ci return; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci list_del(&gs->list); 6088c2ecf20Sopenharmony_ci udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE); 6098c2ecf20Sopenharmony_ci udp_tunnel_sock_release(gs->sock); 6108c2ecf20Sopenharmony_ci kfree_rcu(gs, rcu); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic void geneve_sock_release(struct geneve_dev *geneve) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4); 6168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6178c2ecf20Sopenharmony_ci struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock6, NULL); 6208c2ecf20Sopenharmony_ci#endif 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock4, NULL); 6238c2ecf20Sopenharmony_ci synchronize_net(); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci __geneve_sock_release(gs4); 6268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6278c2ecf20Sopenharmony_ci __geneve_sock_release(gs6); 6288c2ecf20Sopenharmony_ci#endif 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic struct geneve_sock *geneve_find_sock(struct geneve_net *gn, 6328c2ecf20Sopenharmony_ci sa_family_t family, 6338c2ecf20Sopenharmony_ci __be16 dst_port) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct geneve_sock *gs; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci list_for_each_entry(gs, &gn->sock_list, list) { 6388c2ecf20Sopenharmony_ci if (inet_sk(gs->sock->sk)->inet_sport == dst_port && 6398c2ecf20Sopenharmony_ci geneve_get_sk_family(gs) == family) { 6408c2ecf20Sopenharmony_ci return gs; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci return NULL; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int geneve_sock_add(struct geneve_dev *geneve, bool ipv6) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct net *net = geneve->net; 6498c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 6508c2ecf20Sopenharmony_ci struct geneve_dev_node *node; 6518c2ecf20Sopenharmony_ci struct geneve_sock *gs; 6528c2ecf20Sopenharmony_ci __u8 vni[3]; 6538c2ecf20Sopenharmony_ci __u32 hash; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->cfg.info.key.tp_dst); 6568c2ecf20Sopenharmony_ci if (gs) { 6578c2ecf20Sopenharmony_ci gs->refcnt++; 6588c2ecf20Sopenharmony_ci goto out; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6, 6628c2ecf20Sopenharmony_ci geneve->cfg.use_udp6_rx_checksums); 6638c2ecf20Sopenharmony_ci if (IS_ERR(gs)) 6648c2ecf20Sopenharmony_ci return PTR_ERR(gs); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ciout: 6678c2ecf20Sopenharmony_ci gs->collect_md = geneve->cfg.collect_md; 6688c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6698c2ecf20Sopenharmony_ci if (ipv6) { 6708c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock6, gs); 6718c2ecf20Sopenharmony_ci node = &geneve->hlist6; 6728c2ecf20Sopenharmony_ci } else 6738c2ecf20Sopenharmony_ci#endif 6748c2ecf20Sopenharmony_ci { 6758c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock4, gs); 6768c2ecf20Sopenharmony_ci node = &geneve->hlist4; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci node->geneve = geneve; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci tunnel_id_to_vni(geneve->cfg.info.key.tun_id, vni); 6818c2ecf20Sopenharmony_ci hash = geneve_net_vni_hash(vni); 6828c2ecf20Sopenharmony_ci hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]); 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int geneve_open(struct net_device *dev) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 6898c2ecf20Sopenharmony_ci bool metadata = geneve->cfg.collect_md; 6908c2ecf20Sopenharmony_ci bool ipv4, ipv6; 6918c2ecf20Sopenharmony_ci int ret = 0; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata; 6948c2ecf20Sopenharmony_ci ipv4 = !ipv6 || metadata; 6958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6968c2ecf20Sopenharmony_ci if (ipv6) { 6978c2ecf20Sopenharmony_ci ret = geneve_sock_add(geneve, true); 6988c2ecf20Sopenharmony_ci if (ret < 0 && ret != -EAFNOSUPPORT) 6998c2ecf20Sopenharmony_ci ipv4 = false; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci#endif 7028c2ecf20Sopenharmony_ci if (ipv4) 7038c2ecf20Sopenharmony_ci ret = geneve_sock_add(geneve, false); 7048c2ecf20Sopenharmony_ci if (ret < 0) 7058c2ecf20Sopenharmony_ci geneve_sock_release(geneve); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int geneve_stop(struct net_device *dev) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci hlist_del_init_rcu(&geneve->hlist4.hlist); 7158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 7168c2ecf20Sopenharmony_ci hlist_del_init_rcu(&geneve->hlist6.hlist); 7178c2ecf20Sopenharmony_ci#endif 7188c2ecf20Sopenharmony_ci geneve_sock_release(geneve); 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void geneve_build_header(struct genevehdr *geneveh, 7238c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci geneveh->ver = GENEVE_VER; 7268c2ecf20Sopenharmony_ci geneveh->opt_len = info->options_len / 4; 7278c2ecf20Sopenharmony_ci geneveh->oam = !!(info->key.tun_flags & TUNNEL_OAM); 7288c2ecf20Sopenharmony_ci geneveh->critical = !!(info->key.tun_flags & TUNNEL_CRIT_OPT); 7298c2ecf20Sopenharmony_ci geneveh->rsvd1 = 0; 7308c2ecf20Sopenharmony_ci tunnel_id_to_vni(info->key.tun_id, geneveh->vni); 7318c2ecf20Sopenharmony_ci geneveh->proto_type = htons(ETH_P_TEB); 7328c2ecf20Sopenharmony_ci geneveh->rsvd2 = 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (info->key.tun_flags & TUNNEL_GENEVE_OPT) 7358c2ecf20Sopenharmony_ci ip_tunnel_info_opts_get(geneveh->options, info); 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb, 7398c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info, 7408c2ecf20Sopenharmony_ci bool xnet, int ip_hdr_len) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM); 7438c2ecf20Sopenharmony_ci struct genevehdr *gnvh; 7448c2ecf20Sopenharmony_ci int min_headroom; 7458c2ecf20Sopenharmony_ci int err; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 7488c2ecf20Sopenharmony_ci skb_scrub_packet(skb, xnet); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len + 7518c2ecf20Sopenharmony_ci GENEVE_BASE_HLEN + info->options_len + ip_hdr_len; 7528c2ecf20Sopenharmony_ci err = skb_cow_head(skb, min_headroom); 7538c2ecf20Sopenharmony_ci if (unlikely(err)) 7548c2ecf20Sopenharmony_ci goto free_dst; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci err = udp_tunnel_handle_offloads(skb, udp_sum); 7578c2ecf20Sopenharmony_ci if (err) 7588c2ecf20Sopenharmony_ci goto free_dst; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len); 7618c2ecf20Sopenharmony_ci geneve_build_header(gnvh, info); 7628c2ecf20Sopenharmony_ci skb_set_inner_protocol(skb, htons(ETH_P_TEB)); 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cifree_dst: 7668c2ecf20Sopenharmony_ci dst_release(dst); 7678c2ecf20Sopenharmony_ci return err; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic struct rtable *geneve_get_v4_rt(struct sk_buff *skb, 7718c2ecf20Sopenharmony_ci struct net_device *dev, 7728c2ecf20Sopenharmony_ci struct geneve_sock *gs4, 7738c2ecf20Sopenharmony_ci struct flowi4 *fl4, 7748c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info, 7758c2ecf20Sopenharmony_ci __be16 dport, __be16 sport, 7768c2ecf20Sopenharmony_ci __u8 *full_tos) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci bool use_cache = ip_tunnel_dst_cache_usable(skb, info); 7798c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 7808c2ecf20Sopenharmony_ci struct dst_cache *dst_cache; 7818c2ecf20Sopenharmony_ci struct rtable *rt = NULL; 7828c2ecf20Sopenharmony_ci __u8 tos; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (!gs4) 7858c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci memset(fl4, 0, sizeof(*fl4)); 7888c2ecf20Sopenharmony_ci fl4->flowi4_mark = skb->mark; 7898c2ecf20Sopenharmony_ci fl4->flowi4_proto = IPPROTO_UDP; 7908c2ecf20Sopenharmony_ci fl4->daddr = info->key.u.ipv4.dst; 7918c2ecf20Sopenharmony_ci fl4->saddr = info->key.u.ipv4.src; 7928c2ecf20Sopenharmony_ci fl4->fl4_dport = dport; 7938c2ecf20Sopenharmony_ci fl4->fl4_sport = sport; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci tos = info->key.tos; 7968c2ecf20Sopenharmony_ci if ((tos == 1) && !geneve->cfg.collect_md) { 7978c2ecf20Sopenharmony_ci tos = ip_tunnel_get_dsfield(ip_hdr(skb), skb); 7988c2ecf20Sopenharmony_ci use_cache = false; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci fl4->flowi4_tos = RT_TOS(tos); 8018c2ecf20Sopenharmony_ci if (full_tos) 8028c2ecf20Sopenharmony_ci *full_tos = tos; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci dst_cache = (struct dst_cache *)&info->dst_cache; 8058c2ecf20Sopenharmony_ci if (use_cache) { 8068c2ecf20Sopenharmony_ci rt = dst_cache_get_ip4(dst_cache, &fl4->saddr); 8078c2ecf20Sopenharmony_ci if (rt) 8088c2ecf20Sopenharmony_ci return rt; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci rt = ip_route_output_key(geneve->net, fl4); 8118c2ecf20Sopenharmony_ci if (IS_ERR(rt)) { 8128c2ecf20Sopenharmony_ci netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr); 8138c2ecf20Sopenharmony_ci return ERR_PTR(-ENETUNREACH); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci if (rt->dst.dev == dev) { /* is this necessary? */ 8168c2ecf20Sopenharmony_ci netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr); 8178c2ecf20Sopenharmony_ci ip_rt_put(rt); 8188c2ecf20Sopenharmony_ci return ERR_PTR(-ELOOP); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci if (use_cache) 8218c2ecf20Sopenharmony_ci dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr); 8228c2ecf20Sopenharmony_ci return rt; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 8268c2ecf20Sopenharmony_cistatic struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, 8278c2ecf20Sopenharmony_ci struct net_device *dev, 8288c2ecf20Sopenharmony_ci struct geneve_sock *gs6, 8298c2ecf20Sopenharmony_ci struct flowi6 *fl6, 8308c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info, 8318c2ecf20Sopenharmony_ci __be16 dport, __be16 sport) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci bool use_cache = ip_tunnel_dst_cache_usable(skb, info); 8348c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 8358c2ecf20Sopenharmony_ci struct dst_entry *dst = NULL; 8368c2ecf20Sopenharmony_ci struct dst_cache *dst_cache; 8378c2ecf20Sopenharmony_ci __u8 prio; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (!gs6) 8408c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci memset(fl6, 0, sizeof(*fl6)); 8438c2ecf20Sopenharmony_ci fl6->flowi6_mark = skb->mark; 8448c2ecf20Sopenharmony_ci fl6->flowi6_proto = IPPROTO_UDP; 8458c2ecf20Sopenharmony_ci fl6->daddr = info->key.u.ipv6.dst; 8468c2ecf20Sopenharmony_ci fl6->saddr = info->key.u.ipv6.src; 8478c2ecf20Sopenharmony_ci fl6->fl6_dport = dport; 8488c2ecf20Sopenharmony_ci fl6->fl6_sport = sport; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci prio = info->key.tos; 8518c2ecf20Sopenharmony_ci if ((prio == 1) && !geneve->cfg.collect_md) { 8528c2ecf20Sopenharmony_ci prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb); 8538c2ecf20Sopenharmony_ci use_cache = false; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci fl6->flowlabel = ip6_make_flowinfo(prio, info->key.label); 8578c2ecf20Sopenharmony_ci dst_cache = (struct dst_cache *)&info->dst_cache; 8588c2ecf20Sopenharmony_ci if (use_cache) { 8598c2ecf20Sopenharmony_ci dst = dst_cache_get_ip6(dst_cache, &fl6->saddr); 8608c2ecf20Sopenharmony_ci if (dst) 8618c2ecf20Sopenharmony_ci return dst; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6, 8648c2ecf20Sopenharmony_ci NULL); 8658c2ecf20Sopenharmony_ci if (IS_ERR(dst)) { 8668c2ecf20Sopenharmony_ci netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr); 8678c2ecf20Sopenharmony_ci return ERR_PTR(-ENETUNREACH); 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci if (dst->dev == dev) { /* is this necessary? */ 8708c2ecf20Sopenharmony_ci netdev_dbg(dev, "circular route to %pI6\n", &fl6->daddr); 8718c2ecf20Sopenharmony_ci dst_release(dst); 8728c2ecf20Sopenharmony_ci return ERR_PTR(-ELOOP); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (use_cache) 8768c2ecf20Sopenharmony_ci dst_cache_set_ip6(dst_cache, dst, &fl6->saddr); 8778c2ecf20Sopenharmony_ci return dst; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci#endif 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, 8828c2ecf20Sopenharmony_ci struct geneve_dev *geneve, 8838c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); 8868c2ecf20Sopenharmony_ci struct geneve_sock *gs4 = rcu_dereference(geneve->sock4); 8878c2ecf20Sopenharmony_ci const struct ip_tunnel_key *key = &info->key; 8888c2ecf20Sopenharmony_ci struct rtable *rt; 8898c2ecf20Sopenharmony_ci struct flowi4 fl4; 8908c2ecf20Sopenharmony_ci __u8 full_tos; 8918c2ecf20Sopenharmony_ci __u8 tos, ttl; 8928c2ecf20Sopenharmony_ci __be16 df = 0; 8938c2ecf20Sopenharmony_ci __be16 sport; 8948c2ecf20Sopenharmony_ci int err; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (!pskb_inet_may_pull(skb)) 8978c2ecf20Sopenharmony_ci return -EINVAL; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); 9008c2ecf20Sopenharmony_ci rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info, 9018c2ecf20Sopenharmony_ci geneve->cfg.info.key.tp_dst, sport, &full_tos); 9028c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 9038c2ecf20Sopenharmony_ci return PTR_ERR(rt); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci err = skb_tunnel_check_pmtu(skb, &rt->dst, 9068c2ecf20Sopenharmony_ci GENEVE_IPV4_HLEN + info->options_len, 9078c2ecf20Sopenharmony_ci netif_is_any_bridge_port(dev)); 9088c2ecf20Sopenharmony_ci if (err < 0) { 9098c2ecf20Sopenharmony_ci dst_release(&rt->dst); 9108c2ecf20Sopenharmony_ci return err; 9118c2ecf20Sopenharmony_ci } else if (err) { 9128c2ecf20Sopenharmony_ci struct ip_tunnel_info *info; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci info = skb_tunnel_info(skb); 9158c2ecf20Sopenharmony_ci if (info) { 9168c2ecf20Sopenharmony_ci struct ip_tunnel_info *unclone; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci unclone = skb_tunnel_info_unclone(skb); 9198c2ecf20Sopenharmony_ci if (unlikely(!unclone)) { 9208c2ecf20Sopenharmony_ci dst_release(&rt->dst); 9218c2ecf20Sopenharmony_ci return -ENOMEM; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci unclone->key.u.ipv4.dst = fl4.saddr; 9258c2ecf20Sopenharmony_ci unclone->key.u.ipv4.src = fl4.daddr; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, ETH_HLEN)) { 9298c2ecf20Sopenharmony_ci dst_release(&rt->dst); 9308c2ecf20Sopenharmony_ci return -EINVAL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, geneve->dev); 9348c2ecf20Sopenharmony_ci netif_rx(skb); 9358c2ecf20Sopenharmony_ci dst_release(&rt->dst); 9368c2ecf20Sopenharmony_ci return -EMSGSIZE; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (geneve->cfg.collect_md) { 9408c2ecf20Sopenharmony_ci tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb); 9418c2ecf20Sopenharmony_ci ttl = key->ttl; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; 9448c2ecf20Sopenharmony_ci } else { 9458c2ecf20Sopenharmony_ci tos = ip_tunnel_ecn_encap(full_tos, ip_hdr(skb), skb); 9468c2ecf20Sopenharmony_ci if (geneve->cfg.ttl_inherit) 9478c2ecf20Sopenharmony_ci ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb); 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci ttl = key->ttl; 9508c2ecf20Sopenharmony_ci ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (geneve->cfg.df == GENEVE_DF_SET) { 9538c2ecf20Sopenharmony_ci df = htons(IP_DF); 9548c2ecf20Sopenharmony_ci } else if (geneve->cfg.df == GENEVE_DF_INHERIT) { 9558c2ecf20Sopenharmony_ci struct ethhdr *eth = eth_hdr(skb); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (ntohs(eth->h_proto) == ETH_P_IPV6) { 9588c2ecf20Sopenharmony_ci df = htons(IP_DF); 9598c2ecf20Sopenharmony_ci } else if (ntohs(eth->h_proto) == ETH_P_IP) { 9608c2ecf20Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (iph->frag_off & htons(IP_DF)) 9638c2ecf20Sopenharmony_ci df = htons(IP_DF); 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr)); 9698c2ecf20Sopenharmony_ci if (unlikely(err)) 9708c2ecf20Sopenharmony_ci return err; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr, 9738c2ecf20Sopenharmony_ci tos, ttl, df, sport, geneve->cfg.info.key.tp_dst, 9748c2ecf20Sopenharmony_ci !net_eq(geneve->net, dev_net(geneve->dev)), 9758c2ecf20Sopenharmony_ci !(info->key.tun_flags & TUNNEL_CSUM)); 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 9808c2ecf20Sopenharmony_cistatic int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, 9818c2ecf20Sopenharmony_ci struct geneve_dev *geneve, 9828c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); 9858c2ecf20Sopenharmony_ci struct geneve_sock *gs6 = rcu_dereference(geneve->sock6); 9868c2ecf20Sopenharmony_ci const struct ip_tunnel_key *key = &info->key; 9878c2ecf20Sopenharmony_ci struct dst_entry *dst = NULL; 9888c2ecf20Sopenharmony_ci struct flowi6 fl6; 9898c2ecf20Sopenharmony_ci __u8 prio, ttl; 9908c2ecf20Sopenharmony_ci __be16 sport; 9918c2ecf20Sopenharmony_ci int err; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (!pskb_inet_may_pull(skb)) 9948c2ecf20Sopenharmony_ci return -EINVAL; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); 9978c2ecf20Sopenharmony_ci dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info, 9988c2ecf20Sopenharmony_ci geneve->cfg.info.key.tp_dst, sport); 9998c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 10008c2ecf20Sopenharmony_ci return PTR_ERR(dst); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci err = skb_tunnel_check_pmtu(skb, dst, 10038c2ecf20Sopenharmony_ci GENEVE_IPV6_HLEN + info->options_len, 10048c2ecf20Sopenharmony_ci netif_is_any_bridge_port(dev)); 10058c2ecf20Sopenharmony_ci if (err < 0) { 10068c2ecf20Sopenharmony_ci dst_release(dst); 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci } else if (err) { 10098c2ecf20Sopenharmony_ci struct ip_tunnel_info *info = skb_tunnel_info(skb); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (info) { 10128c2ecf20Sopenharmony_ci struct ip_tunnel_info *unclone; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci unclone = skb_tunnel_info_unclone(skb); 10158c2ecf20Sopenharmony_ci if (unlikely(!unclone)) { 10168c2ecf20Sopenharmony_ci dst_release(dst); 10178c2ecf20Sopenharmony_ci return -ENOMEM; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci unclone->key.u.ipv6.dst = fl6.saddr; 10218c2ecf20Sopenharmony_ci unclone->key.u.ipv6.src = fl6.daddr; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, ETH_HLEN)) { 10258c2ecf20Sopenharmony_ci dst_release(dst); 10268c2ecf20Sopenharmony_ci return -EINVAL; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, geneve->dev); 10308c2ecf20Sopenharmony_ci netif_rx(skb); 10318c2ecf20Sopenharmony_ci dst_release(dst); 10328c2ecf20Sopenharmony_ci return -EMSGSIZE; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (geneve->cfg.collect_md) { 10368c2ecf20Sopenharmony_ci prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb); 10378c2ecf20Sopenharmony_ci ttl = key->ttl; 10388c2ecf20Sopenharmony_ci } else { 10398c2ecf20Sopenharmony_ci prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel), 10408c2ecf20Sopenharmony_ci ip_hdr(skb), skb); 10418c2ecf20Sopenharmony_ci if (geneve->cfg.ttl_inherit) 10428c2ecf20Sopenharmony_ci ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb); 10438c2ecf20Sopenharmony_ci else 10448c2ecf20Sopenharmony_ci ttl = key->ttl; 10458c2ecf20Sopenharmony_ci ttl = ttl ? : ip6_dst_hoplimit(dst); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr)); 10488c2ecf20Sopenharmony_ci if (unlikely(err)) 10498c2ecf20Sopenharmony_ci return err; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev, 10528c2ecf20Sopenharmony_ci &fl6.saddr, &fl6.daddr, prio, ttl, 10538c2ecf20Sopenharmony_ci info->key.label, sport, geneve->cfg.info.key.tp_dst, 10548c2ecf20Sopenharmony_ci !(info->key.tun_flags & TUNNEL_CSUM)); 10558c2ecf20Sopenharmony_ci return 0; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci#endif 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 10628c2ecf20Sopenharmony_ci struct ip_tunnel_info *info = NULL; 10638c2ecf20Sopenharmony_ci int err; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (geneve->cfg.collect_md) { 10668c2ecf20Sopenharmony_ci info = skb_tunnel_info(skb); 10678c2ecf20Sopenharmony_ci if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { 10688c2ecf20Sopenharmony_ci netdev_dbg(dev, "no tunnel metadata\n"); 10698c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10708c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 10718c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci } else { 10748c2ecf20Sopenharmony_ci info = &geneve->cfg.info; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci rcu_read_lock(); 10788c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10798c2ecf20Sopenharmony_ci if (info->mode & IP_TUNNEL_INFO_IPV6) 10808c2ecf20Sopenharmony_ci err = geneve6_xmit_skb(skb, dev, geneve, info); 10818c2ecf20Sopenharmony_ci else 10828c2ecf20Sopenharmony_ci#endif 10838c2ecf20Sopenharmony_ci err = geneve_xmit_skb(skb, dev, geneve, info); 10848c2ecf20Sopenharmony_ci rcu_read_unlock(); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (likely(!err)) 10878c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (err != -EMSGSIZE) 10908c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (err == -ELOOP) 10938c2ecf20Sopenharmony_ci dev->stats.collisions++; 10948c2ecf20Sopenharmony_ci else if (err == -ENETUNREACH) 10958c2ecf20Sopenharmony_ci dev->stats.tx_carrier_errors++; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 10988c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic int geneve_change_mtu(struct net_device *dev, int new_mtu) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci if (new_mtu > dev->max_mtu) 11048c2ecf20Sopenharmony_ci new_mtu = dev->max_mtu; 11058c2ecf20Sopenharmony_ci else if (new_mtu < dev->min_mtu) 11068c2ecf20Sopenharmony_ci new_mtu = dev->min_mtu; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 11098c2ecf20Sopenharmony_ci return 0; 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct ip_tunnel_info *info = skb_tunnel_info(skb); 11158c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 11168c2ecf20Sopenharmony_ci __be16 sport; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (ip_tunnel_info_af(info) == AF_INET) { 11198c2ecf20Sopenharmony_ci struct rtable *rt; 11208c2ecf20Sopenharmony_ci struct flowi4 fl4; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci struct geneve_sock *gs4 = rcu_dereference(geneve->sock4); 11238c2ecf20Sopenharmony_ci sport = udp_flow_src_port(geneve->net, skb, 11248c2ecf20Sopenharmony_ci 1, USHRT_MAX, true); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info, 11278c2ecf20Sopenharmony_ci geneve->cfg.info.key.tp_dst, sport, NULL); 11288c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 11298c2ecf20Sopenharmony_ci return PTR_ERR(rt); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci ip_rt_put(rt); 11328c2ecf20Sopenharmony_ci info->key.u.ipv4.src = fl4.saddr; 11338c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 11348c2ecf20Sopenharmony_ci } else if (ip_tunnel_info_af(info) == AF_INET6) { 11358c2ecf20Sopenharmony_ci struct dst_entry *dst; 11368c2ecf20Sopenharmony_ci struct flowi6 fl6; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci struct geneve_sock *gs6 = rcu_dereference(geneve->sock6); 11398c2ecf20Sopenharmony_ci sport = udp_flow_src_port(geneve->net, skb, 11408c2ecf20Sopenharmony_ci 1, USHRT_MAX, true); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info, 11438c2ecf20Sopenharmony_ci geneve->cfg.info.key.tp_dst, sport); 11448c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 11458c2ecf20Sopenharmony_ci return PTR_ERR(dst); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci dst_release(dst); 11488c2ecf20Sopenharmony_ci info->key.u.ipv6.src = fl6.saddr; 11498c2ecf20Sopenharmony_ci#endif 11508c2ecf20Sopenharmony_ci } else { 11518c2ecf20Sopenharmony_ci return -EINVAL; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci info->key.tp_src = sport; 11558c2ecf20Sopenharmony_ci info->key.tp_dst = geneve->cfg.info.key.tp_dst; 11568c2ecf20Sopenharmony_ci return 0; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic const struct net_device_ops geneve_netdev_ops = { 11608c2ecf20Sopenharmony_ci .ndo_init = geneve_init, 11618c2ecf20Sopenharmony_ci .ndo_uninit = geneve_uninit, 11628c2ecf20Sopenharmony_ci .ndo_open = geneve_open, 11638c2ecf20Sopenharmony_ci .ndo_stop = geneve_stop, 11648c2ecf20Sopenharmony_ci .ndo_start_xmit = geneve_xmit, 11658c2ecf20Sopenharmony_ci .ndo_get_stats64 = ip_tunnel_get_stats64, 11668c2ecf20Sopenharmony_ci .ndo_change_mtu = geneve_change_mtu, 11678c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 11688c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 11698c2ecf20Sopenharmony_ci .ndo_fill_metadata_dst = geneve_fill_metadata_dst, 11708c2ecf20Sopenharmony_ci}; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic void geneve_get_drvinfo(struct net_device *dev, 11738c2ecf20Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version)); 11768c2ecf20Sopenharmony_ci strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver)); 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic const struct ethtool_ops geneve_ethtool_ops = { 11808c2ecf20Sopenharmony_ci .get_drvinfo = geneve_get_drvinfo, 11818c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 11828c2ecf20Sopenharmony_ci}; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci/* Info for udev, that this is a virtual tunnel endpoint */ 11858c2ecf20Sopenharmony_cistatic struct device_type geneve_type = { 11868c2ecf20Sopenharmony_ci .name = "geneve", 11878c2ecf20Sopenharmony_ci}; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci/* Calls the ndo_udp_tunnel_add of the caller in order to 11908c2ecf20Sopenharmony_ci * supply the listening GENEVE udp ports. Callers are expected 11918c2ecf20Sopenharmony_ci * to implement the ndo_udp_tunnel_add. 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_cistatic void geneve_offload_rx_ports(struct net_device *dev, bool push) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 11968c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 11978c2ecf20Sopenharmony_ci struct geneve_sock *gs; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci rcu_read_lock(); 12008c2ecf20Sopenharmony_ci list_for_each_entry_rcu(gs, &gn->sock_list, list) { 12018c2ecf20Sopenharmony_ci if (push) { 12028c2ecf20Sopenharmony_ci udp_tunnel_push_rx_port(dev, gs->sock, 12038c2ecf20Sopenharmony_ci UDP_TUNNEL_TYPE_GENEVE); 12048c2ecf20Sopenharmony_ci } else { 12058c2ecf20Sopenharmony_ci udp_tunnel_drop_rx_port(dev, gs->sock, 12068c2ecf20Sopenharmony_ci UDP_TUNNEL_TYPE_GENEVE); 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci rcu_read_unlock(); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci/* Initialize the device structure. */ 12138c2ecf20Sopenharmony_cistatic void geneve_setup(struct net_device *dev) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci ether_setup(dev); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci dev->netdev_ops = &geneve_netdev_ops; 12188c2ecf20Sopenharmony_ci dev->ethtool_ops = &geneve_ethtool_ops; 12198c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci SET_NETDEV_DEVTYPE(dev, &geneve_type); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci dev->features |= NETIF_F_LLTX; 12248c2ecf20Sopenharmony_ci dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; 12258c2ecf20Sopenharmony_ci dev->features |= NETIF_F_RXCSUM; 12268c2ecf20Sopenharmony_ci dev->features |= NETIF_F_GSO_SOFTWARE; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; 12298c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_GSO_SOFTWARE; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci /* MTU range: 68 - (something less than 65535) */ 12328c2ecf20Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 12338c2ecf20Sopenharmony_ci /* The max_mtu calculation does not take account of GENEVE 12348c2ecf20Sopenharmony_ci * options, to avoid excluding potentially valid 12358c2ecf20Sopenharmony_ci * configurations. This will be further reduced by IPvX hdr size. 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_ci dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci netif_keep_dst(dev); 12408c2ecf20Sopenharmony_ci dev->priv_flags &= ~IFF_TX_SKB_SHARING; 12418c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; 12428c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { 12468c2ecf20Sopenharmony_ci [IFLA_GENEVE_ID] = { .type = NLA_U32 }, 12478c2ecf20Sopenharmony_ci [IFLA_GENEVE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) }, 12488c2ecf20Sopenharmony_ci [IFLA_GENEVE_REMOTE6] = { .len = sizeof(struct in6_addr) }, 12498c2ecf20Sopenharmony_ci [IFLA_GENEVE_TTL] = { .type = NLA_U8 }, 12508c2ecf20Sopenharmony_ci [IFLA_GENEVE_TOS] = { .type = NLA_U8 }, 12518c2ecf20Sopenharmony_ci [IFLA_GENEVE_LABEL] = { .type = NLA_U32 }, 12528c2ecf20Sopenharmony_ci [IFLA_GENEVE_PORT] = { .type = NLA_U16 }, 12538c2ecf20Sopenharmony_ci [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG }, 12548c2ecf20Sopenharmony_ci [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 }, 12558c2ecf20Sopenharmony_ci [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, 12568c2ecf20Sopenharmony_ci [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, 12578c2ecf20Sopenharmony_ci [IFLA_GENEVE_TTL_INHERIT] = { .type = NLA_U8 }, 12588c2ecf20Sopenharmony_ci [IFLA_GENEVE_DF] = { .type = NLA_U8 }, 12598c2ecf20Sopenharmony_ci}; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic int geneve_validate(struct nlattr *tb[], struct nlattr *data[], 12628c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci if (tb[IFLA_ADDRESS]) { 12658c2ecf20Sopenharmony_ci if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) { 12668c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS], 12678c2ecf20Sopenharmony_ci "Provided link layer address is not Ethernet"); 12688c2ecf20Sopenharmony_ci return -EINVAL; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) { 12728c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS], 12738c2ecf20Sopenharmony_ci "Provided Ethernet address is not unicast"); 12748c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (!data) { 12798c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 12808c2ecf20Sopenharmony_ci "Not enough attributes provided to perform the operation"); 12818c2ecf20Sopenharmony_ci return -EINVAL; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_ID]) { 12858c2ecf20Sopenharmony_ci __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (vni >= GENEVE_N_VID) { 12888c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID], 12898c2ecf20Sopenharmony_ci "Geneve ID must be lower than 16777216"); 12908c2ecf20Sopenharmony_ci return -ERANGE; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_DF]) { 12958c2ecf20Sopenharmony_ci enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (df < 0 || df > GENEVE_DF_MAX) { 12988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_DF], 12998c2ecf20Sopenharmony_ci "Invalid DF attribute"); 13008c2ecf20Sopenharmony_ci return -EINVAL; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci return 0; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic struct geneve_dev *geneve_find_dev(struct geneve_net *gn, 13088c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info, 13098c2ecf20Sopenharmony_ci bool *tun_on_same_port, 13108c2ecf20Sopenharmony_ci bool *tun_collect_md) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci struct geneve_dev *geneve, *t = NULL; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci *tun_on_same_port = false; 13158c2ecf20Sopenharmony_ci *tun_collect_md = false; 13168c2ecf20Sopenharmony_ci list_for_each_entry(geneve, &gn->geneve_list, next) { 13178c2ecf20Sopenharmony_ci if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) { 13188c2ecf20Sopenharmony_ci *tun_collect_md = geneve->cfg.collect_md; 13198c2ecf20Sopenharmony_ci *tun_on_same_port = true; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci if (info->key.tun_id == geneve->cfg.info.key.tun_id && 13228c2ecf20Sopenharmony_ci info->key.tp_dst == geneve->cfg.info.key.tp_dst && 13238c2ecf20Sopenharmony_ci !memcmp(&info->key.u, &geneve->cfg.info.key.u, sizeof(info->key.u))) 13248c2ecf20Sopenharmony_ci t = geneve; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci return t; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic bool is_tnl_info_zero(const struct ip_tunnel_info *info) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci return !(info->key.tun_id || info->key.tun_flags || info->key.tos || 13328c2ecf20Sopenharmony_ci info->key.ttl || info->key.label || info->key.tp_src || 13338c2ecf20Sopenharmony_ci memchr_inv(&info->key.u, 0, sizeof(info->key.u))); 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic bool geneve_dst_addr_equal(struct ip_tunnel_info *a, 13378c2ecf20Sopenharmony_ci struct ip_tunnel_info *b) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci if (ip_tunnel_info_af(a) == AF_INET) 13408c2ecf20Sopenharmony_ci return a->key.u.ipv4.dst == b->key.u.ipv4.dst; 13418c2ecf20Sopenharmony_ci else 13428c2ecf20Sopenharmony_ci return ipv6_addr_equal(&a->key.u.ipv6.dst, &b->key.u.ipv6.dst); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic int geneve_configure(struct net *net, struct net_device *dev, 13468c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack, 13478c2ecf20Sopenharmony_ci const struct geneve_config *cfg) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 13508c2ecf20Sopenharmony_ci struct geneve_dev *t, *geneve = netdev_priv(dev); 13518c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info = &cfg->info; 13528c2ecf20Sopenharmony_ci bool tun_collect_md, tun_on_same_port; 13538c2ecf20Sopenharmony_ci int err, encap_len; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (cfg->collect_md && !is_tnl_info_zero(info)) { 13568c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 13578c2ecf20Sopenharmony_ci "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified"); 13588c2ecf20Sopenharmony_ci return -EINVAL; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci geneve->net = net; 13628c2ecf20Sopenharmony_ci geneve->dev = dev; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md); 13658c2ecf20Sopenharmony_ci if (t) 13668c2ecf20Sopenharmony_ci return -EBUSY; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* make enough headroom for basic scenario */ 13698c2ecf20Sopenharmony_ci encap_len = GENEVE_BASE_HLEN + ETH_HLEN; 13708c2ecf20Sopenharmony_ci if (!cfg->collect_md && ip_tunnel_info_af(info) == AF_INET) { 13718c2ecf20Sopenharmony_ci encap_len += sizeof(struct iphdr); 13728c2ecf20Sopenharmony_ci dev->max_mtu -= sizeof(struct iphdr); 13738c2ecf20Sopenharmony_ci } else { 13748c2ecf20Sopenharmony_ci encap_len += sizeof(struct ipv6hdr); 13758c2ecf20Sopenharmony_ci dev->max_mtu -= sizeof(struct ipv6hdr); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci dev->needed_headroom = encap_len + ETH_HLEN; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (cfg->collect_md) { 13808c2ecf20Sopenharmony_ci if (tun_on_same_port) { 13818c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 13828c2ecf20Sopenharmony_ci "There can be only one externally controlled device on a destination port"); 13838c2ecf20Sopenharmony_ci return -EPERM; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci } else { 13868c2ecf20Sopenharmony_ci if (tun_collect_md) { 13878c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 13888c2ecf20Sopenharmony_ci "There already exists an externally controlled device on this destination port"); 13898c2ecf20Sopenharmony_ci return -EPERM; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci dst_cache_reset(&geneve->cfg.info.dst_cache); 13948c2ecf20Sopenharmony_ci memcpy(&geneve->cfg, cfg, sizeof(*cfg)); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci err = register_netdevice(dev); 13978c2ecf20Sopenharmony_ci if (err) 13988c2ecf20Sopenharmony_ci return err; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci list_add(&geneve->next, &gn->geneve_list); 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 14078c2ecf20Sopenharmony_ci info->key.tp_dst = htons(dst_port); 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], 14118c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack, 14128c2ecf20Sopenharmony_ci struct geneve_config *cfg, bool changelink) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct ip_tunnel_info *info = &cfg->info; 14158c2ecf20Sopenharmony_ci int attrtype; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) { 14188c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 14198c2ecf20Sopenharmony_ci "Cannot specify both IPv4 and IPv6 Remote addresses"); 14208c2ecf20Sopenharmony_ci return -EINVAL; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_REMOTE]) { 14248c2ecf20Sopenharmony_ci if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) { 14258c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_REMOTE; 14268c2ecf20Sopenharmony_ci goto change_notsup; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci info->key.u.ipv4.dst = 14308c2ecf20Sopenharmony_ci nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (ipv4_is_multicast(info->key.u.ipv4.dst)) { 14338c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE], 14348c2ecf20Sopenharmony_ci "Remote IPv4 address cannot be Multicast"); 14358c2ecf20Sopenharmony_ci return -EINVAL; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_REMOTE6]) { 14408c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 14418c2ecf20Sopenharmony_ci if (changelink && (ip_tunnel_info_af(info) == AF_INET)) { 14428c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_REMOTE6; 14438c2ecf20Sopenharmony_ci goto change_notsup; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci info->mode = IP_TUNNEL_INFO_IPV6; 14478c2ecf20Sopenharmony_ci info->key.u.ipv6.dst = 14488c2ecf20Sopenharmony_ci nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (ipv6_addr_type(&info->key.u.ipv6.dst) & 14518c2ecf20Sopenharmony_ci IPV6_ADDR_LINKLOCAL) { 14528c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], 14538c2ecf20Sopenharmony_ci "Remote IPv6 address cannot be link-local"); 14548c2ecf20Sopenharmony_ci return -EINVAL; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) { 14578c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], 14588c2ecf20Sopenharmony_ci "Remote IPv6 address cannot be Multicast"); 14598c2ecf20Sopenharmony_ci return -EINVAL; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci info->key.tun_flags |= TUNNEL_CSUM; 14628c2ecf20Sopenharmony_ci cfg->use_udp6_rx_checksums = true; 14638c2ecf20Sopenharmony_ci#else 14648c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], 14658c2ecf20Sopenharmony_ci "IPv6 support not enabled in the kernel"); 14668c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 14678c2ecf20Sopenharmony_ci#endif 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_ID]) { 14718c2ecf20Sopenharmony_ci __u32 vni; 14728c2ecf20Sopenharmony_ci __u8 tvni[3]; 14738c2ecf20Sopenharmony_ci __be64 tunid; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci vni = nla_get_u32(data[IFLA_GENEVE_ID]); 14768c2ecf20Sopenharmony_ci tvni[0] = (vni & 0x00ff0000) >> 16; 14778c2ecf20Sopenharmony_ci tvni[1] = (vni & 0x0000ff00) >> 8; 14788c2ecf20Sopenharmony_ci tvni[2] = vni & 0x000000ff; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci tunid = vni_to_tunnel_id(tvni); 14818c2ecf20Sopenharmony_ci if (changelink && (tunid != info->key.tun_id)) { 14828c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_ID; 14838c2ecf20Sopenharmony_ci goto change_notsup; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci info->key.tun_id = tunid; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_TTL_INHERIT]) { 14898c2ecf20Sopenharmony_ci if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT])) 14908c2ecf20Sopenharmony_ci cfg->ttl_inherit = true; 14918c2ecf20Sopenharmony_ci else 14928c2ecf20Sopenharmony_ci cfg->ttl_inherit = false; 14938c2ecf20Sopenharmony_ci } else if (data[IFLA_GENEVE_TTL]) { 14948c2ecf20Sopenharmony_ci info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); 14958c2ecf20Sopenharmony_ci cfg->ttl_inherit = false; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_TOS]) 14998c2ecf20Sopenharmony_ci info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_DF]) 15028c2ecf20Sopenharmony_ci cfg->df = nla_get_u8(data[IFLA_GENEVE_DF]); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_LABEL]) { 15058c2ecf20Sopenharmony_ci info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) & 15068c2ecf20Sopenharmony_ci IPV6_FLOWLABEL_MASK; 15078c2ecf20Sopenharmony_ci if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) { 15088c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL], 15098c2ecf20Sopenharmony_ci "Label attribute only applies for IPv6 Geneve devices"); 15108c2ecf20Sopenharmony_ci return -EINVAL; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_PORT]) { 15158c2ecf20Sopenharmony_ci if (changelink) { 15168c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_PORT; 15178c2ecf20Sopenharmony_ci goto change_notsup; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]); 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_COLLECT_METADATA]) { 15238c2ecf20Sopenharmony_ci if (changelink) { 15248c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_COLLECT_METADATA; 15258c2ecf20Sopenharmony_ci goto change_notsup; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci cfg->collect_md = true; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_UDP_CSUM]) { 15318c2ecf20Sopenharmony_ci if (changelink) { 15328c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_UDP_CSUM; 15338c2ecf20Sopenharmony_ci goto change_notsup; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM])) 15368c2ecf20Sopenharmony_ci info->key.tun_flags |= TUNNEL_CSUM; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) { 15408c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 15418c2ecf20Sopenharmony_ci if (changelink) { 15428c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX; 15438c2ecf20Sopenharmony_ci goto change_notsup; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX])) 15468c2ecf20Sopenharmony_ci info->key.tun_flags &= ~TUNNEL_CSUM; 15478c2ecf20Sopenharmony_ci#else 15488c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX], 15498c2ecf20Sopenharmony_ci "IPv6 support not enabled in the kernel"); 15508c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 15518c2ecf20Sopenharmony_ci#endif 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) { 15558c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 15568c2ecf20Sopenharmony_ci if (changelink) { 15578c2ecf20Sopenharmony_ci attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX; 15588c2ecf20Sopenharmony_ci goto change_notsup; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])) 15618c2ecf20Sopenharmony_ci cfg->use_udp6_rx_checksums = false; 15628c2ecf20Sopenharmony_ci#else 15638c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX], 15648c2ecf20Sopenharmony_ci "IPv6 support not enabled in the kernel"); 15658c2ecf20Sopenharmony_ci return -EPFNOSUPPORT; 15668c2ecf20Sopenharmony_ci#endif 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci return 0; 15708c2ecf20Sopenharmony_cichange_notsup: 15718c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[attrtype], 15728c2ecf20Sopenharmony_ci "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported"); 15738c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic void geneve_link_config(struct net_device *dev, 15778c2ecf20Sopenharmony_ci struct ip_tunnel_info *info, struct nlattr *tb[]) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 15808c2ecf20Sopenharmony_ci int ldev_mtu = 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (tb[IFLA_MTU]) { 15838c2ecf20Sopenharmony_ci geneve_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); 15848c2ecf20Sopenharmony_ci return; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci switch (ip_tunnel_info_af(info)) { 15888c2ecf20Sopenharmony_ci case AF_INET: { 15898c2ecf20Sopenharmony_ci struct flowi4 fl4 = { .daddr = info->key.u.ipv4.dst }; 15908c2ecf20Sopenharmony_ci struct rtable *rt = ip_route_output_key(geneve->net, &fl4); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (!IS_ERR(rt) && rt->dst.dev) { 15938c2ecf20Sopenharmony_ci ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV4_HLEN; 15948c2ecf20Sopenharmony_ci ip_rt_put(rt); 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci break; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 15998c2ecf20Sopenharmony_ci case AF_INET6: { 16008c2ecf20Sopenharmony_ci struct rt6_info *rt; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (!__in6_dev_get(dev)) 16038c2ecf20Sopenharmony_ci break; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci rt = rt6_lookup(geneve->net, &info->key.u.ipv6.dst, NULL, 0, 16068c2ecf20Sopenharmony_ci NULL, 0); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (rt && rt->dst.dev) 16098c2ecf20Sopenharmony_ci ldev_mtu = rt->dst.dev->mtu - GENEVE_IPV6_HLEN; 16108c2ecf20Sopenharmony_ci ip6_rt_put(rt); 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci#endif 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (ldev_mtu <= 0) 16178c2ecf20Sopenharmony_ci return; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci geneve_change_mtu(dev, ldev_mtu - info->options_len); 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int geneve_newlink(struct net *net, struct net_device *dev, 16238c2ecf20Sopenharmony_ci struct nlattr *tb[], struct nlattr *data[], 16248c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci struct geneve_config cfg = { 16278c2ecf20Sopenharmony_ci .df = GENEVE_DF_UNSET, 16288c2ecf20Sopenharmony_ci .use_udp6_rx_checksums = false, 16298c2ecf20Sopenharmony_ci .ttl_inherit = false, 16308c2ecf20Sopenharmony_ci .collect_md = false, 16318c2ecf20Sopenharmony_ci }; 16328c2ecf20Sopenharmony_ci int err; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci init_tnl_info(&cfg.info, GENEVE_UDP_PORT); 16358c2ecf20Sopenharmony_ci err = geneve_nl2info(tb, data, extack, &cfg, false); 16368c2ecf20Sopenharmony_ci if (err) 16378c2ecf20Sopenharmony_ci return err; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci err = geneve_configure(net, dev, extack, &cfg); 16408c2ecf20Sopenharmony_ci if (err) 16418c2ecf20Sopenharmony_ci return err; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci geneve_link_config(dev, &cfg.info, tb); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return 0; 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci/* Quiesces the geneve device data path for both TX and RX. 16498c2ecf20Sopenharmony_ci * 16508c2ecf20Sopenharmony_ci * On transmit geneve checks for non-NULL geneve_sock before it proceeds. 16518c2ecf20Sopenharmony_ci * So, if we set that socket to NULL under RCU and wait for synchronize_net() 16528c2ecf20Sopenharmony_ci * to complete for the existing set of in-flight packets to be transmitted, 16538c2ecf20Sopenharmony_ci * then we would have quiesced the transmit data path. All the future packets 16548c2ecf20Sopenharmony_ci * will get dropped until we unquiesce the data path. 16558c2ecf20Sopenharmony_ci * 16568c2ecf20Sopenharmony_ci * On receive geneve dereference the geneve_sock stashed in the socket. So, 16578c2ecf20Sopenharmony_ci * if we set that to NULL under RCU and wait for synchronize_net() to 16588c2ecf20Sopenharmony_ci * complete, then we would have quiesced the receive data path. 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_cistatic void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4, 16618c2ecf20Sopenharmony_ci struct geneve_sock **gs6) 16628c2ecf20Sopenharmony_ci{ 16638c2ecf20Sopenharmony_ci *gs4 = rtnl_dereference(geneve->sock4); 16648c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock4, NULL); 16658c2ecf20Sopenharmony_ci if (*gs4) 16668c2ecf20Sopenharmony_ci rcu_assign_sk_user_data((*gs4)->sock->sk, NULL); 16678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 16688c2ecf20Sopenharmony_ci *gs6 = rtnl_dereference(geneve->sock6); 16698c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock6, NULL); 16708c2ecf20Sopenharmony_ci if (*gs6) 16718c2ecf20Sopenharmony_ci rcu_assign_sk_user_data((*gs6)->sock->sk, NULL); 16728c2ecf20Sopenharmony_ci#else 16738c2ecf20Sopenharmony_ci *gs6 = NULL; 16748c2ecf20Sopenharmony_ci#endif 16758c2ecf20Sopenharmony_ci synchronize_net(); 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci/* Resumes the geneve device data path for both TX and RX. */ 16798c2ecf20Sopenharmony_cistatic void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4, 16808c2ecf20Sopenharmony_ci struct geneve_sock __maybe_unused *gs6) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock4, gs4); 16838c2ecf20Sopenharmony_ci if (gs4) 16848c2ecf20Sopenharmony_ci rcu_assign_sk_user_data(gs4->sock->sk, gs4); 16858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 16868c2ecf20Sopenharmony_ci rcu_assign_pointer(geneve->sock6, gs6); 16878c2ecf20Sopenharmony_ci if (gs6) 16888c2ecf20Sopenharmony_ci rcu_assign_sk_user_data(gs6->sock->sk, gs6); 16898c2ecf20Sopenharmony_ci#endif 16908c2ecf20Sopenharmony_ci synchronize_net(); 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic int geneve_changelink(struct net_device *dev, struct nlattr *tb[], 16948c2ecf20Sopenharmony_ci struct nlattr *data[], 16958c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 16988c2ecf20Sopenharmony_ci struct geneve_sock *gs4, *gs6; 16998c2ecf20Sopenharmony_ci struct geneve_config cfg; 17008c2ecf20Sopenharmony_ci int err; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* If the geneve device is configured for metadata (or externally 17038c2ecf20Sopenharmony_ci * controlled, for example, OVS), then nothing can be changed. 17048c2ecf20Sopenharmony_ci */ 17058c2ecf20Sopenharmony_ci if (geneve->cfg.collect_md) 17068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Start with the existing info. */ 17098c2ecf20Sopenharmony_ci memcpy(&cfg, &geneve->cfg, sizeof(cfg)); 17108c2ecf20Sopenharmony_ci err = geneve_nl2info(tb, data, extack, &cfg, true); 17118c2ecf20Sopenharmony_ci if (err) 17128c2ecf20Sopenharmony_ci return err; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci if (!geneve_dst_addr_equal(&geneve->cfg.info, &cfg.info)) { 17158c2ecf20Sopenharmony_ci dst_cache_reset(&cfg.info.dst_cache); 17168c2ecf20Sopenharmony_ci geneve_link_config(dev, &cfg.info, tb); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci geneve_quiesce(geneve, &gs4, &gs6); 17208c2ecf20Sopenharmony_ci memcpy(&geneve->cfg, &cfg, sizeof(cfg)); 17218c2ecf20Sopenharmony_ci geneve_unquiesce(geneve, gs4, gs6); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return 0; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic void geneve_dellink(struct net_device *dev, struct list_head *head) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci list_del(&geneve->next); 17318c2ecf20Sopenharmony_ci unregister_netdevice_queue(dev, head); 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cistatic size_t geneve_get_size(const struct net_device *dev) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */ 17378c2ecf20Sopenharmony_ci nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */ 17388c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ 17398c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */ 17408c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_DF */ 17418c2ecf20Sopenharmony_ci nla_total_size(sizeof(__be32)) + /* IFLA_GENEVE_LABEL */ 17428c2ecf20Sopenharmony_ci nla_total_size(sizeof(__be16)) + /* IFLA_GENEVE_PORT */ 17438c2ecf20Sopenharmony_ci nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */ 17448c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */ 17458c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */ 17468c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */ 17478c2ecf20Sopenharmony_ci nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */ 17488c2ecf20Sopenharmony_ci 0; 17498c2ecf20Sopenharmony_ci} 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct geneve_dev *geneve = netdev_priv(dev); 17548c2ecf20Sopenharmony_ci struct ip_tunnel_info *info = &geneve->cfg.info; 17558c2ecf20Sopenharmony_ci bool ttl_inherit = geneve->cfg.ttl_inherit; 17568c2ecf20Sopenharmony_ci bool metadata = geneve->cfg.collect_md; 17578c2ecf20Sopenharmony_ci __u8 tmp_vni[3]; 17588c2ecf20Sopenharmony_ci __u32 vni; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci tunnel_id_to_vni(info->key.tun_id, tmp_vni); 17618c2ecf20Sopenharmony_ci vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2]; 17628c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_GENEVE_ID, vni)) 17638c2ecf20Sopenharmony_ci goto nla_put_failure; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (!metadata && ip_tunnel_info_af(info) == AF_INET) { 17668c2ecf20Sopenharmony_ci if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE, 17678c2ecf20Sopenharmony_ci info->key.u.ipv4.dst)) 17688c2ecf20Sopenharmony_ci goto nla_put_failure; 17698c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM, 17708c2ecf20Sopenharmony_ci !!(info->key.tun_flags & TUNNEL_CSUM))) 17718c2ecf20Sopenharmony_ci goto nla_put_failure; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 17748c2ecf20Sopenharmony_ci } else if (!metadata) { 17758c2ecf20Sopenharmony_ci if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6, 17768c2ecf20Sopenharmony_ci &info->key.u.ipv6.dst)) 17778c2ecf20Sopenharmony_ci goto nla_put_failure; 17788c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, 17798c2ecf20Sopenharmony_ci !(info->key.tun_flags & TUNNEL_CSUM))) 17808c2ecf20Sopenharmony_ci goto nla_put_failure; 17818c2ecf20Sopenharmony_ci#endif 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) || 17858c2ecf20Sopenharmony_ci nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) || 17868c2ecf20Sopenharmony_ci nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label)) 17878c2ecf20Sopenharmony_ci goto nla_put_failure; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->cfg.df)) 17908c2ecf20Sopenharmony_ci goto nla_put_failure; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst)) 17938c2ecf20Sopenharmony_ci goto nla_put_failure; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA)) 17968c2ecf20Sopenharmony_ci goto nla_put_failure; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 17998c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, 18008c2ecf20Sopenharmony_ci !geneve->cfg.use_udp6_rx_checksums)) 18018c2ecf20Sopenharmony_ci goto nla_put_failure; 18028c2ecf20Sopenharmony_ci#endif 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit)) 18058c2ecf20Sopenharmony_ci goto nla_put_failure; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci return 0; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cinla_put_failure: 18108c2ecf20Sopenharmony_ci return -EMSGSIZE; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic struct rtnl_link_ops geneve_link_ops __read_mostly = { 18148c2ecf20Sopenharmony_ci .kind = "geneve", 18158c2ecf20Sopenharmony_ci .maxtype = IFLA_GENEVE_MAX, 18168c2ecf20Sopenharmony_ci .policy = geneve_policy, 18178c2ecf20Sopenharmony_ci .priv_size = sizeof(struct geneve_dev), 18188c2ecf20Sopenharmony_ci .setup = geneve_setup, 18198c2ecf20Sopenharmony_ci .validate = geneve_validate, 18208c2ecf20Sopenharmony_ci .newlink = geneve_newlink, 18218c2ecf20Sopenharmony_ci .changelink = geneve_changelink, 18228c2ecf20Sopenharmony_ci .dellink = geneve_dellink, 18238c2ecf20Sopenharmony_ci .get_size = geneve_get_size, 18248c2ecf20Sopenharmony_ci .fill_info = geneve_fill_info, 18258c2ecf20Sopenharmony_ci}; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_cistruct net_device *geneve_dev_create_fb(struct net *net, const char *name, 18288c2ecf20Sopenharmony_ci u8 name_assign_type, u16 dst_port) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_MAX + 1]; 18318c2ecf20Sopenharmony_ci struct net_device *dev; 18328c2ecf20Sopenharmony_ci LIST_HEAD(list_kill); 18338c2ecf20Sopenharmony_ci int err; 18348c2ecf20Sopenharmony_ci struct geneve_config cfg = { 18358c2ecf20Sopenharmony_ci .df = GENEVE_DF_UNSET, 18368c2ecf20Sopenharmony_ci .use_udp6_rx_checksums = true, 18378c2ecf20Sopenharmony_ci .ttl_inherit = false, 18388c2ecf20Sopenharmony_ci .collect_md = true, 18398c2ecf20Sopenharmony_ci }; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci memset(tb, 0, sizeof(tb)); 18428c2ecf20Sopenharmony_ci dev = rtnl_create_link(net, name, name_assign_type, 18438c2ecf20Sopenharmony_ci &geneve_link_ops, tb, NULL); 18448c2ecf20Sopenharmony_ci if (IS_ERR(dev)) 18458c2ecf20Sopenharmony_ci return dev; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci init_tnl_info(&cfg.info, dst_port); 18488c2ecf20Sopenharmony_ci err = geneve_configure(net, dev, NULL, &cfg); 18498c2ecf20Sopenharmony_ci if (err) { 18508c2ecf20Sopenharmony_ci free_netdev(dev); 18518c2ecf20Sopenharmony_ci return ERR_PTR(err); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* openvswitch users expect packet sizes to be unrestricted, 18558c2ecf20Sopenharmony_ci * so set the largest MTU we can. 18568c2ecf20Sopenharmony_ci */ 18578c2ecf20Sopenharmony_ci err = geneve_change_mtu(dev, IP_MAX_MTU); 18588c2ecf20Sopenharmony_ci if (err) 18598c2ecf20Sopenharmony_ci goto err; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci err = rtnl_configure_link(dev, NULL); 18628c2ecf20Sopenharmony_ci if (err < 0) 18638c2ecf20Sopenharmony_ci goto err; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci return dev; 18668c2ecf20Sopenharmony_cierr: 18678c2ecf20Sopenharmony_ci geneve_dellink(dev, &list_kill); 18688c2ecf20Sopenharmony_ci unregister_netdevice_many(&list_kill); 18698c2ecf20Sopenharmony_ci return ERR_PTR(err); 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(geneve_dev_create_fb); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistatic int geneve_netdevice_event(struct notifier_block *unused, 18748c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci if (event == NETDEV_UDP_TUNNEL_PUSH_INFO || 18798c2ecf20Sopenharmony_ci event == NETDEV_UDP_TUNNEL_DROP_INFO) { 18808c2ecf20Sopenharmony_ci geneve_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO); 18818c2ecf20Sopenharmony_ci } else if (event == NETDEV_UNREGISTER) { 18828c2ecf20Sopenharmony_ci if (!dev->udp_tunnel_nic_info) 18838c2ecf20Sopenharmony_ci geneve_offload_rx_ports(dev, false); 18848c2ecf20Sopenharmony_ci } else if (event == NETDEV_REGISTER) { 18858c2ecf20Sopenharmony_ci if (!dev->udp_tunnel_nic_info) 18868c2ecf20Sopenharmony_ci geneve_offload_rx_ports(dev, true); 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci return NOTIFY_DONE; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic struct notifier_block geneve_notifier_block __read_mostly = { 18938c2ecf20Sopenharmony_ci .notifier_call = geneve_netdevice_event, 18948c2ecf20Sopenharmony_ci}; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic __net_init int geneve_init_net(struct net *net) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gn->geneve_list); 19018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gn->sock_list); 19028c2ecf20Sopenharmony_ci return 0; 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_cistatic void geneve_destroy_tunnels(struct net *net, struct list_head *head) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct geneve_net *gn = net_generic(net, geneve_net_id); 19088c2ecf20Sopenharmony_ci struct geneve_dev *geneve, *next; 19098c2ecf20Sopenharmony_ci struct net_device *dev, *aux; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* gather any geneve devices that were moved into this ns */ 19128c2ecf20Sopenharmony_ci for_each_netdev_safe(net, dev, aux) 19138c2ecf20Sopenharmony_ci if (dev->rtnl_link_ops == &geneve_link_ops) 19148c2ecf20Sopenharmony_ci unregister_netdevice_queue(dev, head); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci /* now gather any other geneve devices that were created in this ns */ 19178c2ecf20Sopenharmony_ci list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) { 19188c2ecf20Sopenharmony_ci /* If geneve->dev is in the same netns, it was already added 19198c2ecf20Sopenharmony_ci * to the list by the previous loop. 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_ci if (!net_eq(dev_net(geneve->dev), net)) 19228c2ecf20Sopenharmony_ci unregister_netdevice_queue(geneve->dev, head); 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cistatic void __net_exit geneve_exit_batch_net(struct list_head *net_list) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci struct net *net; 19298c2ecf20Sopenharmony_ci LIST_HEAD(list); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci rtnl_lock(); 19328c2ecf20Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) 19338c2ecf20Sopenharmony_ci geneve_destroy_tunnels(net, &list); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci /* unregister the devices gathered above */ 19368c2ecf20Sopenharmony_ci unregister_netdevice_many(&list); 19378c2ecf20Sopenharmony_ci rtnl_unlock(); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) { 19408c2ecf20Sopenharmony_ci const struct geneve_net *gn = net_generic(net, geneve_net_id); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci WARN_ON_ONCE(!list_empty(&gn->sock_list)); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_cistatic struct pernet_operations geneve_net_ops = { 19478c2ecf20Sopenharmony_ci .init = geneve_init_net, 19488c2ecf20Sopenharmony_ci .exit_batch = geneve_exit_batch_net, 19498c2ecf20Sopenharmony_ci .id = &geneve_net_id, 19508c2ecf20Sopenharmony_ci .size = sizeof(struct geneve_net), 19518c2ecf20Sopenharmony_ci}; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic int __init geneve_init_module(void) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci int rc; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci rc = register_pernet_subsys(&geneve_net_ops); 19588c2ecf20Sopenharmony_ci if (rc) 19598c2ecf20Sopenharmony_ci goto out1; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci rc = register_netdevice_notifier(&geneve_notifier_block); 19628c2ecf20Sopenharmony_ci if (rc) 19638c2ecf20Sopenharmony_ci goto out2; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci rc = rtnl_link_register(&geneve_link_ops); 19668c2ecf20Sopenharmony_ci if (rc) 19678c2ecf20Sopenharmony_ci goto out3; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci return 0; 19708c2ecf20Sopenharmony_ciout3: 19718c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&geneve_notifier_block); 19728c2ecf20Sopenharmony_ciout2: 19738c2ecf20Sopenharmony_ci unregister_pernet_subsys(&geneve_net_ops); 19748c2ecf20Sopenharmony_ciout1: 19758c2ecf20Sopenharmony_ci return rc; 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_cilate_initcall(geneve_init_module); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_cistatic void __exit geneve_cleanup_module(void) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci rtnl_link_unregister(&geneve_link_ops); 19828c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&geneve_notifier_block); 19838c2ecf20Sopenharmony_ci unregister_pernet_subsys(&geneve_net_ops); 19848c2ecf20Sopenharmony_ci} 19858c2ecf20Sopenharmony_cimodule_exit(geneve_cleanup_module); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 19888c2ecf20Sopenharmony_ciMODULE_VERSION(GENEVE_NETDEV_VER); 19898c2ecf20Sopenharmony_ciMODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>"); 19908c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic"); 19918c2ecf20Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("geneve"); 1992