903 lines
28 KiB
C
903 lines
28 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmpls_netlink.c,v $ $Revision: 1.3 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmpls/src/ipmpls_netlink.c,v $
|
|
* $Author: jonas $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Jonas Rendel <Jonas.Rendel@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#if defined(IPMPLS) && defined(IP_PORT_LKM)
|
|
#include "ipmpls_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#include <ipcom.h>
|
|
#include <ipcom_os.h>
|
|
|
|
#ifdef IP_PORT_LKM
|
|
#include <ipcom_lkm.h>
|
|
#endif
|
|
|
|
#include "ipmpls.h"
|
|
#include "ipmpls_h.h"
|
|
#include "ipmpls_ipstack.h"
|
|
#include "ipmpls_netlink.h"
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPMPLS_NETLINK_DUMP_FIRST_ENTRY 0
|
|
#define IPMPLS_NETLINK_DUMP_FINISHED 1
|
|
#define IPMPLS_NETLINK_DUMP_DONT_FIT 2
|
|
#define IPMPLS_NETLINK_DUMP_TRAILER 3
|
|
|
|
#define IPMPLS_NETLINK_DEF_BUF_SZ 1024
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipmpls_netlink_foreach_cb_data_struct
|
|
{
|
|
Ip_u8 status; /* Message status */
|
|
Ip_u32 seq; /* Message sequence number */
|
|
Ip_pid_t pid; /* Message receiver pid */
|
|
int vr; /* Caller specified vr */
|
|
int type ; /* Requested object type (ilm/nhlfe) */
|
|
Ip_ptrdiff_t args[4]; /* Various callback data */
|
|
Ip_size_t offset; /* Message buffer offset */
|
|
Ip_size_t len; /* Message buffer length */
|
|
Ip_u8 *data; /* Message buffer */
|
|
}
|
|
Ipmpls_netlink_foreach_cb_data;
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_EXTERN Ipmpls_data *ipmpls;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_netlink_rta_put
|
|
*===========================================================================
|
|
* Description: Add a NETLINK route attribute to a NETLINK message.
|
|
* Parameters: buf - Message buffer
|
|
* attrtype - Attribute type
|
|
* attrlen - Lenght of attribute
|
|
* data - Attribute data
|
|
*
|
|
* Returns: Length of attribute incuding header.
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipmpls_netlink_rta_put(void *buf, int attrtype, int attrlen, IP_CONST void *data)
|
|
{
|
|
struct Ipmpls_rtattr *rta = (struct Ipmpls_rtattr *)buf;
|
|
|
|
rta->rta_type = (Ip_u16) attrtype;
|
|
rta->rta_len = (Ip_u16) IPMPLS_RTA_LENGTH (attrlen);
|
|
|
|
if (data)
|
|
ipcom_memcpy(IPMPLS_RTA_DATA(rta), data, attrlen);
|
|
|
|
return (rta->rta_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_netlink_fill
|
|
*===========================================================================
|
|
* Description: Fill a NETLINK message with info about a MPLS object.
|
|
* Parameters: data - Message buffer
|
|
* obj - Pointer to MPLS object
|
|
* op - Pointer to MPLS operations object
|
|
* pid - NETLINK caller pid.
|
|
* seq - NETLINK caller sequence number.
|
|
* msg_type - Message type.
|
|
* len - Available buffer length.
|
|
*
|
|
* Returns: > 0 Success (number of bytes consumed)
|
|
* < 0 Failure
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmpls_netlink_fill(Ip_u8 *data, void *obj, void *op, void *cookie, Ip_pid_t pid,
|
|
int seq, Ip_u8 msg_type, Ip_u16 vr, Ip_size_t *len)
|
|
{
|
|
Ip_size_t objlen;
|
|
Ip_size_t oplen;
|
|
Ip_size_t size;
|
|
Ip_u32 vr32 = (Ip_u32)vr;
|
|
int objattr = 0;
|
|
int opattr = 0;
|
|
struct Ipmpls_nlmsghdr *nlh;
|
|
struct Ipmpls_rtmsg *rtm;
|
|
|
|
switch (msg_type)
|
|
{
|
|
case IPMPLS_RTN_ILM:
|
|
objlen = sizeof(struct Ipmpls_instr_req);
|
|
objattr = IPMPLS_RTA_ILM;
|
|
opattr = IPMPLS_RTA_INSTR;
|
|
oplen = sizeof(struct Ipmpls_instr_req);
|
|
break;
|
|
case IPMPLS_RTN_NHLFE:
|
|
objlen = sizeof(struct Ipmpls_out_label_req);
|
|
objattr = IPMPLS_RTA_NHLFE;
|
|
opattr = IPMPLS_RTA_INSTR;
|
|
oplen = sizeof(struct Ipmpls_instr_req);
|
|
break;
|
|
case IPMPLS_RTN_XC:
|
|
objlen = sizeof(struct Ipmpls_xconnect_req);
|
|
objattr = IPMPLS_RTA_XC;
|
|
opattr = 0;
|
|
oplen = 0;
|
|
case IPMPLS_RTN_TUNNEL:
|
|
objlen = ipcom_strlen(obj) + 1;
|
|
objattr = IPMPLS_RTA_TUNNEL_NAME;
|
|
opattr = IPMPLS_RTA_NHLFE;
|
|
oplen = sizeof(struct Ipmpls_out_label_req);
|
|
break;
|
|
case IPMPLS_RTN_LABELSPACE:
|
|
objlen = sizeof(struct Ipmpls_labelspace_req);
|
|
objattr = IPMPLS_RTA_LABELSPACE;
|
|
opattr = 0;
|
|
oplen = 0;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
size = sizeof(*nlh) + sizeof(*rtm) + IPMPLS_RTA_LENGTH(objlen) + IPMPLS_RTA_LENGTH(oplen);
|
|
|
|
/* Check if entry fits */
|
|
if (*len < size)
|
|
return -1;
|
|
|
|
/* Add netlink header */
|
|
nlh = (struct Ipmpls_nlmsghdr *)data;
|
|
nlh->nlmsg_type = IPMPLS_RTM_NEWRULE;
|
|
nlh->nlmsg_len = IPMPLS_NLMSG_LENGTH(sizeof (*rtm));
|
|
nlh->nlmsg_flags = 0;
|
|
nlh->nlmsg_pid = pid;
|
|
nlh->nlmsg_seq = seq;
|
|
|
|
/* Add route message header */
|
|
rtm = IPMPLS_NLMSG_DATA(nlh);
|
|
ipcom_memset(rtm, 0, sizeof(*rtm));
|
|
|
|
rtm->rtm_family = IP_AF_MPLS;
|
|
rtm->rtm_type = msg_type;
|
|
|
|
/* Add VR as attribute */
|
|
nlh->nlmsg_len += ipmpls_netlink_rta_put(&data[nlh->nlmsg_len],
|
|
IPMPLS_RTA_VR,
|
|
sizeof(Ip_u32),
|
|
&vr32);
|
|
|
|
/* Add object as attribute */
|
|
(void)ipmpls_netlink_rta_put(&data[nlh->nlmsg_len],
|
|
objattr,
|
|
objlen,
|
|
obj);
|
|
|
|
nlh->nlmsg_len += IPMPLS_RTA_SPACE(objlen);
|
|
|
|
if (op)
|
|
{
|
|
/* Add object operations as attribute */
|
|
(void)ipmpls_netlink_rta_put(&data[nlh->nlmsg_len],
|
|
opattr,
|
|
oplen,
|
|
op);
|
|
|
|
nlh->nlmsg_len += IPMPLS_RTA_SPACE(oplen);
|
|
}
|
|
|
|
if (cookie)
|
|
{
|
|
/* Add MPLS route cookie as attribute */
|
|
(void)ipmpls_netlink_rta_put(&data[nlh->nlmsg_len],
|
|
IPMPLS_RTA_COOKIE,
|
|
sizeof(Ipmpls_rt_cookie),
|
|
cookie);
|
|
|
|
nlh->nlmsg_len += IPMPLS_RTA_SPACE(sizeof(Ipmpls_rt_cookie));
|
|
|
|
}
|
|
|
|
*len -= nlh->nlmsg_len;
|
|
return nlh->nlmsg_len;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_netlink_route_foreach_vr
|
|
*===========================================================================
|
|
* Description: Hash table foreach callback. Called once for each virtual
|
|
* router that exists in the system.
|
|
* Parameters: rtab - route table
|
|
* param - callback parameters.
|
|
* Returns: -
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmpls_netlink_route_foreach_vr(Ipmpls_route *rtab, Ipmpls_netlink_foreach_cb_data *param)
|
|
{
|
|
int new_offs;
|
|
Ip_u16 vr = rtab->vr;
|
|
Ipmpls_route *rt = (Ipmpls_route*)param->args[2];
|
|
int type = param->type == IPMPLS_RTN_ILM ? IPMPLS_LABEL_TYPE_GEN : IPMPLS_LABEL_TYPE_KEY;
|
|
|
|
/* Check if specific VR shall be dumped */
|
|
if ((param->vr != IPCOM_VR_ANY) && (param->vr != vr))
|
|
return;
|
|
|
|
/* Skip if message is already full */
|
|
if (param->status == IPMPLS_NETLINK_DUMP_DONT_FIT)
|
|
return;
|
|
|
|
/*
|
|
* If this is a trailer message buffer, make sure it
|
|
* starts dumping where the last message ended
|
|
*/
|
|
if ((param->status == IPMPLS_NETLINK_DUMP_TRAILER) && (vr != (Ip_u16)param->args[0]))
|
|
return;
|
|
|
|
/* Verify that route entry is still valid */
|
|
if (rt)
|
|
rt = rt->netlink_pid == ipcom_getpid() ? rt : IP_NULL;
|
|
|
|
if (rt == IP_NULL)
|
|
rt = (Ipmpls_route*)ipcom_route_first_entry(rtab->head);
|
|
|
|
while (rt)
|
|
{
|
|
|
|
if (IPMPLS_KEY_GET_TYPE(rt->key) == type)
|
|
{
|
|
union {
|
|
struct Ipmpls_in_label_req il;
|
|
struct Ipmpls_out_label_req ol;
|
|
Ipmpls_rt_cookie cookie;
|
|
} u;
|
|
struct Ipmpls_instr_req op;
|
|
int ret;
|
|
unsigned long req;
|
|
unsigned long opreq;
|
|
|
|
ipcom_memset(&op,0,sizeof(op));
|
|
ipcom_memset(&u, 0,sizeof(u));
|
|
|
|
switch(IPMPLS_KEY_GET_TYPE(rt->key))
|
|
{
|
|
case IPMPLS_LABEL_TYPE_GEN:
|
|
req = IPMPLS_SIOCMPLSILMGET;
|
|
opreq = IPMPLS_SIOCGMPLSININSTR;
|
|
u.il.mil_label.ml_type = IPMPLS_KEY_GET_TYPE(rt->key);
|
|
u.il.mil_label.u.ml_gen = IPMPLS_KEY_GET_LABEL(rt->key);
|
|
break;
|
|
case IPMPLS_LABEL_TYPE_KEY:
|
|
req = IPMPLS_SIOCMPLSNHLFEGET;
|
|
opreq = IPMPLS_SIOCGMPLSOUTINSTR;
|
|
u.ol.mol_label.ml_type = IPMPLS_KEY_GET_TYPE(rt->key);
|
|
u.ol.mol_label.u.ml_key = IPMPLS_KEY_GET_LABEL(rt->key);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* Fetch info about the object */
|
|
(void)ipmpls_do_ioctl(req, vr, &u);
|
|
|
|
/* Fetch info about the object operations */
|
|
op.mir_label.ml_type = IPMPLS_KEY_GET_TYPE(rt->key);
|
|
op.mir_label.u.ml_key = IPMPLS_KEY_GET_LABEL(rt->key);
|
|
|
|
ret = ipmpls_do_ioctl(opreq, vr, &op);
|
|
|
|
ipcom_memset(&u.cookie,0, sizeof(u.cookie));
|
|
|
|
new_offs = ipmpls_netlink_fill(¶m->data[param->offset],
|
|
&u,
|
|
ret == 0 ? &op : IP_NULL,
|
|
ipcom_memcmp(&rt->cookie,&u.cookie,sizeof(rt->cookie)) == 0 ? IP_NULL : &rt->cookie,
|
|
param->pid,
|
|
param->seq,
|
|
param->type,
|
|
vr,
|
|
¶m->len);
|
|
|
|
if (new_offs < 0)
|
|
goto dont_fit;
|
|
|
|
param->offset += (Ip_size_t)new_offs;
|
|
}
|
|
|
|
rt = (Ipmpls_route*)ipcom_route_next_entry(&rt->hdr);
|
|
}
|
|
|
|
param->status = IPMPLS_NETLINK_DUMP_FINISHED;
|
|
return;
|
|
|
|
dont_fit:
|
|
/* Set status to full */
|
|
param->status = IPMPLS_NETLINK_DUMP_DONT_FIT;
|
|
param->args[0] = (Ip_ptrdiff_t)vr;
|
|
param->args[1] = (Ip_ptrdiff_t)rt;
|
|
|
|
if (rt)
|
|
rt->netlink_pid = ipcom_getpid();
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmpls_netlink_neitf_foreach
|
|
*===========================================================================
|
|
* Description: Netif table foreach callback. Called once for each interface
|
|
* that exists in the system.
|
|
* Parameters: netif - interface descriptor
|
|
* param - callback parameters.
|
|
* Returns: -
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmpls_netlink_netif_foreach(Ipcom_netif *s_netif, Ip_u16 vr, Ipmpls_netlink_foreach_cb_data *param)
|
|
{
|
|
int new_offs;
|
|
Ipcom_netif *netif = (Ipcom_netif*)param->args[1];
|
|
void *obj;
|
|
void *extra;
|
|
int ret;
|
|
unsigned long req;
|
|
union {
|
|
struct Ipmpls_out_label_req ol;
|
|
struct Ipmpls_labelspace_req ls;
|
|
} u;
|
|
|
|
/* Check if specific VR shall be dumped */
|
|
if ((param->vr != IPCOM_VR_ANY) && (param->vr != vr))
|
|
return;
|
|
|
|
/* Skip if message is already full */
|
|
if (param->status == IPMPLS_NETLINK_DUMP_DONT_FIT)
|
|
return;
|
|
|
|
/*
|
|
* If this is a trailer message buffer, make sure it
|
|
* starts dumping where the last message ended
|
|
*/
|
|
if ((param->status == IPMPLS_NETLINK_DUMP_TRAILER) && (vr != (Ip_u16)param->args[0]))
|
|
return;
|
|
|
|
if (netif == IP_NULL)
|
|
netif = s_netif;
|
|
|
|
ipcom_memset(&u, 0,sizeof(u));
|
|
|
|
switch (param->type)
|
|
{
|
|
case IPMPLS_RTN_TUNNEL:
|
|
{
|
|
Ipmpls_netif *mplsif = (Ipmpls_netif*)netif->plink;
|
|
|
|
if ((netif->type != IP_IFT_MPLS_TUNNEL) || (mplsif == IP_NULL))
|
|
return;
|
|
|
|
req = IPMPLS_SIOCMPLSNHLFEGET;
|
|
u.ol.mol_label.ml_type = IPMPLS_KEY_GET_TYPE(mplsif->key);
|
|
u.ol.mol_label.u.ml_key = IPMPLS_KEY_GET_LABEL(mplsif->key);
|
|
obj = netif->name;
|
|
extra = &u;
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_LABELSPACE:
|
|
|
|
if ((netif->type != IP_IFT_ETHER) && (netif->type != IP_IFT_L2VLAN))
|
|
return;
|
|
|
|
req = IPMPLS_SIOCGLABELSPACEMPLS;
|
|
u.ls.mls_ifindex = netif->ifindex;
|
|
obj = &u;
|
|
extra = IP_NULL;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* Fetch info about the object */
|
|
ret = ipmpls_do_ioctl(req, vr, &u);
|
|
|
|
new_offs = ipmpls_netlink_fill(¶m->data[param->offset],
|
|
obj,
|
|
ret == 0 ? extra : IP_NULL,
|
|
IP_NULL,
|
|
param->pid,
|
|
param->seq,
|
|
param->type,
|
|
vr,
|
|
¶m->len);
|
|
|
|
if (new_offs < 0)
|
|
goto dont_fit;
|
|
|
|
param->offset += (Ip_size_t)new_offs;
|
|
|
|
|
|
param->status = IPMPLS_NETLINK_DUMP_FINISHED;
|
|
return;
|
|
|
|
dont_fit:
|
|
/* Set status to full */
|
|
param->status = IPMPLS_NETLINK_DUMP_DONT_FIT;
|
|
param->args[0] = (Ip_ptrdiff_t)vr;
|
|
param->args[1] = (Ip_ptrdiff_t)netif;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
*===========================================================================
|
|
*
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipmpls_netlink_rtm_new(Ip_u8 *data, Ip_size_t len,
|
|
struct Ipmpls_nlmsghdr *nlh, void *arg, int vr)
|
|
{
|
|
int ret = 0;
|
|
struct Ipmpls_rtmsg *rtm = IPMPLS_NLMSG_DATA(nlh);
|
|
struct Ipmpls_rtattr **rta = arg;
|
|
|
|
(void)data;
|
|
(void)len;
|
|
|
|
switch (rtm->rtm_type)
|
|
{
|
|
case IPMPLS_RTN_ILM:
|
|
if (rta[IPMPLS_RTA_ILM - 1])
|
|
{
|
|
struct Ipmpls_in_label_req *il =
|
|
(struct Ipmpls_in_label_req*)IPMPLS_RTA_DATA(rta[IPMPLS_RTA_ILM -1]);
|
|
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCMPLSILMADD,vr, il);
|
|
|
|
if (rta[IPMPLS_RTA_INSTR - 1] && ((ret == 0) || ret == -IP_ERRNO_EEXIST))
|
|
{
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCSMPLSININSTR,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_INSTR - 1]));
|
|
}
|
|
|
|
if (rta[IPMPLS_RTA_COOKIE - 1] && (ret == 0))
|
|
{
|
|
|
|
if (IPMPLS_RTA_PAYLOAD(rta[IPMPLS_RTA_COOKIE - 1]) > sizeof(Ipmpls_rt_cookie))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ret = ipmpls_set_cookie(&il->mil_label,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_COOKIE - 1]));
|
|
}
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_NHLFE:
|
|
if (rta[IPMPLS_RTA_NHLFE - 1])
|
|
{
|
|
struct Ipmpls_out_label_req *ol =
|
|
(struct Ipmpls_out_label_req*)IPMPLS_RTA_DATA(rta[IPMPLS_RTA_NHLFE -1]);
|
|
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCMPLSNHLFEADD,vr, ol);
|
|
|
|
if (rta[IPMPLS_RTA_INSTR - 1] && ((ret == 0) || ret == -IP_ERRNO_EEXIST))
|
|
{
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCSMPLSOUTINSTR,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_INSTR - 1]));
|
|
}
|
|
|
|
if (rta[IPMPLS_RTA_COOKIE - 1] && (ret == 0))
|
|
{
|
|
|
|
if (IPMPLS_RTA_PAYLOAD(rta[IPMPLS_RTA_COOKIE - 1]) > sizeof(Ipmpls_rt_cookie))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ret = ipmpls_set_cookie(&ol->mol_label,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_COOKIE - 1]));
|
|
}
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_XC:
|
|
if (rta[IPMPLS_RTA_XC - 1])
|
|
{
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCMPLSXCADD,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_XC -1]));
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_LABELSPACE:
|
|
if (rta[IPMPLS_RTA_LABELSPACE - 1])
|
|
{
|
|
ret = ipmpls_do_ioctl(IPMPLS_SIOCSLABELSPACEMPLS,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_LABELSPACE -1]));
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_RTN_TUNNEL:
|
|
{
|
|
void* idata = IP_NULL;
|
|
|
|
if (rta[IPMPLS_RTA_TUNNEL_DATA - 1])
|
|
idata = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_DATA - 1]);
|
|
#if 0
|
|
if (rta[IPMPLS_RTA_TUNNEL_NAME - 1])
|
|
{
|
|
ret = ipcom_mpls_tunnel_create(IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]),
|
|
vr,
|
|
idata);
|
|
}
|
|
#endif
|
|
if (rta[IPMPLS_RTA_NHLFE - 1] && ((ret == 0) || (ret == -IP_ERRNO_EEXIST)))
|
|
{
|
|
struct Ipmpls_out_label_req ol;
|
|
Ipcom_netif *netif;
|
|
Ipmpls_netif *mplsif;
|
|
|
|
ipcom_memcpy(&ol, IPMPLS_RTA_DATA(rta[IPMPLS_RTA_NHLFE -1]), sizeof(ol));
|
|
|
|
netif = (Ipcom_netif*)ipcom_mpls_ioevent(IP_NULL,
|
|
IPMPLS_EIOXNAMETONETIF,
|
|
(void *)IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]),
|
|
(void *)&vr,
|
|
IP_NULL);
|
|
if (netif == IP_NULL)
|
|
return -IP_ERRNO_ENOTFOUND;
|
|
|
|
mplsif = netif->plink;
|
|
|
|
if (mplsif == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ipmpls_key_create(0, &ol.mol_label, &mplsif->key);
|
|
|
|
ret = 0;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
ret = -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
IP_PUBLIC int
|
|
ipmpls_netlink_rtm_del(Ip_u8 *data, Ip_size_t len,
|
|
struct Ipmpls_nlmsghdr *nlh, void *arg, int vr)
|
|
{
|
|
int ret = -IP_ERRNO_EINVAL;
|
|
unsigned long req;
|
|
struct Ipmpls_rtmsg *rtm = IPMPLS_NLMSG_DATA(nlh);
|
|
struct Ipmpls_rtattr **rta = arg;
|
|
void *d;
|
|
|
|
(void)data;
|
|
(void)len;
|
|
|
|
switch (rtm->rtm_type)
|
|
{
|
|
case IPMPLS_RTN_ILM:
|
|
if (rta[IPMPLS_RTA_ILM - 1])
|
|
{
|
|
req = IPMPLS_SIOCMPLSILMDEL;
|
|
d = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_ILM -1]);
|
|
goto do_ioctl;
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_NHLFE:
|
|
if (rta[IPMPLS_RTA_NHLFE - 1])
|
|
{
|
|
req = IPMPLS_SIOCMPLSNHLFEDEL;
|
|
d = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_NHLFE -1]);
|
|
goto do_ioctl;
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_XC:
|
|
if (rta[IPMPLS_RTA_XC - 1])
|
|
{
|
|
req = IPMPLS_SIOCMPLSXCDEL;
|
|
d = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_XC -1]);
|
|
goto do_ioctl;
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_ILMFLUSH:
|
|
req = IPMPLS_SIOCMPLSILMFLUSH;
|
|
d = IP_NULL;
|
|
goto do_ioctl;
|
|
case IPMPLS_RTN_NHLFEFLUSH:
|
|
req = IPMPLS_SIOCMPLSNHLFEFLUSH;
|
|
d = IP_NULL;
|
|
goto do_ioctl;
|
|
case IPMPLS_RTN_TUNNEL:
|
|
if (rta[IPMPLS_RTA_TUNNEL_NAME - 1])
|
|
{
|
|
#if defined(IP_PORT_LKM) && defined(IPCOM_LKM_HAS_MPLS_TUNNEL_UTILS)
|
|
ret = ipcom_mpls_tunnel_destroy(IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]), vr);
|
|
#else
|
|
ret = ipmpls_ioctl_tunnel(IPMPLS_SIOCMPLSTUNNELDEL,
|
|
vr,
|
|
IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]),
|
|
IP_NULL);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
|
|
do_ioctl:
|
|
|
|
return ipmpls_do_ioctl(req, vr, d);
|
|
}
|
|
|
|
|
|
IP_PUBLIC int
|
|
ipmpls_netlink_rtm_get(Ip_u8 *data, Ip_size_t len, struct Ipmpls_nlmsghdr *nlh,
|
|
void *arg, void **out_msg, int vr)
|
|
{
|
|
Ip_size_t totlen = IPMPLS_NETLINK_DEF_BUF_SZ;
|
|
Ip_u8 *buf;
|
|
unsigned long req = IP_NULL;
|
|
unsigned long xreq = 0;
|
|
void *obj = IP_NULL;
|
|
void *extra;
|
|
struct Ipmpls_rtattr **rta = arg;
|
|
struct Ipmpls_rtmsg *rtm = IPMPLS_NLMSG_DATA(nlh);
|
|
union {
|
|
struct Ipmpls_instr_req op;
|
|
struct Ipmpls_out_label_req ol;
|
|
} u;
|
|
int ret;
|
|
|
|
ipcom_memset(&u, 0, sizeof(u));
|
|
|
|
switch (rtm->rtm_type)
|
|
{
|
|
case IPMPLS_RTN_ILM:
|
|
if (rta[IPMPLS_RTA_ILM - 1])
|
|
{
|
|
req = IPMPLS_SIOCMPLSILMGET;
|
|
obj = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_ILM -1]);
|
|
xreq = IPMPLS_SIOCGMPLSININSTR;
|
|
ipcom_memcpy(&u.op.mir_label,
|
|
&((struct Ipmpls_in_label_req*)obj)->mil_label,
|
|
sizeof(Ipmpls_label));
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_NHLFE:
|
|
if (rta[IPMPLS_RTA_NHLFE - 1])
|
|
{
|
|
req = IPMPLS_SIOCMPLSNHLFEGET;
|
|
obj = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_NHLFE -1]);
|
|
xreq = IPMPLS_SIOCGMPLSOUTINSTR;
|
|
ipcom_memcpy(&u.op.mir_label,
|
|
&((struct Ipmpls_out_label_req*)obj)->mol_label,
|
|
sizeof(Ipmpls_label));
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_TUNNEL:
|
|
if (rta[IPMPLS_RTA_TUNNEL_NAME - 1])
|
|
{
|
|
Ipcom_netif *netif;
|
|
Ipmpls_netif *mplsif;
|
|
|
|
netif = (Ipcom_netif*)ipcom_mpls_ioevent(IP_NULL,
|
|
IPMPLS_EIOXNAMETONETIF,
|
|
(void *)IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]),
|
|
(void *)&vr,
|
|
IP_NULL);
|
|
if (netif == IP_NULL)
|
|
return -IP_ERRNO_ENOTFOUND;
|
|
|
|
mplsif = netif->plink;
|
|
|
|
if (mplsif == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
u.ol.mol_label.ml_type = IPMPLS_KEY_GET_TYPE(mplsif->key);
|
|
u.ol.mol_label.u.ml_key = IPMPLS_KEY_GET_LABEL(mplsif->key);
|
|
|
|
obj = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_TUNNEL_NAME - 1]);
|
|
xreq = IPMPLS_SIOCMPLSNHLFEGET;
|
|
goto do_xreq;
|
|
}
|
|
break;
|
|
case IPMPLS_RTN_LABELSPACE:
|
|
if (rta[IPMPLS_RTA_LABELSPACE - 1])
|
|
{
|
|
req = IPMPLS_SIOCGLABELSPACEMPLS;
|
|
obj = IPMPLS_RTA_DATA(rta[IPMPLS_RTA_LABELSPACE - 1]);
|
|
xreq = 0;
|
|
}
|
|
break;
|
|
default:
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
/* Fetch info about the object */
|
|
ret = ipmpls_do_ioctl(req, vr, obj);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
do_xreq:
|
|
/* Fetch info about the object operations */
|
|
if (xreq)
|
|
{
|
|
ret = ipmpls_do_ioctl(xreq, vr, &u);
|
|
|
|
if (ret == 0)
|
|
extra = &u;
|
|
}
|
|
|
|
buf = ipcom_malloc(IPMPLS_NETLINK_DEF_BUF_SZ);
|
|
|
|
if (buf == IP_NULL)
|
|
return -IP_ERRNO_ENOMEM;
|
|
|
|
ipmpls_netlink_fill(buf,
|
|
obj,
|
|
extra,
|
|
IP_NULL,
|
|
nlh->nlmsg_pid,
|
|
nlh->nlmsg_seq,
|
|
rtm->rtm_type,
|
|
vr,
|
|
&totlen);
|
|
|
|
totlen = IPMPLS_NETLINK_DEF_BUF_SZ - totlen;
|
|
*out_msg = buf;
|
|
|
|
return totlen;
|
|
}
|
|
|
|
IP_PUBLIC int
|
|
ipmpls_netlink_rtm_dump(Ip_u8 *data, Ip_size_t len,
|
|
struct Ipmpls_netlink_callback *cb, int vr)
|
|
{
|
|
Ipmpls_netlink_foreach_cb_data *param = (Ipmpls_netlink_foreach_cb_data*)cb->args[0];
|
|
struct Ipmpls_rtmsg *rtm = IPMPLS_NLMSG_DATA(cb->nlh);
|
|
|
|
if (param == IP_NULL)
|
|
{
|
|
/* First dump. Create a param */
|
|
param = ipcom_calloc(1, sizeof(*param));
|
|
|
|
if (param == IP_NULL)
|
|
return 0;
|
|
|
|
param->status = IPMPLS_NETLINK_DUMP_FIRST_ENTRY;
|
|
}
|
|
else if (param->status == IPMPLS_NETLINK_DUMP_FINISHED)
|
|
{
|
|
/* No more entries to dump */
|
|
ipcom_free(param);
|
|
cb->args[0] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
param->len = len;
|
|
param->offset = 0;
|
|
param->data = data;
|
|
param->type = rtm->rtm_type;
|
|
param->vr = vr;
|
|
param->pid = cb->nlh->nlmsg_pid;
|
|
param->seq = cb->nlh->nlmsg_seq;
|
|
|
|
switch (rtm->rtm_type)
|
|
{
|
|
case IPMPLS_RTN_ILM:
|
|
case IPMPLS_RTN_NHLFE:
|
|
ipcom_hash_for_each(ipmpls->label_tables,
|
|
(Ipcom_hash_foreach_cb_func)ipmpls_netlink_route_foreach_vr,
|
|
param);
|
|
break;
|
|
case IPMPLS_RTN_TUNNEL:
|
|
case IPMPLS_RTN_LABELSPACE:
|
|
ipcom_mpls_ioevent(IP_NULL,
|
|
IPMPLS_EIOXFOREACHNETIF,
|
|
(void*)ipmpls_netlink_netif_foreach,
|
|
param,
|
|
IP_NULL);
|
|
break;
|
|
}
|
|
|
|
if (param->status == IPMPLS_NETLINK_DUMP_DONT_FIT)
|
|
param->status = IPMPLS_NETLINK_DUMP_TRAILER;
|
|
|
|
cb->args[0] = (Ip_ptrdiff_t)param;
|
|
|
|
return (int)param->offset;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
#else
|
|
int ipmpls_netlink_empty_file = 1;
|
|
#endif
|