netlink/netlink-message.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Thu, 05 May 2011 15:16:49 +0200
changeset 71 38b25a74e8e7
parent 66 2fe1f3e576c9
permissions -rw-r--r--
avoid calling write upon flush when called by DeleteProcess

/* -*- 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-message.h"
#include "ns3/address-utils.h"
#include "ns3/log.h"

NS_LOG_COMPONENT_DEFINE ("NetlinkMessage");

namespace ns3 {

/***********************************************************************************
* \ NetlinkMessageHeader
***********************************************************************************/
NS_OBJECT_ENSURE_REGISTERED (NetlinkMessageHeader);
NS_OBJECT_ENSURE_REGISTERED (NetlinkMessage);

NetlinkMessageHeader::NetlinkMessageHeader ()
  : m_nlmsgLen (16),
    m_nlmsgType (0),
    m_nlmsgFlags (0),
    m_nlmsgSeq (0),
    m_nlmsgPid (0)
{}

NetlinkMessageHeader::NetlinkMessageHeader (uint16_t type, uint16_t flags, uint32_t seq, uint32_t pid)
  : m_nlmsgLen (16),
    m_nlmsgType (type),
    m_nlmsgFlags (flags),
    m_nlmsgSeq (seq),
    m_nlmsgPid (pid)
{}

void
NetlinkMessageHeader::SetMsgLen (uint32_t v)
{
  m_nlmsgLen = v;
}
void
NetlinkMessageHeader::SetMsgFlags (uint16_t v)
{
  m_nlmsgFlags = v;
}
void
NetlinkMessageHeader::SetMsgType (uint16_t v)
{
  m_nlmsgType = v;
}
void
NetlinkMessageHeader::SetMsgSeq (uint32_t v)
{
  m_nlmsgSeq = v;
}
void
NetlinkMessageHeader::SetMsgPid (uint32_t v)
{
  m_nlmsgPid = v;
}
uint16_t
NetlinkMessageHeader::GetMsgFlags (void) const
{
  return m_nlmsgFlags;
}
uint32_t 
NetlinkMessageHeader::GetMsgLen (void) const
{
  return m_nlmsgLen;
}
uint16_t 
NetlinkMessageHeader::GetMsgType (void) const
{
  return m_nlmsgType;
}
uint32_t
NetlinkMessageHeader::GetMsgSeq (void) const
{
  return m_nlmsgSeq;
}
uint32_t 
NetlinkMessageHeader::GetMsgPid (void) const
{
  return m_nlmsgPid;
}
uint32_t
NetlinkMessageHeader::GetHeaderSize ()
{
  return NETLINK_MSG_HEADER_SIZE;
}
uint32_t
NetlinkMessageHeader::GetPayloadSize (void) const
{
  return NETLINK_MSG_ALIGN (m_nlmsgLen - NETLINK_MSG_HEADER_SIZE);
}

TypeId 
NetlinkMessageHeader::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NetlinkMessageHeader")
    .SetParent<Header> ()
    .AddConstructor<NetlinkMessageHeader> ()
    ;
  return tid;
}
TypeId 
NetlinkMessageHeader::GetInstanceTypeId (void) const
{
  return GetTypeId ();
}
void 
NetlinkMessageHeader::Print (std::ostream &os) const
{
  os << "NetlinkMessageHeader "
     << "len: " << m_nlmsgLen << " "
     << "flags: " << m_nlmsgFlags << " "
     << "type: " << m_nlmsgType << " "
     << "seq: " << m_nlmsgSeq << " "
     << "pid: " << m_nlmsgPid;
}

uint32_t 
NetlinkMessageHeader::GetSerializedSize (void) const
{
  /* this is the size of an nlmsghdr payload. */
  return NETLINK_MSG_HEADER_SIZE;
}

void
NetlinkMessageHeader::Serialize (Buffer::Iterator& start) const
{
  start.WriteU32 (m_nlmsgLen);
  start.WriteU16 (m_nlmsgType);
  start.WriteU16 (m_nlmsgFlags);
  start.WriteU32 (m_nlmsgSeq);
  start.WriteU32 (m_nlmsgPid);
}

