Open Ethernet Networking (OpEN) API Guide and Reference Manual  3.6.0.3
openr_example.c
/*********************************************************************
*
* Copyright 2016-2018 Broadcom.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************
*
* @filename openr_example.c
*
* @purpose Routing Protocol Process Interface (RPPI) Example.
*
* @component OPEN
*
* @note
*
* @create 07/23/2012
*
* @end
*
**********************************************************************/
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <sys/errno.h>
#include <ctype.h>
#include "rpcclt_openapi.h"
#include "proc_util.h"
#include "openapi_common.h"
#include "openapi_mpls.h"
#define RPPI_APP_NAME "oscar"
/* Timeout in select() call. seconds. */
#define XX_SELECT_TIMEOUT 1
#define XX_SERVICE_TIMEOUT 180
/* Maximum number of routes in this application's route table. Includes
* both routes sourced by this application and those learned from RPPI.
* This is not tied to the size of the OPEN route table. */
#define XX_ROUTES_MAX (16 * 1024)
/* Just hard code the administrative distance for routes this application adds */
#define XX_OWN_ROUTE_PREF 19
/* Number of address families supported (IPv4 and IPv6) */
#define XX_AF_NUM 2
/* Maximum number of IPv4 addresses that may be configured on an OPEN routing interface */
#define XX_INTF_IP_MAX 32
/* Maximum string length to be used for inputs */
#define XX_MAX_STRING_LENGTH 256
/* return codes used within example program */
typedef enum
{
XX_E_NONE = 0,
XX_E_FAIL = -1,
XX_E_AGAIN = -2,
XX_E_LIMIT = -3 /* Must come last */
} xx_error_t;
typedef enum
{
/* router event service */
OPEN_ROUTER_EVENT_SVC = 0,
/* best route change service */
OPEN_BEST_ROUTE_SVC,
/* routing policy service */
OPEN_POLICY_SVC,
OPEN_SERVICES_MAX
} OPEN_SERVICE_t;
openapiClientHandle_t clientHandle;
char *openServiceName[OPEN_SERVICES_MAX] = {"Router Event", "Best Route", "Policy"};
/* Names of the protocol and route types the app registers */
char *protocolName = "xrp";
char *protocolCode = "X";
char *routeType1Name = "XRP Internal";
char *routeType1Code = "XI";
char *routeType2Name = "XRP External";
char *routeType2Code = "XE";
/* Record of RPPI event registration */
typedef struct xxRppiSvcReg_s
{
/* 0 if array element not being used. 1 if array element in use. */
uint32_t inUse;
/* RPPI service type */
OPEN_SERVICE_t service;
/* Name used to register for this service */
char clientName[OPEN_RPPI_CLIENT_NAME_MAX_LEN + 1];
/* Linux process ID used to register for this service */
pid_t pid;
/* Client ID returned by RPPI at registration time */
uint32_t clientId;
/* UNIX socket file descriptor for socket opened to receive events for this service */
int32_t sockFd;
/* Time when KEEPALIVE message was last received for this service */
uint32_t lastKeepTime;
} xxRppiSvcReg_t;
/* Local representation of a route */
typedef struct xxRoute_s
{
/* non-zero if this element is in use */
uint32_t inUse;
/* Just to avoid recreating all this stuff, reuse the OPEN representation of a route. */
openRoute_t routeAttrs;
openNextHop_t *routeNextHopList;
/* non-zero if this application is the source for this route. If zero, this is a route
* that RPPI has reported as a best route. */
uint32_t isOurRoute;
/* non-zero if RPPI has reported that this route is used for forwarding */
uint32_t forwarding;
/* Non-zero if current policy permits this route. Only applies to best routes learned
* from OPEN. Routes originated by the example app that are not best routes are
* marked as not permitted. They are permitted, like any other best route, if they
* pass policy, after being identified as a best route. For routes from other sources,
* this might indicate, for example, if this application is allowed to redistribute
* a given route. */
uint32_t permitted;
} xxRoute_t;
/* Local representation of a Routing Interface */
typedef struct xxRouteIntf_s
{
/* non-zero if this element is in use */
uint32_t inUse;
/* Interface Number. Unique to every interface in the table. */
uint32_t intf;
/* Reusing the OPEN_INTF_TYPE for the router interface type */
OPEN_INTF_TYPE_t intfType;
/* Interface Name */
char *intfName;
/* VLAN ID for the interface. Defaults to 0 to indicate VLAN ID is not set.
* Port based routing interfaces, loopback interfaces, and tunnels have no
* VLAN ID. */
uint32_t vlanId;
/* loopback ID for the interface. Only valid for loopback interfaces.
* 0 for all other interfaces. */
uint32_t loopbackId;
/* IP stack ifIndex for the routing interface */
uint32_t ifIndex;
/* Method used to assign IP address to the routing interface. */
/* List of IPv4 addresses configured on the routing interface. */
open_inet_pfx_t ipAddrListIPv4[XX_INTF_IP_MAX];
/* List of IPv6 addresses configured on the routing interface. */
open_inet_pfx_t ipAddrListIPv6[XX_INTF_IP_MAX];
/* IPv4 MTU on the interface */
uint32_t ipMtuIPv4;
/* IPv6 MTU on the interface */
uint32_t ipMtuIPv6;
/* bandwidth value for IPv4 routing interfaces. This is the value
* configured with the "bandwidth" command and my be different from
* the link speed. Used to influence link metric, for example. */
uint32_t bandwidthIPv4;
/* Bandwidth configured for IPv6 routing. */
uint32_t bandwidthIPv6;
/* Whether IPv4 is enabled or disabled on this interface. */
OPEN_CONTROL_t ifStateIPv4;
/* Whether IPv6 is enabled or disabled on this interface. */
OPEN_CONTROL_t ifStateIPv6;
}xxRouteIntf_t;
/* RPPI services this application is currently registered for */
xxRppiSvcReg_t xxRppiServices[OPEN_SERVICES_MAX];
/* Simple routing table. This table includes both routes "originated" by this application
* and the best routes learned from OPEN. Index to the table is destination prefix,
* prefix length, and route type. So route table
* can include two routes to the same prefix with different route types. This might happen
* when this application has a route to a given prefix and RPPI reports a more-preferred route
* to the same prefix. */
xxRoute_t xxRouteTable[XX_ROUTES_MAX];
/* List of routing interfaces reported by OPEN. Table is dynamically allocated to hold
* the maximum number of routing interfaces, as reported by OPEN. Index to the table is
* the interface number. Every routing interface has a unique
* interface number associated with it. */
xxRouteIntf_t *xxRouteIntfTable = NULL;
/* Whether routing is globally enabled or disabled for each address family.
* Indexed by OPEN_AF_t values. */
/* Linux process ID for this application. */
pid_t main_pid;
/* Thread ID for the receive thread */
pthread_t receive_tid;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* Protocol ID and route types registered with RPPI. We assume this "protocol"
* has two route types, internal routes and external routes. */
uint32_t protoId;
uint32_t intRouteType;
uint32_t extRouteType;
uint32_t vrfId;
char *routeMapName = NULL;
char *pfxListName = NULL;
uint32_t xxMaxNextHops = 48;
/* Maximum length of an OPEN interface name */
uint32_t XX_INTF_NAME_LEN_MAX = 0;
/* Maximum number of routing interfaces */
uint32_t XX_ROUTE_INTF_MAX = 0;
uint32_t perfTest = 0;
uint32_t currentTimeGet(void);
void xxPerfTest(void);
void xxCleanup(void);
xx_error_t xxRouteMapSet(char *rmName);
xx_error_t xxPrefixListSet(char *plName);
uint32_t xxPolicyApply(openRoute_t *route);
void xxRouteMapReapply(void);
void xxPrefixListReapply(void);
xx_error_t xxRouteTableAdd(openRoute_t *route,
open_buffdesc *nextHopListBuff,
uint32_t ownRoute, uint32_t forwarding, uint32_t permitted);
xx_error_t xxRouteTableDel(open_inet_addr_t destPfx, uint8_t pfxLen, open_inet_addr_t nhAddr, uint8_t routeType);
void xxRoutingEnable(OPEN_AF_t family);
void xxRoutingDisable(OPEN_AF_t family);
xx_error_t xxRouteIntfTableAdd(uint32_t intf);
xx_error_t xxRouteIntfTableDel(uint32_t intf);
xx_error_t xxGetInterfaceIndexFromTable(uint32_t intf);
void xxPopulateRoutingInterfaceTable(void);
xx_error_t xxIntfIpv4AddrsUpdate(uint32_t intf);
void *xxReceiveThread(void *arg);
xx_error_t xxRppiSvcAdd(OPEN_SERVICE_t svc, char *name, pid_t pid, uint32_t clientId, int32_t fd);
void xxRppiSvcDel(OPEN_SERVICE_t svc);
void xxKeepTimeUpdate(OPEN_SERVICE_t service);
void xxKeepaliveStatusCheck(void);
xx_error_t xxAddressResolve(open_inet_addr_t nhAddr,uint32_t *intIfNum);
uint32_t xxPfxLenToMask(uint32_t pfxLen);
uint32_t xxInetMaskLengthGet(uint32_t mask);
xxRoute_t *xxOwnRouteFind(open_inet_addr_t destPfx, uint8_t pfxLen);
xx_error_t xxOwnRouteAdd(open_inet_addr_t destPfx, uint8_t pfxLen,open_inet_addr_t nhAddr, uint32_t metric,
uint32_t label[OPEN_MAX_MPLS_IMPOSE_LABELS]);
xx_error_t xxOwnRouteDelete(open_inet_addr_t destPfx, uint8_t pfxLen, open_inet_addr_t nhAddr);
void xxWithdrawOwnRoutes(void);
void xxInterfacesShow(void);
void xxLimitsShow(void);
void xxRegistrationsShow(void);
void xxOpenRoutePrint(openRoute_t *route, openNextHop_t *nextHops, uint32_t printHeader);
void xxRoutesShow(void);
void xxOpenRoutesShow(uint32_t vrfId, uint32_t bestOnly);
void xxOpenBestRouteLookup(char **cmd_argv);
void xxOpenRouteFind(char **cmd_argv);
xx_error_t xxAddRoute(uint32_t cmd_argc, char **cmd_argv);
void xxDeleteRoute(uint32_t cmd_argc, char **cmd_argv);
void xxBestRouteChangeMsgProcess(openrBestRouteChangeMsg_t *msg, uint32_t msgLen);
void xxEventProcess(OPEN_SERVICE_t service, void *msg, uint32_t msgLen);
void xxSocketsRead(fd_set *readFds);
uint32_t xxReadFdsGet(fd_set *readFds);
xx_error_t rppiClientSockCreate(char *addrFormat, uint32_t clientId, int *fd);
xx_error_t xxRouterEventClientStart(pid_t myPid, open_buffdesc *myName);
xx_error_t xxBestRouteClientStart(pid_t myPid, open_buffdesc *myName);
xx_error_t xxPolicyClientStart(pid_t myPid, open_buffdesc *myName);
xx_error_t xxRouteTypesRegister(void);
void xxServiceDeregister(OPEN_SERVICE_t service);
const char *ipAddressFormat(open_inet_addr_t *addr, char *buffer);
void nextHopListBuffDescSizeSet(open_buffdesc *nextHopListBuffDesc);
void nextHopListBuffDescStorageFree(open_buffdesc *nextHopListBuffDesc);
uint32_t nextHopListBuffDescStorageAllocate(open_buffdesc *nextHopListBuffDesc);
void nextHopBuffDescPack(openNextHop_t *routeNextHopList, uint32_t listEntryCount, open_buffdesc *nextHopListBuff);
uint32_t nextHopBuffDescUnpack(openNextHop_t *routeNextHopList, open_buffdesc *nextHopListBuff);
/* Get the name of a given OPEN message type */
char *xxMsgTypeNameGet(uint32_t msgType)
{
switch (msgType)
{
case OPENR_KEEPALIVE: return "KEEPALIVE";
case OPENR_BEST_ROUTE_CHANGE: return "BEST ROUTE CHANGE";
case OPENR_RTR_ENABLE: return "IPv4 ROUTING ENABLE";
case OPENR_RTR_DISABLE: return "IPv4 ROUTING DISABLE";
case OPENR_RTR_STARTUP_DONE: return "STARTUP DONE";
case OPENR_RTR_INTF_CREATE: return "INTERFACE CREATE";
case OPENR_RTR_INTF_DELETE: return "INTERFACE DELETE";
case OPENR_RTR_INTF_ENABLE: return "INTERFACE IPv4 ENABLE";
case OPENR_RTR_INTF_DISABLE: return "INTERFACE IPv4 DISABLE";
case OPENR_RTR_INTF_ADDR_CHANGE: return "IPv4 ADDRESS CHANGE";
case OPENR_RTR_INTF_MTU: return "IPv4 MTU CHANGE";
case OPENR_RTR_INTF_BW_CHANGE: return "BANDWIDTH CHANGE";
case OPENR_RTR_INTF_HOST_MODE: return "HOST INTERFACE FOR IPv4";
case OPENR_RTR_INTF_CFG_CHANGE: return "INTERFACE CONFIG CHANGED";
case OPENR_RTR6_ENABLE: return "IPv6 ROUTING ENABLE";
case OPENR_RTR6_DISABLE: return "IPv6 ROUTING DISABLE";
case OPENR_RTR6_STARTUP_DONE: return "IPv6 STARTUP DONE";
case OPENR_RTR6_INTF_CREATE: return "IPv6 INTERFACE CREATE";
case OPENR_RTR6_INTF_DELETE: return "IPv6 INTERFACE DELETE";
case OPENR_RTR6_INTF_ENABLE: return "INTERFACE IPv6 ENABLE";
case OPENR_RTR6_INTF_DISABLE: return "INTERFACE IPv6 DISABLE";
case OPENR_RTR6_INTF_ADDR_CHANGE: return "IPv6 ADDRESS CHANGE";
case OPENR_RTR6_INTF_MTU: return "IPv6 MTU CHANGE";
case OPENR_RTR6_INTF_BW_CHANGE: return "IPv6 BANDWIDTH CHANGE";
case OPENR_RTR6_INTF_HOST_MODE: return "HOST INTERFACE FOR IPv6";
case OPENR_POLICY_CHANGE: return "POLICY CHANGE";
default: return "UNKNOWN";
}
return "UNKNOWN";
}
char *cmd_list = "\n \
help\n \
show ip route\n \
show open routes\n \
show open routes best\n \
show open route <dest-addr>\n \
show open route <pfx> <pfx len>\n \
show interfaces\n \
show limits\n \
show registrations\n \
ip route\n \
no ip route\n \
route-map\n \
no route-map\n \
prefix-list\n \
no prefix-list\n \
quit\n";
/*****************************************************************/
uint32_t currentTimeGet(void)
{
struct timespec tp;
int rc;
static uint32_t beginningOfTime = 0;
rc = clock_gettime(CLOCK_MONOTONIC, &tp);
if (rc < 0)
{
/* No monotonic clock. So do this the hard way. */
struct timeval tv;
memset(&tv, 0, sizeof(tv));
gettimeofday(&tv, 0);
if (beginningOfTime == 0)
{
beginningOfTime = tv.tv_sec;
}
return ((1000 * (tv.tv_sec - beginningOfTime)) + (tv.tv_usec / 1000));
}
return ((1000 * tp.tv_sec) + (tp.tv_nsec / 1000000));
}
/* parse a command into individual tokens */
static void parse_cmd_buf(char *buf, int *argc, char **argv)
{
char *p = buf;
int len = strlen(buf);
char *end = buf + len;
int search_arg_start = 1;
*argc = 0;
while (p < end)
{
if (search_arg_start)
{
if (*p != ' ')
{
argv[*argc] = p;
(*argc)++;
search_arg_start = 0;
}
}
else
{
if (*p == ' ')
{
search_arg_start = 1;
}
}
if (*p == ' ') *p = 0;
p++;
}
}
/*****************************************************************/
void xxPerfTest(void)
{
char myNameStorage[32];
open_buffdesc myName;
perfTest = 1;
xxServiceDeregister(OPEN_BEST_ROUTE_SVC);
memset(myNameStorage, 0, sizeof(myNameStorage));
snprintf(myNameStorage, sizeof(myNameStorage), RPPI_APP_NAME);
myName.pstart = myNameStorage;
myName.size = strlen(myNameStorage) + 1;
if (xxBestRouteClientStart(getpid(), &myName) != XX_E_NONE)
{
xxCleanup();
exit(0);
}
}
void xxTestAddrFormatter(void)
{
char buffer[XX_MAX_STRING_LENGTH];
memset(&addr, 0, sizeof(addr));
addr.family = OPEN_AF_INET6;
addr.addr.ipv6.u.addr32[0] = htonl(0x66000000);
addr.addr.ipv6.u.addr32[1] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[2] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[3] = htonl(0x00000000);
printf("%s\n", ipAddressFormat(&addr, buffer));
addr.addr.ipv6.u.addr32[0] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[1] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[2] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[3] = htonl(0x00000003);
printf("%s\n", ipAddressFormat(&addr, buffer));
addr.addr.ipv6.u.addr32[0] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[1] = htonl(0x000a0000);
addr.addr.ipv6.u.addr32[2] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[3] = htonl(0x00000000);
printf("%s\n", ipAddressFormat(&addr, buffer));
addr.addr.ipv6.u.addr32[0] = htonl(0x80000000);
addr.addr.ipv6.u.addr32[1] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[2] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[3] = htonl(0x00000001);
printf("%s\n", ipAddressFormat(&addr, buffer));
addr.addr.ipv6.u.addr32[0] = htonl(0x01234567);
addr.addr.ipv6.u.addr32[1] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[2] = htonl(0x00000000);
addr.addr.ipv6.u.addr32[3] = htonl(0x89abcdef);
printf("%s\n", ipAddressFormat(&addr, buffer));
addr.addr.ipv6.u.addr32[0] = htonl(0x01230000);
addr.addr.ipv6.u.addr32[1] = htonl(0xdeadbeef);
addr.addr.ipv6.u.addr32[2] = htonl(0xaffe0000);
addr.addr.ipv6.u.addr32[3] = htonl(0x89abcdef);
printf("%s\n", ipAddressFormat(&addr, buffer));
}
/*********************************************************************
* @purpose Parse and process a command from the app's "CLI."
*
* @param[in] cmd_buf The entire command
* @param[in] cmd_argc Number of tokens in the command
* @param[in] cmd_argv Array of tokens
*
* @returns
*
* @note
*
* @end
*********************************************************************/
void xxProcessCommand(char *cmd_buf, uint32_t cmd_argc, char **cmd_argv)
{
pthread_mutex_lock(&mutex);
if (!strcmp("show", cmd_argv[0]))
{
if (!strcmp("interfaces", cmd_argv[1]))
{
xxInterfacesShow();
}
else if (!strcmp("registrations", cmd_argv[1]))
{
xxRegistrationsShow();
}
else if (!strcmp("limits", cmd_argv[1]))
{
xxLimitsShow();
}
else if (!strcmp("ip", cmd_argv[1]))
{
if (!strcmp("route", cmd_argv[2]))
{
xxRoutesShow();
}
else
{
printf("\n invalid command \n");
}
}
else if (!strcmp("open", cmd_argv[1]))
{
if (!strcmp("routes", cmd_argv[2]))
{
if (cmd_argc == 3)
xxOpenRoutesShow(vrfId, 1);
else if (!strcmp("all", cmd_argv[3]))
xxOpenRoutesShow(vrfId, 0);
}
else if (!strcmp("route", cmd_argv[2]))
{
if (cmd_argc == 4)
xxOpenBestRouteLookup(cmd_argv);
else if (cmd_argc == 5)
xxOpenRouteFind(cmd_argv);
}
else
{
printf("\n invalid command \n");
}
}
else
{
printf("\n invalid command \n");
}
}
else if (!strcmp("ip", cmd_argv[0]))
{
if (!strcmp("route",cmd_argv[1]))
{
if (xxAddRoute(cmd_argc, cmd_argv) == XX_E_NONE)
printf("\nRoute added successfully.");
else
printf("\nFailed to add route.");
}
else
{
printf("\n invalid command \n");
}
}
else if (!strcmp("route-map", cmd_argv[0]))
{
xxRouteMapSet(cmd_argv[1]);
xxRouteMapReapply();
}
else if (!strcmp("prefix-list", cmd_argv[0]))
{
xxPrefixListSet(cmd_argv[1]);
xxPrefixListReapply();
}
else if (!strcmp("no", cmd_argv[0]))
{
if (!strcmp("ip",cmd_argv[1]))
{
if (!strcmp("route",cmd_argv[2]))
{
xxDeleteRoute(cmd_argc, cmd_argv);
}
}
else if (!strcmp("route-map", cmd_argv[1]))
{
xxRouteMapSet(NULL);
xxRouteMapReapply();
}
else if (strcmp("prefix-list", cmd_argv[1]))
{
xxPrefixListSet(NULL);
xxPrefixListReapply();
}
}
else if (!strcmp("test", cmd_argv[0]))
{
if (!strcmp("addrfmt",cmd_argv[1]))
{
xxTestAddrFormatter();
}
}
else if (!strcmp("perftest", cmd_argv[0]))
{
xxPerfTest();
}
else
{
/* handle invalid command and enter */
printf("\n");
}
pthread_mutex_unlock(&mutex);
return;
}
/*****************************************************************/
const char *ipAddressFormat(open_inet_addr_t *addr, char *buffer)
{
uint32_t ip4_addr;
uint8_t addr8[16];
int af;
switch (addr->family)
{
af = AF_INET;
ip4_addr = htonl(addr->addr.ipv4);
memcpy(addr8, &ip4_addr, sizeof(ip4_addr));
break;
af = AF_INET6;
memcpy(addr8, addr->addr.ipv6.u.addr8, sizeof(addr8));
break;
default:
/* don't return a NULL ptr here, since many callers print this value directly */
sprintf(buffer, "%u", 0);
return(buffer);
}
return(inet_ntop(af, addr8, buffer, INET6_ADDRSTRLEN));
}
/*****************************************************************/
char *ipAddressAndPrefixFormat(open_inet_addr_t *addr, int prefixLen, char *buffer)
{
char addrBuf[INET6_ADDRSTRLEN];
if (ipAddressFormat(addr, addrBuf) != NULL)
{
snprintf(buffer, INET6_ADDRSTRLEN + 3, "%s/%-2u", addrBuf, prefixLen);
return(buffer);
}
else
return(NULL);
}
/*****************************************************************/
char* getInterfaceType(uint32_t intfType)
{
switch (intfType)
{
return "Port";
return "VLAN";
return "Loop";
return "Tnnl";
}
return "";
}
/*****************************************************************/
char* getInterfaceState(uint32_t ifState)
{
switch (ifState)
{
return "Up";
return "Down";
}
return "";
}
/*****************************************************************/
char* getIpAddrMethod(OPEN_INTF_IP_ADDR_METHOD_t method)
{
switch (method)
{
return "None";
return "Manual";
return "DHCP";
}
return "";
}
/*****************************************************************/
char* getYesNoString(uint32_t value)
{
switch (value)
{
case 0:
return "No";
}
return "Yes";
}
void nextHopListBuffDescSizeSet(open_buffdesc *nextHopListBuffDesc)
{
nextHopListBuffDesc->size = xxMaxNextHops * sizeof(openNextHop_t);
}
uint32_t nextHopListBuffDescStorageAllocate(open_buffdesc *nextHopListBuffDesc)
{
nextHopListBuffDescSizeSet(nextHopListBuffDesc);
if ((nextHopListBuffDesc->pstart = malloc(nextHopListBuffDesc->size)) == NULL)
{
printf("\nFailed to allocate storage for next hop open_buffdesc.");
nextHopListBuffDesc->size = 0;
}
memset(nextHopListBuffDesc->pstart, 0, nextHopListBuffDesc->size);
return(nextHopListBuffDesc->size);
}
void nextHopListBuffDescStorageFree(open_buffdesc *nextHopListBuffDesc)
{
free(nextHopListBuffDesc->pstart);
nextHopListBuffDesc->size = 0;
nextHopListBuffDesc->pstart = NULL;
}
/* copy from open_buffdesc into array of openNextHop_t */
uint32_t nextHopBuffDescUnpack(openNextHop_t *routeNextHopList, open_buffdesc *nextHopListBuff)
{
uint32_t i, j;
openNextHop_t *nhExternal;
if (!routeNextHopList || !nextHopListBuff)
{
/* print debug message? */
return(0);
}
nhExternal = (openNextHop_t *)nextHopListBuff->pstart;
for (i = 0; ((i < xxMaxNextHops) &&
(i < (nextHopListBuff->size/sizeof(openNextHop_t)))); i++)
{
routeNextHopList[i].ifNum = nhExternal->ifNum;
routeNextHopList[i].nhAddr = nhExternal->nhAddr;
for (j = 0; j < OPEN_MAX_MPLS_IMPOSE_LABELS; j++)
{
routeNextHopList[i].label[j] = nhExternal->label[j];
}
nhExternal++;
}
return(i);
}
/* copy from array of openNextHop_t into open_buffdesc */
void nextHopBuffDescPack(openNextHop_t *routeNextHopList, uint32_t listEntryCount, open_buffdesc *nextHopListBuff)
{
uint32_t i, j;
openNextHop_t *nhExternal;
if (!routeNextHopList || !nextHopListBuff)
{
/* print debug message? */
return;
}
nhExternal = (openNextHop_t *)nextHopListBuff->pstart;
for (i = 0; ((i < listEntryCount) &&
(i < (nextHopListBuff->size/sizeof(openNextHop_t)))); i++)
{
nhExternal->ifNum = routeNextHopList[i].ifNum;
nhExternal->nhAddr = routeNextHopList[i].nhAddr;
for (j = 0; j < OPEN_MAX_MPLS_IMPOSE_LABELS; j++)
{
nhExternal->label[j] = routeNextHopList[i].label[j];
}
nhExternal++;
}
nextHopListBuff->size = (i * sizeof(openNextHop_t));
}
/*****************************************************************/
void xxLimitsShow(void)
{
uint32_t protoNameLen;
uint32_t routeTypeNameLen;
uint32_t maxNextHops;
uint32_t routingIntfMax;
uint32_t ifNameSize;
err = openapiRouteProtoNameLenMax(&clientHandle, &protoNameLen);
if (err == OPEN_E_NONE)
printf("\nMaximum protocol name length: %u characters", protoNameLen);
else
printf("\nFailed to get max protocol name length. Error %d.", err);
err = openapiRouteTypeNameLenMax(&clientHandle, &routeTypeNameLen);
if (err == OPEN_E_NONE)
printf("\nMaximum route type name length: %u characters", routeTypeNameLen);
else
printf("\nFailed to get max route type name length. Error %d.", err);
err = openapiMaxNextHopsGet(&clientHandle, &maxNextHops);
if (err == OPEN_E_NONE)
printf("\nECMP limit: %u next hops", maxNextHops);
else
printf("\nFailed to get ECMP limit. Error %d.", err);
err = openapiMaxRoutingInterfacesGet(&clientHandle, &routingIntfMax);
if (err == OPEN_E_NONE)
printf("\nMax routing interfaces: %u", routingIntfMax);
else
printf("\nFailed to get max routing interfaces. Error %d.", err);
err = openapiIntfNameSizeGet(&clientHandle, &ifNameSize);
if (err == OPEN_E_NONE)
printf("\nMax length of an interface name: %u characters", ifNameSize);
else
printf("\nFailed to get max interface name length. Error %d.", err);
}
void xxRegistrationsShow(void)
{
uint32_t i, now;
printf("\n");
printf(" Client Seconds Since \n");
printf("Service Name ID Last Keepalive\n");
printf("-------------------- ------ --------------\n");
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse)
{
now = currentTimeGet() / 1000;
printf("%-20s %-6d %-10d\n",
openServiceName[xxRppiServices[i].service],
xxRppiServices[i].clientId,
(now - xxRppiServices[i].lastKeepTime));
}
}
}
/*********************************************************************
* @purpose List the routing interfaces configured and their details.
*
*
* @returns
*
* @note
*
* @end
*********************************************************************/
void xxInterfacesShow(void)
{
uint32_t i;
uint32_t index;
char ipAddrBuf[XX_MAX_STRING_LENGTH];
printf("\n");
printf(" Addr Bandwidth IP Stack\n");
printf("Intf Name IP Address(es) Type Method State VLANID IP MTU (kbps) IfIndex \n");
printf("---- ---------- ------------------ ----- ------ ----- ------ ------ --------- --------\n");
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
index = 0;
if (xxRouteIntfTable[i].inUse != 0)
{
ipAddressAndPrefixFormat(&xxRouteIntfTable[i].ipAddrListIPv4[index].ipAddr,
xxRouteIntfTable[i].ipAddrListIPv4[index].pfxLen,
ipAddrBuf);
printf("%-4d %-10s %-18s %-5s %-6s %-5s %-6d %-6d %-9d %-8d",
xxRouteIntfTable[i].intf, xxRouteIntfTable[i].intfName, ipAddrBuf,
getInterfaceType(xxRouteIntfTable[i].intfType),
getIpAddrMethod(xxRouteIntfTable[i].ipAddrMethod),
getInterfaceState(xxRouteIntfTable[i].ifStateIPv4),
xxRouteIntfTable[i].vlanId, xxRouteIntfTable[i].ipMtuIPv4,xxRouteIntfTable[i].bandwidthIPv4,
xxRouteIntfTable[i].ifIndex);
index ++;
while (xxRouteIntfTable[i].ipAddrListIPv4[index].ipAddr.addr.ipv4 != 0)
{
ipAddressAndPrefixFormat(&xxRouteIntfTable[i].ipAddrListIPv4[index].ipAddr,
xxRouteIntfTable[i].ipAddrListIPv4[index].pfxLen,
ipAddrBuf);
printf("\n");
printf("%16s%-18s", " ", ipAddrBuf);
index++;
}
printf("\n");
}
}
}
/*****************************************************************/
void xxOpenRoutePrint(openRoute_t *route, openNextHop_t *nextHops, uint32_t printHeader)
{
char destPfxStr[XX_MAX_STRING_LENGTH];
char nhAddr[XX_MAX_STRING_LENGTH];
open_buffdesc intfNameBuf;
open_buffdesc protoNameBuf;
open_buffdesc routeTypeNameBuf;
uint32_t i;
openapiRouteProtoNameLenMax(&clientHandle, &protoNameBuf.size);
openapiRouteTypeNameLenMax(&clientHandle, &routeTypeNameBuf.size);
protoNameBuf.size++; /* leave room for NULL terminator */
protoNameBuf.pstart = malloc(protoNameBuf.size);
routeTypeNameBuf.size++; /* leave room for NULL terminator */
routeTypeNameBuf.pstart = malloc(routeTypeNameBuf.size);
intfNameBuf.size = XX_INTF_NAME_LEN_MAX + 1;
intfNameBuf.pstart = malloc(intfNameBuf.size);
if (!protoNameBuf.pstart || !routeTypeNameBuf.pstart || !intfNameBuf.pstart)
{
printf("\nOut of memory.");
return;
}
printf("\n");
if (printHeader)
{
printf(" Reject +----- NextHop(s) -----+ \n");
printf("Destination Type Pref Metric Route Address Intf Name\n");
printf("----------------- --------------- ---- ------ ------ -------------- ------------------------------\n");
}
ipAddressAndPrefixFormat(&route->destPfx, route->pfxLen, destPfxStr);
if (openapiRouteTypeInfoGet(&clientHandle, route->routeType, &protoNameBuf, &routeTypeNameBuf) != OPEN_E_NONE)
{
strcpy(routeTypeNameBuf.pstart, "Unknown");
}
printf("%-17s %-15s %-4d %-6d %-6s ",
destPfxStr, (char *) routeTypeNameBuf.pstart, route->pref, route->metric,
getYesNoString(route->rejectRoute));
for (i = 0; i < route->numNextHops; i++)
{
ipAddressFormat(&nextHops->nhAddr, nhAddr);
openapiRtrIntfNameGet(&clientHandle, nextHops->ifNum, &intfNameBuf);
if (i != 0)
{
printf("\n");
printf("%53s", " ");
}
printf("%-14s %s", nhAddr, (char *)intfNameBuf.pstart);
nextHops++;
}
free(protoNameBuf.pstart);
free(routeTypeNameBuf.pstart);
free(intfNameBuf.pstart);
}
/*****************************************************************/
void xxOpenRoutesShow(uint32_t vrfId, uint32_t bestOnly)
{
openRoute_t route;
open_buffdesc nextHopListBuff;
openNextHop_t *nextHops;
uint32_t printHeader = 1;
nextHopListBuff.size = xxMaxNextHops * sizeof(openNextHop_t);
nextHopListBuff.pstart = malloc(xxMaxNextHops * sizeof(openNextHop_t));
if (nextHopListBuff.pstart == NULL)
{
printf("\nOut of memory");
return;
}
memset(&route, 0, sizeof(openRoute_t));
if (bestOnly)
err = openapiBestRouteNextGet(&clientHandle, OPEN_AF_INET, &route, &nextHopListBuff);
else
err = openapiRouteNextGet(&clientHandle, OPEN_AF_INET, &route, &nextHopListBuff);
while (err == OPEN_E_NONE)
{
nextHops = (openNextHop_t*) nextHopListBuff.pstart;
xxOpenRoutePrint(&route, nextHops, printHeader);
printHeader = 0;
nextHopListBuff.size = xxMaxNextHops * sizeof(openNextHop_t);
if (bestOnly)
err = openapiBestRouteNextGet(&clientHandle, OPEN_AF_INET, &route, &nextHopListBuff);
else
err = openapiRouteNextGet(&clientHandle, OPEN_AF_INET, &route, &nextHopListBuff);
}
if (err != OPEN_E_NOT_FOUND)
{
printf("\nFailed to get next OPEN best route. Error %d.", err);
}
free(nextHopListBuff.pstart);
}
/*****************************************************************/
void xxOpenRouteFind(char **cmd_argv)
{
char pfxStr[32];
uint32_t pfxLen;
struct sockaddr_in sa;
openRoute_t route;
openNextHop_t *nextHops;
open_buffdesc nextHopListBuff;
/* Read destination prefix */
strcpy(pfxStr, cmd_argv[3]);
if (inet_pton(AF_INET, pfxStr, &(sa.sin_addr)) > 0)
{
pfx.family = OPEN_AF_INET;
pfx.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid IPv4 prefix %s \n", pfxStr);
return;
}
/* Read prefix length */
pfxLen = atoi(cmd_argv[4]);
if ((pfxLen < 4) || (pfxLen > 32))
{
printf("\nInvalid prefix length %u", pfxLen);
return;
}
nextHopListBuff.size = xxMaxNextHops * sizeof(openNextHop_t);
nextHopListBuff.pstart = malloc(xxMaxNextHops * sizeof(openNextHop_t));
if (nextHopListBuff.pstart == NULL)
{
printf("\nOut of memory");
return;
}
err = openapiPrefixFind(&clientHandle, pfx, pfxLen, &route, &nextHopListBuff);
if (err != OPEN_E_NONE)
{
printf("\nFailed to lookup best route to %s/%u. Error %d.", pfxStr, pfxLen, err);
free(nextHopListBuff.pstart);
return;
}
nextHops = (openNextHop_t*) nextHopListBuff.pstart;
xxOpenRoutePrint(&route, nextHops, 1);
free(nextHopListBuff.pstart);
}
/*****************************************************************/
void xxOpenBestRouteLookup(char **cmd_argv)
{
char ipAddrStr[32];
struct sockaddr_in sa;
openRoute_t route;
openNextHop_t *nextHops;
open_buffdesc nextHopListBuff;
/* Read destination */
strcpy(ipAddrStr, cmd_argv[3]);
if (inet_pton(AF_INET, ipAddrStr, &(sa.sin_addr)) > 0)
{
dest.family = OPEN_AF_INET;
dest.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid IPv4 address \n");
return;
}
nextHopListBuff.size = xxMaxNextHops * sizeof(openNextHop_t);
nextHopListBuff.pstart = malloc(xxMaxNextHops * sizeof(openNextHop_t));
if (nextHopListBuff.pstart == NULL)
{
printf("\nOut of memory");
return;
}
err = openapiBestRouteLookup(&clientHandle, dest, &route, &nextHopListBuff);
if (err != OPEN_E_NONE)
{
printf("\nFailed to lookup best route to %s. Error %d.", ipAddrStr, err);
free(nextHopListBuff.pstart);
return;
}
nextHops = (openNextHop_t*) nextHopListBuff.pstart;
xxOpenRoutePrint(&route, nextHops, 1);
free(nextHopListBuff.pstart);
}
/*********************************************************************
* @purpose List routes in the local route table. This includes routes
* "originated" by this application, and best routes learned
* from OPEN.
*
* @returns
*
* @note
*
* @end
*********************************************************************/
void xxRoutesShow(void)
{
uint32_t i;
uint32_t index;
char ipAddr[XX_MAX_STRING_LENGTH];
char nhAddr[XX_MAX_STRING_LENGTH];
open_buffdesc intfNameBuf;
open_buffdesc protoNameBuf;
open_buffdesc routeTypeNameBuf;
/* Ask OPEN how big a protocol name can be */
openapiRouteProtoNameLenMax(&clientHandle, &protoNameBuf.size);
openapiRouteTypeNameLenMax(&clientHandle, &routeTypeNameBuf.size);
protoNameBuf.size++; /* leave room for NULL terminator */
protoNameBuf.pstart = malloc(protoNameBuf.size);
routeTypeNameBuf.size++; /* leave room for NULL terminator */
routeTypeNameBuf.pstart = malloc(routeTypeNameBuf.size);
intfNameBuf.size = XX_INTF_NAME_LEN_MAX + 1;
intfNameBuf.pstart = malloc(intfNameBuf.size);
if (!protoNameBuf.pstart || !routeTypeNameBuf.pstart || !intfNameBuf.pstart)
{
printf("\nOut of memory.");
return;
}
printf("\n");
printf("VRF ID = %d\n", vrfId);
printf("\n");
printf(" Reject Own +----- NextHop(s) -----+ \n");
printf("Destination Type Pref Metric Route Route Fwd Permit Address Intf Name MPLS Label(s)\n");
printf("----------------- --------------- ---- ------ ------ ----- --- ------ -------------- ------------------------------\n");
for (i = 0; i < XX_ROUTES_MAX; i++)
{
index = 0;
if (xxRouteTable[i].inUse != 0)
{
ipAddressAndPrefixFormat(&xxRouteTable[i].routeAttrs.destPfx,
xxRouteTable[i].routeAttrs.pfxLen,
ipAddr);
if (openapiRouteTypeInfoGet(&clientHandle, xxRouteTable[i].routeAttrs.routeType,
&protoNameBuf, &routeTypeNameBuf) != OPEN_E_NONE)
{
strcpy(routeTypeNameBuf.pstart, "Unknown");
}
printf("%-17s %-15s %-4d %-6d %-6s %-5s %-3s %-6s ",
ipAddr, (char *)routeTypeNameBuf.pstart,
xxRouteTable[i].routeAttrs.pref, xxRouteTable[i].routeAttrs.metric,
getYesNoString(xxRouteTable[i].routeAttrs.rejectRoute),
getYesNoString(xxRouteTable[i].isOurRoute),
getYesNoString(xxRouteTable[i].forwarding),
getYesNoString(xxRouteTable[i].permitted));
for (index = 0; index < xxRouteTable[i].routeAttrs.numNextHops; index++)
{
ipAddressFormat(&xxRouteTable[i].routeNextHopList[index].nhAddr, nhAddr);
openapiRtrIntfNameGet(&clientHandle, xxRouteTable[i].routeNextHopList[index].ifNum, &intfNameBuf);
if (index != 0)
{
printf("\n");
printf("%70s", " ");
}
printf("%-14s %-9s", nhAddr, (char *)intfNameBuf.pstart);
if (xxRouteTable[i].routeNextHopList[index].label[0])
{
printf(" %5u,%u,%u", xxRouteTable[i].routeNextHopList[index].label[0],
xxRouteTable[i].routeNextHopList[index].label[1],
xxRouteTable[i].routeNextHopList[index].label[2]);
}
}
printf("\n");
}
}
free(protoNameBuf.pstart);
free(routeTypeNameBuf.pstart);
free(intfNameBuf.pstart);
}
/*********************************************************************
* @purpose Execute the "CLI" command to add a route to the list of routes
* this application is originating.
*
* @param[in] cmd_argc Number of tokens in the command
* @param[in] cmd_argv Array of tokens
*
* @returns
*
* @note
*
* @end
*********************************************************************/
xx_error_t xxAddRoute(uint32_t cmd_argc, char **cmd_argv)
{
uint8_t pfxLen;
char strIPaddr[XX_MAX_STRING_LENGTH];
char strSubnetMask[XX_MAX_STRING_LENGTH];
char strNextHopRtr[XX_MAX_STRING_LENGTH];
char metricStr[XX_MAX_STRING_LENGTH];
char labelStr[XX_MAX_STRING_LENGTH];
uint32_t netMask;
uint32_t metric;
uint32_t label[OPEN_MAX_MPLS_IMPOSE_LABELS];
struct sockaddr_in sa;
if ((cmd_argc < 5) || (cmd_argc > 9))
{
printf("\nUsage: ip route <destination prefix> <subnet mask> <next hop address> [<metric>] "
"[<mpls-label1>] [<mpls-label2>] [<mpls-label3>]");
return(XX_E_FAIL);
}
memset(&destPfx, 0, sizeof(open_inet_addr_t));
memset(&nhAddr, 0, sizeof(open_inet_addr_t));
destPfx.family = OPEN_AF_INET;
nhAddr.family = OPEN_AF_INET;
/* Read destination prefix */
strcpy(strIPaddr,cmd_argv[2]);
if (inet_pton(AF_INET, strIPaddr, &(sa.sin_addr)) > 0)
{
destPfx.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid ip address \n");
return(XX_E_FAIL);
}
/* Read subnet mask and convert to prefix length */
strcpy(strSubnetMask,cmd_argv[3]);
if (inet_pton(AF_INET,strSubnetMask,&(sa.sin_addr)) > 0)
{
netMask = ntohl(sa.sin_addr.s_addr);
pfxLen = xxInetMaskLengthGet(netMask);
}
else
{
printf("\n invalid subnet mask \n");
return(XX_E_FAIL);
}
/* read next hop address */
strcpy(strNextHopRtr,cmd_argv[4]);
if (inet_pton(AF_INET,strNextHopRtr,&(sa.sin_addr)) > 0)
{
nhAddr.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid next hop address \n");
return(XX_E_FAIL);
}
/* Read metric */
if (cmd_argc == 6)
{
strcpy(metricStr,cmd_argv[5]);
metric = atoi(metricStr);
}
else
{
metric = 1;
}
/* Read MPLS labels */
if (cmd_argc >= 7)
{
strcpy(labelStr,cmd_argv[6]);
label[0] = atoi(labelStr);
}
else
{
label[0] = 0;
}
if (cmd_argc >= 8)
{
strcpy(labelStr,cmd_argv[7]);
label[1] = atoi(labelStr);
}
else
{
label[1] = 0;
}
if (cmd_argc >= 9)
{
strcpy(labelStr,cmd_argv[8]);
label[2] = atoi(labelStr);
}
else
{
label[2] = 0;
}
return(xxOwnRouteAdd(destPfx, pfxLen, nhAddr, metric, label));
}
/*********************************************************************
* @purpose Execute the command to remove a route from the list of routes
* this application is originating.
*
* @param[in] cmd_argc Number of tokens in the command
* @param[in] cmd_argv Array of tokens
*
* @returns
*
* @note The user can remove a specific next hop from an ECMP route
* or all next hops for a given destination.
*
* @end
*********************************************************************/
void xxDeleteRoute(uint32_t cmd_argc, char **cmd_argv)
{
uint8_t pfxLen;
char strIPaddr[XX_MAX_STRING_LENGTH];
char strSubnetMask[XX_MAX_STRING_LENGTH];
char strNextHopRtr[XX_MAX_STRING_LENGTH];
uint32_t netMask;
struct sockaddr_in sa;
if ((cmd_argc < 5) || (cmd_argc > 6))
{
printf("\nUsage: no ip route <destination prefix> <subnet mask> [<next hop address>] ");
return;
}
memset(&destPfx, 0, sizeof(open_inet_addr_t));
memset(&nhAddr, 0, sizeof(open_inet_addr_t));
destPfx.family = OPEN_AF_INET;
nhAddr.family = OPEN_AF_INET;
strcpy(strIPaddr,cmd_argv[3]);
if (inet_pton(AF_INET,strIPaddr,&(sa.sin_addr)) > 0)
{
destPfx.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid ip address \n");
return;
}
strcpy(strSubnetMask,cmd_argv[4]);
if (inet_pton(AF_INET,strSubnetMask,&(sa.sin_addr)) > 0)
{
netMask = ntohl(sa.sin_addr.s_addr);
pfxLen = xxInetMaskLengthGet(netMask);
}
else
{
printf("\n invalid subnet mask \n");
return;
}
if (cmd_argc == 6)
{
strcpy(strNextHopRtr,cmd_argv[5]);
if (inet_pton(AF_INET,strNextHopRtr,&(sa.sin_addr)) > 0)
{
nhAddr.addr.ipv4 = ntohl(sa.sin_addr.s_addr);
}
else
{
printf("\n invalid next hop Address \n");
return;
}
}
xxOwnRouteDelete(destPfx, pfxLen, nhAddr);
}
/*****************************************************************/
uint32_t xxPfxLenToMask(uint32_t pfxLen)
{
if (pfxLen > 32)
{
printf("\nInvalid prefix length %u", pfxLen);
return 32;
}
if (pfxLen == 0)
return 0;
else
return 0xFFFFFFFF << (32 - pfxLen);
}
/*****************************************************************/
uint32_t xxInetMaskLengthGet(uint32_t mask)
{
uint32_t maskSize,maskLen, tempLen;
uint32_t maskBit;
uint32_t zeroFound = 0;
maskSize = sizeof(uint32_t) <<3;
maskBit =0x1 << (maskSize-1);
maskLen=0;
for (tempLen =0;tempLen <maskSize;tempLen++)
{
if (!(mask & maskBit))
{
if (zeroFound == 0)
{
zeroFound = 1;
}
}
else
{
if (zeroFound == 1)
{
return -1;
}
maskLen++;
}
mask = mask << 1;
}
return maskLen;
}
/*****************************************************************/
xx_error_t xxRouteMapSet(char *rmName)
{
uint32_t nameLen;
if (routeMapName)
{
/* Route map previously set. Free the previous name. */
free(routeMapName);
routeMapName = NULL;
}
if (rmName)
{
nameLen = strlen(rmName) + 1;
/* Just make sure name isn't ridiculously long. Application doesn't know
* what the exact max name length is in OPEN. */
if (nameLen > XX_MAX_STRING_LENGTH)
return XX_E_FAIL;
routeMapName = (char*) malloc(nameLen);
if (routeMapName == NULL)
return XX_E_FAIL;
strcpy(routeMapName, rmName);
}
return XX_E_NONE;
}
/*****************************************************************/
xx_error_t xxPrefixListSet(char *plName)
{
uint32_t nameLen;
if (pfxListName)
{
/* prefix list previously set. Free the previous name. */
free(pfxListName);
pfxListName = NULL;
}
if (plName)
{
nameLen = strlen(plName) + 1;
/* Just make sure name isn't ridiculously long. Application doesn't know
* what the exact max name length is in OPEN. */
if (nameLen > XX_MAX_STRING_LENGTH)
return XX_E_FAIL;
pfxListName = (char*) malloc(nameLen);
if (pfxListName == NULL)
return XX_E_FAIL;
strcpy(pfxListName, plName);
}
return XX_E_NONE;
}
/*****************************************************************/
uint32_t xxPolicyApply(openRoute_t *route)
{
open_buffdesc policy;
openRmMatchParams_t matchParams;
openRmSetParams_t setParams;
int permitted = 1;
if (routeMapName)
{
policy.pstart = routeMapName;
policy.size = strlen(routeMapName) + 1;
matchParams.prefix = route->destPfx;
matchParams.prefixLen = route->pfxLen;
memset(&setParams, 0, sizeof(openRmSetParams_t));
permitted = openapiRouteMapApply(&clientHandle, &policy, &matchParams, &setParams);
if (permitted == 1)
{
if (setParams.setMetric)
{
route->metric = setParams.metric;
}
}
else if (permitted < 0)
{
/* Error */
printf("\nError %d applying route map %s", permitted, routeMapName);
permitted = 0;
}
}
if (permitted && pfxListName)
{
policy.pstart = pfxListName;
policy.size = strlen(pfxListName) + 1;
permitted = openapiPrefixListApply(&clientHandle, &policy, route->destPfx, route->pfxLen);
if (permitted < 0)
{
/* Error */
printf("\nError %d applying prefix list %s", permitted, pfxListName);
permitted = 0;
}
}
return(uint32_t) permitted;
}
/*****************************************************************/
void xxRouteMapReapply(void)
{
uint32_t i;
open_buffdesc policy;
openRmMatchParams_t matchParams;
openRmSetParams_t setParams;
int permitted = 1;
if (routeMapName)
{
policy.pstart = routeMapName;
policy.size = strlen(routeMapName) + 1;
}
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if ((xxRouteTable[i].inUse) && (xxRouteTable[i].forwarding))
{
if (routeMapName)
{
matchParams.prefix = xxRouteTable[i].routeAttrs.destPfx;
matchParams.prefixLen = xxRouteTable[i].routeAttrs.pfxLen;
memset(&setParams, 0, sizeof(openRmSetParams_t));
permitted = openapiRouteMapApply(&clientHandle, &policy, &matchParams, &setParams);
}
/* We'll just ignore error cases here */
if (permitted >= 0)
{
xxRouteTable[i].permitted = permitted;
if (permitted && setParams.setMetric)
xxRouteTable[i].routeAttrs.metric = setParams.metric;
}
}
}
}
void xxPrefixListReapply(void)
{
uint32_t i;
open_buffdesc policy;
int permitted = 1;
if (pfxListName)
{
policy.pstart = pfxListName;
policy.size = strlen(pfxListName) + 1;
}
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if ((xxRouteTable[i].inUse) && (xxRouteTable[i].forwarding))
{
if (pfxListName)
{
permitted = openapiPrefixListApply(&clientHandle, &policy, xxRouteTable[i].routeAttrs.destPfx,
xxRouteTable[i].routeAttrs.pfxLen);
}
/* We'll just ignore error cases here */
if (permitted >= 0)
{
xxRouteTable[i].permitted = permitted;
}
}
}
}
void xxRouteTableEntryClear(xxRoute_t *entry)
{
uint32_t i;
if (!entry)
{
return;
}
entry->forwarding = 0;
entry->isOurRoute = 0;
entry->permitted = 0;
memset(&entry->routeAttrs, 0, sizeof(openRoute_t));
/* clear out the nexthop list array*/
for (i = 0; i < xxMaxNextHops; i++)
{
memset(&entry->routeNextHopList[i], 0, sizeof(openNextHop_t));
}
entry->inUse = 0;
}
/*********************************************************************
* @purpose Add a route to the local route table.
*
* @param[in] route the route itself
* @param[in] ownRoute Non-zero if this application is the source of this route.
* Zero if this route is learned from RPPI.
* @param[in] forwarding Non-zero if the switch uses this route for forwarding
* @param[in] permitted Non-zero if policy permits this route
*
* @returns
*
* @note
*
* @end
*********************************************************************/
xx_error_t xxRouteTableAdd(openRoute_t *route, open_buffdesc *nextHopListBuff,
uint32_t ownRoute, uint32_t forwarding, uint32_t permitted)
{
uint32_t i;
char addrBuf[INET6_ADDRSTRLEN];
ipAddressFormat(&route->destPfx, addrBuf);
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (xxRouteTable[i].inUse == 0)
{
xxRouteTable[i].inUse = 1;
memcpy(&xxRouteTable[i].routeAttrs, route, sizeof(openRoute_t));
xxRouteTable[i].isOurRoute = ownRoute;
xxRouteTable[i].forwarding = forwarding;
xxRouteTable[i].permitted = permitted;
xxRouteTable[i].routeAttrs.numNextHops =
nextHopBuffDescUnpack(xxRouteTable[i].routeNextHopList, nextHopListBuff);
printf("%s: Added route to %s\n", __FUNCTION__, addrBuf);
return XX_E_NONE;
}
}
return XX_E_FAIL;
}
/*********************************************************************
* @purpose Delete a route from the local route table.
*
* @param[in] destPfx destination prefix
* @param[in] pfxLen destination prefix length
* @param[in] nhAddr If non zero, delete only the next hop specified. Otherwise,
* delete all next hops
* @param[in] routeType type of route
*
* @returns
*
* @note
*
* @end
*********************************************************************/
xx_error_t xxRouteTableDel(open_inet_addr_t destPfx, uint8_t pfxLen, open_inet_addr_t nhAddr, uint8_t routeType)
{
uint32_t i;
uint32_t j;
char addrBuf[INET6_ADDRSTRLEN];
ipAddressFormat(&destPfx, addrBuf);
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (xxRouteTable[i].inUse != 0)
{
if (OPEN_IS_ADDR_EQUAL(&xxRouteTable[i].routeAttrs.destPfx, &destPfx) &&
(xxRouteTable[i].routeAttrs.pfxLen == pfxLen) &&
(xxRouteTable[i].routeAttrs.routeType == routeType))
{
if ((nhAddr.addr.ipv4 == 0) ||
((xxRouteTable[i].routeAttrs.numNextHops == 1) &&
(nhAddr.addr.ipv4 == xxRouteTable[i].routeNextHopList[0].nhAddr.addr.ipv4)))
{
/* Deleting all next hops or only next hop */
xxRouteTableEntryClear(&xxRouteTable[i]);
printf("%s: Deleted route to %s\n", __FUNCTION__, addrBuf);
return XX_E_NONE;
}
else
{
/* Find next hop to delete */
for (j = 0; j < xxMaxNextHops; j++)
{
if (nhAddr.addr.ipv4 == xxRouteTable[i].routeNextHopList[j].nhAddr.addr.ipv4)
{
xxRouteTable[i].routeAttrs.numNextHops--;
memset(&xxRouteTable[i].routeNextHopList[j], 0, sizeof(openNextHop_t));
/* we may have created a hole in the nexthop list, it needs to be packed */
for ( ; j < xxMaxNextHops-1; j++)
{
if (xxRouteTable[i].routeNextHopList[j+1].nhAddr.addr.ipv4 != 0)
xxRouteTable[i].routeNextHopList[j] = xxRouteTable[i].routeNextHopList[j+1];
else
break;
}
if (j < xxMaxNextHops)
{
memset(&xxRouteTable[i].routeNextHopList[j], 0, sizeof(openNextHop_t));
}
return XX_E_NONE;
}
}
}
}
}
}
return XX_E_FAIL;
}
/*********************************************************************
* @purpose Update the routing table attributes for some router events
*
* @returns
*
* @note The router events include enabling and disabling of interfaces
* and ip address change on the interface.
*
* @end
*********************************************************************/
void xxRoutingTableUpdate(void)
{
uint32_t i;
uint32_t index;
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (xxRouteTable[i].inUse != 0)
{
for (index = 0; index < xxRouteTable[i].routeAttrs.numNextHops; index++)
{
if (xxAddressResolve(xxRouteTable[i].routeNextHopList[index].nhAddr,
&xxRouteTable[i].routeNextHopList[index].ifNum) != XX_E_NONE)
{
/* Next hop address is not resolved. Set to 0 to indicate as much. */
xxRouteTable[i].routeNextHopList[index].ifNum = 0;
}
}
}
}
}
/*****************************************************************/
xx_error_t xxAddressResolve(open_inet_addr_t nhAddr, uint32_t *intIfNum)
{
uint32_t intfMask;
uint32_t i, j;
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
if (xxRouteIntfTable[i].inUse != 0)
{
for (j = 0; j < XX_INTF_IP_MAX; j++)
{
if (xxRouteIntfTable[i].ipAddrListIPv4[j].ipAddr.addr.ipv4 != 0)
{
/* Convert prefix length of local address to mask */
intfMask = xxPfxLenToMask(xxRouteIntfTable[i].ipAddrListIPv4[j].pfxLen);
/* See if our local address is in same subnet as the next hop address */
if ((nhAddr.addr.ipv4 & intfMask) ==
(xxRouteIntfTable[i].ipAddrListIPv4[j].ipAddr.addr.ipv4 & intfMask))
{
*intIfNum = xxRouteIntfTable[i].intf;
return XX_E_NONE;
}
}
}
}
}
return XX_E_FAIL;
}
/*********************************************************************
* @purpose Find a route this app added to the local route table.
*
* @param[in] destPfx destination prefix
* @param[in] pfxLen destination prefix length
*
* @returns
*
* @note
*
* @end
*********************************************************************/
xxRoute_t *xxOwnRouteFind(open_inet_addr_t destPfx, uint8_t pfxLen)
{
uint32_t i;
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (xxRouteTable[i].inUse != 0)
{
if ((xxRouteTable[i].routeAttrs.routeType == intRouteType) &&
(xxRouteTable[i].routeAttrs.pfxLen == pfxLen) &&
(OPEN_IS_ADDR_EQUAL(&xxRouteTable[i].routeAttrs.destPfx, &destPfx)))
{
return &xxRouteTable[i];
}
}
}
return NULL;
}
/*********************************************************************
* @purpose Add a route for this application.
*
* @param[in] destPfx destination prefix
* @param[in] pfxLen destination prefix length
* @param[in] nhAddr next hop address
* @param[in] metric route metric
* @param[in] label MPLS label stack
*
* @returns
*
* @note For this test application, this function is intended to be called when
* the user creates a route through this application's "CLI." We find the
* routing interface configured with the subnet that covers the next hop address.
* The route type is always the same. The route is assumed not to be used for
* forwarding until we learn otherwise.
*
* @end
*********************************************************************/
xx_error_t xxOwnRouteAdd(open_inet_addr_t destPfx, uint8_t pfxLen,
open_inet_addr_t nhAddr, uint32_t metric,
uint32_t label[OPEN_MAX_MPLS_IMPOSE_LABELS])
{
openRoute_t route;
open_buffdesc nextHopListBuffDesc;
xxRoute_t *ownRoute;
uint32_t intIfNum = 0, j;
int result;
open_inet_addr_t noNextHop;
openNextHop_t nextHopList[1];
/* UNDO_ME - Remove this once IPMAP is VRF Aware */
if (vrfId == 0)
{
if (xxAddressResolve(nhAddr, &intIfNum) != XX_E_NONE)
{
printf("\n Failed to find an interface for the next hop address \n");
return XX_E_FAIL;
}
}
else
{
/* The catch is to have a connected route to the next hops specified here
or to specify an intIfNum. For now, we will use a special number in the
interface number to escape the next hop verification logic in RTO. Undo
this when IPMAP is VR Aware
*/
intIfNum = 100;
}
memset(&route, 0, sizeof(openRoute_t));
route.destPfx = destPfx;
route.pfxLen = pfxLen;
route.routeType = intRouteType;
route.protoId = protoId;
route.pref = XX_OWN_ROUTE_PREF;
route.metric = metric;
route.numNextHops = 1;
nextHopList[0].ifNum = intIfNum;
nextHopList[0].nhAddr = nhAddr;
for (j = 0; j < OPEN_MAX_MPLS_IMPOSE_LABELS; j++)
{
nextHopList[0].label[j] = label[j];
}
if (nextHopListBuffDescStorageAllocate(&nextHopListBuffDesc) == 0)
{
printf("\n Failed to allocate storage for the next hop list.\n");
return XX_E_FAIL;
}
ownRoute = xxOwnRouteFind(destPfx, pfxLen);
if (ownRoute)
{
if (metric < ownRoute->routeAttrs.metric)
{
/* Replace existing route. */
memset(&noNextHop, 0, sizeof(open_inet_addr_t));
noNextHop.family = destPfx.family;
xxRouteTableDel(destPfx, pfxLen, noNextHop, intRouteType);
nextHopBuffDescPack(nextHopList, 1, &nextHopListBuffDesc);
xxRouteTableAdd(&route, &nextHopListBuffDesc, 1, 0, 0);
if ((result = openapiRouteModVr(&clientHandle, vrfId, &route, &nextHopListBuffDesc)) != OPEN_E_NONE)
{
printf("\nFailed to modify route in OPEN route table");
}
nextHopListBuffDescStorageFree(&nextHopListBuffDesc);
return(result);
}
else if (metric == ownRoute->routeAttrs.metric)
{
/* Same metric. Add next hop if not already in route. */
uint32_t i, foundNextHop;
/* scan nexthop list for this route to see if this nextop is already present */
foundNextHop = 0;
for (i=0; ((i < xxMaxNextHops) &&
(ownRoute->routeNextHopList[i].nhAddr.addr.ipv4 != 0)); i++)
{
if (ownRoute->routeNextHopList[i].nhAddr.addr.ipv4 == nhAddr.addr.ipv4)
{
foundNextHop = 1;
break;
}
}
/* if we did not find the nexthop in the table, add it to the list */
if ((!foundNextHop) && (i < xxMaxNextHops))
{
/* from the above loop, i points to the first free nexthop entry if there is one */
if (ownRoute->routeNextHopList[i].nhAddr.addr.ipv4 == 0)
{
ownRoute->routeNextHopList[i].nhAddr = nhAddr;
ownRoute->routeNextHopList[i].ifNum = intIfNum;
for (j = 0; j < OPEN_MAX_MPLS_IMPOSE_LABELS; j++)
{
ownRoute->routeNextHopList[i].label[j] = label[j];
}
ownRoute->routeAttrs.numNextHops++;
/* now that we modified the nexthop list, tell OPEN */
route.numNextHops = ownRoute->routeAttrs.numNextHops;
nextHopBuffDescPack(ownRoute->routeNextHopList, ownRoute->routeAttrs.numNextHops, &nextHopListBuffDesc);
if ((result = openapiRouteModVr(&clientHandle, vrfId, &route, &nextHopListBuffDesc)) != OPEN_E_NONE)
{
printf("\nFailed to modify route in OPEN route table");
}
foundNextHop = 1;
}
}
nextHopListBuffDescStorageFree(&nextHopListBuffDesc);
if (foundNextHop)
{
return XX_E_NONE;
}
else
{
return XX_E_FAIL;
}
}
}
/* No route to this destination. Add it. */
nextHopBuffDescPack(nextHopList, 1, &nextHopListBuffDesc);
if (xxRouteTableAdd(&route, &nextHopListBuffDesc, 1, 0, 0) != XX_E_NONE)
{
printf("\nFailed to add route to the local routing table ");
nextHopListBuffDescStorageFree(&nextHopListBuffDesc);
return XX_E_FAIL;
}
/* Add route to the NOS routing table */
if ((result = openapiRouteAddVr(&clientHandle, vrfId, &route, &nextHopListBuffDesc)) != OPEN_E_NONE)
{
printf("\nFailed to add route to the NOS routing table. result = %d", result);
/* Continue to add route to the local routing table. */
}
nextHopListBuffDescStorageFree(&nextHopListBuffDesc);
return XX_E_NONE;
}
/*****************************************************************/
void xxWithdrawOwnRoutes(void)
{
uint32_t i;
openRoute_t route;
memset(&route, 0, sizeof(openRoute_t));
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if ((xxRouteTable[i].inUse != 0) &&
(xxRouteTable[i].isOurRoute))
{
route.destPfx = xxRouteTable[i].routeAttrs.destPfx;
route.pfxLen = xxRouteTable[i].routeAttrs.pfxLen;
route.routeType = xxRouteTable[i].routeAttrs.routeType;
openapiRouteDel(&clientHandle, &route);
}
}
}
/*********************************************************************
* @purpose Delete a route for this application.
*
* @param[in] destPfx destination prefix
* @param[in] pfxLen destination prefix length
* @param[in] nhAddr next hop to delete. If 0, all next hops are deleted.
*
* @returns
*
* @note For this test application, this function is intended to be called when
* the user deletes a route through this application's "CLI."
*
* @end
*********************************************************************/
xx_error_t xxOwnRouteDelete(open_inet_addr_t destPfx, uint8_t pfxLen, open_inet_addr_t nhAddr)
{
xxRoute_t *routeTableEntry;
openRoute_t route;
routeTableEntry = xxOwnRouteFind(destPfx, pfxLen);
if (!routeTableEntry)
return XX_E_FAIL;
memset(&route, 0, sizeof(openRoute_t));
route.destPfx = destPfx;
route.pfxLen = pfxLen;
route.routeType = intRouteType;
if ((nhAddr.addr.ipv4 == 0) ||
((nhAddr.addr.ipv4 == routeTableEntry->routeNextHopList[0].nhAddr.addr.ipv4) &&
(routeTableEntry->routeAttrs.numNextHops == 1)))
{
/* Remove route from switch routing table */
if (openapiRouteDelVr(&clientHandle, vrfId, &route, NULL) != OPEN_E_NONE)
{
printf("\nFailed to delete route from switch");
}
/* Remove route from local routing table */
if (xxRouteTableDel(destPfx, pfxLen, nhAddr, intRouteType) != XX_E_NONE)
{
printf("\nFailed to delete route from local routing table");
}
}
else
{
/* Modify route from local routing table first */
if (xxRouteTableDel(destPfx, pfxLen, nhAddr, intRouteType) != XX_E_NONE)
{
printf("\nFailed to delete route from local routing table");
}
/* Modify route in switch routing table */
open_buffdesc nextHopList;
if (routeTableEntry)
{
route.numNextHops = routeTableEntry->routeAttrs.numNextHops;
nextHopListBuffDescStorageAllocate(&nextHopList);
nextHopBuffDescPack(routeTableEntry->routeNextHopList, routeTableEntry->routeAttrs.numNextHops, &nextHopList);
if (openapiRouteModVr(&clientHandle, vrfId, &route, &nextHopList) != OPEN_E_NONE)
{
printf("\nFailed to modify route in switch");
}
nextHopListBuffDescStorageFree(&nextHopList);
}
}
return XX_E_NONE;
}
/*****************************************************************/
xx_error_t xxRppiSvcAdd(OPEN_SERVICE_t svc, char *name, pid_t pid, uint32_t clientId, int32_t fd)
{
uint32_t i;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse == 0)
{
xxRppiServices[i].inUse = 1;
xxRppiServices[i].service = svc;
strncpy(xxRppiServices[i].clientName, name, OPEN_RPPI_CLIENT_NAME_MAX_LEN);
xxRppiServices[i].pid = pid;
xxRppiServices[i].clientId = clientId;
xxRppiServices[i].sockFd = fd;
xxRppiServices[i].lastKeepTime = currentTimeGet() / 1000;
printf("\nSuccessfully registered for OPEN %s service with client ID %u and socket fd %d.",
openServiceName[svc], clientId, fd);
return XX_E_NONE;
}
}
return XX_E_FAIL;
}
/*****************************************************************/
void xxRppiSvcDel(OPEN_SERVICE_t svc)
{
uint32_t i;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if ((xxRppiServices[i].inUse != 0) && (xxRppiServices[i].service == svc))
{
xxRppiServices[i].inUse = 0;
xxRppiServices[i].service = 0;
xxRppiServices[i].clientId = 0;
xxRppiServices[i].sockFd = -1;
xxRppiServices[i].lastKeepTime = 0;
printf("\nSuccessfully removed RPPI service entry for %s service.\n",
openServiceName[svc]);
return;
}
}
return;
}
/*****************************************************************/
uint32_t xxClientIdGet(OPEN_SERVICE_t svc)
{
uint32_t i;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if ((xxRppiServices[i].inUse != 0) && (xxRppiServices[i].service == svc))
{
return xxRppiServices[i].clientId;
}
}
return 0;
}
/*****************************************************************/
void xxKeepTimeUpdate(OPEN_SERVICE_t service)
{
uint32_t now = currentTimeGet() / 1000;
uint32_t i;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if ((xxRppiServices[i].inUse != 0) && (xxRppiServices[i].service == service))
{
xxRppiServices[i].lastKeepTime = now;
}
}
}
/*****************************************************************/
void xxKeepaliveStatusCheck(void)
{
uint32_t now = currentTimeGet() / 1000;
uint32_t i;
xx_error_t xxerr;
char myNameStorage[32];
open_buffdesc myName;
OPEN_SERVICE_t service;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse != 0)
{
if ((now - xxRppiServices[i].lastKeepTime) > XX_SERVICE_TIMEOUT)
{
printf("\nKeepalive timeout for %s service",
openServiceName[xxRppiServices[i].service]);
/* Loss of KEEPALIVES may indicate that RPPI has already deregistered this application.
* Or it may simply mean that the KEEPALIVES stopped getting through or were not
* processed in a timely manner on this end. To be sure both ends tear down the
* relationship, deregister. */
xxServiceDeregister(xxRppiServices[i].service);
/* Close socket for this service */
if (xxRppiServices[i].sockFd)
{
close(xxRppiServices[i].sockFd);
xxRppiServices[i].sockFd = -1;
}
service = xxRppiServices[i].service;
xxRppiSvcDel(xxRppiServices[i].service);
/* Attempt to reregister for service */
memset(myNameStorage, 0, sizeof(myNameStorage));
snprintf(myNameStorage, sizeof(myNameStorage), RPPI_APP_NAME);
myName.pstart = myNameStorage;
myName.size = strlen(myNameStorage) + 1;
xxerr = XX_E_FAIL;
switch (service)
{
case OPEN_ROUTER_EVENT_SVC:
xxerr = xxRouterEventClientStart(getpid(), &myName);
break;
case OPEN_BEST_ROUTE_SVC:
xxerr = xxBestRouteClientStart(getpid(), &myName);
break;
case OPEN_POLICY_SVC:
xxerr = xxPolicyClientStart(getpid(), &myName);
break;
default:
/* no - op */ ;
}
if (xxerr != XX_E_NONE)
{
xxCleanup();
exit(1);
}
}
}
}
}
/*****************************************************************/
uint32_t xxReadFdsGet(fd_set *readFds)
{
uint32_t i;
int32_t maxFd = -1;
FD_ZERO(readFds);
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse && (xxRppiServices[i].sockFd > 0))
{
FD_SET(xxRppiServices[i].sockFd, readFds);
if (xxRppiServices[i].sockFd > maxFd)
{
maxFd = xxRppiServices[i].sockFd;
}
}
}
return maxFd + 1;
}
/*****************************************************************/
void xxPolicyChangeMsgProcess(void *msg, uint32_t msgLen)
{
char *p = ((char*) m) + sizeof(openrPolicyChangeMsg_t);
char polName[XX_MAX_STRING_LENGTH + 1];
uint32_t nameLen;
if (msgLen <= sizeof(openrPolicyChangeMsg_t))
{
printf("\nInvalid policy change message length %u", msgLen);
return;
}
nameLen = msgLen - sizeof(openrPolicyChangeMsg_t);
if (nameLen >= XX_MAX_STRING_LENGTH)
{
printf("\nPolicy name too long -- %u characters", nameLen);
return;
}
memset(polName, 0, sizeof(polName));
strncpy(polName, p, nameLen);
printf("\nReceived policy change message with len %u, seqNo %u, policy type %s, change type %s, %s",
msgLen, m->seqNo,
(m->policyType == OPEN_POLICY_ROUTE_MAP) ? "Route Map" :
(m->policyType == OPEN_POLICY_PREFIX_LIST) ? "Prefix List" : "Invalid",
(m->changeType == OPEN_POLICY_CHANGE) ? "Add/Mod" :
(m->changeType == OPEN_POLICY_DELETE) ? "Del" : "Invalid",
polName);
if (openapiPolicyChangeAck(&clientHandle, xxClientIdGet(OPEN_POLICY_SVC), m->seqNo) != OPEN_E_NONE)
{
printf("\nACK failed");
}
if (routeMapName &&
(m->policyType == OPEN_POLICY_ROUTE_MAP) &&
(strcmp(routeMapName, polName) == 0))
{
xxRouteMapReapply();
}
else if (pfxListName &&
(m->policyType == OPEN_POLICY_PREFIX_LIST) &&
(strcmp(pfxListName, polName) == 0))
{
xxPrefixListReapply();
}
}
/*********************************************************************
* @purpose Process an RPPI event message
*
* @param[in] service RPPI service that send the message
* @param[in] msg Start of message
* @param[in] msgLen Message length, bytes.
*
* @returns
*
* @note
*
* @end
*********************************************************************/
void xxEventProcess(OPEN_SERVICE_t service, void *msg, uint32_t msgLen)
{
uint32_t clientId;
int index;
m = msg;
if (m->msgLen != msgLen)
{
printf("\nError. Read %u bytes of message %u from service %u, but message reports its length as %u\n",
msgLen, m->msgType, service, m->msgLen);
return;
}
/* take care of KEEP ALIVE messages before printing debug message */
if (m->msgType == OPENR_KEEPALIVE)
{
xxKeepTimeUpdate(service);
return;
}
printf("\nReceived message for %s service with msg type %s and length %u bytes\n",
openServiceName[service], xxMsgTypeNameGet(m->msgType), msgLen);
clientId = xxClientIdGet(service);
switch (m->msgType)
{
case OPENR_RTR_ENABLE:
xxRoutingEnable(OPEN_AF_INET);
break;
case OPENR_RTR_DISABLE:
xxRoutingDisable(OPEN_AF_INET);
break;
case OPENR_RTR_STARTUP_DONE:
/* OPEN has finished IPv4 routing initialization. Get the configuration and status
* of all routing interfaces. */
xxPopulateRoutingInterfaceTable();
break;
case OPENR_RTR_INTF_CREATE:
xxRouteIntfTableAdd(m->ifNum);
break;
case OPENR_RTR_INTF_DELETE:
xxRouteIntfTableDel(m->ifNum);
break;
case OPENR_RTR_INTF_ENABLE:
xxRouteIntfTableAdd(m->ifNum);
xxRoutingTableUpdate();
break;
case OPENR_RTR_INTF_DISABLE:
index = xxGetInterfaceIndexFromTable(m->ifNum);
if (index >= 0)
{
xxRouteIntfTableDel(m->ifNum);
}
xxRoutingTableUpdate();
break;
case OPENR_RTR_INTF_MTU:
index = xxGetInterfaceIndexFromTable(m->ifNum);
if (index >= 0)
{
openapiIntfIpMtuGet(&clientHandle, OPEN_AF_INET, m->ifNum, &xxRouteIntfTable[index].ipMtuIPv4);
}
break;
case OPENR_RTR_INTF_BW_CHANGE:
index = xxGetInterfaceIndexFromTable(m->ifNum);
if (index >= 0)
{
openapiIntfBandwidthGet(&clientHandle, OPEN_AF_INET, m->ifNum, &xxRouteIntfTable[index].bandwidthIPv4);
}
break;
case OPENR_RTR_INTF_ADDR_CHANGE:
(void) xxIntfIpv4AddrsUpdate(m->ifNum);
xxRoutingTableUpdate();
break;
case OPENR_RTR_INTF_HOST_MODE:
/* Interface is now a host interface and cannot be used for routing.
* Remove the interface from the local interface table. */
xxRouteIntfTableDel(m->ifNum);
xxRoutingTableUpdate();
break;
case OPENR_BEST_ROUTE_CHANGE:
xxBestRouteChangeMsgProcess((openrBestRouteChangeMsg_t*) msg, msgLen);
break;
case OPENR_POLICY_CHANGE:
xxPolicyChangeMsgProcess(msg, msgLen);
break;
default:
break;
}
if ((m->msgType >= OPENR_RTR_ENABLE) && (m->msgType < OPENR_POLICY_CHANGE))
{
openapiRouterEventAcknowledge(&clientHandle, vrfId, clientId, m->eventSeqNumber);
}
return;
}
/*****************************************************************/
void xxBestRouteAdd(openRoute_t *route, open_buffdesc *nextHopListBuff)
{
uint32_t i;
uint32_t routeFound = 0;
uint32_t permitted;
/* If policy is configured, apply policy to new route to determine whether
* route is permitted */
permitted = xxPolicyApply(route);
/* See if route is already in our route table, either because it is our route,
* or because OPEN previously announced a route to the same destination. */
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (!xxRouteTable[i].inUse)
continue;
if ((xxRouteTable[i].routeAttrs.pfxLen == route->pfxLen) &&
OPEN_IS_ADDR_EQUAL(&xxRouteTable[i].routeAttrs.destPfx, &route->destPfx))
{
/* Route to the same destination */
if (xxRouteTable[i].routeAttrs.routeType == route->routeType)
{
/* This route is an exact match for the route OPEN has added. */
routeFound = 1;
if (xxRouteTable[i].isOurRoute)
{
/* OPEN has selected our route as the best route. Update the forwarding flag. */
xxRouteTable[i].forwarding = 1;
xxRouteTable[i].permitted = permitted;
}
else
{
/* Overwrite existing route with the new route attributes. */
memcpy(&xxRouteTable[i].routeAttrs, route, sizeof(openRoute_t));
xxRouteTable[i].routeAttrs.numNextHops =
nextHopBuffDescUnpack(xxRouteTable[i].routeNextHopList, nextHopListBuff);
xxRouteTable[i].forwarding = 1;
xxRouteTable[i].permitted = permitted;
}
}
else
{
/* New best route has a different route type. The route in our table is no longer
* the best route. */
if (xxRouteTable[i].isOurRoute)
{
/* Other route is forwarding. Our route to this destination is not. */
xxRouteTable[i].forwarding = 0;
}
else
{
/* Simply delete the route that was previously the best */
xxRouteTableEntryClear(&xxRouteTable[i]);
}
}
}
}
if (!routeFound)
{
/* We did not previously have a route to this destination. Add this one. Could not
* be our route, otherwise it would already be in the table. */
xxRouteTableAdd(route, nextHopListBuff, 0, 1, permitted);
}
}
/*****************************************************************/
void xxBestRouteDel(openRoute_t *route)
{
uint32_t i;
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if (!xxRouteTable[i].inUse)
continue;
if ((xxRouteTable[i].routeAttrs.pfxLen == route->pfxLen) &&
OPEN_IS_ADDR_EQUAL(&xxRouteTable[i].routeAttrs.destPfx, &route->destPfx))
{
if (xxRouteTable[i].isOurRoute)
{
/* Our route no longer used for forwarding. But leave it in our route table. */
xxRouteTable[i].forwarding = 0;
}
else
{
/* Other protocol's route has been deleted. Remove from our table. */
xxRouteTableEntryClear(&xxRouteTable[i]);
}
}
}
}
/*****************************************************************/
void xxBestRouteChangeMsgProcess(openrBestRouteChangeMsg_t *msg, uint32_t msgLen)
{
openRoute_t route;
open_buffdesc nextHopListBuffDesc;
uint32_t numChanges = 0;
uint32_t startTime = currentTimeGet();
memset(&route, 0, sizeof(openRoute_t));
if (nextHopListBuffDescStorageAllocate(&nextHopListBuffDesc) == 0)
{
printf("\n Failed to allocate storage for the next hop list.\n");
return;
}
err = openapiBestRouteChangeNextGet(&clientHandle, msg->clientId, &chType, &route, &nextHopListBuffDesc);
while (err == OPEN_E_NONE)
{
/* if running performance test, don't process the route. Too slow on this side. */
if (perfTest == 0)
{
switch (chType)
{
case OPEN_ADD_ROUTE: xxBestRouteAdd(&route, &nextHopListBuffDesc); break;
case OPEN_CHANGE_ROUTE: xxBestRouteAdd(&route, &nextHopListBuffDesc); break;
case OPEN_DELETE_ROUTE: xxBestRouteDel(&route) ; break;
default:
printf("\nInvalid route change type %d", chType);
}
}
numChanges++;
nextHopListBuffDescSizeSet(&nextHopListBuffDesc);
err = openapiBestRouteChangeNextGet(&clientHandle, msg->clientId, &chType, &route, &nextHopListBuffDesc);
}
nextHopListBuffDescStorageFree(&nextHopListBuffDesc);
if (err != OPEN_E_EMPTY)
{
printf("\nError %d retrieving best route changes.", err);
}
else if (perfTest)
{
/* running performance test. print stats. */
uint32_t endTime = currentTimeGet();
printf("\nProcessed %u changes in %u ms (%u changes/sec)\n",
numChanges, endTime - startTime, (1000 * numChanges) / (endTime - startTime));
perfTest = 0;
}
}
/*********************************************************************
* @purpose Read from each socket whose fd is set in the read set. Process
* each event received.
*
* @param[in] readFds Socket read set
*
* @returns
*
* @note
*
* @end
*********************************************************************/
void xxSocketsRead(fd_set *readFds)
{
uint32_t i;
uint32_t bytesRcvd;
unsigned char buffer[RPPI_MSG_SIZE_MAX];
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse && FD_ISSET(xxRppiServices[i].sockFd, readFds))
{
/* Not checking who the message is from. Might be a good idea in a real application. */
do
{
bytesRcvd = recvfrom(xxRppiServices[i].sockFd, &buffer, sizeof(buffer), 0, 0, 0);
} while ((bytesRcvd < 0) && (EINTR == errno));
if (bytesRcvd <= 0)
{
printf("\nFailed to read socket with fd %d for service %d error %s",
xxRppiServices[i].sockFd, xxRppiServices[i].service, (bytesRcvd < 0) ? strerror(errno) : "no data");
}
else
{
xxEventProcess(xxRppiServices[i].service, buffer, bytesRcvd);
}
}
}
}
/*****************************************************************/
void *xxReceiveThread(void *arg)
{
struct timeval timeout;
int32_t ret;
fd_set readFds;
int32_t maxFds = -1; /* highest numbered fd in read set */
while (1)
{
/* Reset read set based on connection state */
maxFds = xxReadFdsGet(&readFds);
/* On linux, select resets the timeout to remaining time. So we must
* reset the timeout every time. */
timeout.tv_sec = XX_SELECT_TIMEOUT;
timeout.tv_usec = 0;
ret = select(maxFds, &readFds, NULL, NULL, &timeout);
if (ret < 0)
{
printf("\nselect() error %d", errno);
}
else if (ret == 0)
{
/* select() timeout. Just fall through and do keepalive check. */
}
else
{
/* One of our sockets has data to be read. Iterate through all sockets. */
pthread_mutex_lock(&mutex);
xxSocketsRead(&readFds);
pthread_mutex_unlock(&mutex);
}
/* Check KEEPALIVE status whenever we receive an event and whenever select()
* times out. */
pthread_mutex_lock(&mutex);
xxKeepaliveStatusCheck();
pthread_mutex_unlock(&mutex);
} /* end of infinite loop */
}
/* Do stuff before exiting */
void xxCleanup(void)
{
uint32_t i;
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if (xxRppiServices[i].inUse == 1)
{
xxServiceDeregister(xxRppiServices[i].service);
}
}
/* remove our routes from switchdrvr route table */
xxWithdrawOwnRoutes();
/* Register with RTO-SyncDB to save the External routes in case of ISSU */
if (openapiExternalRoutesSaveDeRegister (&clientHandle, OPEN_AF_INET, vrfId, protoId)
{
L7PROC_LOGF (L7PROC_LOG_SEVERITY_ERROR, 0, "Failed to De-register External "
"route save mechanism with RTO");
}
/* deregister our routing protocol */
err = openapiRoutingProtocolDeregister(&clientHandle, vrfId, OPEN_AF_INET, protoId);
if (err != OPEN_E_NONE)
{
printf("\nError %d deregistering protoId %u", err, protoId);
}
sleep(1);
if (routeMapName)
free(routeMapName);
if (pfxListName)
free(pfxListName);
/* Log goodbye message with OPEN */
L7PROC_LOGF(L7PROC_LOG_SEVERITY_INFO, 0, "Stopping RPPI example application");
return;
}
/*********************************************************************
* @purpose Create a UNIX datagram socket to receive events for a given service
* from RPPI.
*
* @param[in] addrFormat path and file name format string for this
* RPPI service
* @param[in] clientId client ID RPPI returned at registration
* @param[out] fd socket descriptor
*
* @returns
*
* @note
*
* @end
*********************************************************************/
xx_error_t rppiClientSockCreate(char *addrFormat, uint32_t clientId, int *fd)
{
struct sockaddr_un fpsockaddr;
int addrlen, sockfd = -1;
unsigned int rcvSize = (10 * 1024); /* bytes */
if (fd == NULL)
{
return XX_E_FAIL;
}
memset(&fpsockaddr, 0, sizeof(fpsockaddr));
fpsockaddr.sun_family = AF_UNIX;
snprintf(fpsockaddr.sun_path, sizeof(fpsockaddr.sun_path) - 1, addrFormat, clientId);
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(fpsockaddr.sun_path);
if (0 > (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)))
{
return XX_E_FAIL;
}
unlink((const char *)fpsockaddr.sun_path); /* remove old socket file if it exists */
if (0 > bind(sockfd, (const struct sockaddr *)&fpsockaddr, addrlen))
{
close(sockfd);
return XX_E_FAIL;
}
/* A 10 kbyte socket receive buffer should be sufficient for any RPPI service. */
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvSize, sizeof(rcvSize)) == -1)
{
close(sockfd);
return XX_E_FAIL;
}
*fd = sockfd;
return XX_E_NONE;
}
/*****************************************************************/
void xxServiceDeregister(OPEN_SERVICE_t service)
{
uint32_t i;
open_buffdesc nameBuf;
/* Find the client ID for the given service */
for (i = 0; i < OPEN_SERVICES_MAX; i++)
{
if ((xxRppiServices[i].inUse == 1) && (xxRppiServices[i].service == service))
{
switch (service)
{
case OPEN_ROUTER_EVENT_SVC:
(void) openapiRouterEventDeregister(&clientHandle, vrfId, xxRppiServices[i].clientId);
break;
case OPEN_BEST_ROUTE_SVC:
(void) openapiBestRouteEventDeregister(&clientHandle, xxRppiServices[i].clientId);
break;
case OPEN_POLICY_SVC:
/* deregister by zeroing the set of policies we're interested in */
nameBuf.pstart = xxRppiServices[i].clientName;
nameBuf.size = strlen(xxRppiServices[i].clientName) + 1;
(void) openapiRoutingPolicyRegister(&clientHandle, &nameBuf, xxRppiServices[i].pid, 0, NULL);
break;
default:
printf("\nAttempt to deregister from unknown RPPI service %u", service);
}
if (xxRppiServices[i].sockFd)
{
close(xxRppiServices[i].sockFd);
xxRppiServices[i].sockFd = -1;
}
xxRppiSvcDel(service);
}
}
}
/*****************************************************************/
xx_error_t xxRouterEventClientStart(pid_t myPid, open_buffdesc *myName)
{
xx_error_t xxerr;
uint32_t clientId;
int32_t fd = -1;
/* Register with RPPI as an IPv4 router event client */
err = openapiRouterEventRegister(&clientHandle, OPEN_AF_INET, myPid, vrfId, myName, &clientId);
if (err != OPEN_E_NONE)
{
printf("\nFailed to register as router event client (err = %d) -", err);
switch (err)
{
case OPEN_E_FULL: printf("Client list already full\n"); break;
case OPEN_E_EXISTS: printf("Client name already registered\n"); break;
case OPEN_E_PARAM: printf("Invalid parameter\n"); break;
case OPEN_E_FAIL: printf("General failure\n"); break;
default: printf("Other failure\n");
}
return XX_E_FAIL;
}
/* Create UNIX socket to receive router events */
xxerr = rppiClientSockCreate(ROUTER_EVENT_CLIENT_ADDR, clientId, &fd);
if (xxerr != XX_E_NONE)
{
printf("\nFailed to create router event client socket.");
return xxerr;
}
/* Add the router event service to the list of services currently registered for */
xxRppiSvcAdd(OPEN_ROUTER_EVENT_SVC, myName->pstart, myPid, clientId, fd);
return XX_E_NONE;
}
/*****************************************************************/
xx_error_t xxBestRouteClientStart(pid_t myPid, open_buffdesc *myName)
{
xx_error_t xxerr;
uint32_t clientId;
int32_t fd = -1;
/* Register with RPPI as an IPv4 best route change client */
err = openapiBestRouteEventRegisterVr(&clientHandle, vrfId, OPEN_AF_INET, myPid, myName, &clientId);
while (err == OPEN_E_UNAVAIL)
{
/* switchdrvr process is not yet initialized. Wait for it. */
sleep(1);
err = openapiBestRouteEventRegisterVr(&clientHandle, vrfId, OPEN_AF_INET, myPid, myName, &clientId);
}
if (err != OPEN_E_NONE)
{
printf("\nFailed to register as best route change client");
switch (err)
{
case OPEN_E_FULL: printf("\nClient list already full"); break;
case OPEN_E_EXISTS: printf("\nClient name already registered"); break;
default: printf("\nOther failure");
}
return XX_E_FAIL;
}
printf("RPPI returned client id %d for VRF %d\n", clientId, vrfId);
/* Create UNIX socket to receive best route change events */
xxerr = rppiClientSockCreate(RPPI_BRC_ADDR, clientId, &fd);
if (xxerr != XX_E_NONE)
{
printf("\nFailed to create router event client socket.");
return xxerr;
}
/* Add the best route change service to the list of services currently registered for */
xxRppiSvcAdd(OPEN_BEST_ROUTE_SVC, myName->pstart, myPid, clientId, fd);
return XX_E_NONE;
}
/*****************************************************************/
xx_error_t xxPolicyClientStart(pid_t myPid, open_buffdesc *myName)
{
xx_error_t xxerr;
uint32_t clientId;
int32_t fd = -1;
/* Register with RPPI as an IPv4 best route change client */
err = openapiRoutingPolicyRegister(&clientHandle, myName, myPid,
OPEN_POLICY_ROUTE_MAP | OPEN_POLICY_PREFIX_LIST,
&clientId);
while (err == OPEN_E_UNAVAIL)
{
/* switchdrvr process is not yet initialized. Wait for it. */
sleep(1);
err = openapiRoutingPolicyRegister(&clientHandle, myName, myPid,
OPEN_POLICY_ROUTE_MAP | OPEN_POLICY_PREFIX_LIST,
&clientId);
}
if (err != OPEN_E_NONE)
{
printf("\nFailed to register as routing policy change client");
switch (err)
{
case OPEN_E_FULL: printf("\nClient list already full"); break;
default: printf("\nOther failure");
}
return XX_E_FAIL;
}
/* Create UNIX socket to receive best route change events */
xxerr = rppiClientSockCreate(RPPI_POLICY_CLIENT_ADDR, clientId, &fd);
if (xxerr != XX_E_NONE)
{
printf("\nFailed to create policy event client socket.");
return xxerr;
}
/* Add the best route change service to the list of services currently registered for */
xxRppiSvcAdd(OPEN_POLICY_SVC, myName->pstart, myPid, clientId, fd);
return XX_E_NONE;
}
/*****************************************************************/
void xxPopulateRoutingInterfaceTable(void)
{
uint32_t intf = 0;
OPEN_CONTROL_t globalStatus;
while (openapiRtrIntfNextGet(&clientHandle, intf,&intf) == OPEN_E_NONE)
{
xxRouteIntfTableAdd(intf);
}
/* Get the global routing status, and if routing is globally disabled,
* then disable each routing interface. */
if (openapiRtrAdminModeGet(&clientHandle, OPEN_AF_INET, &globalStatus) == OPEN_E_NONE)
{
if (globalStatus == OPEN_DISABLE)
{
xxRoutingDisable(OPEN_AF_INET);
}
}
}
/*****************************************************************/
void xxRoutingEnable(OPEN_AF_t family)
{
adminMode[family] = OPEN_ENABLE;
}
/*****************************************************************/
void xxRoutingDisable(OPEN_AF_t family)
{
uint32_t i;
adminMode[family] = OPEN_DISABLE;
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
if (xxRouteIntfTable[i].inUse != 0)
{
xxRouteIntfTable[i].ifStateIPv4 = OPEN_DISABLE;
}
}
}
/*****************************************************************/
xx_error_t xxIntfIpv4AddrsUpdate(uint32_t intf)
{
uint32_t j;
open_inet_pfx_t intfAddr;
int32_t index;
xxRouteIntf_t *intfEntry;
index = xxGetInterfaceIndexFromTable(intf);
if (index < 0)
{
return(xx_error_t) index;
}
intfEntry = &xxRouteIntfTable[index];
/* Zero out the address set on the interface before reading the new set */
memset(&intfEntry->ipAddrListIPv4, 0, sizeof(open_inet_pfx_t) * XX_INTF_IP_MAX);
/* Set the address to 0 to get the first address on the interface */
memset(&intfAddr, 0, sizeof(open_inet_pfx_t));
for (j = 0; j < XX_INTF_IP_MAX; j++)
{
err = openapiRtrIntfIpAddrGet(&clientHandle, OPEN_AF_INET, intf, &intfAddr);
if (err == OPEN_E_NONE)
{
/* Copy address into interface table */
memcpy(&intfEntry->ipAddrListIPv4[j], &intfAddr, sizeof(open_inet_pfx_t));
}
else if (err == OPEN_E_EMPTY)
{
/* Reached the end of the list */
return XX_E_NONE;
}
else if (err == OPEN_E_NOT_FOUND)
{
/* Address list must have changed while we were iterating. Try again from
* the beginning. */
return XX_E_AGAIN;
}
else
{
printf("\nFailed to retrieve IP address on interface %s. Error %d.",
intfEntry->intfName, err);
return XX_E_FAIL;
}
}
return XX_E_FAIL;
}
/*****************************************************************/
xx_error_t xxRouteIntfTableAdd(uint32_t intf)
{
uint32_t i;
xx_error_t xxerr;
open_buffdesc intfNameBuf;
OPEN_CONTROL_t clientIdEnable;
xxerr = xxGetInterfaceIndexFromTable(intf);
if (xxerr >= 0)
{
/* interface is already in the table */
i = xxerr;
}
else
{
/* interface not in table yet. Find an empty slot. */
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
if (xxRouteIntfTable[i].inUse == 0)
break;
}
}
if (i >= XX_ROUTE_INTF_MAX)
{
printf("\nFailed to add routing interface to local table because table is full.");
return XX_E_FAIL;
}
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
xxRouteIntfTable[i].inUse = 1;
xxRouteIntfTable[i].intf = intf;
if (openapiRtrIntfTypeGet(&clientHandle, intf, &xxRouteIntfTable[i].intfType) != OPEN_E_NONE)
{
printf("\nFailed to get interface type for interface %u", intf);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
intfNameBuf.size = XX_INTF_NAME_LEN_MAX + 1;
xxRouteIntfTable[i].intfName = malloc(intfNameBuf.size);
intfNameBuf.pstart = xxRouteIntfTable[i].intfName;
err = openapiRtrIntfNameGet(&clientHandle, intf, &intfNameBuf);
if (err != OPEN_E_NONE)
{
printf("\nFailed to get interface %u name. Error %d", intf, err);
free(xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
if (xxRouteIntfTable[i].intfType == OPEN_INTF_TYPE_VLAN)
{
if (openapiRtrIntfVlanIdGet(&clientHandle, intf, &xxRouteIntfTable[i].vlanId) != OPEN_E_NONE)
{
printf("\nFailed to get VLAN ID for interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
}
else if (xxRouteIntfTable[i].intfType == OPEN_INTF_TYPE_LOOPBACK)
{
if (openapiRtrIntfLoopbackIdGet(&clientHandle, intf, &xxRouteIntfTable[i].loopbackId) != OPEN_E_NONE)
{
printf("\nFailed to get loopback ID for interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
}
if (openapiRtrIntfIpStackIfIndexGet(&clientHandle, intf, &xxRouteIntfTable[i].ifIndex) != OPEN_E_NONE)
{
printf("\nFailed to get IP stack interface index for interface %s",
xxRouteIntfTable[i].intfName);
/* This fails on LiNe builds. So don't give up on this type of failure. */
}
if (openapiRtrIntfIpAddrMethodGet(&clientHandle, intf, &xxRouteIntfTable[i].ipAddrMethod, &clientIdEnable) != OPEN_E_NONE)
{
printf("\nFailed to get IP address method of interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
if (xxIntfIpv4AddrsUpdate(intf) != XX_E_NONE)
{
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
if (openapiIntfIpMtuGet(&clientHandle, OPEN_AF_INET, intf, &xxRouteIntfTable[i].ipMtuIPv4) != OPEN_E_NONE)
{
printf("\nFailed to get IPv4 addresses for interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
if (openapiIntfBandwidthGet(&clientHandle, OPEN_AF_INET, intf, &xxRouteIntfTable[i].bandwidthIPv4) != OPEN_E_NONE)
{
printf("\nFailed to get IPv4 bandwidth of interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
if (openapiRtrIntfOperModeGet(&clientHandle, OPEN_AF_INET, intf, &xxRouteIntfTable[i].ifStateIPv4) != OPEN_E_NONE)
{
printf("\nFailed to get IPv4 operational state of interface %s", xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
return XX_E_FAIL;
}
printf("\nAdded routing interface %s to local interface table",
xxRouteIntfTable[i].intfName);
return XX_E_NONE;
}
/*****************************************************************/
xx_error_t xxRouteIntfTableDel(uint32_t intf)
{
uint32_t i;
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
if (xxRouteIntfTable[i].inUse != 0)
{
if (xxRouteIntfTable[i].intf == intf)
{
if (xxRouteIntfTable[i].intfName)
free(xxRouteIntfTable[i].intfName);
memset(&xxRouteIntfTable[i], 0, sizeof(xxRouteIntf_t));
xxRouteIntfTable[i].inUse = 0;
return XX_E_NONE;
}
}
}
return XX_E_FAIL;
}
/*****************************************************************/
xx_error_t xxGetInterfaceIndexFromTable(uint32_t intf)
{
uint32_t i;
for (i = 0; i < XX_ROUTE_INTF_MAX; i++)
{
if (xxRouteIntfTable[i].inUse != 0)
{
if (xxRouteIntfTable[i].intf == intf)
{
return i;
}
}
}
return XX_E_FAIL;
}
/*****************************************************************/
xx_error_t xxRouteTypesRegister(void)
{
char pCode[2];
char rtCode[3];
open_buffdesc protoName;
open_buffdesc protoCode;
open_buffdesc routeTypeName;
open_buffdesc routeTypeCode;
protoName.size = strlen(protocolName) + 1;
protoName.pstart = malloc(protoName.size);
if (protoName.pstart == NULL)
{
printf("Out of memory");
xxCleanup();
exit(1);
}
strcpy(protoName.pstart, protocolName);
strcpy(pCode, protocolCode);
protoCode.size = strlen(pCode) + 1;
protoCode.pstart = pCode;
if (openapiRoutingProtocolRegister(&clientHandle, vrfId, OPEN_AF_INET, &protoName, &protoCode, &protoId) != OPEN_E_NONE)
{
printf("\nRegistered protocol ID %u", protoId);
free(protoName.pstart);
return XX_E_FAIL;
}
else
{
free(protoName.pstart);
}
/* Add first route type */
if (strlen(routeType1Name) > strlen(routeType2Name))
routeTypeName.size = strlen(routeType1Name) + 1;
else
routeTypeName.size = strlen(routeType2Name) + 1;
routeTypeName.pstart = malloc(routeTypeName.size);
if (routeTypeName.pstart == NULL)
{
printf("Out of memory");
xxCleanup();
exit(1);
}
strcpy(routeTypeName.pstart, routeType1Name);
strcpy(rtCode, routeType1Code);
routeTypeCode.size = strlen(rtCode) + 1;
routeTypeCode.pstart = rtCode;
if (openapiRouteTypeRegister(&clientHandle, OPEN_AF_INET, protoId, &routeTypeName,
&routeTypeCode, &intRouteType) != OPEN_E_NONE)
{
free(routeTypeName.pstart);
return XX_E_FAIL;
}
/* Add second route type */
strcpy(routeTypeName.pstart, routeType2Name);
strcpy(rtCode, routeType2Code);
routeTypeCode.size = strlen(rtCode) + 1;
routeTypeCode.pstart = rtCode;
if (openapiRouteTypeRegister(&clientHandle, OPEN_AF_INET, protoId, &routeTypeName,
&routeTypeCode, &extRouteType) != OPEN_E_NONE)
{
free(routeTypeName.pstart);
return XX_E_FAIL;
}
free(routeTypeName.pstart);
/* Register with RTO-SyncDB to save the External routes in case of ISSU */
if (openapiExternalRoutesSaveRegister (&clientHandle, OPEN_AF_INET, vrfId, protoId)
{
L7PROC_LOGF (L7PROC_LOG_SEVERITY_ERROR, 0, "Failed to Register External "
"route save mechanism with RTO");
}
return XX_E_NONE;
}
int main(int argc, char **argv)
{
int rc;
pid_t mainPid;
char myNameStorage[32];
open_buffdesc myName;
char cmd_buf[256];
int cmd_argc;
char *cmd_argv[16];
uint32_t openInitComplete;
uint32_t i;
char openr_app_name[16];
mainPid = getpid();
l7proc_crashlog_register();
/* Read the VRFID if specified */
if (argc == 2)
{
vrfId = atoi(argv[1]);
}
else
{
vrfId = 0;
}
/* In the same VRF instance, multiple best route client may run */
memset(myNameStorage, 0, sizeof(myNameStorage));
snprintf(myNameStorage, sizeof(myNameStorage), "%s-%u:%u", RPPI_APP_NAME, vrfId, mainPid);
myName.pstart = myNameStorage;
myName.size = strlen(myNameStorage) + 1;
snprintf(openr_app_name, 16, "%s-%d%c", RPPI_APP_NAME, vrfId, '\0');
/* Register with OpEN */
if ((rc = openapiClientRegister(openr_app_name, &clientHandle)) != OPEN_E_NONE)
{
printf("\nFailed to initialize RPC to OpEN. Exiting (result = %d)\n", rc);
exit(2);
}
/* RPC call can fail until server starts. Keep trying */
while (openapiConnectivityCheck(&clientHandle) != OPEN_E_NONE)
{
sleep(1);
}
/* Register as a routing protocol */
if (xxRouteTypesRegister() != XX_E_NONE)
{
xxCleanup();
exit(0);
}
/* allocate dynamic storage */
err = openapiMaxNextHopsGet(&clientHandle, &xxMaxNextHops);
if (err != OPEN_E_NONE)
{
printf("\nFailed to get the OPEN maximum number of next hops. Error %d.", err);
exit(1);
}
err = openapiIntfNameSizeGet(&clientHandle, &XX_INTF_NAME_LEN_MAX);
if (err != OPEN_E_NONE)
{
printf("\nFailed to get the maximum length of an OPEN interface name. Error %d.", err);
exit(1);
}
err = openapiMaxRoutingInterfacesGet(&clientHandle, &XX_ROUTE_INTF_MAX);
if (err != OPEN_E_NONE)
{
printf("\nFailed to get the maximum number of OPEN routing interfaces. Error %d.", err);
exit(1);
}
/* Allocate interface table */
xxRouteIntfTable = (xxRouteIntf_t*) malloc(sizeof(xxRouteIntf_t) * XX_ROUTE_INTF_MAX);
if (xxRouteIntfTable == NULL)
{
printf("\nFailed to allocate local interface table.");
exit(1);
}
memset(xxRouteIntfTable, 0, sizeof(xxRouteIntf_t) * XX_ROUTE_INTF_MAX);
for (i = 0; i < XX_ROUTES_MAX; i++)
{
if ((xxRouteTable[i].routeNextHopList = malloc(xxMaxNextHops * sizeof(openNextHop_t))) == NULL)
{
printf("\nFailed to allocate storage for next hops.");
exit(1);
}
memset(xxRouteTable[i].routeNextHopList, 0, xxMaxNextHops * sizeof(openNextHop_t));
}
/* For now, dont spawn router event clients in non-default VRF as IPMAP is not yet ready
with VRF changes */
if (vrfId == 0)
{
if (xxRouterEventClientStart(mainPid, &myName) != XX_E_NONE)
{
xxCleanup();
exit(0);
}
/* Dont register for policy for now*/
#if 0
if (xxPolicyClientStart(mainPid, &myName) != XX_E_NONE)
{
xxCleanup();
exit(0);
}
#endif
}
if (xxBestRouteClientStart(mainPid, &myName) != XX_E_NONE)
{
xxCleanup();
exit(0);
}
/* This logic only handles IPv4. */
err = openapiRoutingStartupStatus(&clientHandle, OPEN_AF_INET, &openInitComplete);
if (err != OPEN_E_NONE)
{
printf("\nFailed to retrieve OPEN initialization status. Error %d.", err);
xxCleanup();
exit(0);
}
else if (openInitComplete)
{
/* OPEN has already sent router events for initial interface state. So we have
* to proactively go back to OPEN and ask for the state of all routing interfaces.
* If OPEN has not yet sent the initial routing interface events, we will get them
* when they are sent. */
/* Do this for all VRFs only when IPMAP has ability to add interfaces to VRFs */
if (!vrfId)
xxPopulateRoutingInterfaceTable();
}
if ((rc = pthread_create(&receive_tid, 0, xxReceiveThread, NULL)) != 0)
{
printf("Failed to create receive thread. Error %d.", rc);
xxCleanup();
exit(0);
}
L7PROC_LOGF(L7PROC_LOG_SEVERITY_INFO, 0, "Successfully started RPPI example application");
/* could read a "config file" at this point to set initial config, if desired. */
/* main loop */
while (1)
{
printf("\n%s> ", RPPI_APP_NAME);
fgets(cmd_buf, 255, stdin);
/* rm newline */
if (cmd_buf[strlen(cmd_buf)-1] == 0x0a)
{
cmd_buf[strlen(cmd_buf)-1] = 0;
}
parse_cmd_buf(cmd_buf, &cmd_argc, cmd_argv);
if (cmd_argc > 0)
{
if (!strcmp("quit", cmd_argv[0]))
{
if (cmd_argc == 1)
{
break;
}
else
{
printf("\n Invalid Command \n");
}
}
else if (!strcmp("?", cmd_argv[0]))
{
if (cmd_argc == 1)
{
printf("%s\n", cmd_list);
}
else
{
printf("\n Invalid Command \n");
}
}
else if (!strcmp("help", cmd_argv[0]))
{
if (cmd_argc == 1)
{
printf("%s\n", cmd_list);
}
else
{
printf("\n Invalid Command \n");
}
}
else
{
xxProcessCommand(cmd_buf, cmd_argc, cmd_argv);
}
}
}
xxCleanup();
(void) openapiClientTearDown(&clientHandle);
return 0;
}