RIP源码分析


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 < 0)

       {

         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;

    }

}

posted @ 2010-01-09 11:15  clara  阅读(1360)  评论(0编辑  收藏  举报