uint32_t
NetlinkMessageHeader::Deserialize (Buffer::Iterator& start)
{
  m_nlmsgLen = start.ReadU32 ();
  m_nlmsgType = start.ReadU16 ();
  m_nlmsgFlags = start.ReadU16 ();
  m_nlmsgSeq = start.ReadU32 ();
  m_nlmsgPid = start.ReadU32 ();

  return GetSerializedSize ();
}




/***********************************************************************************
* \ NetlinkMessageError
***********************************************************************************/

NetlinkMessageError::NetlinkMessageError ()
  : m_error (0)
{
}
NetlinkMessageError::~NetlinkMessageError ()
{}
void 
NetlinkMessageError::SetError (int32_t v)
{
  m_error = v;
}
int32_t
NetlinkMessageError::GetError (void) const
{
  return m_error;
}
void
NetlinkMessageError::SetMsg (NetlinkMessageHeader v)
{
  m_msg = v;
}
NetlinkMessageHeader
NetlinkMessageError::GetMsg (void) const
{
  return m_msg;
}

TypeId 
NetlinkMessageError::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NetlinkMessageError")
    .SetParent<NetlinkPayload> ()
    .AddConstructor<NetlinkMessageError> ()
    ;
  return tid;
}

TypeId 
NetlinkMessageError::GetInstanceTypeId (void) const
{
  return GetTypeId ();
}
void 
NetlinkMessageError::Print (std::ostream &os) const
{  
  os << "----NetlinkMessageError "
     << "error: " << m_error << " "
     << "msg:( ";
  m_msg.Print(os);
  os << " )";
}

uint32_t 
NetlinkMessageError::GetSerializedSize (void) const
{
  /* this is the size of an nlmsgerr payload. */
  return NETLINK_MSG_ERROR_SIZE;
}

void
NetlinkMessageError::Serialize (Buffer::Iterator& start) const
{
  start.WriteU32 (m_error);
  m_msg.Serialize (start);
}

uint32_t
NetlinkMessageError::Deserialize (Buffer::Iterator& start)
{  
  m_error = start.ReadU32 ();
  m_msg.Deserialize (start);
  
  return GetSerializedSize ();
}




/***********************************************************************************
* \ NetlinkMessage
***********************************************************************************/
NetlinkMessage::NetlinkMessage ()
{}

void
NetlinkMessage::SetHeader (NetlinkMessageHeader hdr)
{
  m_hdr = hdr;
}
NetlinkMessageHeader
NetlinkMessage::GetHeader (void)const
{
  return m_hdr;
}
void
NetlinkMessage::SetGeneralMessage (GeneralMessage genmsg)
{
  m_genmsg = genmsg;
  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + genmsg.GetSerializedSize ());
}
void
NetlinkMessage::SetErrorMessage (NetlinkMessageError errmsg)
{
  m_errorMessage = errmsg;
  m_hdr.SetMsgLen(m_hdr.GetSerializedSize () + errmsg.GetSerializedSize ());
}
// the type is one of RTM_NEWLINK,RTM_DELLINK,RTM_GETLINK
void
NetlinkMessage::SetInterfaceInfoMessage (InterfaceInfoMessage v)
{
  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
  m_interfaceTemplate = v;
}
// the type is one of RTM_NEWADDR,RTM_DELADDR,RTM_GETADDR
void NetlinkMessage::SetInterfaceAddressMessage (InterfaceAddressMessage v)
{
  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
  m_addressTemplate = v;
}
// the type  is one of RTM_NEWROUTE,RTM_DELROUTE,RTM_GETROUTE
void NetlinkMessage::SetRouteMessage (RouteMessage v)
{
  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
  m_routeTemplate = v;
}
GeneralMessage
NetlinkMessage::GetGeneralMessage (void) const
{
  return m_genmsg;
}
NetlinkMessageError
NetlinkMessage::GetErrorMessage (void) const
{
  return m_errorMessage;
}
InterfaceInfoMessage
NetlinkMessage::GetInterfaceInfoMessage (void) const
{
  return m_interfaceTemplate;
}
InterfaceAddressMessage
NetlinkMessage::GetInterfaceAddressMessage (void) const
{
  return m_addressTemplate;
}
RouteMessage
NetlinkMessage::GetRouteMessage (void) const
{
  return m_routeTemplate;
}
bool
NetlinkMessage::IsMessageNetlinkControl (uint16_t type)
{
  return (type < NETLINK_RTM_BASE);
}
bool
NetlinkMessage::IsMessageNetlinkRoute (uint16_t type)
{
  return (type >= NETLINK_RTM_BASE && type < NETLINK_RTM_MAX);
}
bool
NetlinkMessage::IsMessageAddress (uint16_t type)
{
  return (type >= NETLINK_RTM_NEWADDR && type <= NETLINK_RTM_GETADDR);
}
bool
NetlinkMessage::IsMessageInterface (uint16_t type)
{
  return (type >= NETLINK_RTM_NEWLINK && type <= NETLINK_RTM_SETLINK);
}
bool
NetlinkMessage::IsMessageRoute (uint16_t type)
{
  return (type >= NETLINK_RTM_NEWROUTE && type <= NETLINK_RTM_GETROUTE);
}
bool
NetlinkMessage::IsMessageTypeGet (uint16_t type)
{
  return ((( type - NETLINK_RTM_BASE)&3) == 2);
}
bool
NetlinkMessage::IsMessageFlagsAck (uint16_t flags)
{
  return (flags & NETLINK_MSG_F_ACK) ? true : false;
}
bool
NetlinkMessage::IsMessageFlagsRequest (uint16_t flags)
{
  return (flags & NETLINK_MSG_F_REQUEST) ? true : false;
}
bool
NetlinkMessage::IsMessageFlagsDump (uint16_t flags)
{
  return (flags & NETLINK_MSG_F_DUMP) ? true : false;
}

