/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #if defined(IPMPLS) && defined(IP_PORT_LKM) #include "ipmpls_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #include #include #ifdef IP_PORT_LKM #include #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