/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2008 Liu Jian
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Liu Jian <liujatp@gmail.com>
* Hajime Tazaki <tazaki@sfc.wide.ad.jp>
*/
#include "netlink-socket.h"
#include "netlink-socket-address.h"
#include "netlink-message.h"
#include "netlink-message-route.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/ipv4-address.h"
#include "ns3/ipv4.h"
#include "ns3/simple-net-device.h"
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include <iostream>
#include <sstream>
#include "ns3/ipv6-address.h"
#include "ns3/ipv6.h"
#include "ns3/ipv4-l3-protocol.h"
#include "ns3/ipv4-static-routing-helper.h"
#include "ns3/ipv4-routing-table-entry.h"
#include "ns3/ipv6-l3-protocol.h"
#include "ns3/ipv6-interface.h"
#include "ns3/ipv6-static-routing-helper.h"
#include "ns3/ipv6-routing-table-entry.h"
#include "ns3/socket.h"
#include "ns3/mac48-address.h"
#include <sys/socket.h>
#include <linux/if.h>
#include <errno.h>
NS_LOG_COMPONENT_DEFINE ("NetlinkSocket");
namespace ns3 {
// GroupSockets store the netlinksocket with noero group value
// it was due to the mulitcast netlink messages.
class GroupSockets
{
public:
static uint32_t GetNSockets(void)
{
return m_Sockets.size();
}
static Ptr<NetlinkSocket> GetSocket(uint32_t index)
{
NS_ASSERT(index < m_Sockets.size());
return m_Sockets[index];
}
static void AddSocket(Ptr<NetlinkSocket>sock)
{
m_Sockets.push_back(sock);
}
private:
/*use a std::vector to store the sockets with nozero group value*/
static std::vector<Ptr<NetlinkSocket> >m_Sockets;
};
std::vector<Ptr<NetlinkSocket> >GroupSockets::m_Sockets;
NS_OBJECT_ENSURE_REGISTERED (NetlinkSocket);
/*
Netlink Socket
*/
TypeId
NetlinkSocket::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::NetlinkSocket")
.SetParent<Socket> ()
.AddConstructor<NetlinkSocket> ()
.AddTraceSource ("Drop", "Drop packet due to receive buffer overflow",
MakeTraceSourceAccessor (&NetlinkSocket::m_dropTrace))
.AddAttribute ("RcvBufSize",
"NetlinkSocket maximum receive buffer size (bytes)",
UintegerValue (0xffffffffl),
MakeUintegerAccessor (&NetlinkSocket::m_rcvBufSize),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("IcmpCallback", "Callback invoked whenever an icmp error is received on this socket.",
CallbackValue (),
MakeCallbackAccessor (&NetlinkSocket::m_icmpCallback),
MakeCallbackChecker ())
;
return tid;
}
NetlinkSocket::NetlinkSocket ()
: m_shutdownSend (false),
m_shutdownRecv (false),
m_rxAvailable (0),
m_srcPid (0),
m_srcGroups (0),
m_dstPid (0),
m_dstGroups (0)
{
NS_LOG_FUNCTION_NOARGS ();
m_errno = ERROR_NOTERROR;
}
NetlinkSocket::~NetlinkSocket ()
{
NS_LOG_FUNCTION (this);
}
void
NetlinkSocket::DoDispose (void)
{
NS_LOG_FUNCTION_NOARGS ();
}
int
NetlinkSocket::ErrnoToSimuErrno (void)
{
switch (m_errno)
{
case Socket::ERROR_ISCONN:
return EISCONN;
case Socket::ERROR_NOTCONN:
return ENOTCONN;
case Socket::ERROR_MSGSIZE:
return EMSGSIZE;
case Socket::ERROR_AGAIN:
return EAGAIN;
case Socket::ERROR_SHUTDOWN:
return ESHUTDOWN;
case Socket::ERROR_OPNOTSUPP:
return EOPNOTSUPP;
case Socket::ERROR_AFNOSUPPORT:
return EAFNOSUPPORT;
case Socket::ERROR_INVAL:
return EINVAL;
case Socket::ERROR_BADF:
return EBADF;
case Socket::ERROR_NOROUTETOHOST:
return EHOSTUNREACH;
case Socket::ERROR_NODEV:
return ENODEV;
case Socket::ERROR_ADDRNOTAVAIL:
return EADDRNOTAVAIL;
case Socket::SOCKET_ERRNO_LAST:
case Socket::ERROR_NOTERROR:
default:
NS_ASSERT (false);
return 0; // quiet compiler
break;
}
}
void
NetlinkSocket::SetNode (Ptr<Node> node)
{
NS_LOG_FUNCTION_NOARGS ();
m_node = node;
}
enum Socket::SocketErrno
NetlinkSocket::GetErrno (void) const
{
NS_LOG_FUNCTION_NOARGS ();
return m_errno;
}
enum Socket::SocketType
NetlinkSocket::GetSocketType (void) const
{
return Socket::NS3_SOCK_DGRAM;
}
Ptr<Node>
NetlinkSocket::GetNode (void) const
{
NS_LOG_FUNCTION_NOARGS ();
return m_node;
}
uint32_t
NetlinkSocket::GetSrcPid (void) const
{
NS_LOG_FUNCTION_NOARGS ();
return m_srcPid;
}
uint32_t
NetlinkSocket::GetSrcGroups (void)const
{
NS_LOG_FUNCTION_NOARGS ();
return m_srcGroups;
}
uint32_t
NetlinkSocket::GetDstPid (void) const
{
NS_LOG_FUNCTION_NOARGS ();
return m_dstPid;
}
uint32_t
NetlinkSocket::GetDstGroups (void)const
{
NS_LOG_FUNCTION_NOARGS ();
return m_dstGroups;
}
int
NetlinkSocket::Bind (void)
{
NS_LOG_FUNCTION_NOARGS ();
NetlinkSocketAddress address;
return DoBind (address);
}
int
NetlinkSocket::Bind (const Address &address)
{
NS_LOG_FUNCTION (this << address);
if (!NetlinkSocketAddress::IsMatchingType (address))
{
m_errno = ERROR_INVAL;
return -1;
}
NetlinkSocketAddress ad = NetlinkSocketAddress::ConvertFrom (address);
return DoBind (ad);
}
int
NetlinkSocket::DoBind (const NetlinkSocketAddress &address)
{
NS_LOG_FUNCTION (this << address);
m_srcPid = address.GetProcessID ();
m_srcGroups = address.GetGroupsMask ();
if (m_srcGroups)
{
GroupSockets::AddSocket(this);
}
return 0;
}
int
NetlinkSocket::Listen (void)
{
NS_LOG_FUNCTION_NOARGS ();
m_errno = Socket::ERROR_OPNOTSUPP;
return -1;
}
uint32_t
NetlinkSocket::GetTxAvailable (void) const
{
NS_LOG_FUNCTION_NOARGS ();
return 0;
}
uint32_t
NetlinkSocket::GetRxAvailable (void) const
{
NS_LOG_FUNCTION_NOARGS ();
// We separately maintain this state to avoid walking the queue
// every time this might be called
return m_rxAvailable;
}
int
NetlinkSocket::ShutdownSend (void)
{
NS_LOG_FUNCTION_NOARGS ();
m_shutdownSend = true;
return 0;
}
int
NetlinkSocket::ShutdownRecv (void)
{
NS_LOG_FUNCTION_NOARGS ();
m_shutdownRecv = true;
return 0;
}
int
NetlinkSocket::Close (void)
{
NS_LOG_FUNCTION_NOARGS ();
ShutdownSend();
ShutdownRecv();
return 0;
}
int
NetlinkSocket::Connect (const Address &address)
{
NS_LOG_FUNCTION (this << address);
m_errno = Socket::ERROR_OPNOTSUPP;
return 0;
}
Ptr<Packet>
NetlinkSocket::Recv (uint32_t maxSize, uint32_t flags)
{
NS_LOG_FUNCTION (this << maxSize<< flags);
if (m_dataReceiveQueue.empty())
{
return 0;
}
Ptr<Packet> p = m_dataReceiveQueue.front ();
if (p->GetSize () <= maxSize)
{
m_dataReceiveQueue.pop ();
m_rxAvailable -= p->GetSize ();
}
else
{
p = 0;
}
return p;
}
Ptr<Packet>
NetlinkSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
{
NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
Ptr<Packet> packet = Recv (maxSize, flags);
if (packet != 0)
{
SocketAddressTag tag;
bool found;
found = packet->FindFirstMatchingByteTag (tag);
NS_ASSERT (found);
fromAddress = tag.GetAddress ();
}
return packet;
}
int
NetlinkSocket::Send (Ptr<Packet> p,uint32_t flags)
{
NS_LOG_FUNCTION (this << p << flags);
NetlinkSocketAddress address = NetlinkSocketAddress(m_dstPid, m_dstGroups);
return SendTo(p, flags, address);
}
int
NetlinkSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress)
{
NS_LOG_FUNCTION (this << p << flags << toAddress);
NetlinkSocketAddress ad;
if (!NetlinkSocketAddress::IsMatchingType (toAddress))
{
NS_LOG_LOGIC ("ERROR_AFNOSUPPORT");
m_errno = ERROR_AFNOSUPPORT;
return -1;
}
ad = NetlinkSocketAddress::ConvertFrom (toAddress);
m_dstPid = ad.GetProcessID();
m_dstGroups = ad.GetGroupsMask();
NS_LOG_INFO ("send netlink message to pid = " << m_dstPid << ", groups = " << m_dstGroups);
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Sending netlink message from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ());
//Ptr<NetlinkSocket>kernel_socket = GetNetlinkSocketByAddress(ad);
//kernel_socket->m_receivedData.push_back(p);
//kernel_socket->NotifyDataReceived(p);
//when netlink socket send packet, the first step is to find the dest netlink socket through address
//then send the packet to it. For we partly implement the netlink-family, the dest address
//is always the kernel(pid = 0), (Actually, there must be one static kernel netlink socket to
//receive/handle messages), we do not setup a kernel socket to receive packet.
//
MultipartNetlinkMessage multipartnlmsg;
uint32_t packet_len, remain_len;
packet_len = p->GetSize ();
remain_len = packet_len;
while (remain_len > NetlinkMessageHeader::GetHeaderSize ())
{
remain_len -= p->RemoveHeader (multipartnlmsg);
NS_ASSERT (remain_len == p->GetSize ());
//actually, message to kernel contains single one netlink message
for (uint32_t i = 0; i < multipartnlmsg.GetNMessages(); i ++)
{
NetlinkMessage nlmsg = multipartnlmsg.GetMessage (i);
if (HandleMessage (nlmsg) < 0)
{
if (m_errno)
{
SendAckMessage (nlmsg, -ErrnoToSimuErrno ());
}
}
else if (NetlinkMessage::IsMessageFlagsAck (nlmsg.GetHeader ().GetMsgFlags ()))
{
SendAckMessage (nlmsg, 0);
}
}
}
NotifyDataSent (packet_len);
NS_LOG_INFO ("netlink socket kernel error " << -m_errno);
return packet_len;
}
int
NetlinkSocket::GetSockName (Address &address) const
{
NS_LOG_FUNCTION_NOARGS ();
NetlinkSocketAddress ad;
ad.SetProcessID (GetSrcPid ());
ad.SetGroupsMask (GetSrcGroups ());
address = ad;
return 0;
}
int
NetlinkSocket::GetPeerName (Address &address) const
{
NS_LOG_FUNCTION_NOARGS ();
// XXX
NS_ASSERT (false);
return -1;
}
bool
NetlinkSocket::SetAllowBroadcast (bool allowBroadcast)
{
NS_ASSERT (false);
return false;
}
bool
NetlinkSocket::GetAllowBroadcast () const
{
NS_ASSERT (false);
return false;
}
void
NetlinkSocket::ForwardUp (Ptr<Packet> packet, NetlinkSocketAddress &address)
{
NS_LOG_FUNCTION (this << packet << address);
if (m_shutdownRecv)
{
return;
}
if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
{
SocketAddressTag tag;
tag.SetAddress (address);
packet->AddByteTag (tag);
m_dataReceiveQueue.push (packet);
m_rxAvailable += packet->GetSize ();
NotifyDataRecv ();
}
else
{
NS_LOG_WARN ("No receive buffer space available. Drop.");
m_dropTrace (packet);
}
}
int32_t
NetlinkSocket::SendMessageUnicast (const MultipartNetlinkMessage &nlmsg, uint32_t pid, int32_t nonblock)
{
NS_LOG_FUNCTION (this << pid << nonblock);
//here we send message instantly
Ptr<Packet> p = Create<Packet> ();
p->AddHeader (nlmsg);
NetlinkSocketAddress address;
address.SetProcessID (pid);
//send packet to user space
ForwardUp (p, address);
return 0;
}
int32_t
NetlinkSocket::SendMessageBroadcast (const MultipartNetlinkMessage &nlmsg,
uint32_t pid,
uint32_t group,
Ptr<Node> node)
{
NS_LOG_FUNCTION ("SendMessageBroadcast" << pid << group);
//fisrt find the dest netlink socket through group value, then attach this nlmsg to its recv-queue
for (uint32_t i = 0; i < GroupSockets::GetNSockets (); i ++)
{
Ptr<NetlinkSocket> nlsock = GroupSockets::GetSocket (i);
if ((nlsock->GetSrcGroups () & group) &&
(nlsock->GetSrcPid () != pid) &&
node == nlsock->GetNode ())
{
//here we send message instantly
Ptr<Packet> p = Create<Packet> ();
p->AddHeader (nlmsg);
NetlinkSocketAddress address;
address.SetProcessID (nlsock->GetSrcPid());
address.SetGroupsMask (group);
//send packet to user space
nlsock->ForwardUp (p, address);
}
}
return 0;
}
void
NetlinkSocket::SendAckMessage (const NetlinkMessage&nlmsg, int32_t err)
{
NS_LOG_FUNCTION (this << err);
NetlinkMessageHeader rep;
NetlinkMessage ackmsg;
NetlinkMessageError errmsg;
rep.SetMsgPid (nlmsg.GetHeader ().GetMsgPid ());
rep.SetMsgSeq (nlmsg.GetHeader ().GetMsgSeq ());
rep.SetMsgType (NETLINK_MSG_ERROR);
rep.SetMsgFlags (0);
errmsg.SetError (err);
//kernel send the whole nlmsg back if error != 0, here we just send the header back
errmsg.SetMsg (nlmsg.GetHeader ());
//then send errmsg back to user space
ackmsg.SetHeader (rep);
ackmsg.SetErrorMessage (errmsg);
SendMessageUnicast (ackmsg, rep.GetMsgPid (), 1);
}
int32_t
NetlinkSocket::HandleMessage (const NetlinkMessage&nlmsg)
{
NS_LOG_FUNCTION (this);
uint16_t type = nlmsg.GetMsgType ();
NetlinkMessageHeader nhr = nlmsg.GetHeader ();
if (nhr.GetMsgLen () < NetlinkMessageHeader::GetHeaderSize ())
{
m_errno = ERROR_INVAL;
return -1;
}
if (NetlinkMessage::IsMessageNetlinkControl (type))
{
NS_LOG_INFO ("netlink control message type not parsed in kernel");
return 0;
}
else if (NetlinkMessage::IsMessageNetlinkRoute (type))
{
return HandleNetlinkRouteMessage (nlmsg);
}
else
{
NS_LOG_INFO ("netlink message type not parsed in kernel");
m_errno = ERROR_INVAL;
return -1;
}
}
int32_t
NetlinkSocket::HandleNetlinkRouteMessage (const NetlinkMessage &nlmsg)
{
NS_LOG_FUNCTION (this);
uint8_t family;
int16_t type;
int32_t err;
/* Only requests are handled by kernel now */
if (!NetlinkMessage::IsMessageFlagsRequest (nlmsg.GetHeader ().GetMsgFlags ()))
return 0;
type = nlmsg.GetMsgType ();
/* A control message: ignore them */
if (NetlinkMessage::IsMessageNetlinkControl (type))
{
return 0;
}
else if (NetlinkMessage::IsMessageNetlinkRoute (type))
{
/* All the messages must have at least 1 byte length */
if (nlmsg.GetPayloadSize () < 1)
return 0;
family = nlmsg.GetFamily ();
/*here we do not deal with different family, default for AF_NET*/
NS_ASSERT(family == AF_INET || family == AF_UNSPEC || family == AF_PACKET || family == AF_INET6);
/*for GET*** message, dump it to userspace*/
if (NetlinkMessage::IsMessageTypeGet (type) &&
NetlinkMessage::IsMessageFlagsDump (nlmsg.GetHeader ().GetMsgFlags ()))
{
DumpNetlinkRouteMessage (nlmsg, type, family);
return -1;
}
/* other types of messages*/
return DoNetlinkRouteMessage (nlmsg, type, family);
}
else/* Unknown message: reply with EINVAL */
{
err = ERROR_INVAL;
return -1;
}
}
int32_t
NetlinkSocket::DumpNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
NS_LOG_FUNCTION (this << type << family);
NS_ASSERT (type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETLINK);
MultipartNetlinkMessage nlmsg_dump;
NetlinkMessageHeader nhr = nlmsg.GetHeader ();
int32_t err;
if (type == NETLINK_RTM_GETADDR)
{
nlmsg_dump = BuildInterfaceAddressDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
}
else if (type == NETLINK_RTM_GETLINK)
{
nlmsg_dump = BuildInterfaceInfoDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
}
else if (type == NETLINK_RTM_GETROUTE)
{
nlmsg_dump = BuildRouteDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
}
else
{
m_errno = ERROR_INVAL;
return -1;
}
//then append netlink message with type NLMSG_DONE
NetlinkMessage nlmsg_done;
NetlinkMessageHeader nhr2 = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI,
nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
nlmsg_done.SetHeader (nhr2);
//kernel append nlmsg_dump size to it, here we omit it
nlmsg_dump.AppendMessage (nlmsg_done);
err = SendMessageUnicast (nlmsg_dump, m_srcPid, 1);
return err;
}
/*here only for ADD/DEL/GET*** types*/
int32_t
NetlinkSocket::DoNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
NS_LOG_FUNCTION (this << type <<family);
int32_t err;
if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
{
err = DoInterfaceAddressMessage (nlmsg, type, family);
}
else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
{
err = DoRouteMessage (nlmsg, type, family);
}
else if (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK)
{
err = DoInterfaceInfoMessage (nlmsg, type, family);
}
else
{
NS_LOG_LOGIC ("netlink message:type( " << type << ") not processed by ns3 now." );
m_errno = ERROR_INVAL;
err = -1;
}
return err;
}
MultipartNetlinkMessage
NetlinkSocket::BuildInterfaceAddressDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
NS_LOG_FUNCTION (this << pid << seq <<family);
MultipartNetlinkMessage nlmsg_dump;
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
{
if (!ipv4->IsUp (i))
continue;
Ipv4Address addri = ipv4->GetAddress (i, 0).GetLocal ();
Ipv4Mask maski = ipv4->GetAddress (i, 0).GetMask ();
Ipv4Address bcast = ipv4->GetAddress (i, 0).GetBroadcast ();
//here get the address mask length
uint32_t mask = maski.Get ();
uint8_t mask_len = 0;
while (mask)
{
mask = mask << 1;
mask_len ++;
}
//next fill the message body
NetlinkMessage nlmsg_ifa;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
InterfaceAddressMessage ifamsg;
ifamsg.SetInterfaceIndex (i);
ifamsg.SetFamily (AF_INET);//default AF_INET
ifamsg.SetLength (mask_len);
ifamsg.SetFlags (0);
ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL, ADDRESS, addri));
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS, ADDRESS, addri));
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
// ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL, STRING, "ns3-ifaddr"));//not used in ns3
//ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST, ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
//XXXother attributes not used by ns3
nlmsg_ifa.SetHeader(nhr);
nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
nlmsg_dump.AppendMessage (nlmsg_ifa);
}
// For IPv6
Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();
for (uint32_t i = 0; i < ipv6->GetNInterfaces(); i ++)
{
if (!ipv6->IsUp (i))
continue;
for (uint32_t j = 0; j < ipv6->GetNAddresses(i); j ++)
{
Ipv6Address addri = ipv6->GetAddress (i, j).GetAddress();
Ipv6Prefix prefix = ipv6->GetAddress (i, j).GetPrefix ();
//here get the address mask length
uint8_t mask_len = prefix.GetPrefixLength();
//loopback address's prefix is wrong... FIXME
if (addri.IsEqual(Ipv6Address::GetLoopback()))
mask_len = 128;
//next fill the message body
NetlinkMessage nlmsg_ifa;
NetlinkMessageHeader nhr = NetlinkMessageHeader(NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
InterfaceAddressMessage ifamsg;
ifamsg.SetInterfaceIndex(i);
ifamsg.SetFamily(AF_INET6);
ifamsg.SetFlags(0);
if (addri.IsLinkLocal())
{
ifamsg.SetLength(64);
ifamsg.SetScope (RouteMessage::RT_SCOPE_LINK);
}
else
{
ifamsg.SetLength(mask_len);
ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
}
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL, ADDRESS, addri));
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS, ADDRESS, addri));
//XXXother attributes not used by ns3
nlmsg_ifa.SetHeader(nhr);
nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
nlmsg_dump.AppendMessage (nlmsg_ifa);
}
}
return nlmsg_dump;
}
MultipartNetlinkMessage
NetlinkSocket::BuildInterfaceInfoDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
NS_LOG_FUNCTION (this << pid << seq <<family);
MultipartNetlinkMessage nlmsg_dump;
for (uint32_t i = 0; i < m_node->GetNDevices (); i ++)
{
Ptr<NetDevice> dev = m_node->GetDevice (i);
Address mac;
Address bcast;
uint32_t mtu;
uint32_t flags = 0;
mac = dev->GetAddress ();
bcast = dev->GetBroadcast ();
mtu = (uint32_t)dev->GetMtu ();
if (dev->IsLinkUp ())
{
flags |= IFF_RUNNING;
flags |= IFF_UP;
}
if (dev->IsBroadcast ())
{
flags |= IFF_BROADCAST;
}
if (dev->IsMulticast ())
{
flags |= IFF_MULTICAST;
}
NetlinkMessage nlmsg_ifinfo;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWLINK, NETLINK_MSG_F_MULTI, seq, pid);
InterfaceInfoMessage ifinfomsg;
ifinfomsg.SetFamily(0); // AF_UNSPEC
ifinfomsg.SetDeviceType (0); // not clear
ifinfomsg.SetInterfaceIndex (i);
ifinfomsg.SetDeviceFlags (flags); // not clear
ifinfomsg.SetChangeMask (0xffffffff);
// the ns3 device have no name, here we set "ns3-device i" for test
std::stringstream ss;
ss << "ns3-device" << i;
ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_IFNAME, STRING, ss.str()));
//not used in ns3
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_TXQLEN, U32, 0));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_WEIGHT, U32, 0));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_OPERSTATE, U8, 0));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINKMODE, U8, 0));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MAP, UNSPEC, 0));
ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_ADDRESS, ADDRESS, mac));
ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_BROADCAST, ADDRESS, bcast));
ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MTU, U32, mtu));
ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINK, U32, i));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_QDISC, STRING, ""));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MASTER, U32, 0));
//ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_STATS, UNSPEC, 0));
nlmsg_ifinfo.SetHeader (nhr);
nlmsg_ifinfo.SetInterfaceInfoMessage (ifinfomsg);
nlmsg_dump.AppendMessage (nlmsg_ifinfo);
}
return nlmsg_dump;
}
MultipartNetlinkMessage
NetlinkSocket::BuildRouteDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
{
NS_LOG_FUNCTION (this << pid << seq <<family);
MultipartNetlinkMessage nlmsg_dump;
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
// We only care about staticRouting for netlink support
Ipv4StaticRoutingHelper routingHelper;
Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
{
NetlinkMessage nlmsg_rt;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
RouteMessage rtmsg;
Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);
rtmsg.SetFamily (AF_INET);
rtmsg.SetDstLength (32);
rtmsg.SetSrcLength (0);
rtmsg.SetTos (0);//not clear
rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
// ns3 use local address as the route src address
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, route.GetSource()));
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, route.GetSource()));//not used in ns3
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
nlmsg_rt.SetHeader (nhr);
nlmsg_rt.SetRouteMessage (rtmsg);
nlmsg_dump.AppendMessage (nlmsg_rt);
}
Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
// We only care about staticRouting for netlink support
Ipv6StaticRoutingHelper routingHelper6;
Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);
for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
{
NetlinkMessage nlmsg_rt;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
RouteMessage rtmsg;
Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);
rtmsg.SetFamily (AF_INET6);
rtmsg.SetDstLength (128);
rtmsg.SetSrcLength (0);
rtmsg.SetTos (0);//not clear
rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
//ns3 use local address as the route src address
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS,
// ipv6->GetSourceAddress(route.GetDest ())));
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS,
// ipv6->GetSourceAddress(route.GetDest ())));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway()));
nlmsg_rt.SetHeader (nhr);
nlmsg_rt.SetRouteMessage (rtmsg);
nlmsg_dump.AppendMessage (nlmsg_rt);
}
return nlmsg_dump;
}
int32_t
NetlinkSocket::DoInterfaceAddressMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
NS_LOG_FUNCTION (this << type << family);
NS_ASSERT (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR);
// XXX
NS_ASSERT_MSG (false, "Not implemented yet (RTM_NEWADDR/RTM_DELADDR)");
InterfaceAddressMessage ifamsg = nlmsg.GetInterfaceAddressMessage ();
Ipv4Address addri, addr_local, bcast;
NetlinkAttribute attr_local;
uint32_t index = ifamsg.GetInterfaceIndex ();
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
int flag4 = 0, flag6 = 0;
if (type == NETLINK_RTM_NEWADDR)
{
//when adding an interface address, it should check the input arguments
//prefix-len and local address attribute
if (ifamsg.GetLength () > 32 ||
ifamsg.GetAttributeByType (attr_local, InterfaceAddressMessage::IF_A_LOCAL) == false)
{
m_errno = ERROR_INVAL;
return -1;
}
}
//get necessary information for add/del, many attributes we not used
for (uint32_t i = 0; i < ifamsg.GetNNetlinkAttribute (); i ++)
{
NetlinkAttribute attr = ifamsg.GetNetlinkAttribute (i);
uint32_t attr_type = attr.GetAttrType ();
switch(attr_type)
{
case InterfaceAddressMessage::IF_A_ADDRESS:
addri = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
break;
case InterfaceAddressMessage::IF_A_BROADCAST:
bcast = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
break;
case InterfaceAddressMessage::IF_A_LOCAL:
addr_local = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
break;
case InterfaceAddressMessage::IF_A_LABEL:
case InterfaceAddressMessage::IF_A_ANYCAST:
break;
}
}
if (type == NETLINK_RTM_NEWADDR)
{
//when adding an interface address by index, if the indexed interface was not exist,
//create an new NetDevice with an new index and set the address
//otherwise set the indexed interface directly
if (index >= ipv4->GetNInterfaces ())
{
Ptr<SimpleNetDevice> dev;
dev = CreateObject<SimpleNetDevice> ();
dev ->SetAddress (Mac48Address::Allocate ());
m_node->AddDevice (dev);
uint32_t netdev_idx = ipv4->AddInterface (dev);
// FIXME!
Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
ipv4->AddAddress (netdev_idx, ipv4Addr);
ipv4->SetUp (netdev_idx);
NS_LOG_INFO ("Add an interface address at index "<< netdev_idx << "but not the ifamsg input" << index);
}
else
{
Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
ipv4->AddAddress (index, ipv4Addr);
if (!ipv4->IsUp (index))
ipv4->SetUp (index);
}
flag4 = 1;
}
else//type == NETLINK_RTM_DELADDR
{
//when delete an interface address by index, if the indexed interface was not exist
//return an error EINVAL, otherwise set down the interface which has the addri
if (index >= ipv4->GetNInterfaces ())
{
m_errno = ERROR_NODEV;
return -1;
}
else
{
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
{
Ipv4Address ad = ipv4->GetAddress (i, 0).GetLocal ();
if (ad == addri && ipv4->IsUp (i))
{
ipv4->SetDown (i);
break;
}
if (i == ipv4->GetNInterfaces () - 1)
{
m_errno = ERROR_ADDRNOTAVAIL;
return -1;
}
}
flag4 = 1;
}
}
//then send an broadcast message, let all user know this operation happened
NetlinkMessage nlmsg_broadcast = nlmsg;
NetlinkMessageHeader nhr;
nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
nlmsg_broadcast.SetHeader (nhr);
if (flag4)
{
SendMessageBroadcast (nlmsg_broadcast, 0, NETLINK_RTM_GRP_IPV4_IFADDR, GetNode ());
}
else if (flag6)
{
SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_IFADDR, GetNode ());
}
return 0;
}
int32_t
NetlinkSocket::DoInterfaceInfoMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
NS_LOG_FUNCTION (this << type << family);
NS_ASSERT (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK);
InterfaceInfoMessage ifinfomsg = nlmsg.GetInterfaceInfoMessage ();
// XXX
NS_ASSERT_MSG (false, "Not implemented yet (RTM_GETLINK/RTM_SETLINK)");
return -1;
}
Address
NetlinkSocket::ConvertFrom (uint8_t family, const Address &address)
{
Address retval;
if (family == AF_INET)
{
retval = Ipv4Address::ConvertFrom (address);
}
else if (family == AF_INET6)
{
retval = Ipv6Address::ConvertFrom (address);
}
return retval;
}
int32_t
NetlinkSocket::DoRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
{
NS_LOG_FUNCTION (this << type << family);
NS_ASSERT (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE ||type == NETLINK_RTM_GETROUTE);
RouteMessage rtmsg = nlmsg.GetRouteMessage ();
Ipv4Address src, dest, gateway;
Ipv6Address src6, dest6, gateway6;
uint32_t index = 0;
int attr_flags[RouteMessage::RT_A_MAX] = {0};
uint8_t dstlen = rtmsg.GetDstLength ();
//get necessary information for add/del, many attributes we not used
for (uint32_t i = 0; i < rtmsg.GetNNetlinkAttribute (); i ++)
{
NetlinkAttribute attr = rtmsg.GetNetlinkAttribute (i);
uint32_t attr_type = attr.GetAttrType ();
attr_flags[attr_type] = 1;
switch(attr_type)
{
case RouteMessage::RT_A_DST:
if (family == AF_INET)
{
dest = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
else if (family == AF_INET6)
{
dest6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
break;
case RouteMessage::RT_A_SRC:
if (family == AF_INET)
{
src = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
else if (family == AF_INET6)
{
src6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
break;
case RouteMessage::RT_A_OIF:
index = attr.GetAttrPayload ().GetU32 ();
break;
case RouteMessage::RT_A_GATEWAY:
if (family == AF_INET)
{
gateway = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
else if (family == AF_INET6)
{
gateway6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
}
break;
case RouteMessage::RT_A_IIF:
case RouteMessage::RT_A_PRIORITY:
case RouteMessage::RT_A_PREFSRC:
case RouteMessage::RT_A_METRICS:
case RouteMessage::RT_A_MULTIPATH:
case RouteMessage::RT_A_PROTOINFO:
case RouteMessage::RT_A_FLOW:
case RouteMessage::RT_A_CACHEINFO:
case RouteMessage::RT_A_SESSION:
case RouteMessage::RT_A_MP_ALGO:
case RouteMessage::RT_A_TABLE:
NS_LOG_INFO("route attribute not used by ns3" << attr_type);
//not used by ns3
break;
}
}
// Sigh....
Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
Ipv4StaticRoutingHelper routingHelper;
Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);
Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();
Ipv6StaticRoutingHelper routingHelper6;
Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Route message, type: " << type << "; from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
<< " to " << dest<< " through " << gateway);
if (type == NETLINK_RTM_NEWROUTE)
{
//ns3 add a route entry only depends on 2 or 3 attribute
//other route msg attibute were ignored
if (attr_flags[RouteMessage::RT_A_DST])
{
if (family == AF_INET)
{
if (!attr_flags[RouteMessage::RT_A_OIF])
{
bool found = 0;
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
{
for (uint32_t j = 0; j < ipv4->GetNAddresses (i); j++)
{
if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
{
Ipv4Mask mask = ipv4->GetAddress (i, j).GetMask ();
if (mask.IsMatch (ipv4->GetAddress (i, j).GetLocal (), gateway))
{
index = i;
found = true;
break;
}
}
if (found) break;
}
}
if (!found)
{
NS_LOG_DEBUG ("No suitable interface to add an route entry");
m_errno = ERROR_ADDRNOTAVAIL;
return -1;
}
}
if (dstlen == 32)
{
int exist_flag = 0;
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
{
Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
if (dest == rt.GetDest ())
{
exist_flag = 1;
}
}
if (exist_flag)
{ //route to dest already exists
int delete_flag = 0;
if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_REPLACE)
{
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
{
Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
if (dest == rt.GetDest ())
{
ipv4Static->RemoveRoute (i);
NS_LOG_DEBUG ("Route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to "
<< dest << " through " << gateway << " removed");
delete_flag = 1;
}
}
if (!delete_flag)
{
NS_LOG_INFO ("no route entry removed by dest address in new route sector " << dest);
m_errno = ERROR_INVAL;
return -1;
}
}
else
{
NS_LOG_DEBUG ("Route exists but overwriting declined!");
}
if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
{
NS_LOG_DEBUG (Simulator::Now().GetSeconds() << "Overwrite route from "
<< m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest<< " through " << gateway << " with index" << index);
ipv4Static->AddHostRouteTo (dest, gateway, index);
}
else
{
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Overwrite route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
<< " to " << dest<< " through " << "self" << " with index" << index);
ipv4Static->AddHostRouteTo (dest, index);
}
}
else
{ //route to dest doesn't exist
if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_CREATE)
{
if (attr_flags[RouteMessage::RT_A_GATEWAY])
{
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
<< " to " << dest<< " through " << gateway << " with index" << index);
ipv4Static->AddHostRouteTo (dest, gateway, index);
}
else
{
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
<< " to " << dest<< " through " << "self" << " with index" << index);
ipv4Static->AddHostRouteTo (dest, index);
}
}
else
{
NS_LOG_ERROR ("Route doesn't exist but writing declined!");
}
}
NS_LOG_DEBUG ("=After change attempt=");
//Dump of table
NS_LOG_DEBUG (m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << ":");
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
{
Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
NS_LOG_DEBUG (rt.GetDest () << " through " << rt.GetGateway ());
}
NS_LOG_DEBUG ("= = = = = = = = = = =");
}
else // dstlen != 32
{
if (attr_flags[RouteMessage::RT_A_GATEWAY])
{
ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), gateway, index);
}
else
{
ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), index);
}
}
}
else if (family == AF_INET6)
{
if (!attr_flags[RouteMessage::RT_A_OIF])
{
#ifdef FIXME
if (ipv6->GetIfIndexForDestination (gateway6, index) == false)
{
NS_LOG_INFO ("No suitable interface to add an route entry");
m_errno = ERROR_ADDRNOTAVAIL;
return -1;
}
#endif
}
Ipv6Prefix pref (dstlen);
if (attr_flags[RouteMessage::RT_A_GATEWAY])
{
ipv6Static->AddNetworkRouteTo (dest6, pref, gateway6, index);
}
else
{
ipv6Static->AddNetworkRouteTo (dest6, pref, Ipv6Address("::"), index);
}
}
}
else
{
NS_LOG_INFO("too few attributes to add an route entry");
m_errno = ERROR_INVAL;
return -1;
}
}
else if (type == NETLINK_RTM_DELROUTE)
{
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Route delete request from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
<< " to " << dest<< " through " << gateway);
if (attr_flags[RouteMessage::RT_A_DST])
{
int delete_flag = 0;
if (family == AF_INET)
{
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
{
Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
if (gateway == rt.GetGateway () && dest == rt.GetDest ())
{
ipv4Static->RemoveRoute (i);
delete_flag = 1;
}
}
}
else if (family == AF_INET6)
{
for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
{
Ipv6RoutingTableEntry rt = ipv6Static->GetRoute (i);
if (gateway6 == rt.GetGateway () && dest6 == rt.GetDest ())
{
ipv6Static->RemoveRoute (i);
delete_flag = 1;
}
}
}
if (!delete_flag)
{
NS_LOG_INFO ("no route entry removed by dest address " << dest);
m_errno = ERROR_INVAL;
return -1;
}
}
else
{
NS_LOG_INFO ("too few attributes to add an route entry");
m_errno = ERROR_INVAL;
return -1;
}
}
else// type == NETLINK_RTM_GETROUTE
{
NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "GetRoute "<< "from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest);
if (!attr_flags[RouteMessage::RT_A_DST])
{
NS_LOG_INFO ("too few attributes to get an route entry");
m_errno = ERROR_INVAL;
return -1;
}
int get_flag = 0;
if (family == AF_INET)
{
for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
{
Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);
//find the route entry with same dest address and send unicast to user space
if (dest.IsEqual (route.GetDest ()))
{
// Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
NetlinkMessage nlmsg_route;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0,
nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
RouteMessage rtmsg;
//fill rtmsg and attributes
rtmsg.SetFamily (AF_INET);
rtmsg.SetDstLength (32);
rtmsg.SetSrcLength (0);
rtmsg.SetTos (0);//not clear
rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
//ns3 use local address as the route src address
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
//fill an netlink message body
nlmsg_route.SetHeader (nhr);
nlmsg_route.SetRouteMessage (rtmsg);
SendMessageUnicast (nlmsg_route, m_srcPid, 1);
get_flag = 1;
}
}
}
else if (family == AF_INET6)
{
for (uint32_t i = 0; i < ipv6Static->GetNRoutes(); i ++)
{
Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);
//find the route entry with same dest address and send unicast to user space
if (dest6.IsEqual (route.GetDest ()))
{
NetlinkMessage nlmsg_route;
NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0,
nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
RouteMessage rtmsg;
//fill rtmsg and attributes
rtmsg.SetFamily (AF_INET6);
rtmsg.SetDstLength (32);
rtmsg.SetSrcLength (0);
rtmsg.SetTos (0);//not clear
rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
//ns3 use local address as the route src address
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
// rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
//fill an netlink message body
nlmsg_route.SetHeader (nhr);
nlmsg_route.SetRouteMessage (rtmsg);
SendMessageUnicast (nlmsg_route, m_srcPid, 1);
get_flag = 1;
}
}
}
if (!get_flag)
{
NS_LOG_INFO ("no route entry exist by dest address" << dest);
m_errno = ERROR_INVAL;
return -1;
}
}
//then send an broadcast message, let all user know this operation happened
MultipartNetlinkMessage nlmsg_multi;
NetlinkMessage nlmsg_broadcast = nlmsg;
NetlinkMessage nlmsg_done;
NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
nlmsg_done.SetHeader (nhr_done);
nlmsg_multi.AppendMessage (nlmsg);
nlmsg_multi.AppendMessage (nlmsg_done);
SendMessageBroadcast (nlmsg_multi, 0, NETLINK_RTM_GRP_IPV4_ROUTE, GetNode ());
// SendMessageBroadcast(nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
return 0;
}
int32_t
NetlinkSocket::NotifyIfLinkMessage (Address address, uint16_t type, uint8_t family)
{
NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfLinkMessage)");
return 0;
}
int32_t
NetlinkSocket::NotifyIfAddrMessage (Ipv6Interface* interface, Ipv6Address addr, int cmd)
{
MultipartNetlinkMessage nlmsg_multi;
NetlinkMessage nlmsg_ifa;
NetlinkMessageHeader nhr = NetlinkMessageHeader (cmd, NETLINK_MSG_F_MULTI, 0, 0);
InterfaceAddressMessage ifamsg;
NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfAddrMessage)");
// FIXME!
Ipv6Prefix prefix = Ipv6Prefix(64);
//here get the address mask length
uint8_t bytes[16];
prefix.GetBytes (bytes);
uint8_t mask_len = 0;
for (int j = 0; j < 16; j++)
{
while (bytes[j])
{
bytes[j] = bytes[j] << 1;
mask_len ++;
}
}
ifamsg.SetInterfaceIndex (interface->GetDevice ()->GetIfIndex ());
ifamsg.SetFamily (AF_INET6);
ifamsg.SetLength (mask_len);
ifamsg.SetFlags (0);
ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL, ADDRESS, addr));
ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS, ADDRESS, addr));
// ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
// ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL, STRING, "ns3-ifaddr"));//not used in ns3
//ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST, ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
//XXXother attributes not used by ns3
nlmsg_ifa.SetHeader (nhr);
nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
NetlinkMessage nlmsg_done;
NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
nlmsg_done.SetHeader (nhr_done);
nlmsg_multi.AppendMessage (nlmsg_ifa);
nlmsg_multi.AppendMessage (nlmsg_done);
SendMessageBroadcast (nlmsg_multi, 0, RTMGRP_IPV6_IFADDR, interface->GetDevice ()->GetNode ());
return 0;
}
#ifdef FIXME
int32_t
NetlinkSocket::NotifyRouteMessage(Ojbect route, uint16_t type, uint8_t family)
{
NetlinkMessage nlmsg_broadcast = nlmsg;
NetlinkMessageHeader nhr;
NS_ASSERT_MSG (false, "Not implemented yet");
nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
nlmsg_broadcast.SetHeader (nhr);
SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
return 0;
}
#endif
}//namespace ns3