/****************************************************************************** * mplslib.c * * User-space interface library for MPLS-on-Linux. * * - The actual interface functions * * Copyright (c) 2000, K A Fraser */ #include "mpls.h" #include #include #include /* * See comment in mpls.c which explains why we do this. */ int socket(int domain, int type, int protocol); int bind(int sockfd, struct sockaddr *my_addr, int addrlen); int sendmsg(int s, const struct msghdr *msg, unsigned int flags); int recvmsg(int s, const struct msghdr *msg, unsigned int flags); int close(int fd); int printf(const char *format, ...); extern int errno; typedef struct nlmsg_st { struct nlmsghdr nh; #ifdef LABEL_STACKING char data[100]; /* Label stacking made the message grow */ #else char data[50]; #endif } nlmsg_t; static int fd; static int seq; static int mpls_sendmsg(void *mpls_msg, int mpls_msglen, int mpls_cmd) { nlmsg_t nlmsg; struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { 0 }; int ssize; int *msg_data; /* Prevent that core dump that took me an hour to find */ ssize = sizeof(nlmsg_t) - sizeof(struct nlmsghdr); if(mpls_msglen > ssize) { errno = ENOMEM; return -1; } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nlmsg.nh.nlmsg_len = sizeof(nlmsg); nlmsg.nh.nlmsg_type = mpls_cmd; nlmsg.nh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg.nh.nlmsg_seq = seq++; nlmsg.nh.nlmsg_pid = 0; iov.iov_base = (void *)&nlmsg; iov.iov_len = nlmsg.nh.nlmsg_len; msg.msg_name = (void *)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; memcpy(NLMSG_DATA(&nlmsg.nh), mpls_msg, mpls_msglen); if ( sendmsg(fd, &msg, 0) < 0 ) return(-1); if ( recvmsg(fd, &msg, 0) < 0 ) return(-1); msg_data = (int *)NLMSG_DATA(&nlmsg.nh); if(msg_data) { if ( (errno = -(*msg_data) )) return(-1); } return(0); } /****************************************************************************** **** INITIALISATION */ int mpls_init(void) { struct sockaddr_nl addr; fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_MPLS); if ( fd < 0 ) return(-1); memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; if ( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) { return(-1); } seq = 0; return(0); } void mpls_cleanup(void) { close(fd); } /****************************************************************************** **** COMMAND FUNCTIONS */ int mpls_add_switch_mapping(switch_mapping_t *sm) { return(mpls_sendmsg(sm, sizeof(*sm), MPLSMSG_ADD_SWITCH_MAPPING)); } int mpls_del_switch_mapping(cid_t *cid) { return(mpls_sendmsg(cid, sizeof(*cid), MPLSMSG_DEL_SWITCH_MAPPING)); } int mpls_add_port_mapping(port_mapping_t *pm) { return(mpls_sendmsg(pm, sizeof(*pm), MPLSMSG_ADD_PORT_MAPPING)); } int mpls_del_port_mapping(int port) { return(mpls_sendmsg(&port, sizeof(port), MPLSMSG_DEL_PORT_MAPPING)); } int mpls_add_ingress_mapping(ingress_mapping_t *im) { return(mpls_sendmsg(im, sizeof(*im), MPLSMSG_ADD_INGRESS_MAPPING)); } int mpls_del_ingress_mapping(fec_t *fec) { return(mpls_sendmsg(fec, sizeof(*fec), MPLSMSG_DEL_INGRESS_MAPPING)); } int mpls_add_egress_mapping(egress_mapping_t *em) { return(mpls_sendmsg(em, sizeof(*em), MPLSMSG_ADD_EGRESS_MAPPING)); } int mpls_del_egress_mapping(cid_t *cid) { return(mpls_sendmsg(cid, sizeof(*cid), MPLSMSG_DEL_EGRESS_MAPPING)); } #ifdef LABEL_STACKING int mpls_add_label_pop(cid_t *cid) { return(mpls_sendmsg(cid, sizeof(*cid), MPLSMSG_ADD_LABEL_POP)); } int mpls_del_label_pop(cid_t *cid) { return(mpls_sendmsg(cid, sizeof(*cid), MPLSMSG_DEL_LABEL_POP)); } #endif /* LABEL_STACKING */ int mpls_flush_all(void) { return(mpls_sendmsg(NULL, 0, MPLSMSG_FLUSH_ALL)); } int mpls_debug_on(void) { return(mpls_sendmsg(NULL, 0, MPLSMSG_DEBUG_ON)); } int mpls_debug_off(void) { return(mpls_sendmsg(NULL, 0, MPLSMSG_DEBUG_OFF)); }