/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifdef IPMPLS #include "ipmpls_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #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 **************************************************************************** */