Exemple #1
0
static void
destroy(const struct xt_tgdtor_param *par)
{
	struct xt_MPLS_target_info *mplsinfo = par->targinfo;
	MPLS_ENTER;
	if (mplsinfo->nhlfe)
		mpls_nhlfe_release(mplsinfo->nhlfe);
	MPLS_EXIT;
}
int mpls_set_out_label_mtu(struct mpls_out_label_req *out)
{
	struct mpls_nhlfe *nhlfe = NULL;
	int retval = 0;
	unsigned int key;

	BUG_ON(!out);
	MPLS_ENTER;

	key = out->mol_label.u.ml_key;

	nhlfe = mpls_get_nhlfe(key);

	if (unlikely(!nhlfe)) {
		MPLS_DEBUG("Node %u does not exists in radix tree\n", key);
		MPLS_EXIT;
		return -ESRCH;
	}

	/* Update the MTU if possible */
	if (nhlfe->nhlfe_mtu_limit >= out->mol_mtu) {
		nhlfe->nhlfe_mtu = out->mol_mtu;
	} else {
		MPLS_DEBUG("MTU is larger than lower layer (%d > %d)\n",
			out->mol_mtu, nhlfe->nhlfe_mtu_limit);

		/* release the refcnt held by mpls_get_nhlfe */
		mpls_nhlfe_release(nhlfe);
		return -EINVAL;
	}

	/* release the refcnt held by mpls_get_nhlfe */
	mpls_nhlfe_release(nhlfe);

	/* force the layer 3 protocols to re-find and dsts (NHLFEs),
	 * thus picking up the new MTU
	 */
	mpls_proto_cache_flush_all(&init_net);

	MPLS_EXIT;
	return retval;
}
int
mpls_set_out_label_propagate_ttl(struct mpls_out_label_req *mol)
{
	unsigned int key	  = mpls_label2key(0,&mol->mol_label);
	struct mpls_nhlfe *nhlfe = mpls_get_nhlfe(key);
	if (!nhlfe)
		return -ESRCH;

	nhlfe->nhlfe_propagate_ttl = mol->mol_propagate_ttl;

	mpls_nhlfe_release(nhlfe);
	return 0;
}
int 
mpls_set_out_label_instrs (struct mpls_instr_req *mir)
{
	struct mpls_label *ml     = &mir->mir_label;
	unsigned int key	  = mpls_label2key(0,ml);
	struct mpls_nhlfe *nhlfe = mpls_get_nhlfe(key);
	int ret;

	if (unlikely(!nhlfe)) 
		return -ESRCH;

	ret = mpls_set_out_instrs (mir->mir_instr,mir->mir_instr_length, nhlfe);
	mpls_nhlfe_release(nhlfe);
	return ret;
}
struct mpls_nhlfe* 
mpls_remove_nhlfe (unsigned int key)
{
	struct mpls_nhlfe *nhlfe = NULL;

	MPLS_ENTER;

	nhlfe = radix_tree_delete(&mpls_nhlfe_tree, key);
	if (!nhlfe)
		MPLS_DEBUG("NHLFE node with key %u not found.\n",key);

	list_del_rcu(&nhlfe->global);

	/* release the refcnt for the tree hold it */
	mpls_nhlfe_release (nhlfe);

	MPLS_EXIT;
	return nhlfe;
}
Exemple #6
0
int mpls_set_nexthop (struct shim_blk *sblk, struct dst_entry *dst)
{
	struct mpls_nhlfe *nhlfe = NULL;
	unsigned int key;
	int ret;

	MPLS_ENTER;

	memcpy(&key, sblk->data, sizeof(key));
	nhlfe = mpls_get_nhlfe(key);
	if (unlikely(!nhlfe)) {
		MPLS_EXIT;
		return -ENXIO;
	}

	ret = mpls_set_nexthop2(nhlfe, dst);
	mpls_nhlfe_release(nhlfe);
	MPLS_EXIT;
 	return ret;
}
int 
mpls_del_out_label(struct mpls_out_label_req *out) 
{
	struct mpls_nhlfe *nhlfe = NULL;
	unsigned int key;

	MPLS_ENTER;

	key = mpls_label2key(0,&out->mol_label);

        nhlfe = mpls_get_nhlfe(key);
	if (unlikely(!nhlfe)) {
		MPLS_DEBUG("Node %u was not in tree\n",key);
		MPLS_EXIT;
		return  -ESRCH;
	}

	spin_lock_bh (&mpls_nhlfe_lock);

	/* at this point a NHLFE that can be deleted will have a refcnt
	 * of 2, one from mpls_get_nhlfe() we just executed and the
	 * other that from when it was added to the tree
	 */
	if (atomic_read(&nhlfe->__refcnt) > 2) {
		/* someone else is hold a refcnt, we can't delete */

		/* release the refcnt we aquired in mpls_get_nhlfe() */
		mpls_nhlfe_release (nhlfe);
		spin_unlock_bh (&mpls_nhlfe_lock);

		MPLS_DEBUG("Node %u is being used\n",key);
		MPLS_EXIT;
		return -EBUSY;
	}

	/*
	 *	This code starts the process of removing a NHLFE from the
	 *	system.  The first thing we we do it remove it from the tree
	 *	so no one else can get a reference to it.  Then we notify the
	 *	higher layer protocols that they should give up thier references
	 *	soon (does not need to happen immediatly, the dst system allows
	 *	for this.  Finally we schedule the RCU system to call
	 *	dst_rcu_free() which waits until all CPUs have finished
	 *	thier current work and then calls dst_rcu_free() which
	 *	kicks the dst system into action once the dst system knows
	 *	everyone is done using this "dst" it calls mpls_dst_destroy().
	 */

	/* remove the NHLFE from the tree (which decs the refcnt we held when
	 * it was added to the tree)
	 */
	mpls_remove_nhlfe(nhlfe->nhlfe_key);
	spin_unlock_bh (&mpls_nhlfe_lock);

	mpls_nhlfe_event(MPLS_CMD_DELNHLFE, nhlfe, 0, 0);

	/* destrory the instructions on this nhlfe, so as to no longer
	 * hold refs to interfaces and other NHLFEs.
	 *
	 * Remember NHLFEs may stick around in the dst system even
	 * after we've removed it from the tree.  So this will result
	 * in traffic using the NHLFE to be dropped
	 */
	mpls_destroy_out_instrs (nhlfe);

	/* let the dst system know we're done with this NHLFE and
	 * schedule all higher layer protocol to give up their references */
	dst_release(&nhlfe->u.dst);
	nhlfe->u.dst.obsolete = 1;
	mpls_proto_cache_flush_all(&init_net);

	/* since high layer protocols may still be using us in there caches
	 * we need to use call_rcu() and dst_rcu_free() to take care
	 * of actually cleaning up NHLFE
	 */
	call_rcu(&nhlfe->u.dst.rcu_head, dst_rcu_free);

	/* release the refcnt we aquired in mpls_get_nhlfe() */
	mpls_nhlfe_release (nhlfe);

	MPLS_EXIT;
	return 0;
}
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; 
}
Exemple #9
0
int 
mpls_detach_in2out(struct mpls_xconnect_req *req) 
{
	struct mpls_instr       *mi  = NULL;
	struct mpls_nhlfe    *nhlfe = NULL;
	struct mpls_ilm     *ilm = NULL;
	unsigned int     key = 0;
	int labelspace;
	int ret = 0;

	MPLS_ENTER;
	BUG_ON(!req);

	/* Hold a ref to the ILM, The 'in' segment */ 
	labelspace = req->mx_in.ml_index;
	key        = mpls_label2key(labelspace,&(req->mx_in));
	ilm = mpls_get_ilm(key);
	if (unlikely(!ilm)) {
		MPLS_DEBUG("Node %u does not exist in radix tree\n",key);
		ret = -ESRCH;
		goto err_no_ilm;
	}

	/* Check that there is an instruction set! */
	if (unlikely(!ilm->ilm_instr)) {
		MPLS_DEBUG("No instruction Set!")
		ret = -ESRCH;
		goto err_no_ilm_instr;
	}


	/* Fetch the last instr, make sure it is FWD*/
	for (mi = ilm->ilm_instr; mi->mi_next;mi = mi->mi_next); /* nop*/

	if (!mi   ||   mi->mi_opcode != MPLS_OP_FWD) {
		MPLS_DEBUG("opcode not found!\n");
		ret = -ENXIO;
		goto err_no_fwd;
	}

	/* Get the current held nhlfe for the last in instr */
	nhlfe = mi->mi_data;
	key = mpls_label2key(0,&(req->mx_out));

	/* Make sure it is the good nhlfe */
	if (!nhlfe ||  key != nhlfe->nhlfe_key) {
		/* Do not release the NHLFE, it was invalid */ 
		MPLS_DEBUG("Invalid NHLFE  %u\n",key);
		ret = -ENXIO;
		goto err_no_nhlfe;
	}

	/* The new last opcode for this ILM is now peek */
	mi->mi_opcode = MPLS_OP_PEEK;
	/* With no data */
	mi->mi_data   = NULL; 

	/* Release the NHLFE held by the Opcode (cf. mpls_attach_in2out) */

	mpls_xc_event(MPLS_CMD_DELXC, ilm, nhlfe);
	mpls_nhlfe_release(nhlfe); 
	ret = 0;
err_no_nhlfe:
err_no_fwd:
	/* Release the ILM after use */
	mpls_ilm_release(ilm);
err_no_ilm_instr:
err_no_ilm:
	MPLS_EXIT;
	return ret;
}
Exemple #10
0
int 
mpls_attach_in2out(struct mpls_xconnect_req *req) 
{
	struct mpls_instr       *mi  = NULL; 
	struct mpls_nhlfe    *nhlfe = NULL;
	struct mpls_ilm     *ilm = NULL;
	unsigned short op = 0;
	int  labelspace, key;

	MPLS_ENTER;
	labelspace = req->mx_in.ml_index;

	/* Hold a ref to the ILM */
	key = mpls_label2key(labelspace,&(req->mx_in));
	ilm = mpls_get_ilm(key);
	if (unlikely(!ilm))  {
		MPLS_DEBUG("Node %u does not exist in radix tree\n",key);
		MPLS_EXIT;
		return -ESRCH;
	}

	/* Hold a ref to the NHLFE */
	key = mpls_label2key(0,&(req->mx_out));
	nhlfe = mpls_get_nhlfe(key);
	if (unlikely(!nhlfe)) {
		MPLS_DEBUG("Node %u does not exist in radix tree\n",key);
		mpls_ilm_release(ilm);
		MPLS_EXIT;
		return -ESRCH;
	}

	if (unlikely(!ilm->ilm_instr)) {
		MPLS_DEBUG("No instruction Set!")
		mpls_ilm_release(ilm);
		mpls_nhlfe_release(nhlfe);
		MPLS_EXIT;
		return -ESRCH;
	}



	/*
	 * Update the instructions: now, instead of "DLV"/"PEEK", now
	 * we "FWD". The NHLFE is not released (is held by the opcode). 
	 */

	/* Lookup the last instr */
	for (mi = ilm->ilm_instr; mi->mi_next;mi = mi->mi_next); /* nop*/

	op = mi->mi_opcode;

	switch (op) {
		case MPLS_OP_DLV:
			mi->mi_opcode = MPLS_OP_FWD;
			mi->mi_data   = (void*)nhlfe;
			break;
		case MPLS_OP_FWD:
			mpls_xc_event(MPLS_CMD_DELXC, ilm,
				_mpls_as_nhlfe(mi->mi_data));
			mpls_nhlfe_release(_mpls_as_nhlfe(mi->mi_data));
			mi->mi_data   = (void*)nhlfe;
			break;
		case MPLS_OP_PEEK:
			mi->mi_opcode = MPLS_OP_FWD;
			mi->mi_data   = (void*)nhlfe;
			break;
	}
	mpls_xc_event(MPLS_CMD_NEWXC, ilm, nhlfe);
	mpls_ilm_release(ilm);
	return 0; 
}
static inline void 
mpls_nhlfe_release_safe (struct mpls_nhlfe *nhlfe)
{
	if (nhlfe)
		mpls_nhlfe_release (nhlfe);
}