static struct vport *gre_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct net_device *dev; struct vport *vport; int err; vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms); if (IS_ERR(vport)) return vport; rtnl_lock(); dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER); if (IS_ERR(dev)) { rtnl_unlock(); ovs_vport_free(vport); return ERR_CAST(dev); } err = dev_change_flags(dev, dev->flags | IFF_UP); if (err < 0) { rtnl_delete_link(dev); rtnl_unlock(); ovs_vport_free(vport); return ERR_PTR(err); } rtnl_unlock(); return vport; }
static struct vport *vxlan_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; struct vxlan_port *vxlan_port; struct vxlan_sock *vs; struct vport *vport; struct nlattr *a; u16 dst_port; int err; if (!options) { err = -EINVAL; goto error; } a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); if (a && nla_len(a) == sizeof(u16)) { dst_port = nla_get_u16(a); } else { /* Require destination port from userspace. */ err = -EINVAL; goto error; } vport = ovs_vport_alloc(sizeof(struct vxlan_port), &ovs_vxlan_vport_ops, parms); if (IS_ERR(vport)) return vport; vxlan_port = vxlan_vport(vport); strncpy(vxlan_port->name, parms->name, IFNAMSIZ); a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); if (a) { err = vxlan_configure_exts(vport, a); if (err) { ovs_vport_free(vport); goto error; } } vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, vxlan_port->exts); if (IS_ERR(vs)) { ovs_vport_free(vport); return (void *)vs; } vxlan_port->vs = vs; return vport; error: return ERR_PTR(err); }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); err = netdev_master_upper_dev_link(netdev_vport->dev, get_dpdev(vport->dp)); if (err) goto error_unlock; err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); netdev_init(); return vport; error_master_upper_dev_unlink: netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); #ifdef HAVE_RHEL_OVS_HOOK rcu_assign_pointer(netdev_vport->dev->ax25_ptr, vport); atomic_inc(&nr_bridges); rcu_assign_pointer(openvswitch_handle_frame_hook, netdev_frame_hook); #else err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_unlock; #endif dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; #ifndef HAVE_RHEL_OVS_HOOK error_unlock: #endif rtnl_unlock(); error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static void internal_dev_destructor(struct net_device *dev) { struct vport *vport = ovs_internal_dev_get_vport(dev); ovs_vport_free(vport); free_netdev(dev); }
static void free_port_rcu(struct rcu_head *rcu) { struct netdev_vport *netdev_vport = container_of(rcu, struct netdev_vport, rcu); dev_put(netdev_vport->dev); ovs_vport_free(vport_from_priv(netdev_vport)); }
static void vport_netdev_free(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); if (vport->dev) dev_put(vport->dev); ovs_vport_free(vport); }
static void free_port_rcu(struct rcu_head *rcu) { struct patch_vport *patch_vport = container_of(rcu, struct patch_vport, rcu); kfree((struct patch_config __force *)patch_vport->patchconf); ovs_vport_free(vport_from_priv(patch_vport)); }
static void internal_dev_destructor(struct net_device *dev) { struct vport *vport = ovs_internal_dev_get_vport(dev); ovs_vport_free(vport); #ifndef HAVE_NEEDS_FREE_NETDEV free_netdev(dev); #endif }
static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; struct internal_dev *internal_dev; int err; vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } vport->dev = alloc_netdev(sizeof(struct internal_dev), parms->name, NET_NAME_USER, do_setup); if (!vport->dev) { err = -ENOMEM; goto error_free_vport; } vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!vport->dev->tstats) { err = -ENOMEM; goto error_free_netdev; } #ifdef HAVE_IFF_PHONY_HEADROOM vport->dev->needed_headroom = vport->dp->max_headroom; #endif dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); internal_dev = internal_dev_priv(vport->dev); internal_dev->vport = vport; /* Restrict bridge port to current netns. */ if (vport->port_no == OVSP_LOCAL) vport->dev->features |= NETIF_F_NETNS_LOCAL; rtnl_lock(); err = register_netdevice(vport->dev); if (err) goto error_unlock; dev_set_promiscuity(vport->dev, 1); rtnl_unlock(); netif_start_queue(vport->dev); return vport; error_unlock: rtnl_unlock(); free_percpu(vport->dev->tstats); error_free_netdev: free_netdev(vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static void netdev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); synchronize_rcu(); dev_put(netdev_vport->dev); ovs_vport_free(vport); }
static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; struct internal_dev *internal_dev; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), parms->name, NET_NAME_UNKNOWN, do_setup); if (!netdev_vport->dev) { err = -ENOMEM; goto error_free_vport; } dev_net_set(netdev_vport->dev, ovs_dp_get_net(vport->dp)); internal_dev = internal_dev_priv(netdev_vport->dev); internal_dev->vport = vport; /* Restrict bridge port to current netns. */ if (vport->port_no == OVSP_LOCAL) netdev_vport->dev->features |= NETIF_F_NETNS_LOCAL; rtnl_lock(); err = register_netdevice(netdev_vport->dev); if (err) goto error_free_netdev; dev_set_promiscuity(netdev_vport->dev, 1); rtnl_unlock(); netif_start_queue(netdev_vport->dev); return vport; error_free_netdev: rtnl_unlock(); free_netdev(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
/* * 重要!通过相应的参数进行网络设备的注册 * 何时调用? */ static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; // 看vport_netdev.h中的定义 int err; //根据具体的ovs_netdev_vport_ops和参数构造一个vport // 第一个参数代表私有数据的大小,这里正是要放struct netdev_vport vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } /* 重要!就是设置net_device两个字段 netdev_rx_handler_register - register receive handler * @dev: device to register a handler for * @rx_handler: receive handler to register * @rx_handler_data: data pointer that is used by rx handler */ err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_put; dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; return vport; error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static void free_port_rcu(struct rcu_head *rcu) { struct netdev_vport *netdev_vport = container_of(rcu, struct netdev_vport, rcu); #ifdef HAVE_RHEL_OVS_HOOK rcu_assign_pointer(netdev_vport->dev->ax25_ptr, NULL); if (atomic_dec_and_test(&nr_bridges)) rcu_assign_pointer(openvswitch_handle_frame_hook, NULL); #endif dev_put(netdev_vport->dev); ovs_vport_free(vport_from_priv(netdev_vport)); }
static struct vport *patch_create(const struct vport_parms *parms) { struct vport *vport; struct patch_vport *patch_vport; const char *peer_name; struct patch_config *patchconf; struct net *net = ovs_dp_get_net(parms->dp); int err; vport = ovs_vport_alloc(sizeof(struct patch_vport), &ovs_patch_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } patch_vport = patch_vport_priv(vport); strcpy(patch_vport->name, parms->name); patchconf = kmalloc(sizeof(struct patch_config), GFP_KERNEL); if (!patchconf) { err = -ENOMEM; goto error_free_vport; } err = patch_set_config(vport, parms->options, patchconf); if (err) goto error_free_patchconf; random_ether_addr(patchconf->eth_addr); rcu_assign_pointer(patch_vport->patchconf, patchconf); peer_name = patchconf->peer_name; hlist_add_head(&patch_vport->hash_node, hash_bucket(net, peer_name)); rcu_assign_pointer(patch_vport->peer, ovs_vport_locate(net, peer_name)); update_peers(net, patch_vport->name, vport); return vport; error_free_patchconf: kfree(patchconf); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
struct vport *ovs_netdev_link(struct vport *vport, const char *name) { int err; vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), name); if (!vport->dev) { err = -ENODEV; goto error_free_vport; } if (vport->dev->flags & IFF_LOOPBACK || (vport->dev->type != ARPHRD_ETHER && vport->dev->type != ARPHRD_NONE) || ovs_is_internal_dev(vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); err = netdev_master_upper_dev_link(vport->dev, get_dpdev(vport->dp), NULL, NULL, NULL); if (err) goto error_unlock; err = netdev_rx_handler_register(vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; dev_disable_lro(vport->dev); dev_set_promiscuity(vport->dev, 1); vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; error_master_upper_dev_unlink: netdev_upper_dev_unlink(vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: dev_put(vport->dev); error_free_vport: ovs_vport_free(vport); return ERR_PTR(err); }
static struct vport *geneve_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; struct geneve_port *geneve_port; struct net_device *dev; struct vport *vport; struct nlattr *a; u16 dst_port; int err; if (!options) { err = -EINVAL; goto error; } a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); if (a && nla_len(a) == sizeof(u16)) { dst_port = nla_get_u16(a); } else { /* Require destination port from userspace. */ err = -EINVAL; goto error; } vport = ovs_vport_alloc(sizeof(struct geneve_port), &ovs_geneve_vport_ops, parms); if (IS_ERR(vport)) return vport; geneve_port = geneve_vport(vport); geneve_port->dst_port = dst_port; rtnl_lock(); dev = geneve_dev_create_fb(net, parms->name, NET_NAME_USER, dst_port); if (IS_ERR(dev)) { rtnl_unlock(); ovs_vport_free(vport); return ERR_CAST(dev); } dev_change_flags(dev, dev->flags | IFF_UP); rtnl_unlock(); return vport; error: return ERR_PTR(err); }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(&init_net, parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_put; dev_set_promiscuity(netdev_vport->dev, 1); netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; return vport; error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static struct vport *stt_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; struct stt_port *stt_port; struct stt_sock *stt_sock; struct vport *vport; struct nlattr *a; int err; u16 dst_port; if (!options) { err = -EINVAL; goto error; } a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); if (a && nla_len(a) == sizeof(u16)) { dst_port = nla_get_u16(a); } else { /* Require destination port from userspace. */ err = -EINVAL; goto error; } vport = ovs_vport_alloc(sizeof(struct stt_port), &ovs_stt_vport_ops, parms); if (IS_ERR(vport)) return vport; stt_port = stt_vport(vport); strncpy(stt_port->name, parms->name, IFNAMSIZ); stt_sock = stt_sock_add(net, htons(dst_port), stt_rcv, vport); if (IS_ERR(stt_sock)) { ovs_vport_free(vport); return ERR_CAST(stt_sock); } stt_port->stt_sock = stt_sock; return vport; error: return ERR_PTR(err); }
static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; struct internal_dev *internal_dev; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), parms->name, do_setup); if (!netdev_vport->dev) { err = -ENOMEM; goto error_free_vport; } internal_dev = internal_dev_priv(netdev_vport->dev); internal_dev->vport = vport; err = register_netdevice(netdev_vport->dev); if (err) goto error_free_netdev; dev_set_promiscuity(netdev_vport->dev, 1); netif_start_queue(netdev_vport->dev); return vport; error_free_netdev: free_netdev(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static struct vport *vxlan_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; struct net_device *dev; struct vport *vport; struct nlattr *a; int err; struct vxlan_config conf = { .no_share = true, .flags = VXLAN_F_COLLECT_METADATA, }; if (!options) { err = -EINVAL; goto error; } a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); if (a && nla_len(a) == sizeof(u16)) { conf.dst_port = htons(nla_get_u16(a)); } else { /* Require destination port from userspace. */ err = -EINVAL; goto error; } vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms); if (IS_ERR(vport)) return vport; a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); if (a) { err = vxlan_configure_exts(vport, a, &conf); if (err) { ovs_vport_free(vport); goto error; } } rtnl_lock(); dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf); if (IS_ERR(dev)) { rtnl_unlock(); ovs_vport_free(vport); return ERR_CAST(dev); } dev_change_flags(dev, dev->flags | IFF_UP); rtnl_unlock(); return vport; error: return ERR_PTR(err); } static struct vport *vxlan_create(const struct vport_parms *parms) { struct vport *vport; vport = vxlan_tnl_create(parms); if (IS_ERR(vport)) return vport; return ovs_netdev_link(vport, parms->name); } static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct dp_upcall_info *upcall) { struct vxlan_dev *vxlan = netdev_priv(vport->dev); struct net *net = ovs_dp_get_net(vport->dp); unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info); __be16 dst_port = vxlan_dev_dst_port(vxlan, family); __be16 src_port; int port_min; int port_max; inet_get_local_port_range(net, &port_min, &port_max); src_port = udp_flow_src_port(net, skb, 0, 0, true); return ovs_tunnel_get_egress_info(upcall, net, skb, IPPROTO_UDP, src_port, dst_port); } static struct vport_ops ovs_vxlan_netdev_vport_ops = { .type = OVS_VPORT_TYPE_VXLAN, .create = vxlan_create, .destroy = ovs_netdev_tunnel_destroy, .get_options = vxlan_get_options, .send = ovs_netdev_send, .get_egress_tun_info = vxlan_get_egress_tun_info, }; static int __init ovs_vxlan_tnl_init(void) { return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops); } static void __exit ovs_vxlan_tnl_exit(void) { ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops); }
static void free_vport_rcu(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); ovs_vport_free(vport); }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); //TODO:这里直接获取, 原因 netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); /** * netdev_master_upper_dev_link - Add a master link to the upper device * @dev: device * @upper_dev: new upper device * * Adds a link to device which is upper to this one. In this case, only * one master upper device can be linked, although other non-master devices * might be linked as well. The caller must hold the RTNL lock. * On a failure a negative errno code is returned. On success the reference * counts are adjusted and the function returns zero. */ err = netdev_master_upper_dev_link(netdev_vport->dev, get_dpdev(vport->dp)); if (err) goto error_unlock; /** * netdev_rx_handler_register - register receive handler * @dev: device to register a handler for * @rx_handler: receive handler to register * @rx_handler_data: data pointer that is used by rx handler * * Register a receive handler for a device. This handler will then be * called from __netif_receive_skb. A negative errno code is returned * on a failure. * * The caller must hold the rtnl_mutex. * * For a general description of rx_handler, see enum rx_handler_result. */ err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; dev_set_promiscuity(netdev_vport->dev, 1); netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; error_master_upper_dev_unlink: netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }