/** * ovs_vport_del - delete existing vport device * * @vport: vport to delete. * * Detaches @vport from its datapath and destroys it. It is possible to fail * for reasons such as lack of memory. ovs_mutex must be held. */ void ovs_vport_del(struct vport *vport) { ASSERT_OVSL(); hlist_del_rcu(&vport->hash_node); vport->ops->destroy(vport); }
void vxbox_flow_free(struct sw_flow *flow, bool deferred) { if (!flow) return; if (flow->mask) { struct sw_flow_mask *mask = flow->mask; /* vxbox-lock is required to protect mask-refcount and * mask list. */ ASSERT_OVSL(); BUG_ON(!mask->ref_count); mask->ref_count--; if (!mask->ref_count) { list_del_rcu(&mask->list); if (deferred) call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb); else kfree(mask); } } if (deferred) call_rcu(&flow->rcu, rcu_free_flow_callback); else flow_free(flow); }
/** * ovs_vport_del - delete existing vport device * * @vport: vport to delete. * * Detaches @vport from its datapath and destroys it. It is possible to fail * for reasons such as lack of memory. ovs_mutex must be held. */ void ovs_vport_del(struct vport *vport) { ASSERT_OVSL(); //将 vport->hash_node 从其对应的链表中删除; hlist_del_rcu(&vport->hash_node); //递减 vport->ops->owner 的引用计数 module_put(vport->ops->owner); vport->ops->destroy(vport); }
void vxlan_sock_release(struct vxlan_sock *vs) { ASSERT_OVSL(); queue_work(system_wq, &vs->del_work); }
static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, vxlan_rcv_t *rcv, void *data) { struct vxlan_sock *vs; struct sock *sk; struct sockaddr_in vxlan_addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_ANY), .sin_port = port, }; int rc; vs = kmalloc(sizeof(*vs), GFP_KERNEL); if (!vs) { pr_debug("memory alocation failure\n"); return ERR_PTR(-ENOMEM); } INIT_WORK(&vs->del_work, vxlan_del_work); /* Create UDP socket for encapsulation receive. */ rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vs->sock); if (rc < 0) { pr_debug("UDP socket create failed\n"); kfree(vs); return ERR_PTR(rc); } /* Put in proper namespace */ sk = vs->sock->sk; sk_change_net(sk, net); rc = kernel_bind(vs->sock, (struct sockaddr *) &vxlan_addr, sizeof(vxlan_addr)); if (rc < 0) { pr_debug("bind for UDP socket %pI4:%u (%d)\n", &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc); sk_release_kernel(sk); kfree(vs); return ERR_PTR(rc); } vs->rcv = rcv; vs->data = data; /* Disable multicast loopback */ inet_sk(sk)->mc_loop = 0; rcu_assign_sk_user_data(vs->sock->sk, vs); /* Mark socket as an encapsulation socket. */ udp_sk(sk)->encap_type = 1; udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv; udp_encap_enable(); return vs; } struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, vxlan_rcv_t *rcv, void *data, bool no_share, u32 flags) { return vxlan_socket_create(net, port, rcv, data); } void vxlan_sock_release(struct vxlan_sock *vs) { ASSERT_OVSL(); rcu_assign_sk_user_data(vs->sock->sk, NULL); queue_work(system_wq, &vs->del_work); }