protocol isis issues(续1.2----地址转化相关)

来源:互联网 发布:数据分析基础知识 编辑:程序博客网 时间:2024/05/16 06:53

在unix-socket-fd.cc:698中,有地址转换函数PosixAddressToNs3Address()。顾名思义,是将Posix标准的地址转换位Ns3中定义的地址。

isis协议中的调用:

#0  ns3::UnixSocketFd::PosixAddressToNs3Address (this=0xb49212c0,     my_addr=0xb4af6e98, addrlen=20) at ../model/unix-socket-fd.cc:733#1  0xb7e4964c in ns3::UnixSocketFd::Bind (this=0xb49212c0,     my_addr=0xb4af6e98, addrlen=20) at ../model/unix-socket-fd.cc:802#2  0xb7e61b9b in dce_bind (fd=8, my_addr=0xb4af6e98, addrlen=20)    at ../model/dce-fd.cc:450#3  0xb4f8ab35 in bind () at ../model/libc-ns3.h:182#4  0xb4a5efda in open_packet_socket (circuit=0xb4a0b3a4)    at isis_pfpacket.c:129#5  0xb4a5f161 in isis_sock_init (circuit=0xb4a0b3a4) at isis_pfpacket.c:180#6  0xb4a4716c in isis_circuit_up (circuit=0xb4a0b3a4) at isis_circuit.c:581#7  0xb4a5941a in isis_csm_state_change (event=2, circuit=0xb4a0b3a4,     arg=0xb4a0b7a4) at isis_csm.c:140#8  0xb4a56c41 in isis_zebra_if_add (command=1, zclient=0xb4a264e4, length=53)    at isis_zebra.c:78#9  0xb4a83576 in zclient_read (thread=0xb4af70c8) at zclient.c:900#10 0xb4a714c4 in thread_call (thread=0xb4af70c8) at thread.c:1177#11 0xb4a3cd4b in main (argc=5, argv=0x80c62d8, envp=0x80c6338)    at isis_main.c:353#12 0xb7e0b7c6 in ns3::DceManager::DoStartProcess (context=0x80c6b98)    at ../model/dce-manager.cc:283#13 0xb7e960ff in ns3::TaskManager::Trampoline (context=0x8089890)    at ../model/task-manager.cc:274

#4 isis_pfpacket.c:107的open_packet_socket()函数—

static intopen_packet_socket (struct isis_circuit *circuit){  struct sockaddr_ll s_addr;  int fd, retval = ISIS_OK;  fd = socket ( PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));  if (fd < 0)    {      zlog_warn ("open_packet_socket(): socket() failed %s",         safe_strerror (errno));      return ISIS_WARNING;    }  /*   * Bind to the physical interface   */  memset (&s_addr, 0, sizeof (struct sockaddr_ll));  s_addr.sll_family = AF_PACKET;  s_addr.sll_protocol = htons (ETH_P_ALL);  s_addr.sll_ifindex = circuit->interface->ifindex;  if (bind (fd, (struct sockaddr *) (&s_addr),        sizeof (struct sockaddr_ll)) < 0)    {      zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));      return ISIS_WARNING;    }    ...
  • 先创建一个sockaddr_ll结构的对象s_addr
  • memset()函数把s_addr清零。(作用同unix网络编程中的bzero)
  • 设置地址组,支持的协议和端口。
  • 结构体sockaddr_ll(原始套接字会使用它):
struct sockaddr_ll {    unsigned short  sll_family;   /* 总是 AF_PACKET */     __be16      sll_protocol;     /* 物理层的协议 */    int     sll_ifindex;          /* 接口号 */     unsigned short  sll_hatype;   /* 报头类型 */     unsigned char   sll_pkttype;  /* 分组类型 */    unsigned char   sll_halen;    /* 地址长度 */    unsigned char   sll_addr[8];  /* 物理层地址 */ };

    sll_protocoll:取值在linux/if_ether.h中,可以指定我们所感兴趣的二层协议;
    sll_ifindex:置为0表示处理所有接口,对于单网卡的机器就不存在“所有”的概念了。
     sll_hatype:ARP硬件地址类型,定义在 linux/if_arp.h 中。 取ARPHRD_ETHER时表示为以太网。
    sll_pkttype:包含分组类型。目前,有效的分组类型有:目标地址是本地主机的分组用的 PACKET_HOST,物理层广播分组用的 PACKET_BROADCAST ,发送到一个物理层多路广播地址的分组用的 PACKET_MULTICAST,在混杂(promiscuous)模式下的设备驱动器发向其他主机的分组用的 PACKET_OTHERHOST,源于本地主机的分组被环回到分组套接口用的 PACKET_OUTGOING。这些类型只对接收到的分组有意义。
    sll_addr和sll_halen指示物理层(如以太网,802.3,802.4或802.5等)地址及其长度,严格依赖于具体的硬件设备。
