Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9764
  • 博文数量: 2
  • 博客积分: 1435
  • 博客等级: 上尉
  • 技术积分: 40
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-21 15:48
文章分类

全部博文(2)

文章存档

2011年(1)

2009年(1)

我的朋友
最近访客

分类: LINUX

2009-04-21 16:06:38

由于工作原因,看了一阵子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 < 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.cvoid 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;

    }

}

阅读(1511) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:博客已升级,请注意变更地址

给主人留下些什么吧!~~