Annotation of embedaddon/quagga/babeld/babel_main.c, revision 1.1

1.1     ! misho       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, Q_SIGC(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>