NetlinkMessage::operator MultipartNetlinkMessage (void) const
{
  MultipartNetlinkMessage multi_nlmsg;
  multi_nlmsg.AppendMessage (*this);
  return multi_nlmsg;
}

TypeId 
NetlinkMessage::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NetlinkMessage")
    .SetParent<Header> ()
    .AddConstructor<NetlinkMessage> ()
    ;
  return tid;
}
TypeId 
NetlinkMessage::GetInstanceTypeId (void) const
{
  return GetTypeId ();
}

uint32_t
NetlinkMessage::GetTotalSize (void) const
{
  return NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ());
}

uint32_t
NetlinkMessage::GetMsgSize (void) const
{
  return m_hdr.GetMsgLen ();
}

uint32_t
NetlinkMessage::GetPayloadSize (void) const
{
  return m_hdr.GetPayloadSize ();
}
uint16_t
NetlinkMessage::GetMsgType (void) const
{
  return m_hdr.GetMsgType ();
}

uint8_t
NetlinkMessage::GetFamily(void) const
{
  if (IsMessageTypeGet (GetMsgType ()))
    {
      NS_LOG_DEBUG ("TypeGetMsg");
    }
  if (IsMessageAddress (m_hdr.GetMsgType ()))
    {
      return m_addressTemplate.GetFamily ();
    }
  else if (IsMessageInterface(m_hdr.GetMsgType ()))
    {
      return m_interfaceTemplate.GetFamily ();
    }
  else if (IsMessageRoute(m_hdr.GetMsgType ()))
    {
      return m_routeTemplate.GetFamily ();
    }
  else if (IsMessageFlagsDump (m_hdr.GetMsgFlags ()))
    {
      return m_genmsg.GetFamily (); //value is said to be always set to AF_UNSPEC
    }
  else
    {
      NS_LOG_WARN ("Netlink message type not supported, return AF_UNSPEC");
      return 0;
    }
}

void 
NetlinkMessage::Print (std::ostream &os) const
{
  uint16_t type = m_hdr.GetMsgType ();

  os << "NetlinkMessage  ";
  os << " ----Header:(";
  m_hdr.Print(os);
  os << ")";

  if (type == NETLINK_MSG_DONE )
    {
      os << "multipart message ends here";
    }
  else if (type == NETLINK_MSG_ERROR )
    {
      m_errorMessage.Print (os);
    }
  else if (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK)
    {
      m_genmsg.Print (os);
    }  
  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE)
    {
      m_routeTemplate.Print (os);
    }
  else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
    {
      m_addressTemplate.Print (os);
    }
  else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_DELLINK)
    {
      m_interfaceTemplate.Print (os);
    }
  else
    {
      os << "service not supported yet( " << type <<")";
    }
}
uint32_t 
NetlinkMessage::GetSerializedSize (void) const
{
  return NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ());
}

