1123 lines
33 KiB
C
1123 lines
33 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmpls_cmd_mplsctl.c,v $ $Revision: 1.19.10.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmpls/src/ipmpls_cmd_mplsctl.c,v $
|
|
* $Author: hsun $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
*
|
|
* Design and implementation by Jonas Rendel <jonas@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmpls_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPMPLS_INCLUDE_CMD
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom.h>
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_shell.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_getopt.h>
|
|
#include <ipcom_cmd.h>
|
|
|
|
#include "ipmpls.h"
|
|
#include "ipmpls_h.h"
|
|
|
|
struct Ipmpls_op_cmd
|
|
{
|
|
char *name;
|
|
Ip_u16 code;
|
|
};
|
|
|
|
IP_STATIC struct Ipmpls_op_cmd ipmpls_op[] = {
|
|
{
|
|
"pop",
|
|
IPMPLS_OP_POP
|
|
},
|
|
{
|
|
"peek",
|
|
IPMPLS_OP_PEEK
|
|
},
|
|
{
|
|
"push",
|
|
IPMPLS_OP_PUSH
|
|
},
|
|
{
|
|
"dlv",
|
|
IPMPLS_OP_DLV
|
|
},
|
|
{
|
|
"fwd",
|
|
IPMPLS_OP_FWD
|
|
},
|
|
{
|
|
"set",
|
|
IPMPLS_OP_SET
|
|
},
|
|
{
|
|
"setrx",
|
|
IPMPLS_OP_SET_RX
|
|
},
|
|
{
|
|
"rtab",
|
|
IPMPLS_OP_SET_VR
|
|
},
|
|
{
|
|
"vr",
|
|
IPMPLS_OP_SET_VR
|
|
},
|
|
{
|
|
IP_NULL,
|
|
IPMPLS_OP_NOP
|
|
},
|
|
};
|
|
|
|
IP_STATIC int ipmpls_cmd_handle_op(unsigned long sioc, char *key,
|
|
char *labelspace, char *op, Ip_bool silent);
|
|
|
|
IP_STATIC Ip_fd mpls_fd = IP_INVALID_SOCKET;
|
|
|
|
/*
|
|
*===========================================================================
|
|
* impls_cmd_handle_labelspace
|
|
*===========================================================================
|
|
* Description: Label Space command handler
|
|
*
|
|
* Parameters: cmd - command
|
|
* if_name - interface name
|
|
* labelspace - label space
|
|
* silent - silent flag
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
impls_cmd_handle_labelspace(int cmd, char *if_name, char *labelspace, Ip_bool silent)
|
|
{
|
|
struct Ipmpls_labelspace_req lreq;
|
|
unsigned long sioc;
|
|
int ret = -1;
|
|
|
|
lreq.mls_family = 0;
|
|
lreq.mls_ifindex = ipcom_if_nametoindex(if_name);
|
|
lreq.mls_labelspace = labelspace ? ipcom_atoi(labelspace) : 0;
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'd':
|
|
lreq.mls_labelspace = 0;
|
|
/* fall through */
|
|
case 'a':
|
|
sioc = IPMPLS_SIOCSLABELSPACEMPLS;
|
|
break;
|
|
case 'g':
|
|
sioc = IPMPLS_SIOCGLABELSPACEMPLS;
|
|
break;
|
|
default:
|
|
return ret;
|
|
}
|
|
|
|
ret = ipcom_socketioctl(mpls_fd, sioc, &lreq);
|
|
|
|
if(((ret == 0) && (cmd == 'g')) && !silent)
|
|
ipcom_printf("Interface: %s ,Labelspace: %d",if_name, lreq.mls_labelspace);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_tunnel
|
|
*===========================================================================
|
|
* Description: MPLS tunnel command handler.
|
|
*
|
|
* Parameters: cmd - IOCTL command
|
|
* if_name - interoace name.
|
|
* nhlfe_key - NHLFE key
|
|
* mtu - MTU
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_tunnel(int cmd, char *if_name, char *nhlfe_key, char *mtu)
|
|
{
|
|
int ret = -1;
|
|
unsigned long sioc;
|
|
struct Ip_ifreq ifreq;
|
|
struct Ipmpls_label label;
|
|
Ipmpls_ifreq_data data;
|
|
char *d;
|
|
|
|
|
|
ipcom_memset(&data, 0, sizeof(data));
|
|
|
|
d = ipcom_strchr(if_name,'#');
|
|
|
|
if (d)
|
|
{
|
|
*d++ = 0;
|
|
data.vr = (Ip_u16)ipcom_atoi(d);
|
|
}
|
|
|
|
if (ipcom_strlen(if_name) >= IP_IFNAMSIZ)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ipcom_strcpy(ifreq.ifr_name, if_name);
|
|
ifreq.ip_ifr_data = &data;
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'a':
|
|
if (mtu)
|
|
data.mtu = ipcom_atoi(mtu);
|
|
sioc = IPMPLS_SIOCMPLSTUNNELADD;
|
|
break;
|
|
case 'd':
|
|
sioc = IPMPLS_SIOCMPLSTUNNELDEL;
|
|
break;
|
|
case 'g':
|
|
sioc = IPMPLS_SIOCMPLSTUNNELGETOUT;
|
|
break;
|
|
case 'b':
|
|
sioc = IPMPLS_SIOCMPLSTUNNELADDOUT;
|
|
goto do_key;
|
|
case 'u':
|
|
sioc = IPMPLS_SIOCMPLSTUNNELDELOUT ;
|
|
do_key:
|
|
if (nhlfe_key)
|
|
{
|
|
label.ml_type = IPMPLS_LABEL_TYPE_KEY;
|
|
label.u.ml_key = ipcom_atoi(nhlfe_key);
|
|
label.ml_index = 0;
|
|
label.__refcnt = 0;
|
|
|
|
ipcom_memcpy(&ifreq.ip_ifr_data, &label, sizeof(label));
|
|
}
|
|
else
|
|
goto out;
|
|
break;
|
|
default:
|
|
goto out;
|
|
}
|
|
|
|
ret = ipcom_socketioctl(mpls_fd, sioc, &ifreq);
|
|
|
|
if ((sioc == IPMPLS_SIOCMPLSTUNNELGETOUT) && (ret == 0))
|
|
{
|
|
ipcom_memcpy(&label, &ifreq.ip_ifr_data, sizeof(label));
|
|
ipcom_printf("NHLFE Key: %d\n",label.u.ml_key);
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_nhlfe
|
|
*===========================================================================
|
|
* Description: NHLFE command handler
|
|
*
|
|
* Parameters: cmd - Command
|
|
* nlhfe_key - Key
|
|
* op - Operation Code String
|
|
* mtu - MTU op string
|
|
* silent - Silent flag
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_nhlfe(int cmd, char *nhlfe_key, char *op, char *mtu, Ip_bool silent, Ip_u8 ttl)
|
|
{
|
|
int ret = -1;
|
|
unsigned long sioc;
|
|
struct Ipmpls_out_label_req olreq;
|
|
|
|
|
|
ipcom_memset(&olreq, 0 , sizeof(olreq));
|
|
|
|
olreq.mol_mtu = mtu ? ipcom_atoi(mtu) : 0;
|
|
olreq.mol_propagate_ttl = ttl;
|
|
|
|
if (!nhlfe_key)
|
|
goto out;
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'a':
|
|
if (op)
|
|
{
|
|
ret = ipmpls_cmd_handle_op(IPMPLS_SIOCSMPLSOUTINSTR, nhlfe_key, IP_NULL, op, silent);
|
|
goto out;
|
|
}
|
|
else
|
|
sioc = IPMPLS_SIOCMPLSNHLFEADD;
|
|
break;
|
|
case 'd':
|
|
sioc = IPMPLS_SIOCMPLSNHLFEDEL;
|
|
break;
|
|
case 'g':
|
|
sioc = IPMPLS_SIOCMPLSNHLFEGET;
|
|
break;
|
|
default:
|
|
goto out;
|
|
}
|
|
|
|
olreq.mol_label.ml_type = IPMPLS_LABEL_TYPE_KEY;
|
|
olreq.mol_label.u.ml_key = ipcom_atoi(nhlfe_key);
|
|
olreq.mol_label.ml_index = 0;
|
|
|
|
if ((ret = ipcom_socketioctl(mpls_fd, sioc, &olreq)) == 0)
|
|
{
|
|
if (!silent && cmd == 'a')
|
|
{
|
|
ipcom_printf("NHLFE Key: %lu"IP_LF, olreq.mol_label.u.ml_key);
|
|
}
|
|
else if (cmd == 'g')
|
|
{
|
|
char buf[30];
|
|
|
|
(void)ipcom_strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", ipcom_localtime((Ip_time_t*)&olreq.mol_age));
|
|
|
|
if (!silent)
|
|
{
|
|
ipcom_printf("NHLFE Key : %lu"IP_LF, olreq.mol_label.u.ml_key);
|
|
ipcom_printf("Label Space: %u"IP_LF, olreq.mol_label.ml_index);
|
|
ipcom_printf("Age : %s"IP_LF, buf);
|
|
ipcom_printf("MTU : %lu"IP_LF, olreq.mol_mtu);
|
|
ipcom_printf("TTL : %d"IP_LF, olreq.mol_propagate_ttl);
|
|
}
|
|
|
|
(void)ipcom_sprintf(buf, "%lu", olreq.mol_label.u.ml_key);
|
|
if ((ret = ipmpls_cmd_handle_op(IPMPLS_SIOCGMPLSOUTINSTR, buf, IP_NULL, IP_NULL, silent)) < 0)
|
|
{
|
|
if (!silent)
|
|
ipcom_printf("Operations: No label operations found"IP_LF);
|
|
ret = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_ilm
|
|
*===========================================================================
|
|
* Description: ILM command handler
|
|
*
|
|
* Parameters: cmd - ILM command
|
|
* ilm_key - ILM key
|
|
* proto - Protocol string
|
|
* op - Operation Code string
|
|
* silent - Silent flag
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_ilm(int cmd, char *ilm_key, char *proto, char *op, Ip_bool silent)
|
|
{
|
|
int ret = -1;
|
|
unsigned long sioc;
|
|
struct Ipmpls_in_label_req ilreq;
|
|
char *labelspace;
|
|
|
|
if (!ilm_key)
|
|
goto out;
|
|
|
|
labelspace = strchr(ilm_key, ':');
|
|
|
|
if(labelspace)
|
|
*labelspace++ = 0;
|
|
|
|
ipcom_memset(&ilreq, 0 , sizeof(ilreq));
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'a':
|
|
if (op)
|
|
{
|
|
ret = ipmpls_cmd_handle_op(IPMPLS_SIOCSMPLSININSTR,
|
|
ilm_key, labelspace, op, silent);
|
|
goto out;
|
|
}
|
|
else
|
|
{
|
|
sioc = IPMPLS_SIOCMPLSILMADD;
|
|
|
|
if (proto && (ipcom_strcmp("ipv4",proto) == 0))
|
|
ilreq.mil_proto = IP_IPPROTO_IP;
|
|
else if (proto && (ipcom_strcmp("ipv6",proto) == 0))
|
|
ilreq.mil_proto = IP_IPPROTO_IPV6;
|
|
else
|
|
goto out;
|
|
}
|
|
break;
|
|
case 'd':
|
|
sioc = IPMPLS_SIOCMPLSILMDEL;
|
|
break;
|
|
case 'g':
|
|
sioc = IPMPLS_SIOCMPLSILMGET;
|
|
break;
|
|
default:
|
|
goto out;
|
|
}
|
|
|
|
ilreq.mil_label.ml_type = IPMPLS_LABEL_TYPE_GEN;
|
|
ilreq.mil_label.u.ml_gen = ipcom_atoi(ilm_key);
|
|
ilreq.mil_label.ml_index = labelspace ? ipcom_atoi(labelspace) : 0;
|
|
|
|
|
|
if ((ret = ipcom_socketioctl(mpls_fd, sioc, &ilreq)) == 0)
|
|
{
|
|
if (cmd == 'g')
|
|
{
|
|
char buf[30];
|
|
|
|
(void)ipcom_strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", ipcom_localtime((Ip_time_t*)&ilreq.mil_age));
|
|
|
|
if (!silent)
|
|
{
|
|
ipcom_printf("Label : %lu"IP_LF, ilreq.mil_label.u.ml_gen);
|
|
ipcom_printf("Label Space: %d"IP_LF, ilreq.mil_label.ml_index);
|
|
ipcom_printf("Age : %s"IP_LF, buf);
|
|
ipcom_printf("Protocol : %s"IP_LF, ilreq.mil_proto == IP_IPPROTO_IP ? "ipv4" : "ipv6");
|
|
}
|
|
|
|
if ((ret = ipmpls_cmd_handle_op(IPMPLS_SIOCGMPLSININSTR, ilm_key, labelspace, IP_NULL, silent)) < 0)
|
|
{
|
|
if (!silent)
|
|
ipcom_printf("Operations : No label operations found"IP_LF);
|
|
ret = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_xc
|
|
*===========================================================================
|
|
* Description: Cross-Connect command handler
|
|
*
|
|
* Parameters: cmd - command
|
|
* ilm_key - ILM key
|
|
* nhlfe_key - NHLFE key
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_xc(int cmd, char *ilm_key, char *nhlfe_key)
|
|
{
|
|
int ret = -1;
|
|
struct Ipmpls_xconnect_req xcreq;
|
|
unsigned long sioc;
|
|
char *labelspace;
|
|
|
|
if ((!ilm_key) || (!nhlfe_key))
|
|
goto out;
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'b':
|
|
sioc = IPMPLS_SIOCMPLSXCADD;
|
|
break;
|
|
case 'u':
|
|
sioc = IPMPLS_SIOCMPLSXCDEL;
|
|
break;
|
|
case 'g':
|
|
sioc = IPMPLS_SIOCMPLSXCGET;
|
|
break;
|
|
default:
|
|
goto out;
|
|
}
|
|
|
|
labelspace = ipcom_strchr(ilm_key, ':');
|
|
|
|
if (labelspace)
|
|
*labelspace++ = 0;
|
|
|
|
xcreq.mx_in.ml_type = IPMPLS_LABEL_TYPE_GEN;
|
|
xcreq.mx_in.u.ml_gen = ipcom_atoi(ilm_key);
|
|
xcreq.mx_in.ml_index = labelspace ? ipcom_atoi(labelspace) : 0;
|
|
|
|
xcreq.mx_out.ml_type = IPMPLS_LABEL_TYPE_KEY;
|
|
xcreq.mx_out.u.ml_key = ipcom_atoi(nhlfe_key);
|
|
xcreq.mx_out.ml_index = 0;
|
|
|
|
ret = ipcom_socketioctl(mpls_fd, sioc, &xcreq);
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* impls_cmd_ll_ntop
|
|
*===========================================================================
|
|
* Description: Creates a string representation of the hardware address.
|
|
* Parameters: dl - The hardware address.
|
|
* strptr - Will hold the sting representation of the address.
|
|
* strlen - The length of the buffer pointer to by 'strptr'
|
|
* Returns: The string represenstion.
|
|
*
|
|
*/
|
|
#if 0
|
|
IP_STATIC IP_CONST char *
|
|
ipmpls_cmd_ll_ntop(struct Ip_sockaddr_ll *ll, char *str, Ip_size_t len)
|
|
{
|
|
int alen;
|
|
|
|
alen = ll->sll_halen;
|
|
|
|
if (alen > 0)
|
|
{
|
|
int x;
|
|
int slen;
|
|
|
|
for (x = 0; x < alen; x++)
|
|
{
|
|
slen = len - x * 3;
|
|
if (slen < 0)
|
|
break;
|
|
ipcom_snprintf(&str[x * 3], slen, "%02x%s", ll->sll_addr[x],
|
|
x + 1 == alen ? "\0" : ":");
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_op(
|
|
*===========================================================================
|
|
* Description: Operation code command handler
|
|
*
|
|
* Parameters: sioc - IOCTL command
|
|
* key - Key string
|
|
* labelspace - Labe Space string
|
|
* op - Operation Code String
|
|
* silent - Silent flag
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_op(unsigned long sioc, char *key, char* labelspace, char *op, Ip_bool silent)
|
|
{
|
|
struct Ipmpls_instr_req opreq;
|
|
int ret = -1;
|
|
int i = 0;
|
|
|
|
ipcom_memset(&opreq, 0, sizeof(opreq));
|
|
|
|
if ((sioc == IPMPLS_SIOCSMPLSININSTR) || (sioc == IPMPLS_SIOCGMPLSININSTR))
|
|
opreq.mir_label.ml_type = IPMPLS_LABEL_TYPE_GEN;
|
|
else
|
|
opreq.mir_label.ml_type = IPMPLS_LABEL_TYPE_KEY;
|
|
|
|
opreq.mir_label.u.ml_gen = ipcom_atoi(key);
|
|
opreq.mir_label.ml_index = labelspace ? ipcom_atoi(labelspace) : 0;
|
|
|
|
if ((sioc == IPMPLS_SIOCSMPLSININSTR) || (sioc == IPMPLS_SIOCSMPLSOUTINSTR))
|
|
{
|
|
int j;
|
|
char *d;
|
|
struct Ip_sockaddr *sa;
|
|
|
|
/* Set operation */
|
|
for(i = 0; i < IPMPLS_NUM_OPS && op && *op; i++)
|
|
{
|
|
if (sioc == IPMPLS_SIOCSMPLSININSTR)
|
|
opreq.mir_instr[i].mir_direction = IPMPLS_IN;
|
|
else
|
|
opreq.mir_instr[i].mir_direction = IPMPLS_OUT;
|
|
|
|
/* Operations are stored as op:data:data:data:op:data:op:op */
|
|
if ((d = ipcom_strchr(op, ',')) != IP_NULL)
|
|
*d++ = 0;
|
|
|
|
/* Get opcode */
|
|
for (j = 0; ipmpls_op[j].name; j++)
|
|
if (ipcom_strcmp(op, ipmpls_op[j].name) == 0)
|
|
break;
|
|
|
|
opreq.mir_instr[i].mir_opcode = ipmpls_op[j].code;
|
|
|
|
/* Handle opcode */
|
|
switch (ipmpls_op[j].code)
|
|
{
|
|
case IPMPLS_OP_POP:
|
|
case IPMPLS_OP_PEEK:
|
|
case IPMPLS_OP_DLV:
|
|
/* These ops do not come with any data */
|
|
op = d && *d ? --d : IP_NULL;
|
|
break;
|
|
case IPMPLS_OP_PUSH:
|
|
case IPMPLS_OP_FWD:
|
|
{
|
|
char *c;
|
|
/* Format op,key or op,type:labelspace:label */
|
|
if (!d || !*d)
|
|
goto bad_data_out;
|
|
|
|
/* Setup null-terminated label string */
|
|
op = ipcom_strchr(d, ',');
|
|
if (op)
|
|
*op = 0;
|
|
|
|
c = ipcom_strchr(d,':');
|
|
|
|
if (c)
|
|
{
|
|
/* type:labelspace:label syntax */
|
|
*c = 0;
|
|
opreq.mir_instr[i].mir_data.push.ml_type = ipcom_atoi(d);
|
|
d = c + 1;
|
|
c = ipcom_strchr(d,':');
|
|
if (!c)
|
|
goto bad_data_out;
|
|
*c = 0;
|
|
opreq.mir_instr[i].mir_data.push.ml_index = ipcom_atoi(d);
|
|
d = c + 1;
|
|
opreq.mir_instr[i].mir_data.push.u.ml_key = ipcom_atoi(d);
|
|
}
|
|
else
|
|
{
|
|
/* key syntax */
|
|
opreq.mir_instr[i].mir_data.push.ml_type = IPMPLS_LABEL_TYPE_KEY;
|
|
opreq.mir_instr[i].mir_data.push.u.ml_key = ipcom_atoi(d);
|
|
opreq.mir_instr[i].mir_data.push.ml_index = 0;
|
|
}
|
|
}
|
|
break;
|
|
case IPMPLS_OP_SET:
|
|
/*
|
|
* Format:
|
|
* NHLFE: op,<interface name>,<next hop address>
|
|
* ILM : op,<gateway address>
|
|
*/
|
|
|
|
if (!d || !*d)
|
|
goto bad_data_out;
|
|
|
|
if (sioc == IPMPLS_SIOCSMPLSOUTINSTR)
|
|
{
|
|
/* NHLFE SET */
|
|
|
|
/* Setup null-terminated interface string */
|
|
op = ipcom_strchr(d, ',');
|
|
|
|
if (!op || !*op)
|
|
goto bad_data_out;
|
|
*op++ = 0;
|
|
|
|
opreq.mir_instr[i].mir_data.set.mni_if = ipcom_if_nametoindex(d);
|
|
d = op;
|
|
}
|
|
|
|
sa = &opreq.mir_instr[i].mir_data.set.a.sa;
|
|
|
|
op = ipcom_strchr(d, ',');
|
|
|
|
/* Setup null-terminated address string */
|
|
if (op)
|
|
*op = 0;
|
|
|
|
/* Convert address string to sockaddr */
|
|
if (ipcom_getsockaddrbyaddr(IP_AF_INET, d, sa) < 0)
|
|
if (ipcom_getsockaddrbyaddr(IP_AF_INET6, d, sa) < 0)
|
|
{
|
|
if (ipcom_getsockaddrbyaddr(IP_AF_LINK, d, sa) < 0)
|
|
goto bad_data_out;
|
|
}
|
|
break;
|
|
case IPMPLS_OP_SET_RX:
|
|
/* Format op,<interface name> */
|
|
if (!d || !*d)
|
|
goto bad_data_out;
|
|
|
|
/* Setup null-terminated interface name string */
|
|
op = ipcom_strchr(d, ',');
|
|
if (op)
|
|
*op = 0;
|
|
opreq.mir_instr[i].mir_data.set_rx = ipcom_if_nametoindex(d);
|
|
break;
|
|
case IPMPLS_OP_SET_VR:
|
|
/* Format op,<rtab index> */
|
|
if (!d || !*d)
|
|
goto bad_data_out;
|
|
|
|
/* Setup null-terminated interface name string */
|
|
op = ipcom_strchr(d, ',');
|
|
if (op)
|
|
*op = 0;
|
|
opreq.mir_instr[i].mir_data.set_rtab = ipcom_atoi(d);
|
|
break;
|
|
case IPMPLS_OP_NOP:
|
|
/* oops. Invalid opname */
|
|
goto bad_op_out;
|
|
}
|
|
|
|
if (op)
|
|
op++;
|
|
|
|
}
|
|
|
|
opreq.mir_instr_length = (Ip_u8)i;
|
|
}
|
|
|
|
|
|
ret = ipcom_socketioctl(mpls_fd, sioc, &opreq);
|
|
|
|
if ((ret == 0) && ((sioc == IPMPLS_SIOCGMPLSININSTR) || (sioc == IPMPLS_SIOCGMPLSOUTINSTR)))
|
|
{
|
|
char buf[50];
|
|
if (!silent)
|
|
ipcom_printf("Operations : ");
|
|
|
|
/* Get operation */
|
|
for (i=0; i < opreq.mir_instr_length; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
if (!silent)
|
|
ipcom_printf(",");
|
|
}
|
|
|
|
/* Handle opcode */
|
|
switch (opreq.mir_instr[i].mir_opcode)
|
|
{
|
|
case IPMPLS_OP_POP:
|
|
if (!silent)
|
|
ipcom_printf("pop");
|
|
break;
|
|
case IPMPLS_OP_PEEK:
|
|
if (!silent)
|
|
ipcom_printf("peek");
|
|
break;
|
|
case IPMPLS_OP_DLV:
|
|
if (!silent)
|
|
ipcom_printf("dlv,%s",opreq.mir_family == IP_IPPROTO_IP ? "ipv4" : "ipv6");
|
|
break;
|
|
case IPMPLS_OP_PUSH:
|
|
if (!silent)
|
|
ipcom_printf("push,%lu",opreq.mir_instr[i].mir_data.push.u.ml_gen);
|
|
break;
|
|
case IPMPLS_OP_FWD:
|
|
if (!silent)
|
|
ipcom_printf("fwd,%lu:%lu:%lu",
|
|
opreq.mir_instr[i].mir_data.push.ml_type,
|
|
opreq.mir_instr[i].mir_data.push.ml_index,
|
|
opreq.mir_instr[i].mir_data.push.u.ml_key);
|
|
break;
|
|
case IPMPLS_OP_SET:
|
|
if (sioc == IPMPLS_SIOCGMPLSOUTINSTR)
|
|
{
|
|
char addrstr[64];
|
|
char namebuf[64];
|
|
void* addr = IP_NULL;
|
|
struct Ip_sockaddr *sa = &opreq.mir_instr[i].mir_data.set.a.sa;
|
|
|
|
|
|
switch (sa->sa_family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
addr = &opreq.mir_instr[i].mir_data.set.a.sin.sin_addr;
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
addr = &opreq.mir_instr[i].mir_data.set.a.sin6.sin6_addr;
|
|
break;
|
|
#endif
|
|
default:
|
|
goto bad_data_out;
|
|
}
|
|
|
|
ipcom_inet_ntop(sa->sa_family,
|
|
addr,
|
|
addrstr,
|
|
sizeof(addrstr));
|
|
|
|
/* NHFLE */
|
|
|
|
if (!silent)
|
|
ipcom_printf("set,%s,%s", ipcom_if_indextoname(opreq.mir_instr[i].mir_data.set.mni_if, namebuf), addrstr);
|
|
}
|
|
else
|
|
{
|
|
/* ILM */
|
|
if (!silent)
|
|
ipcom_printf("set,%s",
|
|
ipcom_cmd_sockaddr_to_str(&opreq.mir_instr[i].mir_data.set.a.sa,
|
|
IP_FALSE,
|
|
IP_TRUE,
|
|
buf,
|
|
sizeof(buf)));
|
|
}
|
|
break;
|
|
case IPMPLS_OP_SET_RX:
|
|
if (!silent)
|
|
ipcom_printf("setrx,%s",ipcom_if_indextoname(opreq.mir_instr[i].mir_data.set_rx, buf));
|
|
break;
|
|
case IPMPLS_OP_SET_VR:
|
|
if (!silent)
|
|
ipcom_printf("vr,%lu",opreq.mir_instr[i].mir_data.set_rtab);
|
|
break;
|
|
case IPMPLS_OP_NOP:
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
if (!silent)
|
|
ipcom_printf(IP_LF);
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
bad_data_out:
|
|
if (!silent)
|
|
ipcom_fprintf(ip_stderr,"Invalid data for operation code: %s"IP_LF,op);
|
|
return ret;
|
|
bad_op_out:
|
|
if (!silent)
|
|
ipcom_fprintf(ip_stderr,"Invalid operation code: %s"IP_LF,op);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_cmd_handle_table
|
|
*===========================================================================
|
|
* Description: Table command handler
|
|
*
|
|
* Parameters: cmd - command
|
|
* table - table string
|
|
*
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_cmd_handle_table(int cmd, char *table)
|
|
{
|
|
int ret = -1;
|
|
unsigned long sioc;
|
|
|
|
(void)cmd;
|
|
|
|
if (table && (ipcom_strcmp(table,"nhlfe") == 0))
|
|
sioc = IPMPLS_SIOCMPLSNHLFEFLUSH;
|
|
else if (table && (ipcom_strcmp(table,"ilm") == 0))
|
|
sioc = IPMPLS_SIOCMPLSILMFLUSH;
|
|
else
|
|
goto out;
|
|
|
|
ret = ipcom_socketioctl(mpls_fd, sioc, IP_NULL);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipdhcps_cmd_dhcps
|
|
*===========================================================================
|
|
* Description: Shell command used to start,stop and configure the DHCP
|
|
* server.
|
|
* Parameters: argc - The number of arguments passed to the command.
|
|
* argv - The arguments passed to the command.
|
|
* Returns: 0 = success,
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipmpls_cmd_mplsctl(int argc, char **argv)
|
|
{
|
|
char *op = IP_NULL;
|
|
char *ilm_key = IP_NULL;
|
|
char *nhlfe_key = IP_NULL;
|
|
char *if_name = IP_NULL;
|
|
char *proto = IP_NULL;
|
|
char *mtu = IP_NULL;
|
|
char *labelspace = IP_NULL;
|
|
char *table = IP_NULL;
|
|
char *vr = IP_NULL;
|
|
|
|
int ret = -1;
|
|
int cmd = 0;
|
|
int opt;
|
|
int cur_vr;
|
|
int new_vr;
|
|
|
|
Ip_bool silent = IP_FALSE;
|
|
Ip_u8 ttl = 0;
|
|
|
|
if (argc < 3)
|
|
goto usage;
|
|
|
|
#ifndef IP_PORT_LAS
|
|
new_vr = cur_vr = ipcom_proc_vr_get();
|
|
#else
|
|
(void)cur_vr;
|
|
#endif
|
|
|
|
ipcom_getopt_clear();
|
|
|
|
while ((opt = ipcom_getopt(argc, argv, "stadgbuf:i:n:l:I:o:m:p:V:")) != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'f':
|
|
table = ip_optarg;
|
|
/* fall through */
|
|
case 'a':
|
|
case 'd':
|
|
case 'g':
|
|
case 'b':
|
|
case 'u':
|
|
cmd = opt;
|
|
break;
|
|
case 'i':
|
|
ilm_key = ip_optarg;
|
|
break;
|
|
case 'n':
|
|
nhlfe_key = ip_optarg;
|
|
break;
|
|
case 'l':
|
|
labelspace = ip_optarg;
|
|
break;
|
|
case 'I':
|
|
if_name = ip_optarg;
|
|
break;
|
|
case 'o':
|
|
op = ip_optarg;
|
|
break;
|
|
case 'p':
|
|
proto = ip_optarg;
|
|
break;
|
|
case 'm':
|
|
mtu = ip_optarg;
|
|
break;
|
|
case 'V':
|
|
vr = ip_optarg;
|
|
break;
|
|
case 's':
|
|
silent = IP_TRUE;
|
|
break;
|
|
case 't':
|
|
ttl = 1;
|
|
break;
|
|
default:
|
|
goto usage;
|
|
}
|
|
}
|
|
|
|
mpls_fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM,0);
|
|
|
|
if (mpls_fd < 0)
|
|
{
|
|
ipcom_fprintf(ip_stderr, "Failed to open socket with error code %d (%s)"IP_LF,
|
|
ipcom_errno,
|
|
ipcom_strerror(ipcom_errno));
|
|
return -1;
|
|
}
|
|
|
|
if (vr != IP_NULL)
|
|
{
|
|
|
|
|
|
new_vr = ipcom_atoi(vr);
|
|
#ifdef IP_PORT_LAS
|
|
ret = ipcom_setsockopt(mpls_fd, IP_SOL_SOCKET, IP_SO_X_VR, &new_vr, sizeof(new_vr));
|
|
|
|
if (ret < 0)
|
|
{
|
|
ipcom_fprintf(ip_stderr, "Failed to set VR to %d"IP_LF, new_vr);
|
|
return -1;
|
|
}
|
|
#else
|
|
ipcom_proc_vr_set(new_vr);
|
|
#endif
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'a':
|
|
case 'd':
|
|
if (if_name && labelspace)
|
|
ret = impls_cmd_handle_labelspace(cmd, if_name, labelspace, silent);
|
|
else if (if_name)
|
|
ret = ipmpls_cmd_handle_tunnel(cmd, if_name, nhlfe_key, mtu);
|
|
else if (nhlfe_key)
|
|
ret = ipmpls_cmd_handle_nhlfe(cmd, nhlfe_key, op, mtu, silent, ttl);
|
|
else if (ilm_key)
|
|
ret = ipmpls_cmd_handle_ilm(cmd, ilm_key, proto, op, silent);
|
|
break;
|
|
case 'g':
|
|
if (if_name)
|
|
{
|
|
ret = impls_cmd_handle_labelspace(cmd, if_name, IP_NULL, silent);
|
|
|
|
if (ret < 0)
|
|
ret = ipmpls_cmd_handle_tunnel(cmd, if_name, nhlfe_key, mtu);
|
|
}
|
|
if (nhlfe_key)
|
|
ret = ipmpls_cmd_handle_nhlfe(cmd, nhlfe_key, IP_NULL, IP_NULL, silent, ttl);
|
|
if (ilm_key)
|
|
ret = ipmpls_cmd_handle_ilm(cmd, ilm_key, IP_NULL, IP_NULL, silent);
|
|
break;
|
|
case 'b':
|
|
case 'u':
|
|
if (ilm_key && nhlfe_key)
|
|
ret = ipmpls_cmd_handle_xc(cmd, ilm_key, nhlfe_key);
|
|
else if (if_name && nhlfe_key)
|
|
ret = ipmpls_cmd_handle_tunnel(cmd, if_name, nhlfe_key, mtu);
|
|
break;
|
|
|
|
case 'f':
|
|
ret = ipmpls_cmd_handle_table (cmd, table);
|
|
break;
|
|
}
|
|
|
|
ipcom_socketclose(mpls_fd);
|
|
|
|
#ifndef IP_PORT_LAS
|
|
if (cur_vr != new_vr)
|
|
ipcom_proc_vr_set(cur_vr);
|
|
#endif
|
|
|
|
if (ret < 0)
|
|
{
|
|
ipcom_fprintf(ip_stderr, "Failed with error code %d (%s)"IP_LF,
|
|
ipcom_errno,
|
|
ipcom_strerror(ipcom_errno));
|
|
}
|
|
|
|
return ret;
|
|
|
|
usage:
|
|
ipcom_fprintf(ip_stderr,
|
|
"Usage: mplsctl [-s] [-a] [-d] [-b] [-u] [-f ilm | nhlfe]"IP_LF
|
|
"[-I <interface name>] [-n <nhlfe key>] [-i <ilm key>]"IP_LF
|
|
"[-l <label space>] [-o <label operations>] [-m <mtu>]"IP_LF
|
|
"[-p <proto>] [-t <ttl>]" IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
"Command options:"IP_LF
|
|
"-s Silent mode (i.e. no output to stdout)"IP_LF
|
|
"-a Add an object"IP_LF
|
|
"-d Delete an object"IP_LF
|
|
"-b Bind an object to another"IP_LF
|
|
"-u Unbind an object"IP_LF
|
|
"-f Flush the ilm | nhlfe table"IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
"Object options:"IP_LF
|
|
"-I Interface name. Used together with tunnels and label spaces"IP_LF
|
|
"-n NHLFE key. Used with NHLFE:s, Tunnels and Cross-Connects"IP_LF
|
|
"-i ILM key. Used with ILM:s and Cross-Connects"IP_LF
|
|
"-p Protocol descriptor. Either ipv4 or ipv6"IP_LF
|
|
"-m MTU. Used with tunnels and NHLFE:s"IP_LF
|
|
"-t Set MPLS TTL to the value specified in the payload IP header (default 255)."IP_LF
|
|
" Used with NHLFE:s"IP_LF
|
|
"-o Label operations (comma separated). Used with NHLFE:s and ILM:s"IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
"Other options:"IP_LF
|
|
"-V Virtual router index"IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
" Valid NHLFE label operations:"IP_LF
|
|
" push,<label> - Push a label"IP_LF
|
|
" fwd,<key> - Forward the packet using the NHLFE identified with the key."IP_LF
|
|
" set,<ifname>,<next hop address> - For NHLFE: Set the outgoing interface and nexthop address."IP_LF
|
|
" Valid formats for the nexthop address: IPv4,IPv6,MAC"IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
" Valid ILM label operations:"IP_LF
|
|
" pop - Pop a label"IP_LF
|
|
" peek - Look at the label on top of the label stack and perform"IP_LF
|
|
" the operations associated with it"IP_LF
|
|
" dlv - Deliver packet to the IPv4/IPv6 stack"IP_LF
|
|
" push,<label> - Push a label"IP_LF
|
|
" fwd,<key> - Forward the packet using the NHLFE identified with the key."IP_LF
|
|
" set,<destination address> - For ILM: Set destination address to route to"IP_LF
|
|
" Valid formats for the destination address: IPv4,IPv6"IP_LF
|
|
" setrx,<ifname> - Set receiving interface."IP_LF
|
|
" vr,<index> - Set IPv4/IPv6 route table to use when forwarding."IP_LF IP_LF
|
|
" NOTE: The setrx operation can not be used in combination with the vr operation"IP_LF IP_LF);
|
|
ipcom_fprintf(ip_stderr,
|
|
"Examples:"IP_LF
|
|
" Add an IPv4 ILM with label 4711 in labelspace 17:"IP_LF
|
|
" mplsctl -a -i 4711:17 -p ipv4"IP_LF
|
|
" Add some operations on an ILM:"IP_LF
|
|
" mplsctl -a -i 4711:17 -o pop,setrx,eth0,dlv"IP_LF
|
|
" Add a NHLFE with autogenerated key:"IP_LF
|
|
" mplsctl -a -n 0"IP_LF
|
|
" Add a NHLFE with user defined key (1234):"IP_LF
|
|
" mplsctl -a -n 1234"IP_LF
|
|
" Add some operations on an NHLFE:"IP_LF
|
|
" mplsctl -a -n 1234 -o push,2345,set,eth0,10.1.1.1"IP_LF
|
|
" Add a Cross-Connect (ILM-NHLFE):"IP_LF
|
|
" mplsctl -b -i 4711:17 -n 1234"IP_LF);
|
|
return ret;
|
|
}
|
|
|
|
#endif /* #ifdef IPMPLS_INCLUDE_CMD */
|