/* holding rtnl */ static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf) { struct rtable *rth = rtnl_dereference(vrf->rth); struct rtable *rth_local = rtnl_dereference(vrf->rth_local); struct net *net = dev_net(dev); struct dst_entry *dst; RCU_INIT_POINTER(vrf->rth, NULL); RCU_INIT_POINTER(vrf->rth_local, NULL); synchronize_rcu(); /* move dev in dst's to loopback so this VRF device can be deleted * - based on dst_ifdown */ if (rth) { dst = &rth->dst; dev_put(dst->dev); dst->dev = net->loopback_dev; dev_hold(dst->dev); dst_release(dst); } if (rth_local) { dst = &rth_local->dst; dev_put(dst->dev); dst->dev = net->loopback_dev; dev_hold(dst->dev); dst_release(dst); } }
void bnxt_ulp_irq_restart(struct bnxt *bp, int err) { struct bnxt_en_dev *edev = bp->edev; struct bnxt_ulp_ops *ops; if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED)) return; if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) { struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP]; struct bnxt_msix_entry *ent = NULL; if (!ulp->msix_requested) return; ops = rtnl_dereference(ulp->ulp_ops); if (!ops || !ops->ulp_irq_restart) return; if (!err) { ent = kcalloc(ulp->msix_requested, sizeof(*ent), GFP_KERNEL); if (!ent) return; bnxt_fill_msix_vecs(bp, ent); } ops->ulp_irq_restart(ulp->handle, ent); kfree(ent); } }
void qdisc_destroy(struct Qdisc *qdisc) { const struct Qdisc_ops *ops = qdisc->ops; if (qdisc->flags & TCQ_F_BUILTIN || !atomic_dec_and_test(&qdisc->refcnt)) return; #ifdef CONFIG_NET_SCHED qdisc_list_del(qdisc); qdisc_put_stab(rtnl_dereference(qdisc->stab)); #endif gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); if (ops->reset) ops->reset(qdisc); if (ops->destroy) ops->destroy(qdisc); module_put(ops->owner); dev_put(qdisc_dev(qdisc)); kfree_skb_list(qdisc->gso_skb); /* * gen_estimator est_timer() might access qdisc->q.lock, * wait a RCU grace period before freeing qdisc. */ call_rcu(&qdisc->rcu_head, qdisc_rcu_free); }
/* Must be protected by RTNL */ int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) { struct net_port_vlans *pv = NULL; int err; ASSERT_RTNL(); pv = rtnl_dereference(br->vlan_info); if (pv) return __vlan_add(pv, vid, flags); /* Create port vlan infomration */ pv = kzalloc(sizeof(*pv), GFP_KERNEL); if (!pv) return -ENOMEM; pv->parent.br = br; err = __vlan_add(pv, vid, flags); if (err) goto out; rcu_assign_pointer(br->vlan_info, pv); return 0; out: kfree(pv); return err; }
/** * tipc_l2_device_event - handle device events from network device * @nb: the context of the notification * @evt: the type of event * @ptr: the net device that the event was on * * This function is called by the Ethernet driver in case of link * change event. */ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, void *ptr) { struct tipc_bearer *b_ptr; struct net_device *dev = netdev_notifier_info_to_dev(ptr); if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; b_ptr = rtnl_dereference(dev->tipc_ptr); if (!b_ptr) return NOTIFY_DONE; b_ptr->mtu = dev->mtu; switch (evt) { case NETDEV_CHANGE: if (netif_carrier_ok(dev)) break; case NETDEV_DOWN: case NETDEV_CHANGEMTU: tipc_reset_bearer(b_ptr); break; case NETDEV_CHANGEADDR: b_ptr->media->raw2addr(b_ptr, &b_ptr->addr, (char *)dev->dev_addr); tipc_reset_bearer(b_ptr); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: bearer_disable(b_ptr, false); break; } return NOTIFY_OK; }
static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc) { struct net_device_context *ndc = netdev_priv(dev); struct netvsc_device *ndev = rtnl_dereference(ndc->nvdev); struct rndis_device *rndis_dev; int i; if (!ndev) return -ENODEV; if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; rndis_dev = ndev->extension; if (indir) { for (i = 0; i < ITAB_NUM; i++) if (indir[i] >= VRSS_CHANNEL_MAX) return -EINVAL; for (i = 0; i < ITAB_NUM; i++) rndis_dev->ind_table[i] = indir[i]; } if (!key) { if (!indir) return 0; key = rndis_dev->rss_key; } return rndis_filter_set_rss_param(rndis_dev, key, ndev->num_chn); }
int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb) { int err; int i = cb->args[0]; struct tipc_bearer *bearer; struct tipc_nl_msg msg; struct net *net = sock_net(skb->sk); struct tipc_net *tn = net_generic(net, tipc_net_id); if (i == MAX_BEARERS) return 0; msg.skb = skb; msg.portid = NETLINK_CB(cb->skb).portid; msg.seq = cb->nlh->nlmsg_seq; rtnl_lock(); for (i = 0; i < MAX_BEARERS; i++) { bearer = rtnl_dereference(tn->bearer_list[i]); if (!bearer) continue; err = __tipc_nl_add_bearer(&msg, bearer); if (err) break; } rtnl_unlock(); cb->args[0] = i; return skb->len; }
static int patch_set_options(struct vport *vport, struct nlattr *options) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct patch_config *patchconf; int err; patchconf = kmemdup(rtnl_dereference(patch_vport->patchconf), sizeof(struct patch_config), GFP_KERNEL); if (!patchconf) { err = -ENOMEM; goto error; } err = patch_set_config(vport, options, patchconf); if (err) goto error_free; assign_config_rcu(vport, patchconf); hlist_del(&patch_vport->hash_node); rcu_assign_pointer(patch_vport->peer, ovs_vport_locate(ovs_dp_get_net(vport->dp), patchconf->peer_name)); hlist_add_head(&patch_vport->hash_node, hash_bucket(ovs_dp_get_net(vport->dp), patchconf->peer_name)); return 0; error_free: kfree(patchconf); error: return err; }
static void netvsc_set_multicast_list(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); rndis_filter_update(nvdev); }
void unregister_vlan_dev(struct net_device *dev, struct list_head *head) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev = vlan->real_dev; struct vlan_info *vlan_info; struct vlan_group *grp; u16 vlan_id = vlan->vlan_id; ASSERT_RTNL(); vlan_info = rtnl_dereference(real_dev->vlan_info); BUG_ON(!vlan_info); grp = &vlan_info->grp; if (vlan_id) vlan_vid_del(real_dev, vlan_id); grp->nr_vlan_devs--; if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_leave(dev); vlan_group_set_device(grp, vlan_id, NULL); unregister_netdevice_queue(dev, head); if (grp->nr_vlan_devs == 0) vlan_gvrp_uninit_applicant(real_dev); dev_put(real_dev); }
static struct net *vxcan_get_link_net(const struct net_device *dev) { struct vxcan_priv *priv = netdev_priv(dev); struct net_device *peer = rtnl_dereference(priv->peer); return peer ? dev_net(peer) : dev_net(dev); }
/* Must be protected by RTNL */ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) { struct net_port_vlans *pv = NULL; int err; ASSERT_RTNL(); pv = rtnl_dereference(port->vlan_info); if (pv) return __vlan_add(pv, vid, flags); /* Create port vlan infomration */ pv = kzalloc(sizeof(*pv), GFP_KERNEL); if (!pv) { err = -ENOMEM; goto clean_up; } pv->port_idx = port->port_no; pv->parent.port = port; err = __vlan_add(pv, vid, flags); if (err) goto clean_up; rcu_assign_pointer(port->vlan_info, pv); return 0; clean_up: kfree(pv); return err; }
int register_vlan_dev(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; u16 vlan_id = vlan->vlan_id; struct vlan_group *grp, *ngrp = NULL; int err; grp = rtnl_dereference(real_dev->vlgrp); if (!grp) { ngrp = grp = vlan_group_alloc(real_dev); if (!grp) return -ENOBUFS; err = vlan_gvrp_init_applicant(real_dev); if (err < 0) goto out_free_group; } err = vlan_group_prealloc_vid(grp, vlan_id); if (err < 0) goto out_uninit_applicant; err = register_netdevice(dev); if (err < 0) goto out_uninit_applicant; /* Account for reference in struct vlan_dev_info */ dev_hold(real_dev); netif_stacked_transfer_operstate(real_dev, dev); linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place * it into our local structure. */ vlan_group_set_device(grp, vlan_id, dev); grp->nr_vlans++; if (ngrp) { if (ops->ndo_vlan_rx_register) ops->ndo_vlan_rx_register(real_dev, ngrp); rcu_assign_pointer(real_dev->vlgrp, ngrp); } if (real_dev->features & NETIF_F_HW_VLAN_FILTER) ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); return 0; out_uninit_applicant: if (ngrp) vlan_gvrp_uninit_applicant(real_dev); out_free_group: if (ngrp) { /* Free the group, after all cpu's are done. */ call_rcu(&ngrp->rcu, vlan_rcu_free); } return err; }
static void veth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct veth_priv *priv = netdev_priv(dev); struct net_device *peer = rtnl_dereference(priv->peer); data[0] = peer ? peer->ifindex : 0; }
static void tcf_sample_cleanup(struct tc_action *a) { struct tcf_sample *s = to_sample(a); struct psample_group *psample_group; psample_group = rtnl_dereference(s->psample_group); RCU_INIT_POINTER(s->psample_group, NULL); psample_group_put(psample_group); }
/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface * * Mark L2 bearer as inactive so that incoming buffers are thrown away */ void tipc_disable_l2_media(struct tipc_bearer *b) { struct net_device *dev; dev = (struct net_device *)rtnl_dereference(b->media_ptr); RCU_INIT_POINTER(dev->tipc_ptr, NULL); synchronize_net(); dev_put(dev); }
/* holding rtnl */ static void vrf_rt6_release(struct net_vrf *vrf) { struct rt6_info *rt6 = rtnl_dereference(vrf->rt6); rcu_assign_pointer(vrf->rt6, NULL); if (rt6) dst_release(&rt6->dst); }
static unsigned long mall_get(struct tcf_proto *tp, u32 handle) { struct cls_mall_head *head = rtnl_dereference(tp->root); struct cls_mall_filter *f = head->filter; if (f && f->handle == handle) return (unsigned long) f; return 0; }
/* holding rtnl */ static void vrf_rtable_release(struct net_vrf *vrf) { struct rtable *rth = rtnl_dereference(vrf->rth); rcu_assign_pointer(vrf->rth, NULL); if (rth) dst_release(&rth->dst); }
static void assign_config_rcu(struct vport *vport, struct patch_config *new_config) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct patch_config *old_config; old_config = rtnl_dereference(patch_vport->patchconf); rcu_assign_pointer(patch_vport->patchconf, new_config); call_rcu(&old_config->rcu, free_config); }
static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, struct rtnl_link_ops *ops) { struct ip_tunnel *t; t = rtnl_dereference(itn->collect_md_tun); if (!t) return; unregister_netdevice_queue(t->dev, head); }
void br_vlan_flush(struct net_bridge *br) { struct net_port_vlans *pv; ASSERT_RTNL(); pv = rtnl_dereference(br->vlan_info); if (!pv) return; __vlan_flush(pv); }
static void netvsc_get_channels(struct net_device *net, struct ethtool_channels *channel) { struct net_device_context *net_device_ctx = netdev_priv(net); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); if (nvdev) { channel->max_combined = nvdev->max_chn; channel->combined_count = nvdev->num_chn; } }
static int veth_close(struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); struct net_device *peer = rtnl_dereference(priv->peer); netif_carrier_off(dev); if (peer) netif_carrier_off(peer); return 0; }
static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); int ret; u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20; struct vmbus_channel *chn; netif_tx_disable(net); ret = rndis_filter_close(nvdev); if (ret != 0) { netdev_err(net, "unable to close device (ret %d).\n", ret); return ret; } /* Ensure pending bytes in ring are read */ while (true) { aread = 0; for (i = 0; i < nvdev->num_chn; i++) { chn = nvdev->chan_table[i].channel; if (!chn) continue; hv_get_ringbuffer_availbytes(&chn->inbound, &aread, &awrite); if (aread) break; hv_get_ringbuffer_availbytes(&chn->outbound, &aread, &awrite); if (aread) break; } retry++; if (retry > retry_max || aread == 0) break; msleep(msec); if (msec < 1000) msec *= 2; } if (aread) { netdev_err(net, "Ring buffer not empty after closing rndis\n"); ret = -ETIMEDOUT; } return ret; }
int register_vlan_dev(struct net_device *dev) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev = vlan->real_dev; u16 vlan_id = vlan->vlan_id; struct vlan_info *vlan_info; struct vlan_group *grp; int err; err = vlan_vid_add(real_dev, vlan_id); if (err) return err; vlan_info = rtnl_dereference(real_dev->vlan_info); /* vlan_info should be there now. vlan_vid_add took care of it */ BUG_ON(!vlan_info); grp = &vlan_info->grp; if (grp->nr_vlan_devs == 0) { err = vlan_gvrp_init_applicant(real_dev); if (err < 0) goto out_vid_del; } err = vlan_group_prealloc_vid(grp, vlan_id); if (err < 0) goto out_uninit_applicant; err = register_netdevice(dev); if (err < 0) goto out_uninit_applicant; /* Account for reference in struct vlan_dev_priv */ dev_hold(real_dev); netif_stacked_transfer_operstate(real_dev, dev); linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place * it into our local structure. */ vlan_group_set_device(grp, vlan_id, dev); grp->nr_vlan_devs++; return 0; out_uninit_applicant: if (grp->nr_vlan_devs == 0) vlan_gvrp_uninit_applicant(real_dev); out_vid_del: vlan_vid_del(real_dev, vlan_id); return err; }
static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg) { struct cls_mall_head *head = rtnl_dereference(tp->root); struct cls_mall_filter *f = head->filter; if (arg->count < arg->skip) goto skip; if (arg->fn(tp, (unsigned long) f, arg) < 0) arg->stop = 1; skip: arg->count++; }
/** * tipc_bearer_find - locates bearer object with matching bearer name */ struct tipc_bearer *tipc_bearer_find(const char *name) { struct tipc_bearer *b_ptr; u32 i; for (i = 0; i < MAX_BEARERS; i++) { b_ptr = rtnl_dereference(bearer_list[i]); if (b_ptr && (!strcmp(b_ptr->name, name))) return b_ptr; } return NULL; }
void nbp_vlan_flush(struct net_bridge_port *port) { struct net_port_vlans *pv; ASSERT_RTNL(); pv = rtnl_dereference(port->vlan_info); if (!pv) return; __vlan_flush(pv); }
void tipc_bearer_stop(void) { struct tipc_bearer *b_ptr; u32 i; for (i = 0; i < MAX_BEARERS; i++) { b_ptr = rtnl_dereference(bearer_list[i]); if (b_ptr) { bearer_disable(b_ptr, true); bearer_list[i] = NULL; } } }