免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1424 | 回复: 0
打印 上一主题 下一主题

RIP源码分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-21 16:06 |只看该作者 |倒序浏览
由于工作原因,看了一阵子RIP的源码,写个大概出来,以防止以后忘的快。代码是自己一行一行的看的,没有找到半点资料,比较郁闷。至于要看懂RIP源码,得先熟悉RIP协议,其实RIP应该是路由协议里最简单得了,google一下,网上很多。
  
首先进入
Int main (int argc, char **argv)
{
  char *p;
  int daemon_mode = 0;
  char *progname;
  struct thread thread;

  /* Set umask before anything for security */
  umask (0027);

  /* Get program name. */
  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
  
  /* First of all we need logging init. */
//在这里设置log
  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP,
                        LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);

  /* Command line option parse. */
  while (1)
    {
      int opt;
//解析参数
      opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0);
   
      if (opt == EOF)
       break;

      switch (opt)
       {
       case 0:
         break;
       case 'd':
         daemon_mode = 1;
         break;
       case 'f':
         config_file = optarg;
         break;
       case 'A':
         vty_addr = optarg;
         break;
        case 'i':
          pid_file = optarg;
          break;
       case 'P':
         vty_port = atoi (optarg);
         break;
       case 'r':
         retain_mode = 1;
         break;
       case 'v':
         print_version (progname);
         exit (0);
         break;
       case 'h':
         usage (progname, 0);
         break;
       default:
         usage (progname, 1);
         break;
       }
    }

  /* Prepare master thread. */
  master = thread_master_create ();

  /* Library initialization. */
  signal_init ();
  cmd_init (1);
  vty_init ();
  memory_init ();
  keychain_init ();

  /* RIP related initialization. */
  rip_init ();
  rip_if_init ();
  rip_zclient_init ();
  rip_peer_init ();

  /* Sort all installed commands. */
  sort_node ();

  /* Get configuration file. */
  vty_read_config (config_file, config_current, config_default);

  /* Change to the daemon program. */
  if (daemon_mode)  //进入后台运行,成为守护进程
    daemon (0, 0);

  /* Pid file create. */
  pid_output (pid_file);

  /* Create VTY's socket */
  
  vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);

  /* Execute each thread. */
  while (thread_fetch (master, &thread))//真正执行线程在这里
    thread_call (&thread);

  /* Not reached. */
  exit (0);
}
先看看thread_call (&thread);这一行,进入此函数
void
thread_call (struct thread *thread)
{
  unsigned long thread_time;
  RUSAGE_T ru;

  GETRUSAGE (&thread->ru);

  (*thread->func) (thread);//此处调用线程链表的钩子函数,具体钩子函数是什么,待会看

  GETRUSAGE (&ru);

  thread_time = thread_consumed_time (&ru, &thread->ru);

#ifdef THREAD_CONSUMED_TIME_CHECK
  if (thread_time > 200000L)
    {
      /*
       * We have a CPU Hog on our hands.
       * Whinge about it now, so we're aware this is yet another task
       * to fix.
       */
      zlog_err ("CPU HOG task %lx ran for %ldms",
                /* FIXME: report the name of the function somehow */
              (unsigned long) thread->func,
              thread_time / 1000L);
    }
#endif /* THREAD_CONSUMED_TIME_CHECK */
}

在看看thread_fetch,贴出代码
struct thread *
thread_fetch (struct thread_master *m, struct thread *fetch)
{
  int num;
  int ready;
  struct thread *thread;
  fd_set readfd;
  fd_set writefd;
  fd_set exceptfd;
  struct timeval timer_now;
  struct timeval timer_val;
  struct timeval *timer_wait;
  struct timeval timer_nowait;

  timer_nowait.tv_sec = 0;
  timer_nowait.tv_usec = 0;
  while (1)
    {
      /* Normal event is the highest priority.  */event事件优先级最高,其实就是触发更新,所谓触发更新,就是路由表一改变,马上调用线程的钩子函数,多播出去
      if ((thread = thread_trim_head (&m->event)) != NULL)
       return thread_run (m, thread, fetch);

      /* Execute timer.  */
      gettimeofday (&timer_now, NULL);
//在这里看是否超时,也就是一个路由表项在180S内没有更新,则将对应的线程从活动链表取出,放入master->unuse链表。说白了就是把此线程挂起,不再执行
      for (thread = m->timer.head; thread; thread = thread->next)
       if (timeval_cmp (timer_now, thread->u.sands) >= 0)
         {
           thread_list_delete (&m->timer, thread);
           return thread_run (m, thread, fetch);
         }
//如果接收到新的RIP数据包,则读入,采用select机制
      /* If there are any ready threads, process top of them.  */
      if ((thread = thread_trim_head (&m->ready)) != NULL)
       return thread_run (m, thread, fetch);

      /* Structure copy.  */
      readfd = m->readfd;
      writefd = m->writefd;
      exceptfd = m->exceptfd;

      /* Calculate select wait timer. */
      timer_wait = thread_timer_wait (m, &timer_val);

      num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);

      if (num == 0)
       continue;

      if (num
       {
         if (errno == EINTR)
           continue;

         zlog_warn ("select() error: %s", strerror (errno));
         return NULL;
       }

      /* Normal priority read thead. */
      ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);

      /* Write thead. */
      ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);

      if ((thread = thread_trim_head (&m->ready)) != NULL)
       return thread_run (m, thread, fetch);
    }
}
通过以上分析,发现就是RIP经过初始化后,然后进入一个while死循环,在这个死循环中根据不同的优先级去执行不同的线程钩子函数。而这些钩子函数在什么地方注册的呢,进入ripd.c的void rip_event (enum rip_event event, int sock)函数。
void
rip_event (enum rip_event event, int sock)
{
  int jitter = 0;

  switch (event)
{
//read事件,通过thread_add_read注册的钩子函数为rip_read.
    case RIP_READ:
      rip->t_read = thread_add_read (master, rip_read, NULL, sock);
      break;
//update事件,通过thread_add_read注册的钩子函数为rip_update.   
case RIP_UPDATE_EVENT:
      if (rip->t_update)
       {
         thread_cancel (rip->t_update);
         rip->t_update = NULL;
       }
      jitter = rip_update_jitter (rip->update_time);
      rip->t_update =
       thread_add_timer (master, rip_update, NULL,
                       sock ? 2 : rip->update_time + jitter);
      break;
//触发更新,通过thread_add_read注册的钩子函数为rip_triggered_update.
    case RIP_TRIGGERED_UPDATE:
       printf("come in RIP_TRIGGERED_UPDATE\n");//jimmy
      if (rip->t_triggered_interval)
       rip->trigger = 1;
      else if (! rip->t_triggered_update)
          {
          printf("add event rip_triggered_update\n");//jimmy
       rip->t_triggered_update =
         thread_add_event (master, rip_triggered_update, NULL, 0);
          }
      break;
    default:
      break;
    }
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94761/showart_1905542.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP