Files
m241Neelima/components/ip_net2-6.9/ipmpls/src/ipmpls.c
T
2026-07-30 11:19:44 +05:30

1975 lines
57 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmpls.c,v $ $Revision: 1.73.10.3 $
* $Source: /home/interpeak/CVSRoot/ipmpls/src/ipmpls.c,v $
* $Author: hsun $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Jonas Rendel <Jonas.Rendel@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifdef IPMPLS
#include "ipmpls_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_type.h>
#include <ipcom_os.h>
#include <ipcom_pkt.h>
#include <ipcom_route.h>
#include <ipcom_netif.h>
#include <ipcom_shell.h>
#include <ipcom_strlib.h>
#include <ipcom_sysvar.h>
#include <ipcom_syslog.h>
#include "ipmpls.h"
#include "ipmpls_h.h"
#include "ipmpls_ipstack.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPMPLS_NETIF_LINK_HDR_SIZE 14
#if defined(_WRS_CONFIG_IPMPLS_SYSLOG_PRIORITY)
#define IPCOM_SYSLOG_PRIORITY _WRS_CONFIG_IPMPLS_SYSLOG_PRIORITY
#else
#define IPCOM_SYSLOG_PRIORITY IPCOM_SYSLOG_PRIO_DEFAULT
#endif
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMPLS
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int ipmpls_dlv(Ipcom_netif *netif, struct Ip_sockaddr *dst,
Ipcom_pkt *pkt, int proto);
IP_STATIC int ipmpls_process_label (Ipcom_netif *netif,
Ipmpls_route *entry,
Ip_bool first, Ipcom_pkt *pkt,
int recursion_limit);
IP_STATIC void ipmpls_netif_nhlfe_flush(Ipcom_netif *netif, Ip_u16 vr, Ipmpls_nhlfe *nhlfe);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
Ipmpls_data *ipmpls;
IP_STATIC Ipmpls_route ipmpls_ilm_explicit_ipv4;
IP_STATIC Ipmpls_route ipmpls_ilm_explicit_ipv6;
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmpls_sysv_fwdconf_parse_cb
*===========================================================================
* Description: Parses and executes preconfigures mplsctl commands stored
* as sysvars
* Parameters:
* Returns:
*
*/
#ifdef IPMPLS_INCLUDE_CMD
IP_STATIC int
ipmpls_sysv_fwdconf_parse_cb(const char *name, const char *value,
int flags, void *cookie)
{
int retval = -1;
int argc;
char **argv = IP_NULL;
Ipcom_shell_cmd *cmd;
(void)name;
(void)cookie;
(void)flags;
if (ipcom_parse_argstr((char*)value, (int*)&argc, &argv) != IPCOM_SUCCESS)
{
/* Add log */
goto out;
}
if ((cmd = ipcom_shell_find_cmd(argv[0])) == IP_NULL)
{
/* Add log */
goto out;
}
if (cmd->hook(argc, argv) != IPCOM_SUCCESS)
{
/* Add log */
goto out;
}
retval = 0;
out:
if(argv != IP_NULL)
ipcom_free(argv);
return retval;
}
#endif
/*
*===========================================================================
* ipmpls_load_fwdconfig
*===========================================================================
* Description: Loads ipmpls forwarding preconfiguration
* Parameters:
* Returns:
*
*/
#ifdef IPMPLS_INCLUDE_CMD
IP_STATIC void
ipmpls_load_fwdconfig(void)
{
(void)ipcom_sysvar_for_each("ipmpls.fwdconf",
ipmpls_sysv_fwdconf_parse_cb,
IP_NULL);
}
#endif
/*
*===========================================================================
* ipmpls_nhlfe_lock
*===========================================================================
* Description: Lock NHLFE object
* Parameters: nhlfe - NHLFE object
*
* Returns:
*
*/
IP_STATIC void
ipmpls_nhlfe_lock(Ipmpls_nhlfe *nhlfe)
{
if (nhlfe)
nhlfe->refcnt++;
}
/*
*===========================================================================
* ipmpls_nhlfe_unlock
*===========================================================================
* Description: Unlock NHLFE object
* Parameters: nhlfe - NHLFE object
*
* Returns:
*
*/
IP_STATIC void
ipmpls_nhlfe_unlock(Ipmpls_nhlfe *nhlfe)
{
if (nhlfe)
{
if (--nhlfe->refcnt < 0)
ipcom_free(nhlfe);
}
}
/*
*===========================================================================
* ipmpls_mpls_route_notify
*===========================================================================
* Description: Used as IPCOM route table callback for ILM route objects.
* Initiates a newly added ILM entry with some default
* operations (pop,peek).
*
* Parameters: rtab - ILM route table
* ilm - ILM entry
* code - Route table operation code
* Returns: -
*
*/
IP_STATIC void
ipmpls_mpls_route_notify(struct Ipcom_route_struct *rtab,
Ipmpls_route *route,
int code)
{
(void)rtab;
switch (code)
{
case IPCOM_ROUTE_CODE_ADD:
if (IPMPLS_KEY_GET_TYPE(route->key) == IPMPLS_LABEL_TYPE_GEN)
{
/* Setup default ILM op list (pop,peek) */
route->oplist = ipmpls_oplist_create(2);
if (route->oplist)
{
Ipmpls_opcode_elem *ops = route->oplist->opcodes;
/* Setup default ops */
ops[0].opcode = IPMPLS_OP_POP;
ops[0].data.ptr = IP_NULL;
ops[1].opcode = IPMPLS_OP_PEEK;
ops[1].data.ptr = IP_NULL;
}
}
break;
case IPCOM_ROUTE_CODE_REMOVE:
if (IPMPLS_KEY_GET_TYPE(route->key) == IPMPLS_LABEL_TYPE_GEN)
{
/* Release resources */
ipmpls_oplist_remove(route->oplist);
ipcom_free(route);
}
else if (IPMPLS_KEY_GET_TYPE(route->key) == IPMPLS_LABEL_TYPE_KEY)
{
if (route->refcnt > 0)
{
/*
* Scan interface list for MPLS tunnel interfaces
* referencing this NHLFE entry.
*/
(void)ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXFOREACHNETIF,
(void*)ipmpls_netif_nhlfe_flush,
route,
IP_NULL);
/*
* Scan the IP route tables for pseudo wire routes
* referencing this NHLFE entry.
*/
(void)ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXFLUSHSHORTCUTROUTES,
route,
IP_NULL,
IP_NULL);
}
/* Release resources */
if (route->oplist)
ipmpls_oplist_remove(route->oplist);
ipmpls_nhlfe_unlock((Ipmpls_nhlfe*)route);
}
break;
}
}
/*
*===========================================================================
* ipmpls_route_flush
*===========================================================================
* Description: Used as callback when flushing a MPLS route table.
* Parameters: rt - Route entry
* data -
* Returns: Always IP_TRUE
*
*/
IP_STATIC Ip_bool
ipmpls_route_flush(Ipmpls_route *rt, void* data)
{
Ip_u32 *type = (Ip_u32*)data;
if (IPMPLS_KEY_GET_TYPE(rt->key) == *type)
return IP_TRUE;
else
return IP_FALSE;
}
/*
*===========================================================================
* ipmpls_label_table_hash_key
*===========================================================================
* Description: Calculates a hash value for the label table search key.
* Parameters: key - A search key.
* Returns: Hash value.
*
*/
IP_STATIC unsigned
ipmpls_route_table_hash_key(Ip_u16 *key)
{
return (unsigned)*key;
}
/*
*===========================================================================
* ipmpls_il,_table_hash_obj
*===========================================================================
* Description: Calculates a hash value for the label table.
* Parameters: rt_head - A route table head.
* Returns: Hash value.
*
*/
IP_STATIC unsigned
ipmpls_route_table_hash_obj(Ipmpls_route *rt)
{
return (unsigned)rt->vr;
}
/*
*===========================================================================
* ipmpls_route_table_hash_cmp
*===========================================================================
* Description: Checks if the key matches the label table head.
* Parameters: rt_head - A route table head.
* key - A search key.
* Returns: IP_TRUE if the key matches the element.
*
*/
IP_STATIC Ip_bool
ipmpls_route_table_hash_cmp(Ipmpls_route *rt, Ip_u16 *vr)
{
return (rt->vr == *vr);
}
/*
*===========================================================================
* ipmpls_route_tablecreate
*===========================================================================
* Description: IPMPLS route table constructor routine
* Parameters:
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_STATIC int
ipmpls_route_table_create(Ip_u16 vr)
{
Ipmpls_route *tree;
tree = ipcom_calloc(1, sizeof(Ipmpls_route));
if (tree == IP_NULL)
{
IPCOM_LOG1(WARNING,"IPMPLS :: Failed to create MPLS route table for vr=%d", vr);
return -IP_ERRNO_ENOMEM;
}
/* Add a MPLS route tree for VR 0 */
tree->head = ipcom_route_new_table(IPMPLS_KEY_BITS,
(Ipcom_route_notify_func)ipmpls_mpls_route_notify);
if (tree->head == IP_NULL)
{
IPCOM_LOG1(WARNING,"IPMPLS :: Failed to create MPLS route table for vr=%d", vr);
ipcom_free(tree);
return -IP_ERRNO_ENOMEM;
}
tree->vr = vr;
if (ipcom_hash_add(ipmpls->label_tables, tree) != IPCOM_SUCCESS)
{
IPCOM_LOG1(WARNING,"IPMPLS :: Failed to add MPLS route table for vr=%d to MPLS route table hash table.", vr);
ipcom_route_free_table(tree->head);
ipcom_free(tree);
return -IP_ERRNO_ENOMEM;
}
return 0;
}
/*
*===========================================================================
* ipmpls_dlv
*===========================================================================
* Description: Delivers to IP stack
* Parameters: netif - Receiving interface
* dst - Specific destinatination address
* pkt - IP packet
* proto - IPv4 or IPv6
*
* Returns: 0 - ok
* <0 - failed
*
*/
IP_STATIC int
ipmpls_dlv(Ipcom_netif *netif, struct Ip_sockaddr *dst,
Ipcom_pkt *pkt, int proto)
{
switch (proto)
{
#ifdef IPCOM_USE_INET
case IP_IPPROTO_IP:
if (netif->link_tap)
{
/* Let the tap handler copy the packet */
netif->link_tap(netif, pkt, IP_PACKET_HOST, ip_htons(IP_ETH_P_IP), pkt->start, pkt->start);
}
return ipcom_mpls_ioevent(netif, IPMPLS_EIOXINPUT_IN, pkt, dst, IP_NULL);
#endif
#ifdef IPCOM_USE_INET6
case IP_IPPROTO_IPV6:
if (netif->link_tap)
{
/* Let the tap handler copy the packet */
netif->link_tap(netif, pkt, IP_PACKET_HOST, ip_htons(IP_ETH_P_IPV6), pkt->start, pkt->start);
}
return ipcom_mpls_ioevent(netif, IPMPLS_EIOXINPUT_IN6, pkt, dst, IP_NULL);
#endif
default:
return -IP_ERRNO_EPFNOSUPPORT;
}
}
/*
*===========================================================================
* ipmpls_output
*===========================================================================
* Description: Outputs a MPLS packet through the link layer of the local IP.
* stack.
* Layer 2 info is exctracted by the local IP stack using
* standard neighbor probing.
*
* Parameters: netif - Outgoing interface
* nexthop - Next hop Layer3 address (IP_AF_INET/IP_AF_INET6)
* pkt - MPLS packet.
* penultimate - Tells if IPMPLS is acting as a penultimate LSR on
* for this packet. The frame type shall then be set
* according to the PDU.
*
* Returns: 0 Ok
* <0 Failure
*
*/
IP_STATIC int
ipmpls_output(Ipcom_netif *netif, struct Ip_sockaddr *nexthop, Ipcom_pkt *pkt, Ip_bool penultimate)
{
int ret;
int ev;
if (netif == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
switch(netif->type)
{
case IP_IFT_ETHER:
case IP_IFT_L2VLAN:
if (nexthop == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_ENETUNREACH);
switch(nexthop->sa_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
ev = IPMPLS_EIOXARPPROBE;
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
ev = IPMPLS_EIOXNDPROBE;
break;
#endif
default:
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
}
pkt->ifindex = netif->ifindex;
ret = ipcom_mpls_ioevent(netif,
ev,
pkt,
nexthop,
&penultimate);
/* The packet is taken care of by the ARP/ND probe,
* so don't attempt to free it here
*/
if (ret != 0)
return ret;
break;
default:
IPMPLS_ERROUT(IP_ERRNO_ENODEV);
}
return 0;
errout:
ipcom_pkt_free(pkt);
return -ret;
}
/*
*===========================================================================
* ipmpls_process_label
*===========================================================================
* Description: Do label processing on a packet. Used on both transmit and
* receive packets.
*
* Parameters: netif - interface
* entry - IPMPLS route entry (ILM/NHLFE)
* dir - Direction (IN/OUT)
* first - used for s_bit handling on the label
* pkt - MPLS packet (IN) or PDU (out)
* peeked - Is true if this routine is called recursively
* upon a peek operation.
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_STATIC int
ipmpls_process_label (Ipcom_netif *netif, Ipmpls_route *entry,
Ip_bool first, Ipcom_pkt *pkt, int recursion_limit)
{
Ipmpls_nhlfe *nhlfe = (Ipmpls_nhlfe *) entry;
Ipmpls_ilm *ilm = (Ipmpls_ilm *) entry;
int i = 0;
Ipcom_pkt *new_pkt;
int pkt_len;
Ipmpls_opcode_elem *op;
Ipmpls_label_hdr label;
Ip_bool s_bit = first;
int ret;
Ip_u8 ttl = 255;
int dir;
struct Ip_sockaddr *sa = IP_NULL;
dir = IPMPLS_KEY_GET_TYPE(entry->key) == IPMPLS_LABEL_TYPE_GEN ? IPMPLS_IN : IPMPLS_OUT;
if (entry->oplist == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
if ((dir == IPMPLS_OUT) && (nhlfe->ttl == 1) && first)
{
ttl = (Ip_u8)ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXGET_TTL,
pkt,
IP_NULL,
IP_NULL);
}
for (i = 0; i < entry->oplist->num_opcodes; i++)
{
op = &entry->oplist->opcodes[i];
label = IP_GET_NTOHL(&pkt->data[pkt->start]);
switch (op->opcode)
{
case IPMPLS_OP_PUSH:
/* Push a label onto the label stack
* Valid: both IN and OUT
*/
ipcom_memset(&label, 0, IPMPLS_LABEL_SIZE);
IPMPLS_LABEL_SET_LABEL(label, op->data.push.u.ml_gen);
IPMPLS_LABEL_SET_TTL(label,
(dir == IPMPLS_IN) ? ilm->ttl : ttl);
/* If the current label has the S bit set, re-set it */
if (first)
{
IPMPLS_LABEL_SET_S(label);
first = IP_FALSE;
}
label = ip_htonl(label);
/* Check if the packet is big enough
* to accomodate a pushed label
*/
pkt_len = pkt->end - pkt->start;
/* if (pkt->start >= ipcom_conf_max_link_hdr_size + IPMPLS_LABEL_SIZE) */
if (pkt->start >= IPMPLS_NETIF_LINK_HDR_SIZE + IPMPLS_LABEL_SIZE)
{
pkt->start -= IPMPLS_LABEL_SIZE;
IP_SET_32ON8(&pkt->data[pkt->start], label);
break;
}
new_pkt = ipcom_pkt_malloc(pkt->end + IPMPLS_LABEL_SIZE,
IP_FLAG_FC_STACKCONTEXT);
if (new_pkt == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_ENOMEM);
new_pkt->fd = pkt->fd;
new_pkt->vr_index = pkt->vr_index;
new_pkt->ifindex = pkt->ifindex;
new_pkt->flags = pkt->flags;
new_pkt->ipstart = pkt->ipstart + IPMPLS_LABEL_SIZE;
new_pkt->start = pkt->start;
new_pkt->end = pkt->end + IPMPLS_LABEL_SIZE;
/* Copy the packet's data preceeding the start */
ipcom_memcpy(new_pkt->data, pkt->data, pkt->start);
*(Ipmpls_label_hdr *) &new_pkt->data[pkt->start] = label;
/* Last copy the data proceeding the label */
ipcom_memcpy(&new_pkt->data[pkt->start + IPMPLS_LABEL_SIZE],
&pkt->data[pkt->start],
pkt_len);
/* Free the original packet and assign the new packet */
ipcom_pkt_free(pkt);
/* Update the packet end indicator, in order to reflect the
* addition of the new label
*/
pkt = new_pkt;
break;
case IPMPLS_OP_POP:
/* Pop a label from the label stack
* Valid: IN & OUT
*/
/* If the first variable is set, it means we have already reached
* the bottom of the stack
*/
if (first)
IPMPLS_ERROUT(IP_ERRNO_EPERM);
first = s_bit = IPMPLS_LABEL_GET_S(label);
pkt->start += IPMPLS_LABEL_SIZE;
if (first)
/* We are at the IP header */
pkt->ipstart = pkt->start;
break;
case IPMPLS_OP_SET:
/* For outgoing: Set Tx interface and nexthop address.
* For incoming: Set destination address to route packet to.
* Valid: IN & OUT
*/
if (dir == IPMPLS_OUT)
{
/* Set Tx interface */
if (ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXINDEXTONETIF,
&op->data.set.ifindex,
&netif,
IP_NULL) != 0)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
}
sa = &op->data.set.a.sa;
break;
case IPMPLS_OP_SET_RX:
/* Set Rx interface
* Valid: IN
*/
if (dir != IPMPLS_IN)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
/* Set Rx interface */
if (ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXINDEXTONETIF,
&op->data.set.ifindex,
&netif,
IP_NULL) != 0)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
pkt->ifindex = netif->ifindex;
break;
case IPMPLS_OP_SET_VR:
/* Set a specific RTAB to use when routing the packet.
* Valid: IN
*/
{
Ip_u16 vr = (Ip_u16)op->data.set.ifindex;
if (ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXRTABTONETIF,
&vr,
&netif,
IP_NULL) != 0)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
pkt->vr_index = vr;
pkt->ifindex = netif->ifindex;
}
break;
case IPMPLS_OP_PEEK:
if (recursion_limit < 0)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
if (s_bit)
return ipmpls_dlv(netif, sa, pkt, IPMPLS_ILM_PROTO(ilm));
else
return ipmpls_input(netif, pkt, recursion_limit - 1);
case IPMPLS_OP_DLV:
/* Deliver packet to stack
* Valid: IN
*/
if (dir != IPMPLS_IN)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
return ipmpls_dlv(netif, sa, pkt, IPMPLS_ILM_PROTO(ilm));
case IPMPLS_OP_FWD:
{
Ipmpls_route *next;
/* Forward to another MPLS object
* Valid: IN | OUT
*
* This will recursively call back into here,
* but the recursion limit will prevent it from doing it too
* many times.
*/
if (recursion_limit < 0)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
next = ipmpls_route_lookup(pkt->vr_index, &op->data.fwd);
if (next == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_EHOSTUNREACH);
/* Not permitted to forward to itself */
if (next == entry)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
/* We are assuming that the FWD is last on the op list */
return ipmpls_process_label(netif, next, first,
pkt, recursion_limit - 1);
}
default:
break;
}
}
/* If we are here and the packet is inbound, then we might have an
* op problem, since one of the ops should have taken care of the packet...
*/
if (dir == IPMPLS_IN)
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
/* If we are here it is an outbound packet...*/
return ipmpls_output(netif, sa, pkt, first);
errout:
ipcom_pkt_free(pkt);
return -ret;
}
/*
*===========================================================================
* ipmpls_netif_nhlfe_flush
*===========================================================================
* Description: Remove a NHLFE reference from a MPLS tunnel interface.
* Parameters: netif - MPLS tunnel interface
* nhlfe - NHLFE object.
*
* Returns: -
*
*/
IP_STATIC void
ipmpls_netif_nhlfe_flush(Ipcom_netif *netif, Ip_u16 vr, Ipmpls_nhlfe *nhlfe)
{
Ipmpls_netif *mplsif;
(void)vr;
if (netif->type == IP_IFT_MPLS_TUNNEL)
{
mplsif = (Ipmpls_netif*)netif->plink;
if (mplsif && (mplsif->nhlfe == nhlfe))
{
ipmpls_nhlfe_unlock(mplsif->nhlfe);
mplsif->nhlfe = IP_NULL;
}
}
}
/*
*===========================================================================
* ipmpls_do_input
*===========================================================================
* Description: Input handler for ethernet frames. pkt->start is the offset
* to the ethernet header.
* Parameters: pkt - The ethernet frame.
* Returns: 0 = success, <0 error code
*
*/
IP_STATIC int
ipmpls_do_input(Ipcom_netif *netif, Ipcom_pkt *pkt, int rlimit)
{
Ipmpls_label_hdr lh;
Ip_u32 lblval;
Ipmpls_label label;
int labelspace;
Ipmpls_ilm *ilm;
Ipmpls_key key;
int ret;
/* Extract the label, and adapt it to use label space info */
lh = IP_GET_NTOHL(&pkt->data[pkt->start]);
/* Get labelspace */
ret = ipmpls_labelspace_get(netif, &labelspace);
if (ret != 0)
IPMPLS_ERROUT(-ret);
lblval = IPMPLS_LABEL_GET_LABEL(lh);
/* Check for special handling in the case of implicit labels */
switch (lblval)
{
case IPMPLS_LABEL_IPV4_EXPLICIT_NULL:
return ipmpls_process_label(netif, &ipmpls_ilm_explicit_ipv4, IP_FALSE,
pkt, rlimit);
case IPMPLS_LABEL_IPV6_EXPLICIT_NULL:
return ipmpls_process_label(netif, &ipmpls_ilm_explicit_ipv6, IP_FALSE,
pkt, rlimit);
case IPMPLS_LABEL_IMPLICIT_NULL:
/* This shouldn't appear in traffic,
* it is only used by the LDP to indicate stack popping and
* thus should be translated to a pop by the LDP stack.
*/
IPMPLS_ERROUT(IP_ERRNO_EINVAL);
}
/* Create a label used in the key_create function */
label.__refcnt = 0;
label.ml_type = IPMPLS_LABEL_TYPE_GEN;
label.u.ml_gen = lblval;
ipmpls_key_create(labelspace, &label, &key);
ilm = ipmpls_route_lookup(pkt->vr_index, &key);
if (ilm == IP_NULL)
IPMPLS_ERROUT(IP_ERRNO_EHOSTUNREACH);
/* Now perform label specific operations as described by the
* ILM instructions this should leave the packet in a state that
* can be presented to the next layer, be that IP, MPLS or link layer
*/
return ipmpls_process_label(netif, ilm, IP_FALSE, pkt, rlimit);
errout:
ipcom_pkt_free(pkt);
return -ret;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmpls_nhlfe_key_autogenerate
*===========================================================================
* Description: Auto generate a new unique NHLFE key.
* Parameters: key - Pointer to NHLFE key
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_nhlfe_key_autogenerate(Ipmpls_key *key)
{
int ret = -1;
Ip_u16 vr = 0;
if (ipmpls->ipmpls_last_nhlfe_label == 0xFFFF)
ipmpls->ipmpls_last_nhlfe_label = 0;
*key = IPMPLS_KEY_SET_TYPE(*key, ((Ip_u32)IPMPLS_LABEL_TYPE_KEY));
*key = IPMPLS_KEY_SET_LABELSPACE(*key, 0);
*key = IPMPLS_KEY_SET_LABEL(*key, ++(ipmpls->ipmpls_last_nhlfe_label));
(void)ipcom_mpls_ioevent(IP_NULL,IPMPLS_EIOXGET_USER_VR, &vr,IP_NULL,IP_NULL);
while (IPMPLS_KEY_GET_LABEL(*key) < 0xFFFF)
{
if (!ipmpls_route_lookup(vr, key))
{
ipmpls->ipmpls_last_nhlfe_label = (Ip_u16)IPMPLS_KEY_GET_LABEL(*key);
ret = 0;
break;
}
*key = IPMPLS_KEY_SET_LABEL(*key, IPMPLS_KEY_GET_LABEL(*key) + 1);
}
return ret;
}
/*
*===========================================================================
* ipmpls_route_flush_tree
*===========================================================================
* Description: Flush a MPLS route table
* Parameters: tree_ix - table index
* type - table type (ILM/NHLFE)
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_route_flush_tree(Ip_u16 ix, Ip_u32 type)
{
int ret = 0;
Ipmpls_route *tree;
tree = (Ipmpls_route*)ipcom_hash_get(ipmpls->label_tables, &ix);
if (tree == IP_NULL)
IPMPLS_ERROUT(-IP_ERRNO_EINVAL);
/* Flush tree */
ipcom_route_walk_tree(tree->head,
(Ipcom_route_walk_cb)ipmpls_route_flush,
&type);
errout:
return ret;
}
/*
*===========================================================================
* ipmpls_route_lookup
*===========================================================================
* Description: Do a lookup in a MPLS route table.
* Parameters: tree_ix - Route table index
* key - MPLS key
* type - Table type (ILM/NHLFE)
*
* Returns:
*
*/
IP_GLOBAL Ipmpls_route*
ipmpls_route_lookup(Ip_u16 ix, Ipmpls_key *key)
{
Ipmpls_route *route = IP_NULL;
Ipmpls_route *tree = IP_NULL;
Ip_bool perfect = IP_FALSE;
tree = (Ipmpls_route*)ipcom_hash_get(ipmpls->label_tables, &ix);
if (tree)
{
route = (Ipmpls_route*)ipcom_route_lookup(tree->head,
(const void *) key,
&perfect);
if (!perfect)
route = IP_NULL;
}
return route;
}
/*
*===========================================================================
* ipmpls_route_add
*===========================================================================
* Description: Add a new entry in a MPLS route table.
* Parameters: tree_index - Route table index
* key - MPLS key for the new entry
* route - The MPLS route entry (ILM/NHLFE)
* type - ILM/NHLFE
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_route_add(Ip_u16 vr, Ipmpls_key *key, Ipmpls_route *route)
{
Ipmpls_route *tree;
Ip_time_t t;
tree = ipcom_hash_get(ipmpls->label_tables, &vr);
if (tree == IP_NULL)
return -IP_ERRNO_EINVAL;
route->age = ipcom_time(&t);
route->hdr.key = &route->key;
route->vr = vr;
route->head = tree->head;
ipcom_memcpy(&route->key, key, sizeof(Ipmpls_key));
return ipcom_route_add(route->head, &route->hdr);
}
/*
*===========================================================================
* ipmpls_route_remove
*===========================================================================
* Description: Remove a MPLS route entry (ILM/NHLFE)
* Parameters: route - The route entry
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_route_remove(Ipmpls_route *route)
{
return ipcom_route_remove(route->head, &route->hdr);
}
/*
*===========================================================================
* ipmpls_key_create
*===========================================================================
* Description: Compose a MPLS key out of label space and label value
* Parameters: labelspace - Label Space
* label - Label entry
* key - Key entry
*
* Returns: Pointer to key.
*
*/
IP_GLOBAL Ipmpls_key *
ipmpls_key_create(int labelspace, Ipmpls_label *label, Ipmpls_key *key)
{
ipcom_memset(key, 0, sizeof(*key)),
*key = IPMPLS_KEY_SET_TYPE(*key, label->ml_type);
*key = IPMPLS_KEY_SET_LABEL(*key, label->u.ml_gen);
*key = IPMPLS_KEY_SET_LABELSPACE(*key, labelspace);
return key;
}
/*
*===========================================================================
* ipmpls_set_labelspace
*===========================================================================
* Description: Sets MPLS label space on an ethernet device
* Parameters: [in] netif - device descriptor
* [in] labelspace - label space
* Returns: 0 = success, <0 = error code.
*
*/
IP_GLOBAL int
ipmpls_labelspace_set(Ipcom_netif *netif, int labelspace)
{
struct Ipmpls_eth_if_mpls_data *mpls_data;
int ret = -IP_ERRNO_EFAULT;
if ((netif->type == IP_IFT_ETHER) || (netif->type == IP_IFT_L2VLAN))
{
/* Access the mpls private data on the ethernet device */
if (netif->plink)
mpls_data = (struct Ipmpls_eth_if_mpls_data*)netif->plink;
else
{
mpls_data = ipcom_calloc(1, sizeof(struct Ipmpls_eth_if_mpls_data));
netif->plink = mpls_data;
}
if(mpls_data)
{
mpls_data->mpls_labelspace = labelspace;
ret = 0;
}
}
else
{
/* Not an Ethernet interface */
ret = -IP_ERRNO_EPERM;
}
return ret;
}
/*
*===========================================================================
* ipmpls_labelspace_get
*===========================================================================
* Description: Gets MPLS label space from an ethernet device
* Parameters: [in] netif - device descriptor
* [out] labelspace - label space
* Returns: 0 = success, <0 = error code.
*
*/
IP_GLOBAL int
ipmpls_labelspace_get(Ipcom_netif *netif, int *labelspace)
{
int ret = 0;
if ((netif->type == IP_IFT_ETHER) || (netif->type == IP_IFT_L2VLAN))
{
/* Access the mpls private data on the ethernet device */
if (netif->plink)
*labelspace = ((struct Ipmpls_eth_if_mpls_data*)netif->plink)->mpls_labelspace;
else
*labelspace = 0;
}
else
{
/* Not an Ethernet interface */
ret = -IP_ERRNO_EPERM;
}
return ret;
}
/*
*===========================================================================
* ipmpls_oplist_remove
*===========================================================================
* Description: Flush a MPLS operation list
* Parameters: oplist - Pointer to operation list.
*
* Returns: -
*
*/
IP_GLOBAL void
ipmpls_oplist_remove(Ipmpls_opcode_list *oplist)
{
int i;
Ipmpls_opcode_elem *op;
for (i = 0; i < oplist->num_opcodes; i++)
{
op = &oplist->opcodes[i];
switch (op->opcode)
{
case IPMPLS_OP_POP:
case IPMPLS_OP_PEEK:
case IPMPLS_OP_PUSH:
case IPMPLS_OP_FWD:
case IPMPLS_OP_DLV:
case IPMPLS_OP_SET_RX:
case IPMPLS_OP_SET:
break;
}
}
ipcom_free(oplist);
}
/*
*===========================================================================
* ipmpls_oplist_create
*===========================================================================
* Description: Allocate memory for a new operation list
* Parameters: n_elem - Number of elements to be held in the list
*
* Returns: Pointer to oplist Ok
* IP_NULL Failed
*
*/
IP_GLOBAL Ipmpls_opcode_list *ipmpls_oplist_create(Ip_u8 n_elem)
{
Ipmpls_opcode_list *oplist;
oplist = ipcom_calloc(1, sizeof(Ipmpls_opcode_list));
if (oplist == IP_NULL)
return IP_NULL;
oplist->num_opcodes = n_elem;
return oplist;
}
/*
*===========================================================================
* ipmpls_opcode_setup
*===========================================================================
* Description: Setup a MPLS operation list.
* Parameters: dst - The MPLS operation list.
* src - The MPLS operation configuration list.
* n_elem - Number of elements to handle.
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_opcode_setup(Ipmpls_opcode_elem *dst, Ipmpls_instr_elem *src,
Ip_u8 n_elem)
{
Ip_u8 i;
Ipcom_netif *netif;
int ret = 0;
int ifindex;
for(i = 0; i < n_elem; i++)
{
dst[i].opcode = src[i].mir_opcode;
switch (dst[i].opcode)
{
case IPMPLS_OP_POP:
case IPMPLS_OP_PEEK:
case IPMPLS_OP_DLV:
/* These operations do not carry any data */
dst[i].data.ptr = IP_NULL;
break;
case IPMPLS_OP_SET_RX:
/* Set receiving interface. Check if valid index */
ifindex = src[i].mir_data.set_rx;
if (ipcom_mpls_ioevent(IP_NULL, IPMPLS_EIOXINDEXTONETIF,
&ifindex, &netif, IP_NULL) == 0)
{
dst[i].data.set.ifindex = ifindex;
ipcom_memset(&dst[i].data.set.a,0,sizeof(dst[i].data.set.a));
}
else
IPMPLS_ERROUT(-IP_ERRNO_EINVAL);
break;
case IPMPLS_OP_SET_VR:
/* Set route . Check if valid index */
if (ipcom_mpls_ioevent(IP_NULL, IPMPLS_EIOXRTABTONETIF,
&src[i].mir_data.set_rtab,
&netif, IP_NULL) == 0)
{
dst[i].data.set.ifindex = src[i].mir_data.set_rtab;
ipcom_memset(&dst[i].data.set.a, 0, sizeof(dst[i].data.set.a));
}
else
IPMPLS_ERROUT(-IP_ERRNO_EINVAL);
break;
case IPMPLS_OP_PUSH:
/* Push a new MPLS label on the packet */
dst[i].data.push = src[i].mir_data.push;
break;
case IPMPLS_OP_FWD:
/* Store key to next MPLS route object */
ipmpls_key_create(0, &src[i].mir_data.fwd, &dst[i].data.fwd);
/* FWD must always be last */
goto errout;
case IPMPLS_OP_SET:
{
/*
* Save GW address to be used when doing DLV
*/
ipcom_memcpy(&dst[i].data.set.a,
&src[i].mir_data.set.a,
sizeof(src[i].mir_data.set.a));
if (src[i].mir_direction == IPMPLS_OUT)
{
/*
* NHLFE SET
* Set nexthop address and outgoing interface.
*/
if (ipcom_mpls_ioevent(IP_NULL,
IPMPLS_EIOXINDEXTONETIF,
&src[i].mir_data.set.mni_if,
&netif,
IP_NULL) != 0)
IPMPLS_ERROUT(-IP_ERRNO_EINVAL);
if (((netif->type != IP_IFT_ETHER) && (netif->type != IP_IFT_L2VLAN)))
IPMPLS_ERROUT(-IP_ERRNO_EINVAL);
/* Convert to internal ifindex for faster lookup */
dst[i].data.set.ifindex = netif->ifindex;
}
break;
}
}
}
errout:
return ret;
}
/*
*===========================================================================
* ipmpls_opcode_copy
*===========================================================================
* Description: Copy a operation list to a operation configuration list.
* Parameters: src - The MPLS operation list
* dst - The MPLS operation configuration list
* n_elem - Number of elements
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_GLOBAL int
ipmpls_opcode_copy(Ipmpls_opcode_list *src,
Ipmpls_instr_elem *dst,
Ip_u8 *n_elem)
{
Ip_u8 i;
int ret = 0;
Ipmpls_opcode_elem *op;
for (i = 0; i < src->num_opcodes; i++)
{
op = &src->opcodes[i];
ipcom_memset(&dst[i], 0, sizeof(Ipmpls_instr_elem));
dst[i].mir_opcode = op->opcode;
switch (op->opcode)
{
case IPMPLS_OP_POP:
case IPMPLS_OP_PEEK:
case IPMPLS_OP_DLV:
/* These operations do not carry any data */
break;
case IPMPLS_OP_SET_RX:
dst[i].mir_data.set_rx = op->data.set.ifindex;
break;
case IPMPLS_OP_SET_VR:
dst[i].mir_data.set_rtab = op->data.set.ifindex;
break;
case IPMPLS_OP_PUSH:
/* Push a new MPLS label on the packet */
dst[i].mir_data.push = op->data.push;
break;
case IPMPLS_OP_FWD:
dst[i].mir_data.fwd.ml_type = IPMPLS_KEY_GET_TYPE(op->data.fwd);
dst[i].mir_data.fwd.ml_index = IPMPLS_KEY_GET_LABELSPACE(op->data.fwd);
dst[i].mir_data.fwd.u.ml_gen = IPMPLS_KEY_GET_LABEL(op->data.fwd);
break;
case IPMPLS_OP_SET:
{
dst[i].mir_data.set.mni_if = op->data.set.ifindex;
ipcom_memcpy(&dst[i].mir_data.set.a,
&op->data.set.a,
sizeof(dst[i].mir_data.set.a));
#ifdef IP_PORT_LKM
{
/* Fix for Linux style sockaddr*/
Ip_u16 *family = (Ip_u16*)&dst[i].mir_data.set.a.sa.sa_family;
*family = (Ip_u16)(dst[i].mir_data.set.a.sa.sa_family);
}
#endif
}
break;
case IPMPLS_OP_NOP:
/* finished */
goto out;
}
}
out:
*n_elem = i;
return ret;
}
/*
*===========================================================================
* ipmpls_opcode_get_last
*===========================================================================
* Description: Get last operation element in a list.
* Parameters: oplist - Operation list
*
* Returns: Last operation element.
*
*/
IP_GLOBAL Ipmpls_opcode_elem *
ipmpls_opcode_get_last(Ipmpls_opcode_list *oplist)
{
return &oplist->opcodes[oplist->num_opcodes - 1];
}
/*
*===========================================================================
* ipmpls_opcode_get_last
*===========================================================================
* Description: Associate a specified ILM with a certain tunnel interface.
* Parameters: netif - Pointer to tunnel interface.
* data - Contains key to ILM.
*
* Returns: 0 Ok
* <0 Error
*
*/
IP_GLOBAL int
ipmpls_ilm_to_tunnel_map (Ipcom_netif *netif, Ip_u16 vr, Ip_u32 data)
{
int ret = -1;
Ipmpls_key key;
Ipmpls_label label;
Ipmpls_route *ilm;
/*
* An in label has been specified and shall
* be associated with this interface.
*/
label.ml_type = IPMPLS_LABEL_TYPE_GEN;
label.u.ml_key = data;
label.ml_index = 0;
(void)ipmpls_key_create(0, &label, &key);
ilm = ipmpls_route_lookup(vr, &key);
if (ilm)
{
if (ilm->oplist)
ipmpls_oplist_remove(ilm->oplist);
/*
* Set the ILM oplist to:
* pop,setrx="this tunnel",dlv
*/
ilm->oplist = ipmpls_oplist_create(3);
if (ilm->oplist)
{
ilm->oplist->opcodes[0].opcode = IPMPLS_OP_POP;
ilm->oplist->opcodes[0].data.ptr = IP_NULL;
ilm->oplist->opcodes[1].opcode = IPMPLS_OP_SET_RX;
ilm->oplist->opcodes[1].data.set.ifindex = netif->ifindex;
ilm->oplist->opcodes[2].opcode = IPMPLS_OP_DLV;
ilm->oplist->opcodes[2].data.ptr = IP_NULL;
ret = 0;
}
}
return ret;
}
/*
*===========================================================================
* ipmpls_set_cookie
*===========================================================================
* Description: Set a cooke on a certain MPLS route entry
* Parameters: l - label (key)
* vr - VR index
* data - cookie data.
*
* Returns: 0 Ok
* <0 Error
*
*/
IP_GLOBAL int
ipmpls_set_cookie(Ipmpls_label *l, Ip_u16 vr, void* data)
{
Ipmpls_key key;
Ipmpls_route *rt;
(void)ipmpls_key_create(l->ml_index, l, &key);
rt = ipmpls_route_lookup(vr, &key);
if (rt)
{
ipcom_memcpy(&rt->cookie, data, sizeof(Ipmpls_rt_cookie));
return 0;
}
return -IP_ERRNO_EINVAL;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmpls_create
*===========================================================================
* Description: IPMPLS constructor routine
* Parameters:
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_PUBLIC int
ipmpls_create(void)
{
int ret;
Ipmpls_route *rt;
Ipmpls_opcode_list *oplist;
ipmpls = ipcom_calloc(1, sizeof(Ipmpls_data));
if (ipmpls == IP_NULL)
return -IP_ERRNO_ENOMEM;
ipcom_memset(&ipmpls_ilm_explicit_ipv4,
0,
sizeof(ipmpls_ilm_explicit_ipv4));
ipcom_memset(&ipmpls_ilm_explicit_ipv6,
0,
sizeof(ipmpls_ilm_explicit_ipv6));
ipmpls->label_tables = ipcom_hash_new((Ipcom_hash_obj_func) ipmpls_route_table_hash_obj,
(Ipcom_hash_key_func) ipmpls_route_table_hash_key,
(Ipcom_hash_cmp_func) ipmpls_route_table_hash_cmp);
if (ipmpls->label_tables == IP_NULL)
{
IPCOM_LOG0(WARNING,"IPMPLS :: Failed to create ILM hash table");
return -IP_ERRNO_ENOMEM;
}
ret = ipmpls_route_table_create(0);
if (ret < 0)
return ret;
/* Setup the explicit labels */
/* Prepare the oplist */
oplist = ipcom_calloc(1, sizeof(Ipmpls_opcode_list));
if (oplist == IP_NULL)
return IP_ERRNO_ENOMEM;
oplist->num_opcodes = 2;
oplist->opcodes[0].dir = IPMPLS_IN;
oplist->opcodes[0].opcode = IPMPLS_OP_POP;
oplist->opcodes[1].dir = IPMPLS_IN;
oplist->opcodes[1].opcode = IPMPLS_OP_DLV;
/* Setup the entry, reuse the oplist if same ops are required */
rt = &ipmpls_ilm_explicit_ipv4;
rt->oplist = oplist;
rt->key = IPMPLS_KEY_SET_TYPE(rt->key, IPMPLS_LABEL_TYPE_GEN);
IPMPLS_ILM_PROTO(rt) = IP_IPPROTO_IP;
rt = &ipmpls_ilm_explicit_ipv6;
rt->oplist = oplist;
rt->key = IPMPLS_KEY_SET_TYPE(rt->key, IPMPLS_LABEL_TYPE_GEN);
IPMPLS_ILM_PROTO(rt) = IP_IPPROTO_IPV6;
return 0;
}
/*
*===========================================================================
* ipmpls_start
*===========================================================================
* Description: IPMPLS start routine
* Parameters: -
* Returns: IPCOM_SUCESS - Ok
* other - Failed
*
*/
IP_PUBLIC Ip_err
ipmpls_start(void)
{
Ip_err ret = IPCOM_SUCCESS;
#ifdef IPMPLS_INCLUDE_CMD
ret = ipcom_shell_add_cmd("mplsctl",
"mplsctl ...",
"MPLS forwarding engine shell tool",
(Ipcom_shell_cmd_type) ipmpls_cmd_mplsctl,
IPCOM_SHELL_PRIO_SAME,
IPCOM_PROC_STACK_DEFAULT);
/* Load preconfigured forwarding configs */
ipmpls_load_fwdconfig();
#endif
return ret;
}
/*
*===========================================================================
* ipmpls_version
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC const char *
ipmpls_version(void)
{
return "@(#) IPMPLS $Name: VXWORKS_ITER40_2019102207 $ - INTERPEAK_COPYRIGHT_STRING";
}
/*
*===========================================================================
* ipmpls_input
*===========================================================================
* Description: Input handler for ethernet frames. pkt->start is the offset
* to the ethernet header.
* Parameters: pkt - The ethernet frame.
* Returns: 0 = success, <0 error code
*
*/
IP_PUBLIC int
ipmpls_input(Ipcom_netif *netif, Ipcom_pkt *pkt, Ip_bool peeked)
{
(void)peeked;
return ipmpls_do_input(netif, pkt, IPMPLS_RECURSION_LIMIT);
}
/*
*===========================================================================
* ipmpls_tunnel_output
*===========================================================================
* Description: Outputs a packet transmitted via a MPLS tunnel interface.
* Parameters: netif - The network interface on which the packet should
* be sent.
* pkt - The packet to send.
* Returns: 0 = success, <0 = error code.
*
*/
IP_PUBLIC int
ipmpls_tunnel_output(Ipcom_netif *netif, Ipcom_pkt *pkt)
{
Ipmpls_netif *mplsif = (Ipmpls_netif *) netif->plink;
ip_assert(netif != IP_NULL);
ip_assert(netif->type == IP_IFT_MPLS_TUNNEL);
if (mplsif->nhlfe == IP_NULL)
{
mplsif->nhlfe = ipmpls_route_lookup(pkt->vr_index, &mplsif->key);
if (mplsif->nhlfe == IP_NULL)
return -IP_ERRNO_EHOSTUNREACH;
netif->mtu = IPMPLS_NHLFE_MTU(mplsif->nhlfe);
ipmpls_nhlfe_lock(mplsif->nhlfe);
}
if (netif->link_tap)
{
/* Let the tap handler copy the packet */
netif->link_tap(netif, pkt, IP_PACKET_OUTGOING, 0, pkt->ipstart, pkt->ipstart);
}
return ipmpls_process_label(netif, mplsif->nhlfe, IP_TRUE, pkt, IPMPLS_RECURSION_LIMIT);
}
/*
*===========================================================================
* ipmpls_shortcut_route_output
*===========================================================================
* Description: Outputs a packet forwarded via a MPLS pseudo wire route.
* Parameters: nhlfe - Pointer to the NHLFE to be used for forwarding.
* pkt - The packet to send.
* Returns: 0 = success, <0 = error code.
*
*/
IP_PUBLIC int
ipmpls_shortcut_route_output(Ip_u32 key, Ipcom_pkt *pkt)
{
Ipmpls_label label;
Ipmpls_nhlfe *nhlfe;
label.ml_type = IPMPLS_LABEL_TYPE_KEY;
label.u.ml_key = key;
nhlfe = ipmpls_route_lookup(pkt->vr_index,
ipmpls_key_create(0, &label, &key));
if (nhlfe == IP_NULL)
return -IP_ERRNO_EHOSTUNREACH;
return ipmpls_process_label(IP_NULL,
nhlfe,
IP_TRUE,
pkt,
IPMPLS_RECURSION_LIMIT);
}
/*
*===========================================================================
* ipmpls_shortcut_route_nhlfe_lookup
*===========================================================================
* Description: Keep for backwards compatiblilty.
* Parameters:
* Returns: 0 Ok
* <0 Failed
*
*/
IP_PUBLIC int
ipmpls_shortcut_route_nhlfe_lookup(struct Ip_sockaddr_mpls *sa_mpls)
{
(void)sa_mpls;
return 0;
}
/*
*===========================================================================
* ipmpls_if_init
*===========================================================================
* Description: MPLS tunnel interface constructor routine.
* Parameters: netif - MPLS tunnel interface
* Returns: 0 Ok
* <0 Failed
*
*/
IP_PUBLIC int
ipmpls_if_init(Ipcom_netif *netif)
{
Ipmpls_netif *mplsif;
/* Allocate MPLS private link data */
netif->plink = ipcom_malloc(sizeof(Ipmpls_netif));
mplsif = (Ipmpls_netif *) netif->plink;
if (mplsif == IP_NULL)
return -IP_ERRNO_ENOMEM;
ipcom_memset(mplsif, 0, sizeof(Ipmpls_netif));
netif->flags = IP_IFF_NOARP /* | IP_IFF_POINTOPOINT */;
netif->mtu = IPMPLS_DEFAULT_MTU;
return 0;
}
/*
*===========================================================================
* ipmpls_if_free
*===========================================================================
* Description: MPLS tunnel interface destructor routine.
* Parameters: netif - MPLS tunnel interface
* Returns: 0 Ok
* <0 Failed
*/
IP_PUBLIC int
ipmpls_if_free(Ipcom_netif *netif)
{
Ipmpls_netif *mplsif = (Ipmpls_netif *)netif->plink;
if (mplsif)
ipcom_free(mplsif);
return 0;
}
/*
*===========================================================================
* ipmpls_tunnel_ioctl
*===========================================================================
* Description: MPLS tunnel IOCTL handler
* Parameters: netif - MPLS tunnel interface
* cmd - IOCTL command
* data - IOCTL data
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_PUBLIC int
ipmpls_tunnel_ioctl(Ipcom_netif *netif, Ip_u32 cmd, void *data)
{
int ret = 0;
Ipmpls_netif *mplsif;
struct Ip_ifreq *ifreq = (struct Ip_ifreq *) data;
mplsif = (Ipmpls_netif *) netif->plink;
ip_assert(mplsif != IP_NULL);
switch(cmd)
{
case IP_SIOCXOPEN:
(void)ipcom_mpls_ioevent(netif, IPMPLS_EIOXIF_OPEN, IP_NULL, IP_NULL, IP_NULL);
if (mplsif->key)
(void)ipcom_mpls_ioevent(netif, IPMPLS_EIOXIF_RUNNING, IP_NULL, IP_NULL, IP_NULL);
break;
case IP_SIOCXCLOSE:
(void)ipcom_mpls_ioevent(netif, IPMPLS_EIOXIF_CLOSE, IP_NULL, IP_NULL, IP_NULL);
(void)ipcom_mpls_ioevent(netif, IPMPLS_EIOXIF_STOP, IP_NULL, IP_NULL, IP_NULL);
break;
case IPMPLS_SIOCMPLSTUNNELADDOUT:
if (ifreq == IP_NULL)
return -IP_ERRNO_EINVAL;
ipmpls_key_create(0, (Ipmpls_label *) &ifreq->ip_ifr_data, &mplsif->key);
if (IP_BIT_ISSET(netif->flags, IP_IFF_UP))
(void)ipcom_mpls_ioevent(netif, IPMPLS_EIOXIF_RUNNING, IP_NULL, IP_NULL, IP_NULL);
break;
case IPMPLS_SIOCMPLSTUNNELDELOUT:
{
Ipmpls_key key;
if (ifreq == IP_NULL)
return -IP_ERRNO_EINVAL;
ipmpls_key_create(0, (Ipmpls_label *) &ifreq->ip_ifr_data, &key);
if (key == mplsif->key)
{
ipmpls_nhlfe_unlock(mplsif->nhlfe);
mplsif->nhlfe = IP_NULL;
mplsif->key = 0;
netif->mtu = IPMPLS_DEFAULT_MTU;
IP_BIT_CLR(netif->flags, IP_IFF_RUNNING);
}
}
break;
case IPMPLS_SIOCMPLSTUNNELGETOUT:
if (ifreq == IP_NULL)
return -IP_ERRNO_EINVAL;
{
Ipmpls_label *label = (Ipmpls_label *) &ifreq->ip_ifr_data;
label->ml_type = IPMPLS_KEY_GET_TYPE(mplsif->key);
label->u.ml_key = IPMPLS_KEY_GET_LABEL(mplsif->key);
label->ml_index = 0;
}
break;
default:
ret = -IP_ERRNO_EINVAL;
break;
}
return ret;
}
/*
*===========================================================================
* ipmpls_route_table_notify
*===========================================================================
* Description: MPLS route table handler
* Parameters: vr - vr index
* is_added - boolean (added or deleted)
*
* Returns: 0 Ok
* <0 Failed
*
*/
IP_PUBLIC void
ipmpls_route_table_notify(Ip_u16 vr, Ip_bool is_added)
{
Ipmpls_route *tree;
if (vr == 0)
return;
if (is_added)
(void)ipmpls_route_table_create(vr);
else
{
/* Delete table */
tree = (Ipmpls_route*)ipcom_hash_get(ipmpls->label_tables, &vr);
if (tree)
{
/* Flush tree from ILMs and NHLFEs */
(void)ipmpls_route_flush_tree(vr, IPMPLS_LABEL_TYPE_GEN);
(void)ipmpls_route_flush_tree(vr, IPMPLS_LABEL_TYPE_KEY);
ipcom_route_free_table(tree->head);
if (ipcom_hash_remove(ipmpls->label_tables, tree) != IPCOM_SUCCESS)
IP_PANIC();
ipcom_free(tree);
}
}
}
#else
int ipmpls_empty_file = 1;
#endif
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/