File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / babeld / babel_main.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:37 2013 UTC (11 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

    1: /*  
    2:  *  This file is free software: you may copy, redistribute and/or modify it  
    3:  *  under the terms of the GNU General Public License as published by the  
    4:  *  Free Software Foundation, either version 2 of the License, or (at your  
    5:  *  option) any later version.  
    6:  *  
    7:  *  This file is distributed in the hope that it will be useful, but  
    8:  *  WITHOUT ANY WARRANTY; without even the implied warranty of  
    9:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
   10:  *  General Public License for more details.  
   11:  *  
   12:  *  You should have received a copy of the GNU General Public License  
   13:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
   14:  *  
   15:  * This file incorporates work covered by the following copyright and  
   16:  * permission notice:  
   17:  *  
   18: 
   19: Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
   20: 
   21: Permission is hereby granted, free of charge, to any person obtaining a copy
   22: of this software and associated documentation files (the "Software"), to deal
   23: in the Software without restriction, including without limitation the rights
   24: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   25: copies of the Software, and to permit persons to whom the Software is
   26: furnished to do so, subject to the following conditions:
   27: 
   28: The above copyright notice and this permission notice shall be included in
   29: all copies or substantial portions of the Software.
   30: 
   31: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   32: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   33: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   34: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   35: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   36: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   37: THE SOFTWARE.
   38: */
   39: 
   40: /* include zebra library */
   41: #include <zebra.h>
   42: #include "getopt.h"
   43: #include "if.h"
   44: #include "log.h"
   45: #include "thread.h"
   46: #include "privs.h"
   47: #include "sigevent.h"
   48: #include "version.h"
   49: #include "command.h"
   50: #include "vty.h"
   51: #include "memory.h"
   52: 
   53: #include "babel_main.h"
   54: #include "babeld.h"
   55: #include "util.h"
   56: #include "kernel.h"
   57: #include "babel_interface.h"
   58: #include "neighbour.h"
   59: #include "route.h"
   60: #include "xroute.h"
   61: #include "message.h"
   62: #include "resend.h"
   63: #include "babel_zebra.h"
   64: 
   65: 
   66: static void babel_init (int argc, char **argv);
   67: static char *babel_get_progname(char *argv_0);
   68: static void babel_fail(void);
   69: static void babel_init_random(void);
   70: static void babel_replace_by_null(int fd);
   71: static void babel_init_signals(void);
   72: static void babel_exit_properly(void);
   73: static void babel_save_state_file(void);
   74: 
   75: 
   76: struct thread_master *master;     /* quagga's threads handler */
   77: struct timeval babel_now;         /* current time             */
   78: 
   79: unsigned char myid[8];            /* unique id (mac address of an interface) */
   80: int debug = 0;
   81: 
   82: int resend_delay = -1;
   83: static const char *pidfile = PATH_BABELD_PID;
   84: 
   85: const unsigned char zeroes[16] = {0};
   86: const unsigned char ones[16] =
   87:     {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   88:      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
   89: 
   90: static const char *state_file = DAEMON_VTY_DIR "/babel-state";
   91: 
   92: unsigned char protocol_group[16]; /* babel's link-local multicast address */
   93: int protocol_port;                /* babel's port */
   94: int protocol_socket = -1;         /* socket: communicate with others babeld */
   95: 
   96: static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
   97: static char *babel_config_file = NULL;
   98: static char *babel_vty_addr = NULL;
   99: static int babel_vty_port = BABEL_VTY_PORT;
  100: 
  101: /* Babeld options. */
  102: struct option longopts[] =
  103: {
  104:     { "daemon",      no_argument,       NULL, 'd'},
  105:     { "config_file", required_argument, NULL, 'f'},
  106:     { "pid_file",    required_argument, NULL, 'i'},
  107:     { "socket",      required_argument, NULL, 'z'},
  108:     { "help",        no_argument,       NULL, 'h'},
  109:     { "vty_addr",    required_argument, NULL, 'A'},
  110:     { "vty_port",    required_argument, NULL, 'P'},
  111:     { "user",        required_argument, NULL, 'u'},
  112:     { "group",       required_argument, NULL, 'g'},
  113:     { "version",     no_argument,       NULL, 'v'},
  114:     { 0 }
  115: };
  116: 
  117: /* babeld privileges */
  118: static zebra_capabilities_t _caps_p [] =
  119: {
  120:     ZCAP_NET_RAW,
  121:     ZCAP_BIND
  122: };
  123: static struct zebra_privs_t babeld_privs =
  124: {
  125: #if defined(QUAGGA_USER)
  126:     .user = QUAGGA_USER,
  127: #endif
  128: #if defined QUAGGA_GROUP
  129:     .group = QUAGGA_GROUP,
  130: #endif
  131: #ifdef VTY_GROUP
  132:     .vty_group = VTY_GROUP,
  133: #endif
  134:     .caps_p = _caps_p,
  135:     .cap_num_p = 2,
  136:     .cap_num_i = 0
  137: };
  138: 
  139: 
  140: int
  141: main(int argc, char **argv)
  142: {
  143:     struct thread thread;
  144:     /* and print banner too */
  145:     babel_init(argc, argv);
  146:     while (thread_fetch (master, &thread)) {
  147:         thread_call (&thread);
  148:     }
  149:     return 0;
  150: }
  151: 
  152: static void
  153: babel_usage (char *progname, int status)
  154: {
  155:   if (status != 0)
  156:     fprintf (stderr, "Try `%s --help' for more information.\n", progname);
  157:   else
  158:     {
  159:       printf ("Usage : %s [OPTION...]\n\
  160: Daemon which manages Babel routing protocol.\n\n\
  161: -d, --daemon       Runs in daemon mode\n\
  162: -f, --config_file  Set configuration file name\n\
  163: -i, --pid_file     Set process identifier file name\n\
  164: -z, --socket       Set path of zebra socket\n\
  165: -A, --vty_addr     Set vty's bind address\n\
  166: -P, --vty_port     Set vty's port number\n\
  167: -u, --user         User to run as\n\
  168: -g, --group        Group to run as\n\
  169: -v, --version      Print program version\n\
  170: -h, --help         Display this help and exit\n\
  171: \n\
  172: Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
  173:     }
  174:   exit (status);
  175: }
  176: 
  177: /* make initialisations witch don't need infos about kernel(interfaces, etc.) */
  178: static void
  179: babel_init(int argc, char **argv)
  180: {
  181:     int rc, opt;
  182:     int do_daemonise = 0;
  183:     char *progname = NULL;
  184: 
  185:     /* Set umask before anything for security */
  186:     umask (0027);
  187:     progname = babel_get_progname(argv[0]);
  188: 
  189:     /* set default log (lib/log.h) */
  190:     zlog_default = openzlog(progname, ZLOG_BABEL,
  191:                             LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
  192:     /* set log destination as stdout until the config file is read */
  193:     zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING);
  194: 
  195:     babel_init_random();
  196: 
  197:     /* set the Babel's default link-local multicast address and Babel's port */
  198:     parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
  199:     protocol_port = 6696;
  200: 
  201:     /* get options */
  202:     while(1) {
  203:         opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
  204:         if(opt < 0)
  205:             break;
  206: 
  207:         switch(opt) {
  208:             case 0:
  209:                 break;
  210:             case 'd':
  211:                 do_daemonise = -1;
  212:                 break;
  213:             case 'f':
  214:                 babel_config_file = optarg;
  215:                 break;
  216:             case 'i':
  217:                 pidfile = optarg;
  218:                 break;
  219:             case 'z':
  220:                 zclient_serv_path_set (optarg);
  221:                 break;
  222:             case 'A':
  223:                 babel_vty_addr = optarg;
  224:                 break;
  225:             case 'P':
  226:                 babel_vty_port = atoi (optarg);
  227:                 if (babel_vty_port <= 0 || babel_vty_port > 0xffff)
  228:                     babel_vty_port = BABEL_VTY_PORT;
  229:                 break;
  230:             case 'u':
  231:                 babeld_privs.user = optarg;
  232:                 break;
  233:             case 'g':
  234:                 babeld_privs.group = optarg;
  235:                 break;
  236:             case 'v':
  237:                 print_version (progname);
  238:                 exit (0);
  239:                 break;
  240:             case 'h':
  241:                 babel_usage (progname, 0);
  242:                 break;
  243:             default:
  244:                 babel_usage (progname, 1);
  245:                 break;
  246:         }
  247:     }
  248: 
  249:     /* create the threads handler */
  250:     master = thread_master_create ();
  251: 
  252:     /* Library inits. */
  253:     zprivs_init (&babeld_privs);
  254:     babel_init_signals();
  255:     cmd_init (1);
  256:     vty_init (master);
  257:     memory_init ();
  258: 
  259:     resend_delay = BABEL_DEFAULT_RESEND_DELAY;
  260: 
  261:     babel_replace_by_null(STDIN_FILENO);
  262: 
  263:     if (do_daemonise && daemonise() < 0) {
  264:         zlog_err("daemonise: %s", safe_strerror(errno));
  265:         exit (1);
  266:     }
  267: 
  268:     /* write pid file */
  269:     if (pid_output(pidfile) < 0) {
  270:         zlog_err("error while writing pidfile");
  271:         exit (1);
  272:     };
  273: 
  274:     /* init some quagga's dependencies, and babeld's commands */
  275:     babeld_quagga_init();
  276:     /* init zebra client's structure and it's commands */
  277:     /* this replace kernel_setup && kernel_setup_socket */
  278:     babelz_zebra_init ();
  279: 
  280:     /* Sort all installed commands. */
  281:     sort_node ();
  282: 
  283:     /* Get zebra configuration file. */
  284:     zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
  285:     vty_read_config (babel_config_file, babel_config_default);
  286: 
  287:     /* Create VTY socket */
  288:     vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH);
  289: 
  290:     /* init buffer */
  291:     rc = resize_receive_buffer(1500);
  292:     if(rc < 0)
  293:         babel_fail();
  294: 
  295:     schedule_neighbours_check(5000, 1);
  296: 
  297:     zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
  298: }
  299: 
  300: /* return the progname (without path, example: "./x/progname" --> "progname") */
  301: static char *
  302: babel_get_progname(char *argv_0) {
  303:     char *p = strrchr (argv_0, '/');
  304:     return (p ? ++p : argv_0);
  305: }
  306: 
  307: static void
  308: babel_fail(void)
  309: {
  310:     exit(1);
  311: }
  312: 
  313: /* initialize random value, and set 'babel_now' by the way. */
  314: static void
  315: babel_init_random(void)
  316: {
  317:     gettime(&babel_now);
  318:     int rc;
  319:     unsigned int seed;
  320: 
  321:     rc = read_random_bytes(&seed, sizeof(seed));
  322:     if(rc < 0) {
  323:         zlog_err("read(random): %s", safe_strerror(errno));
  324:         seed = 42;
  325:     }
  326: 
  327:     seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
  328:     srandom(seed);
  329: }
  330: 
  331: /*
  332:  close fd, and replace it by "/dev/null"
  333:  exit if error
  334:  */
  335: static void
  336: babel_replace_by_null(int fd)
  337: {
  338:     int fd_null;
  339:     int rc;
  340: 
  341:     fd_null = open("/dev/null", O_RDONLY);
  342:     if(fd_null < 0) {
  343:         zlog_err("open(null): %s", safe_strerror(errno));
  344:         exit(1);
  345:     }
  346: 
  347:     rc = dup2(fd_null, fd);
  348:     if(rc < 0) {
  349:         zlog_err("dup2(null, 0): %s", safe_strerror(errno));
  350:         exit(1);
  351:     }
  352: 
  353:     close(fd_null);
  354: }
  355: 
  356: /*
  357:  Load the state file: check last babeld's running state, usefull in case of
  358:  "/etc/init.d/babeld restart"
  359:  */
  360: void
  361: babel_load_state_file(void)
  362: {
  363:     int fd;
  364:     int rc;
  365: 
  366:     fd = open(state_file, O_RDONLY);
  367:     if(fd < 0 && errno != ENOENT)
  368:         zlog_err("open(babel-state: %s)", safe_strerror(errno));
  369:     rc = unlink(state_file);
  370:     if(fd >= 0 && rc < 0) {
  371:         zlog_err("unlink(babel-state): %s", safe_strerror(errno));
  372:         /* If we couldn't unlink it, it's probably stale. */
  373:         close(fd);
  374:         fd = -1;
  375:     }
  376:     if(fd >= 0) {
  377:         char buf[100];
  378:         char buf2[100];
  379:         int s;
  380:         long t;
  381:         rc = read(fd, buf, 99);
  382:         if(rc < 0) {
  383:             zlog_err("read(babel-state): %s", safe_strerror(errno));
  384:         } else {
  385:             buf[rc] = '\0';
  386:             rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
  387:             if(rc == 3 && s >= 0 && s <= 0xFFFF) {
  388:                 unsigned char sid[8];
  389:                 rc = parse_eui64(buf2, sid);
  390:                 if(rc < 0) {
  391:                     zlog_err("Couldn't parse babel-state.");
  392:                 } else {
  393:                     struct timeval realnow;
  394:                     debugf(BABEL_DEBUG_COMMON,
  395:                            "Got %s %d %ld from babel-state.",
  396:                            format_eui64(sid), s, t);
  397:                     gettimeofday(&realnow, NULL);
  398:                     if(memcmp(sid, myid, 8) == 0)
  399:                         myseqno = seqno_plus(s, 1);
  400:                     else
  401:                         zlog_err("ID mismatch in babel-state. id=%s; old=%s",
  402:                                  format_eui64(myid),
  403:                                  format_eui64(sid));
  404:                 }
  405:             } else {
  406:                 zlog_err("Couldn't parse babel-state.");
  407:             }
  408:         }
  409:         close(fd);
  410:         fd = -1;
  411:     }
  412: }
  413: 
  414: static void
  415: babel_sigexit(void)
  416: {
  417:     zlog_notice("Terminating on signal");
  418: 
  419:     babel_exit_properly();
  420: }
  421: 
  422: static void
  423: babel_sigusr1 (void)
  424: {
  425:     zlog_rotate (NULL);
  426: }
  427: 
  428: static void
  429: babel_init_signals(void)
  430: {
  431:     static struct quagga_signal_t babel_signals[] =
  432:     {
  433:         {
  434:             .signal = SIGUSR1,
  435:             .handler = &babel_sigusr1,
  436:         },
  437:         {
  438:             .signal = SIGINT,
  439:             .handler = &babel_sigexit,
  440:         },
  441:         {
  442:             .signal = SIGTERM,
  443:             .handler = &babel_sigexit,
  444:         },
  445:     };
  446: 
  447:     signal_init (master, array_size(babel_signals), babel_signals);
  448: }
  449: 
  450: static void
  451: babel_exit_properly(void)
  452: {
  453:     debugf(BABEL_DEBUG_COMMON, "Exiting...");
  454:     usleep(roughly(10000));
  455:     gettime(&babel_now);
  456: 
  457:     /* Uninstall and flush all routes. */
  458:     debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
  459:     flush_all_routes();
  460:     babel_interface_close_all();
  461:     babel_zebra_close_connexion();
  462:     babel_save_state_file();
  463:     debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
  464:     if(pidfile)
  465:         unlink(pidfile);
  466:     debugf(BABEL_DEBUG_COMMON, "Done.");
  467: 
  468:     exit(0);
  469: }
  470: 
  471: static void
  472: babel_save_state_file(void)
  473: {
  474:     int fd;
  475:     int rc;
  476: 
  477:     debugf(BABEL_DEBUG_COMMON, "Save state file.");
  478:     fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
  479:     if(fd < 0) {
  480:         zlog_err("creat(babel-state): %s", safe_strerror(errno));
  481:         unlink(state_file);
  482:     } else {
  483:         struct timeval realnow;
  484:         char buf[100];
  485:         gettimeofday(&realnow, NULL);
  486:         rc = snprintf(buf, 100, "%s %d %ld\n",
  487:                       format_eui64(myid), (int)myseqno,
  488:                       (long)realnow.tv_sec);
  489:         if(rc < 0 || rc >= 100) {
  490:             zlog_err("write(babel-state): overflow.");
  491:             unlink(state_file);
  492:         } else {
  493:             rc = write(fd, buf, rc);
  494:             if(rc < 0) {
  495:                 zlog_err("write(babel-state): %s", safe_strerror(errno));
  496:                 unlink(state_file);
  497:             }
  498:             fsync(fd);
  499:         }
  500:         close(fd);
  501:     }
  502: }
  503: 
  504: void
  505: show_babel_main_configuration (struct vty *vty)
  506: {
  507:     vty_out(vty,
  508:             "pid file                = %s%s"
  509:             "state file              = %s%s"
  510:             "configuration file      = %s%s"
  511:             "protocol informations:%s"
  512:             "  multicast address     = %s%s"
  513:             "  port                  = %d%s"
  514:             "vty address             = %s%s"
  515:             "vty port                = %d%s"
  516:             "id                      = %s%s"
  517:             "allow_duplicates        = %s%s"
  518:             "kernel_metric           = %d%s",
  519:             pidfile, VTY_NEWLINE,
  520:             state_file, VTY_NEWLINE,
  521:             babel_config_file ? babel_config_file : babel_config_default,
  522:             VTY_NEWLINE,
  523:             VTY_NEWLINE,
  524:             format_address(protocol_group), VTY_NEWLINE,
  525:             protocol_port, VTY_NEWLINE,
  526:             babel_vty_addr ? babel_vty_addr : "None",
  527:             VTY_NEWLINE,
  528:             babel_vty_port, VTY_NEWLINE,
  529:             format_eui64(myid), VTY_NEWLINE,
  530:             format_bool(allow_duplicates), VTY_NEWLINE,
  531:             kernel_metric, VTY_NEWLINE);
  532: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>