#include "unix/zebraRouteMgr.h"
void ZebraRouteMgr::OnClientSocketEvent(ProtoSocket& theSocket,
ProtoSocket::Event theEvent)
{
}
ZebraRouteMgr::ZebraRouteMgr()
:zPipe(ProtoPipe::STREAM)
{
}
ZebraRouteMgr::~ZebraRouteMgr()
{
Close();
}
bool ZebraRouteMgr::SetForwarding(bool state)
{
return true;
}
bool ZebraRouteMgr::Open(const void* )
{
if ((descriptor = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
{
printf("ZebraRouteMgr::Open() socket(NETLINK_ROUTE) error: %s\n",
strerror(errno));
return false;
}
else
{
pid = (UINT32)getpid();
}
if (!zPipe.Connect("/var/run/zserv.api")) {
if(!zPipe.Connect("/var/run/quagga/zserv.api")) {
printf("ZebraRouteMgr::Open fail to connect %s\n",zPipe.GetErrorString());
printf("ZebraRouteMgr::Open tries to connect to /var/run/zserv.api and /var/run/quagga/zserv.api. Is Zebra running? Is its runs directory one of the above (set durring zebra configure)?\n");
return false;
}
}
return true;
} bool ZebraRouteMgr::IsOpen() const
{
return zPipe.IsOpen();
}
void ZebraRouteMgr::Close()
{
if (IsOpen())
{
zPipe.Close();
}
}
bool ZebraRouteMgr::SetRoute(const ProtoAddress& dst,
unsigned int prefixLen,
const ProtoAddress& gw,
unsigned int ifIndex,
int metric)
{
unsigned char *s = obuf;
unsigned short *p ;
unsigned int len;
p = (unsigned short *)s;
*p = htons(ZEBRA_HEADER_SIZE);
s +=2 ; *s++ = ZEBRA_HEADER_MARKER; *s++ = ZEBRA_VERSION; p = (unsigned short *)s;
*p = htons(ZEBRA_IPV4_ROUTE_ADD); s += 2;
*s++ = 0 ; *s++ = 0 ; *s++ = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_DISTANCE;
*s++ = prefixLen; unsigned long ipLong;
ipLong = dst.IPv4GetAddress(); ipLong = htonl(ipLong);
int prefixInBytes = (prefixLen +7 )/8;
memcpy(s,&ipLong,prefixInBytes); s += prefixInBytes;
*s++ = 2; *s++ = ZEBRA_NEXTHOP_IPV4; ipLong = gw.IPv4GetAddress(); ipLong = htonl(ipLong);
memcpy(s,&ipLong,4); s += 4;
*s++ = ZEBRA_NEXTHOP_IFINDEX; ipLong = htonl(ifIndex);
memcpy(s,&ipLong,4); s += 4;
*s++ = metric;
len = s - obuf;
ipLong = htons(len); p = (unsigned short *)obuf;
*p = htons(len);
zPipe.Send((char *)obuf,len);
return true;
}
bool ZebraRouteMgr::DeleteRoute(const ProtoAddress& dst,
unsigned int prefixLen,
const ProtoAddress& gw,
unsigned int ifIndex)
{
unsigned char *s = obuf;
unsigned short *p ;
unsigned int len;
p = (unsigned short *)s;
*p = htons(ZEBRA_HEADER_SIZE);
s +=2 ; *s++ = ZEBRA_HEADER_MARKER; *s++ = ZEBRA_VERSION; p = (unsigned short *)s;
*p = htons(ZEBRA_IPV4_ROUTE_DELETE); s += 2;
*s++ = 0 ; *s++ = 0 ; *s++ = ZAPI_MESSAGE_NEXTHOP ;
*s++ = prefixLen; unsigned long ipLong;
ipLong = dst.IPv4GetAddress(); ipLong = htonl(ipLong);
int prefixInBytes = (prefixLen +7 )/8;
memcpy(s,&ipLong,prefixInBytes); s += prefixInBytes;
*s++ = 2; *s++ = ZEBRA_NEXTHOP_IPV4; ipLong = gw.IPv4GetAddress(); ipLong = htonl(ipLong);
memcpy(s,&ipLong,4); s += 4;
*s++ = ZEBRA_NEXTHOP_IFINDEX; ipLong = htonl(ifIndex);
memcpy(s,&ipLong,4); s += 4;
len = s - obuf;
ipLong = htons(len); p = (unsigned short *)obuf;
*p = htons(len);
zPipe.Send((char *)obuf,len);
return true;
}
bool ZebraRouteMgr::GetRoute(const ProtoAddress& dst,
unsigned int prefixLen,
ProtoAddress& gw,
unsigned int& ifIndex,
int& metric)
{
return true;
}
bool ZebraRouteMgr::GetAllRoutes(ProtoAddress::Type addrType,
ProtoRouteTable& routeTable)
{
return true;
}
void
ZebraRouteMgr::PrintBuffer(char* buffer,int len,int dlevel)
{
for(int i=0;i<(int)len;i++)
{
printf("%02X ",(unsigned char)buffer[i]);
if(i % 4 == 3)
printf("\n");
}
}
bool ZebraRouteMgr::GetInterfaceAddressList(unsigned int ifIndex,
ProtoAddress::Type addrType,
ProtoAddressList& addrList)
{
ProtoAddressList localAddrList; struct
{
struct nlmsghdr msg;
struct ifaddrmsg ifa;
} req;
memset(&req, 0, sizeof(req));
req.msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.msg.nlmsg_type = RTM_GETADDR;
req.msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH ;
UINT32 seq = sequence++;
req.msg.nlmsg_seq = seq;
req.msg.nlmsg_pid = pid;
unsigned int addrLength = 0;
switch (addrType)
{
case ProtoAddress::IPv4:
req.ifa.ifa_family = AF_INET;
req.ifa.ifa_prefixlen = 32;
addrLength = 4;
break;
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
req.ifa.ifa_family = AF_INET6;
req.ifa.ifa_prefixlen = 128;
addrLength = 16;
break;
#endif default:
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() invalid destination address!\n");
return false;
break;
}
req.ifa.ifa_flags = 0; req.ifa.ifa_scope = RT_SCOPE_UNIVERSE;
req.ifa.ifa_index = ifIndex;
int result = send(descriptor, &req, req.msg.nlmsg_len, 0);
if (result < 0)
{
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() send() error: %s\n",
strerror(errno));
return false;
}
bool done = false;
while(!done)
{
char buffer[1024];
int msgLen = recv(descriptor, buffer, 1024, 0);
if (msgLen < 0)
{
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() recv() error: %s\n", strerror(errno));
return false;
}
struct nlmsghdr* msg = (struct nlmsghdr*)buffer;
for (; 0 != NLMSG_OK(msg, (unsigned int)msgLen); msg = NLMSG_NEXT(msg, msgLen))
{
#ifndef CORE_NAMESPACES
if ((msg->nlmsg_pid == (UINT32)pid) && (msg->nlmsg_seq == seq))
#else
if (msg->nlmsg_seq == seq)
#endif {
switch (msg->nlmsg_type)
{
case NLMSG_NOOP:
break;
case NLMSG_ERROR:
{
struct nlmsgerr* errorMsg = (struct nlmsgerr*)NLMSG_DATA(msg);
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() recvd NLMSG_ERROR error seq:%d code:%d...\n",
msg->nlmsg_seq, errorMsg->error);
return false;
break;
}
case NLMSG_DONE:
done = true;
break;
case RTM_NEWADDR:
{
struct ifaddrmsg* ifa = (struct ifaddrmsg*)NLMSG_DATA(msg);
struct rtattr* rta = IFA_RTA(ifa);
int rtaLen = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
for (; RTA_OK(rta, rtaLen);
rta = RTA_NEXT(rta, rtaLen))
{
switch (rta->rta_type)
{
case IFA_ADDRESS:
case IFA_LOCAL:
{
if (ifa->ifa_index == ifIndex)
{
switch (ifa->ifa_scope)
{
case RT_SCOPE_UNIVERSE:
{
ProtoAddress theAddress;
theAddress.SetRawHostAddress(addrType, (char*)RTA_DATA(rta), addrLength);
if (theAddress.IsValid())
{
if (!addrList.Insert(theAddress))
{
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() error: couldn't add to addrList\n");
done = true;
}
}
break;
}
case RT_SCOPE_SITE:
case RT_SCOPE_LINK:
{
ProtoAddress theAddress;
theAddress.SetRawHostAddress(addrType, (char*)RTA_DATA(rta), addrLength);
if (theAddress.IsValid() && !localAddrList.Insert(theAddress))
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() error: couldn't add to localAddrList\n");
break;
}
default:
break;
}
}
break;
}
case IFA_BROADCAST:
{
break;
}
default:
break;
} } break;
}
default:
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() matching reply type:%d len:%d bytes\n",
msg->nlmsg_type, msg->nlmsg_len);
break;
} }
else
{
if (NLMSG_ERROR == msg->nlmsg_type)
{
struct nlmsgerr* errorMsg = (struct nlmsgerr*)NLMSG_DATA(msg);
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() recvd NLMSG_ERROR seq:%d code:%d\n",
msg->nlmsg_seq, errorMsg->error);
}
} } }
ProtoAddressList::Iterator iterator(localAddrList);
ProtoAddress localAddr;
while (iterator.GetNextAddress(localAddr))
{
if (!addrList.Insert(localAddr))
{
PLOG(PL_ERROR, "LinuxRouteMgr::GetInterfaceAddressList() error: couldn't add localAddr to addrList\n");
break;
}
}
if (addrList.IsEmpty())
PLOG(PL_WARN, "LinuxRouteMgr::GetInterfaceAddressList() warning: no addresses found\n");
return true;
}