void
NetlinkMessage::Serialize (Buffer::Iterator& start) const
{
  NS_LOG_FUNCTION (this);
  //  Print (std::cout);
  uint16_t type = m_hdr.GetMsgType ();

  m_hdr.Serialize (start);

  if (type == NETLINK_MSG_DONE)
    {
      //nothing done
    }
  else if (type == NETLINK_MSG_ERROR)
    {
      m_errorMessage.Serialize (start);
    }  
  else if (NetlinkMessage::IsMessageFlagsDump (m_hdr.GetMsgFlags ()) && 
           (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK))
    {
      m_genmsg.Serialize (start);
    }  
  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
    {
      m_routeTemplate.Serialize (start);
    }
  else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
    {
      m_addressTemplate.Serialize (start);
    }
  else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_SETLINK)
    {
      m_interfaceTemplate.Serialize (start);
    }
  else
    {
    }  
}


uint32_t
NetlinkMessage::Deserialize (Buffer::Iterator&start)
{
  uint32_t remaining;

  m_hdr.Deserialize (start);
  remaining = NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ()) - m_hdr.GetSerializedSize ();
  
  //Deserialize service module
  uint16_t type = GetMsgType ();
  if (remaining)
    {        
      if (type == NETLINK_MSG_DONE)
        {
          //do nothing
        }
      else if (type == NETLINK_MSG_ERROR)
        {
          remaining -= m_errorMessage.Deserialize (start);
        }      
      else if (NetlinkMessage::IsMessageFlagsDump (m_hdr.GetMsgFlags()) &&
               (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK))
        {
          remaining -= m_genmsg.Deserialize (start, remaining);
        }
      else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
        {
          remaining -= m_routeTemplate.Deserialize (start, remaining);
        }
      else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
        {
          remaining -= m_addressTemplate.Deserialize (start, remaining);
        }
      else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_SETLINK)
        {
          remaining -= m_interfaceTemplate.Deserialize (start, remaining);
        }
      else
        {
          //do nothing
        }
    }

  return GetSerializedSize ();
}


/***********************************************************************************
* \ MultipartNetlinkMessage
***********************************************************************************/
MultipartNetlinkMessage::MultipartNetlinkMessage ()
{}

TypeId 
MultipartNetlinkMessage::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::MultipartNetlinkMessage")
    .SetParent<Header> ()
    .AddConstructor<MultipartNetlinkMessage> ()
    ;
  return tid;
}
TypeId 
MultipartNetlinkMessage::GetInstanceTypeId (void) const
{
  return GetTypeId ();
}

void
MultipartNetlinkMessage::Print (std::ostream &os) const
{
  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
    {
      m_netlinkMessages[i].Print (os);
    }
}
uint32_t
MultipartNetlinkMessage::GetSerializedSize (void) const
{
  uint32_t len = 0;

  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
    {
      len +=  m_netlinkMessages[i].GetSerializedSize ();
    }
  return len;
}
void
MultipartNetlinkMessage::Serialize (Buffer::Iterator start) const
{
  NS_LOG_FUNCTION ("Multi" << this);
  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
    {
      m_netlinkMessages[i].Serialize (start);
    }
}
uint32_t
MultipartNetlinkMessage::Deserialize (Buffer::Iterator start)
{
  while (1)
    {
      NetlinkMessage nlmsg;
      nlmsg.Deserialize (start);
      AppendMessage (nlmsg);

      if (!(nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_MULTI))
        {
          break;
        }

      if (nlmsg.GetHeader ().GetMsgType() == NETLINK_MSG_DONE)
        {
          break;
        }
    }
  return GetSerializedSize ();
}

void
MultipartNetlinkMessage::AppendMessage (NetlinkMessage nlmsg)
{
  m_netlinkMessages.push_back (nlmsg);
}

void
MultipartNetlinkMessage::Clear ()
{
  m_netlinkMessages.clear ();
}

uint32_t
MultipartNetlinkMessage::GetNMessages (void) const
{
  return m_netlinkMessages.size ();
}
NetlinkMessage
MultipartNetlinkMessage::GetMessage (uint32_t index) const
{
  NS_ASSERT(index < m_netlinkMessages.size ());
  return m_netlinkMessages[index];
}

}; // namespace ns3