缺省情况下,从任何接口收到的符合指定协议的所有数据报文都会被传送到原始PACKET套接字口,而使用bind系统调用并以一个sochddr_ll结构体对象将PACKET套接字与某个网络接口相绑定,就可使我们的PACKET原始套接字只接收指定接口的数据报文。

  • 最后进入bind()函数。

#1 unix-socket-fd.cc:796的Bind()函数–

intUnixSocketFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen){  Thread *current = Current ();  NS_LOG_FUNCTION (this << current);  NS_ASSERT (current != 0);  Address ad = PosixAddressToNs3Address (my_addr, addrlen);  int result = m_socket->Bind (ad);  if (result == -1)    {      current->err = ErrnoToSimuErrno ();    }  return result;}

#0 unix-socket-fd.cc:698的PosixAddressToNs3Address(const struct sockaddr *my_addr, socklen_t addrlen) const函数—

/*原程序中没有对AF_PACKET的处理*/ else if(my_addr->sa_family == AF_PACKET)   {      const struct sockaddr_ll *addr = (const struct sockaddr_ll *)my_addr;      PacketSocketAddress paaddress=PacketSocketAddress();      memset (&paaddress, 0, sizeof (paaddress));      paaddress.SetProtocol(addr->sll_protocol);      //paaddress.SetSingleDevice(addr->sll_ifindex);      paaddress.SetAllDevices();      Address address=Address(6,addr->sll_addr,sizeof(addr->sll_addr));      paaddress.SetPhysicalAddress(address);      return paaddress;    }
  • 传入的参数为isis_pfpacket.c中创建的结构体sockaddr_ll对象s_addr,但在bind()函数中进行了强制类型转化为sockaddr结构。
    这里写图片描述
  • 之后又把它转化为sockaddr_ll结构后赋值给addr。
    这里写图片描述
  • 创建PacketSocketAddress类的一个对象paaddress。设置协议,网络接口。
    这里写图片描述
    十六进制显示数据:
    这里写图片描述
    PacketSocketAddress类的私有成员变量:
 /*4个变量*/  uint16_t m_protocol;    //!< Protocol  bool m_isSingleDevice;  //!< True if directed to a specific outgoing NetDevice  uint32_t m_device;      //!< Outgoing NetDevice index  Address m_address;      //!< Destination address /*2个成员函数*/    /**   * \brief Return the Type of address.   * \return type of address   */  static uint8_t GetType (void);  /**   * \brief Convert an instance of this class to a polymorphic Address instance.   * \returns a new Address instance   */  Address ConvertTo (void) const;
  • 创建Address类的一个对象address,然后把它赋值给PacketSocketAddress类的m_address。
    Address类的私有成员变量:
  uint8_t m_type; //!< Type of the address  uint8_t m_len;  //!< Length of the address  uint8_t m_data[MAX_SIZE]; //!< The address value
  • return paaddress; 调用PacketSocketAddress.cc中的
PacketSocketAddress::operator Address () const{  return ConvertTo ();}

    然后调用ConvertTo()函数:

Address PacketSocketAddress::ConvertTo (void) const{  NS_LOG_FUNCTION (this);  Address address;  uint8_t buffer[Address::MAX_SIZE];  buffer[0] = m_protocol & 0xff;  buffer[1] = (m_protocol >> 8) & 0xff;  buffer[2] = (m_device >> 24) & 0xff;  buffer[3] = (m_device >> 16) & 0xff;  buffer[4] = (m_device >> 8) & 0xff;  buffer[5] = (m_device >> 0) & 0xff;  buffer[6] = m_isSingleDevice ? 1 : 0;  uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7);  return Address (GetType (), buffer, 7 + copied);}

    返回一个Address类的对象。

参考:原始套接字的魔力

0 0