Ejemplo n.º 1
0
struct mpls_ilm* 
mpls_get_ilm_by_label (struct mpls_label *label, int labelspace, char bos) 
{
	struct mpls_ilm *ilm = NULL;

	/* handle the reserved label range */
	if (label->ml_type == MPLS_LABEL_GEN && label->u.ml_gen < 16) {
		int want_bos = mpls_reserved[label->u.ml_gen].bos;
		MPLS_DEBUG("%s\n",mpls_reserved[label->u.ml_gen].msg);
		ilm = mpls_reserved[label->u.ml_gen].ilm;
		if (unlikely(!ilm)) {
			MPLS_DEBUG("invalid incoming label, dropping\n");
			return NULL;
		}
		mpls_ilm_hold(ilm);
		if ((want_bos && !bos) || (!want_bos && bos)) {
			mpls_ilm_release (ilm);
			MPLS_DEBUG("invalid incoming labelstack, dropping\n");
			return NULL;
		}
	} else {
		/* not reserved label */
		ilm = mpls_get_ilm (mpls_label2key(labelspace,label));
		if (unlikely(!ilm)) {
			MPLS_DEBUG("unknown incoming label, dropping\n");
			return NULL;
		}
	}
	return ilm;
}
Ejemplo n.º 2
0
int 
mpls_del_in_label(struct mpls_in_label_req *in) 
{
	struct mpls_ilm *ilm = NULL;
	struct mpls_label   *ml  = NULL; 
	unsigned int key         = 0;

	MPLS_ENTER;
	BUG_ON(!in);
	ml  = &in->mil_label;
	key = mpls_label2key(/* labelspace*/ ml->ml_index, ml);

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

	spin_lock_bh (&mpls_ilm_lock);

	if (atomic_read(&ilm->u.dst.__refcnt) != 2) {
		/* someone else is hold a refcnt, we can't delete */

		/* release the refcnt we aquired in mpls_get_ilm() */
		mpls_ilm_release (ilm);
		spin_unlock_bh (&mpls_ilm_lock);

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

	/*
	 * Remove a ILM from the tree
	 */
	ilm = mpls_remove_ilm(key);

	spin_unlock_bh (&mpls_ilm_lock);

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

	__mpls_del_in_label(ilm);

	MPLS_EXIT;
	return 0; 
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
int mpls_set_nexthop2(struct mpls_nhlfe *nhlfe, struct dst_entry *dst)
{
	MPLS_ENTER;

	dst->metrics[RTAX_MTU-1] = nhlfe->nhlfe_mtu;
	dst->child = dst_clone(&nhlfe->u.dst);
	MPLS_DEBUG("nhlfe: %p mtu: %d dst: %p\n", nhlfe, nhlfe->nhlfe_mtu,
		&nhlfe->u.dst);

	MPLS_EXIT;
	return 0;
}
Ejemplo n.º 5
0
struct mpls_ilm*
mpls_ilm_dst_alloc(unsigned int key, struct mpls_label *ml,
	unsigned short family, struct mpls_instr_elem *instr, int instr_len)
{
	struct mpls_ilm *ilm;
	int result;

	MPLS_ENTER;

	ilm = dst_alloc (&ilm_dst_ops);
	if (unlikely(!ilm))
		goto ilm_dst_alloc_0;

	memcpy(&(ilm->ilm_label),ml,sizeof(struct mpls_label));
	INIT_LIST_HEAD(&ilm->dev_entry);
	INIT_LIST_HEAD(&ilm->nhlfe_entry);
	INIT_LIST_HEAD(&ilm->global);

	ilm->ilm_instr      = NULL;
	ilm->ilm_key        = key;
	ilm->ilm_labelspace = ml->ml_index;
	ilm->ilm_age        = jiffies;
	ilm->ilm_proto      = mpls_proto_find_by_family(family);
	ilm->ilm_fix_hh     = 0;
	if (unlikely(!ilm->ilm_proto)) {
		MPLS_DEBUG("Unable to find protocol driver for '0x%04x'\n",
			family);
		goto ilm_dst_alloc_1;
	} else {
		ilm->u.dst.input = ilm->ilm_proto->local_deliver;
	}
	ilm->u.dst.dev	    = init_net.loopback_dev;

	result = mpls_set_in_instrs(instr, instr_len, ilm);

	if (result)
		goto ilm_dst_alloc_2;

	MPLS_EXIT;
	return ilm;

/* Error Path */
ilm_dst_alloc_2:
	mpls_proto_release(ilm->ilm_proto);
ilm_dst_alloc_1:
	ilm->u.dst.obsolete = 1;
	dst_free(&ilm->u.dst);

ilm_dst_alloc_0:
	MPLS_EXIT;
	return NULL;
}
Ejemplo n.º 6
0
inline MPLS_IN_OPCODE_PROTOTYPE(mpls_in_op_set_ds)
{
	unsigned short *ds = data;
	MPLS_ENTER;
	if (!MPLSCB(*pskb)->bos) {
		MPLS_DEBUG("SET_DS and not BOS\n");
		MPLS_EXIT;
		return MPLS_RESULT_DROP;
	}
	MPLSCB(*pskb)->prot->change_dsfield(*pskb, *ds);
	MPLS_EXIT;
	return MPLS_RESULT_SUCCESS;
}
Ejemplo n.º 7
0
int 
mpls_insert_ilm (unsigned int key, struct mpls_ilm *ilm) 
{
	int retval = 0;

	mpls_ilm_hold (ilm);
	retval = radix_tree_insert (&mpls_ilm_tree, key, ilm);
	if (unlikely(retval)) {
		MPLS_DEBUG("Error create node with key %u in radix tree\n",key);
		retval = -ENOMEM;
	}
	list_add_rcu(&ilm->global, &mpls_ilm_list);
	return retval;
}
Ejemplo n.º 8
0
static int __mpls_set_labelspace(struct net_device *dev, int labelspace)
{
	struct mpls_interface *mif = dev->mpls_ptr;

	MPLS_ENTER;
	BUG_ON(!mif);

	mif->labelspace = labelspace;

	MPLS_DEBUG("Set labelspace for %s to %d\n",
			dev->name, labelspace);

	MPLS_EXIT;
	return 0;
}
Ejemplo n.º 9
0
struct mpls_ilm* 
mpls_remove_ilm (unsigned int key)
{
	struct mpls_ilm *ilm = NULL;

	MPLS_ENTER;
	ilm = radix_tree_delete (&mpls_ilm_tree, key);
	if (!ilm) {
		MPLS_DEBUG("node key %u not found.\n",key);
		return NULL;
	}

	list_del_rcu(&ilm->global);
	mpls_ilm_release (ilm);

	MPLS_EXIT;
	return ilm;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
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; 
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
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; 
}
Ejemplo n.º 15
0
int 
mpls_add_in_label (const struct mpls_in_label_req *in) 
{
	struct mpls_ilm *ilm     = NULL; /* New ILM to insert */
	struct mpls_label *ml    = NULL; /* Requested Label */
	unsigned int key         = 0;    /* Key to use */
	int retval               = 0;
	struct mpls_instr_elem instr[2];

	MPLS_ENTER;

	BUG_ON(!in);
	ml = (struct mpls_label *)&in->mil_label;

	if (mpls_is_reserved_label(ml)) {
		MPLS_DEBUG("Unable to add reserved label to ILM\n");
		retval = -EINVAL;
		goto error;
	}

	/* Obtain key */
	key = mpls_label2key(/* labelspace*/ ml->ml_index, ml);

	/* Check if the node already exists */ 
	ilm = mpls_get_ilm(key);
	if (unlikely(ilm)) {
		printk (MPLS_ERR "MPLS: node %u already exists\n",key);
		mpls_ilm_release(ilm);  
		retval = -EEXIST;
		goto error;
	} 

	/*
	 * Allocate a new input Information/Label,
	 */

	instr[0].mir_direction = MPLS_IN;
	instr[0].mir_opcode    = MPLS_OP_POP;
	instr[1].mir_direction = MPLS_IN;
	instr[1].mir_opcode    = MPLS_OP_PEEK;

	ilm = mpls_ilm_dst_alloc (key, ml, in->mil_proto, instr, 2);
	if (unlikely(!ilm)) {
		retval = -ENOMEM;
		goto error;
	}

	/* Insert into ILM tree */
	spin_lock_bh (&mpls_ilm_lock);
	if (unlikely(mpls_insert_ilm(key,ilm))) {
		mpls_ilm_release (ilm);
		spin_unlock_bh (&mpls_ilm_lock);

		ilm->u.dst.obsolete = 1;
		dst_free (&ilm->u.dst);
		retval = -ENOMEM;
		goto error;
	}

	mpls_ilm_hold(ilm);
	spin_unlock_bh (&mpls_ilm_lock);

	/* we have hold a refcnt to the ilm across mpls_ilm_event()
	 * to make sure it can't disappear
	 */
	mpls_ilm_event(MPLS_CMD_NEWILM, ilm);
	mpls_ilm_release(ilm);

error:
	MPLS_EXIT;
	return retval;
}
Ejemplo n.º 16
0
int mpls_push (struct sk_buff **skb, struct mpls_label *ml) 
{
	struct sk_buff *o = NULL; 
	struct sk_buff *n = NULL;
	unsigned int label = 0;
	u32 shim;

	MPLS_ENTER;
	o = *skb;
	if (unlikely(!ml)) {
		MPLS_DEBUG("no outgoing label\n");
		return MPLS_RESULT_DROP;
	}

try_again:
	if(likely((MPLSCB(o)->gap >= MPLS_SHIM_SIZE) || (o->data - o->head >= MPLS_SHIM_SIZE))) {
		/*
		 * if we have room between data and end of mac_header
		 * just shift the data,transport_header,network_header pointers and use the room
		 * this would happen if we had a pop previous to this
		 */
		MPLS_DEBUG("using gap\n");
		skb_push(o,MPLS_SHIM_SIZE);
		o->transport_header -= MPLS_SHIM_SIZE;
		o->network_header -= MPLS_SHIM_SIZE;
		MPLSCB(o)->gap -= MPLS_SHIM_SIZE;
		if (MPLSCB(o)->gap < 0) {
			MPLSCB(o)->gap = 0;
		}
	} else {
		/*
		 * we have no room in the inn, go ahead and create a new sk_buff
		 * with enough extra room for one shim
		 */
		MPLS_DEBUG("creating larger packet\n");
		
		if(!(n = skb_realloc_headroom(o, 32))) {
			return MPLS_RESULT_DROP;
		}

		MPLSCB(n)->gap = 0;

		MPLS_DEBUG("dump old packet\n");
		MPLS_DEBUG_CALL(mpls_skb_dump(o));
		kfree_skb(o);

		MPLS_DEBUG("dump new packet\n");
		MPLS_DEBUG_CALL(mpls_skb_dump(n));

		o = *skb = n;

		goto try_again;
	}

	switch(ml->ml_type) {
		case MPLS_LABEL_GEN:
			label = ml->u.ml_gen;
			break;
		default:
			MPLS_DEBUG("invalid label type(%d)\n",ml->ml_type);
			goto push_end;
	}

	/*
	 * no matter what layer 2 we are on, we need the shim! (mpls-encap RFC)
	 */
	shim = htonl(((label & 0xFFFFF) << 12) |
		     ((MPLSCB(o)->exp & 0x7) << 9) |
		     ((MPLSCB(o)->bos & 0x1) << 8) |
		      (MPLSCB(o)->ttl & 0xFF));
	memmove(o->data,&shim,MPLS_SHIM_SIZE);
	MPLSCB(o)->label = label;
	MPLSCB(o)->bos = 0;
	MPLSCB(o)->popped_bos = 0;

push_end:
	MPLS_EXIT;
	return MPLS_RESULT_SUCCESS;;
}