int mpls_insert_nhlfe (unsigned int key, struct mpls_nhlfe *nhlfe) { int retval = 0; retval = radix_tree_insert (&mpls_nhlfe_tree, key, nhlfe); if (unlikely(retval)) retval = -ENOMEM; list_add_rcu(&nhlfe->global, &mpls_nhlfe_list); /* hold it for being in the tree */ mpls_nhlfe_hold (nhlfe); return retval; }
struct mpls_nhlfe* mpls_get_nhlfe (unsigned int key) { struct mpls_nhlfe *nhlfe = NULL; rcu_read_lock(); nhlfe = radix_tree_lookup (&mpls_nhlfe_tree, key); smp_read_barrier_depends(); if (likely(nhlfe)) { mpls_nhlfe_hold(nhlfe); } rcu_read_unlock(); return nhlfe; }
inline MPLS_OUT_OPCODE_PROTOTYPE(mpls_out_op_set) { struct dst_entry *dst = &(_mpls_as_nhlfe(data))->dst; MPLS_ENTER; /* Don't hold the dev we place in skb->dev, the dst is already holding it for us */ skb_set_dev(*pskb, dst->dev); mpls_nhlfe_hold(*nhlfe); /* dst_hold */ /* * Update the dst field of the skbuff in "real time" */ skb_dst_set(*pskb, dst); MPLS_EXIT; return MPLS_RESULT_SUCCESS; }
int mpls_add_out_label (struct mpls_out_label_req *out, int seq, int pid) { struct mpls_nhlfe *nhlfe = NULL; unsigned int key = 0; int retval = 0; MPLS_ENTER; BUG_ON(!out); /* Create a new key */ key = mpls_get_out_key(); /* * Check if the NHLFE is already in the tree. * It should not exist. In fact, it is impossible :) */ nhlfe = mpls_get_nhlfe (key); if (unlikely(nhlfe)) { MPLS_DEBUG("Node %u already exists in radix tree\n",key); /* release the refcnt held by mpls_get_nhlfe */ mpls_nhlfe_release (nhlfe); retval = -EEXIST; goto error; } /* * Allocate a new Output Information/Label, */ nhlfe = nhlfe_dst_alloc (key); if (unlikely(!nhlfe)) { retval = -ENOMEM; goto error; } /* Insert into NHLFE tree */ spin_lock_bh (&mpls_nhlfe_lock); if (unlikely(mpls_insert_nhlfe (key,nhlfe))) { spin_unlock_bh (&mpls_nhlfe_lock); nhlfe->u.dst.obsolete = 1; dst_free (&nhlfe->u.dst); goto error; } /* make sure that the dst system doesn't delete this until we're * done with it */ dst_hold(&nhlfe->u.dst); mpls_nhlfe_hold(nhlfe); spin_unlock_bh (&mpls_nhlfe_lock); /* we need to hold a ref to the nhlfe while calling * mpls_nhlfe_event so it can't disappear */ mpls_nhlfe_event(MPLS_CMD_NEWNHLFE, nhlfe, seq, pid); mpls_nhlfe_release(nhlfe); out->mol_label.ml_type = MPLS_LABEL_KEY; out->mol_label.u.ml_key = key; error: MPLS_EXIT; return retval; }