18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2012 Nicira, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <net/dst.h> 148c2ecf20Sopenharmony_ci#include <net/xfrm.h> 158c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "datapath.h" 188c2ecf20Sopenharmony_ci#include "vport-internal_dev.h" 198c2ecf20Sopenharmony_ci#include "vport-netdev.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct internal_dev { 228c2ecf20Sopenharmony_ci struct vport *vport; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct vport_ops ovs_internal_vport_ops; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct internal_dev *internal_dev_priv(struct net_device *netdev) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci return netdev_priv(netdev); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Called with rcu_read_lock_bh. */ 338c2ecf20Sopenharmony_cistatic netdev_tx_t 348c2ecf20Sopenharmony_ciinternal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int len, err; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci len = skb->len; 398c2ecf20Sopenharmony_ci rcu_read_lock(); 408c2ecf20Sopenharmony_ci err = ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL); 418c2ecf20Sopenharmony_ci rcu_read_unlock(); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (likely(!err)) { 448c2ecf20Sopenharmony_ci struct pcpu_sw_netstats *tstats = this_cpu_ptr(netdev->tstats); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci u64_stats_update_begin(&tstats->syncp); 478c2ecf20Sopenharmony_ci tstats->tx_bytes += len; 488c2ecf20Sopenharmony_ci tstats->tx_packets++; 498c2ecf20Sopenharmony_ci u64_stats_update_end(&tstats->syncp); 508c2ecf20Sopenharmony_ci } else { 518c2ecf20Sopenharmony_ci netdev->stats.tx_errors++; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int internal_dev_open(struct net_device *netdev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci netif_start_queue(netdev); 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int internal_dev_stop(struct net_device *netdev) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci netif_stop_queue(netdev); 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void internal_dev_getinfo(struct net_device *netdev, 698c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci strlcpy(info->driver, "openvswitch", sizeof(info->driver)); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const struct ethtool_ops internal_dev_ethtool_ops = { 758c2ecf20Sopenharmony_ci .get_drvinfo = internal_dev_getinfo, 768c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void internal_dev_destructor(struct net_device *dev) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct vport *vport = ovs_internal_dev_get_vport(dev); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ovs_vport_free(vport); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void 878c2ecf20Sopenharmony_ciinternal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 908c2ecf20Sopenharmony_ci stats->rx_errors = dev->stats.rx_errors; 918c2ecf20Sopenharmony_ci stats->tx_errors = dev->stats.tx_errors; 928c2ecf20Sopenharmony_ci stats->tx_dropped = dev->stats.tx_dropped; 938c2ecf20Sopenharmony_ci stats->rx_dropped = dev->stats.rx_dropped; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci dev_fetch_sw_netstats(stats, dev->tstats); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct net_device_ops internal_dev_netdev_ops = { 998c2ecf20Sopenharmony_ci .ndo_open = internal_dev_open, 1008c2ecf20Sopenharmony_ci .ndo_stop = internal_dev_stop, 1018c2ecf20Sopenharmony_ci .ndo_start_xmit = internal_dev_xmit, 1028c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 1038c2ecf20Sopenharmony_ci .ndo_get_stats64 = internal_get_stats, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic struct rtnl_link_ops internal_dev_link_ops __read_mostly = { 1078c2ecf20Sopenharmony_ci .kind = "openvswitch", 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void do_setup(struct net_device *netdev) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci ether_setup(netdev); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci netdev->max_mtu = ETH_MAX_MTU; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci netdev->netdev_ops = &internal_dev_netdev_ops; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci netdev->priv_flags &= ~IFF_TX_SKB_SHARING; 1198c2ecf20Sopenharmony_ci netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH | 1208c2ecf20Sopenharmony_ci IFF_NO_QUEUE; 1218c2ecf20Sopenharmony_ci netdev->needs_free_netdev = true; 1228c2ecf20Sopenharmony_ci netdev->priv_destructor = NULL; 1238c2ecf20Sopenharmony_ci netdev->ethtool_ops = &internal_dev_ethtool_ops; 1248c2ecf20Sopenharmony_ci netdev->rtnl_link_ops = &internal_dev_link_ops; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | 1278c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | 1288c2ecf20Sopenharmony_ci NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci netdev->vlan_features = netdev->features; 1318c2ecf20Sopenharmony_ci netdev->hw_enc_features = netdev->features; 1328c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; 1338c2ecf20Sopenharmony_ci netdev->hw_features = netdev->features & ~NETIF_F_LLTX; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci eth_hw_addr_random(netdev); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic struct vport *internal_dev_create(const struct vport_parms *parms) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct vport *vport; 1418c2ecf20Sopenharmony_ci struct internal_dev *internal_dev; 1428c2ecf20Sopenharmony_ci struct net_device *dev; 1438c2ecf20Sopenharmony_ci int err; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms); 1468c2ecf20Sopenharmony_ci if (IS_ERR(vport)) { 1478c2ecf20Sopenharmony_ci err = PTR_ERR(vport); 1488c2ecf20Sopenharmony_ci goto error; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci dev = alloc_netdev(sizeof(struct internal_dev), 1528c2ecf20Sopenharmony_ci parms->name, NET_NAME_USER, do_setup); 1538c2ecf20Sopenharmony_ci vport->dev = dev; 1548c2ecf20Sopenharmony_ci if (!vport->dev) { 1558c2ecf20Sopenharmony_ci err = -ENOMEM; 1568c2ecf20Sopenharmony_ci goto error_free_vport; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 1598c2ecf20Sopenharmony_ci if (!vport->dev->tstats) { 1608c2ecf20Sopenharmony_ci err = -ENOMEM; 1618c2ecf20Sopenharmony_ci goto error_free_netdev; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); 1658c2ecf20Sopenharmony_ci internal_dev = internal_dev_priv(vport->dev); 1668c2ecf20Sopenharmony_ci internal_dev->vport = vport; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Restrict bridge port to current netns. */ 1698c2ecf20Sopenharmony_ci if (vport->port_no == OVSP_LOCAL) 1708c2ecf20Sopenharmony_ci vport->dev->features |= NETIF_F_NETNS_LOCAL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci rtnl_lock(); 1738c2ecf20Sopenharmony_ci err = register_netdevice(vport->dev); 1748c2ecf20Sopenharmony_ci if (err) 1758c2ecf20Sopenharmony_ci goto error_unlock; 1768c2ecf20Sopenharmony_ci vport->dev->priv_destructor = internal_dev_destructor; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dev_set_promiscuity(vport->dev, 1); 1798c2ecf20Sopenharmony_ci rtnl_unlock(); 1808c2ecf20Sopenharmony_ci netif_start_queue(vport->dev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return vport; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cierror_unlock: 1858c2ecf20Sopenharmony_ci rtnl_unlock(); 1868c2ecf20Sopenharmony_ci free_percpu(dev->tstats); 1878c2ecf20Sopenharmony_cierror_free_netdev: 1888c2ecf20Sopenharmony_ci free_netdev(dev); 1898c2ecf20Sopenharmony_cierror_free_vport: 1908c2ecf20Sopenharmony_ci ovs_vport_free(vport); 1918c2ecf20Sopenharmony_cierror: 1928c2ecf20Sopenharmony_ci return ERR_PTR(err); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void internal_dev_destroy(struct vport *vport) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci netif_stop_queue(vport->dev); 1988c2ecf20Sopenharmony_ci rtnl_lock(); 1998c2ecf20Sopenharmony_ci dev_set_promiscuity(vport->dev, -1); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* unregister_netdevice() waits for an RCU grace period. */ 2028c2ecf20Sopenharmony_ci unregister_netdevice(vport->dev); 2038c2ecf20Sopenharmony_ci free_percpu(vport->dev->tstats); 2048c2ecf20Sopenharmony_ci rtnl_unlock(); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic netdev_tx_t internal_dev_recv(struct sk_buff *skb) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct net_device *netdev = skb->dev; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (unlikely(!(netdev->flags & IFF_UP))) { 2128c2ecf20Sopenharmony_ci kfree_skb(skb); 2138c2ecf20Sopenharmony_ci netdev->stats.rx_dropped++; 2148c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci skb_dst_drop(skb); 2188c2ecf20Sopenharmony_ci nf_reset_ct(skb); 2198c2ecf20Sopenharmony_ci secpath_reset(skb); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 2228c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 2238c2ecf20Sopenharmony_ci skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 2248c2ecf20Sopenharmony_ci dev_sw_netstats_rx_add(netdev, skb->len); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci netif_rx(skb); 2278c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic struct vport_ops ovs_internal_vport_ops = { 2318c2ecf20Sopenharmony_ci .type = OVS_VPORT_TYPE_INTERNAL, 2328c2ecf20Sopenharmony_ci .create = internal_dev_create, 2338c2ecf20Sopenharmony_ci .destroy = internal_dev_destroy, 2348c2ecf20Sopenharmony_ci .send = internal_dev_recv, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint ovs_is_internal_dev(const struct net_device *netdev) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci return netdev->netdev_ops == &internal_dev_netdev_ops; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistruct vport *ovs_internal_dev_get_vport(struct net_device *netdev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci if (!ovs_is_internal_dev(netdev)) 2458c2ecf20Sopenharmony_ci return NULL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return internal_dev_priv(netdev)->vport; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciint ovs_internal_dev_rtnl_link_register(void) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci int err; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci err = rtnl_link_register(&internal_dev_link_ops); 2558c2ecf20Sopenharmony_ci if (err < 0) 2568c2ecf20Sopenharmony_ci return err; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci err = ovs_vport_ops_register(&ovs_internal_vport_ops); 2598c2ecf20Sopenharmony_ci if (err < 0) 2608c2ecf20Sopenharmony_ci rtnl_link_unregister(&internal_dev_link_ops); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return err; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_civoid ovs_internal_dev_rtnl_link_unregister(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci ovs_vport_ops_unregister(&ovs_internal_vport_ops); 2688c2ecf20Sopenharmony_ci rtnl_link_unregister(&internal_dev_link_ops); 2698c2ecf20Sopenharmony_ci} 270