opensm源码

路由算法此版本为opensm3.5版本, 涉及到的路由算法有以下几种: 1. Min Hop算法 2. UPDN 路由算法 3. DNUP路由算法 4. Fat-tree路由算法 5. LASH 路由算法 6.DOR 路由算法 7.Torus-2QoS路由算法等等 UPDN算法极力推荐使用, 该算法旨在防止死锁在子网构成循环中发生。 死锁这种情况不再在任何两个主机之间发送数据中发生。 因此建议使用UPDN路由算法。胖树这种算法对于高负载的情况会发生。

应用介绍

此版本为opensm3.5版本, 涉及到的路由算法有以下几种:

1.  Min Hop算法

2.  UPDN 路由算法

3. DNUP路由算法

4. Fat-tree路由算法

5. LASH 路由算法

6.DOR 路由算法

7.Torus-2QoS路由算法等等

UPDN算法极力推荐使用, 该算法旨在防止死锁在子网构成循环中发生。 死锁这种情况不再在任何两个主机之间发送数据中发生。 因此建议使用UPDN路由算法。胖树这种算法对于高负载的情况会发生死锁。

此代码纯c编写,主代码如下,其中最让人值得学习的是其中用了很多层回调函数,其中用了纯c编写的数据库,进行数据的存储,效率极高,具体可以查看源码

int main(int argc, char *argv[])
{
    osm_opensm_t osm;
    osm_subn_opt_t opt;
    ib_net64_t sm_key = 0;
    ib_api_status_t status;
    uint32_t temp, dbg_lvl;
    boolean_t run_once_flag = FALSE;
    int32_t vendor_debug = 0;
    int next_option;
    char *conf_template = NULL;
    const char *config_file = NULL;
    uint32_t val;
    const char *const short_option =
        "F:c:i:w:O:f:ed:D:g:l:L:s:t:a:u:m:X:R:zM:U:S:P:Y:ANZ:WBIQvVhoryxp:n:q:k:C:G:H:";

    /*
       In the array below, the 2nd parameter specifies the number
       of arguments as follows:
       0: no arguments
       1: argument
       2: optional
     */
    const struct option long_option[] = {
        {"version", 0, NULL, 12},
        {"config", 1, NULL, 'F'},
        {"create-config", 1, NULL, 'c'},
        {"debug", 1, NULL, 'd'},
        {"guid", 1, NULL, 'g'},
        {"ignore_guids", 1, NULL, 'i'},
        {"hop_weights_file", 1, NULL, 'w'},
        {"dimn_ports_file", 1, NULL, 'O'},
        {"port_search_ordering_file", 1, NULL, 'O'},
        {"lmc", 1, NULL, 'l'},
        {"sweep", 1, NULL, 's'},
        {"timeout", 1, NULL, 't'},
        {"verbose", 0, NULL, 'v'},
        {"D", 1, NULL, 'D'},
        {"log_file", 1, NULL, 'f'},
        {"log_limit", 1, NULL, 'L'},
        {"erase_log_file", 0, NULL, 'e'},
        {"Pconfig", 1, NULL, 'P'},
        {"no_part_enforce", 0, NULL, 'N'},
        {"part_enforce", 1, NULL, 'Z'},
        {"allow_both_pkeys", 0, NULL, 'W'},
        {"qos", 0, NULL, 'Q'},
        {"qos_policy_file", 1, NULL, 'Y'},
        {"congestion_control", 0, NULL, 128},
        {"cc_key", 1, NULL, 129},
        {"maxsmps", 1, NULL, 'n'},
        {"console", 1, NULL, 'q'},
        {"V", 0, NULL, 'V'},
        {"help", 0, NULL, 'h'},
        {"once", 0, NULL, 'o'},
        {"reassign_lids", 0, NULL, 'r'},
        {"priority", 1, NULL, 'p'},
        {"smkey", 1, NULL, 'k'},
        {"routing_engine", 1, NULL, 'R'},
        {"ucast_cache", 0, NULL, 'A'},
        {"connect_roots", 0, NULL, 'z'},
        {"lid_matrix_file", 1, NULL, 'M'},
        {"lfts_file", 1, NULL, 'U'},
        {"sadb_file", 1, NULL, 'S'},
        {"root_guid_file", 1, NULL, 'a'},
        {"cn_guid_file", 1, NULL, 'u'},
        {"io_guid_file", 1, NULL, 'G'},
        {"port-shifting", 0, NULL, 11},
        {"scatter-ports", 1, NULL, 14},
        {"max_reverse_hops", 1, NULL, 'H'},
        {"ids_guid_file", 1, NULL, 'm'},
        {"guid_routing_order_file", 1, NULL, 'X'},
        {"stay_on_fatal", 0, NULL, 'y'},
        {"honor_guid2lid", 0, NULL, 'x'},
#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
        {"console-port", 1, NULL, 'C'},
#endif
        {"daemon", 0, NULL, 'B'},
        {"pidfile", 1, NULL, 'J'},
        {"inactive", 0, NULL, 'I'},
#ifdef ENABLE_OSM_PERF_MGR
        {"perfmgr", 0, NULL, 1},
        {"perfmgr_sweep_time_s", 1, NULL, 2},
#endif
        {"prefix_routes_file", 1, NULL, 3},
        {"consolidate_ipv6_snm_req", 0, NULL, 4},
        {"do_mesh_analysis", 0, NULL, 5},
        {"lash_start_vl", 1, NULL, 6},
        {"sm_sl", 1, NULL, 7},
        {"retries", 1, NULL, 8},
        {"log_prefix", 1, NULL, 9},
        {"torus_config", 1, NULL, 10},
        {"guid_routing_order_no_scatter", 0, NULL, 13},
        {NULL, 0, NULL, 0}    /* Required at the end of the array */
    };

    /* force stdout to be line-buffered */
    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);

    /* Make sure that the opensm and complib were compiled using
       same modes (debug/free) */
    if (osm_is_debug() != cl_is_debug()) {
        fprintf(stderr,
            "ERROR: OpenSM and Complib were compiled using different modes\n");
        fprintf(stderr, "ERROR: OpenSM debug:%d Complib debug:%d \n",
            osm_is_debug(), cl_is_debug());
        exit(1);
    }

    printf("-------------------------------------------------\n");
    printf("%s\n", OSM_VERSION);

    do {
        next_option = getopt_long_only(argc, argv, short_option,
                           long_option, NULL);
        switch (next_option) {
        case 'F':
            config_file = optarg;
            printf("Config file is `%s`:\n", config_file);
            break;
        default:
            break;
        }
    } while (next_option != -1);

    optind = 0;        /* reset command line */

    if (!config_file)
        config_file = OSM_DEFAULT_CONFIG_FILE;

    osm_subn_set_default_opt(&opt);

    if (osm_subn_parse_conf_file(config_file, &opt) < 0)
        printf("\nFail to parse config file \'%s\'\n", config_file);

    printf("Command Line Arguments:\n");
    do {
        next_option = getopt_long_only(argc, argv, short_option,
                           long_option, NULL);
        switch (next_option) {
        case 12:    /* --version - already printed above */
            exit(0);
            break;
        case 'F':
            break;
        case 'c':
            conf_template = optarg;
            printf(" Creating config file template \'%s\'.\n",
                   conf_template);
            break;
        case 'o':
            /*
               Run once option.
             */
            run_once_flag = TRUE;
            printf(" Run Once\n");
            break;

        case 'r':
            /*
               Reassign LIDs subnet option.
             */
            opt.reassign_lids = TRUE;
            printf(" Reassign LIDs\n");
            break;

        case 'i':
            /*
               Specifies ignore guids file.
             */
            SET_STR_OPT(opt.port_prof_ignore_file, optarg);
            printf(" Ignore Guids File = %s\n",
                   opt.port_prof_ignore_file);
            break;

        case 'w':
            SET_STR_OPT(opt.hop_weights_file, optarg);
            printf(" Hop Weights File = %s\n",
                   opt.hop_weights_file);
            break;

        case 'O':
            SET_STR_OPT(opt.port_search_ordering_file, optarg);
            printf(" Port Search Ordering/Dimension Ports File = %s\n",
                   opt.port_search_ordering_file);
            break;

        case 'g':
            /*
               Specifies port guid with which to bind.
             */
            opt.guid = cl_hton64(strtoull(optarg, NULL, 16));
            if (!opt.guid)
                /* If guid is 0 - need to display the
                 * guid list */
                opt.guid = INVALID_GUID;
            else
                printf(" Guid <0x%" PRIx64 ">\n",
                       cl_hton64(opt.guid));
            break;

        case 's':
            val = strtol(optarg, NULL, 0);
            /* Check that the number is not too large */
            if (((uint32_t) (val * 1000000)) / 1000000 != val)
                fprintf(stderr,
                    "ERROR: sweep interval given is too large. Ignoring it.\n");
            else {
                opt.sweep_interval = val;
                printf(" sweep interval = %d\n",
                       opt.sweep_interval);
            }
            break;

        case 't':
            val = strtoul(optarg, NULL, 0);
            opt.transaction_timeout = strtoul(optarg, NULL, 0);
            if (val == 0)
                fprintf(stderr, "ERROR: timeout value 0 is invalid. Ignoring it.\n");
            else {
                opt.transaction_timeout = val;
                printf(" Transaction timeout = %u\n",
                       opt.transaction_timeout);
            }
            break;

        case 'n':
            opt.max_wire_smps = strtoul(optarg, NULL, 0);
            if (opt.max_wire_smps == 0 ||
                opt.max_wire_smps > 0x7FFFFFFF)
                opt.max_wire_smps = 0x7FFFFFFF;
            printf(" Max wire smp's = %d\n", opt.max_wire_smps);
            break;

        case 'q':
            /*
             * OpenSM interactive console
             */
            if (strcmp(optarg, OSM_DISABLE_CONSOLE) == 0
                || strcmp(optarg, OSM_LOCAL_CONSOLE) == 0
#ifdef ENABLE_OSM_CONSOLE_SOCKET
                || strcmp(optarg, OSM_REMOTE_CONSOLE) == 0
#endif
#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
                || strcmp(optarg, OSM_LOOPBACK_CONSOLE) == 0
#endif
                )
                SET_STR_OPT(opt.console, optarg);
            else
                printf("-console %s option not understood\n",
                       optarg);
            break;

#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
        case 'C':
            opt.console_port = strtol(optarg, NULL, 0);
            break;
#endif

        case 'd':
            dbg_lvl = strtol(optarg, NULL, 0);
            printf(" d level = 0x%x\n", dbg_lvl);
            if (dbg_lvl == 0) {
                printf(" Debug mode: Ignore Other SMs\n");
                opt.ignore_other_sm = TRUE;
            } else if (dbg_lvl == 1) {
                printf(" Debug mode: Forcing Single Thread\n");
                opt.single_thread = TRUE;
            } else if (dbg_lvl == 2) {
                printf(" Debug mode: Force Log Flush\n");
                opt.force_log_flush = TRUE;
            } else if (dbg_lvl == 3) {
                printf
                    (" Debug mode: Disable multicast support\n");
                opt.disable_multicast = TRUE;
            }
            /*
             * NOTE: Debug level 4 used to be used for memory
             * tracking but this is now deprecated
             */
            else if (dbg_lvl == 5)
                vendor_debug++;
            else
                printf(" OpenSM: Unknown debug option %d"
                       " ignored\n", dbg_lvl);
            break;

        case 'l':
            temp = strtoul(optarg, NULL, 0);
            if (temp > 7) {
                fprintf(stderr,
                    "ERROR: LMC must be 7 or less.\n");
                return -1;
            }
            opt.lmc = (uint8_t) temp;
            printf(" LMC = %d\n", temp);
            break;

        case 'D':
            opt.log_flags = strtol(optarg, NULL, 0);
            printf(" verbose option -D = 0x%x\n", opt.log_flags);
            break;

        case 'f':
            SET_STR_OPT(opt.log_file, optarg);
            break;

        case 'L':
            opt.log_max_size = strtoul(optarg, NULL, 0);
            printf(" Log file max size is %u MBytes\n",
                   opt.log_max_size);
            break;

        case 'e':
            opt.accum_log_file = FALSE;
            printf(" Creating new log file\n");
            break;

        case 'J':
            pidfile = optarg;
            break;

        case 'P':
            SET_STR_OPT(opt.partition_config_file, optarg);
            break;

        case 'N':
            opt.no_partition_enforcement = TRUE;
            break;

        case 'Z':
            if (strcmp(optarg, OSM_PARTITION_ENFORCE_BOTH) == 0
                || strcmp(optarg, OSM_PARTITION_ENFORCE_IN) == 0
                || strcmp(optarg, OSM_PARTITION_ENFORCE_OUT) == 0
                || strcmp(optarg, OSM_PARTITION_ENFORCE_OFF) == 0) {
                SET_STR_OPT(opt.part_enforce, optarg);
                if (strcmp(optarg, OSM_PARTITION_ENFORCE_BOTH) == 0)
                    opt.part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_BOTH;
                else if (strcmp(optarg, OSM_PARTITION_ENFORCE_IN) == 0)
                    opt.part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_IN;
                else if (strcmp(optarg, OSM_PARTITION_ENFORCE_OUT) == 0)
                    opt.part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_OUT;
                else
                    opt.part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_OFF;
            } else
                printf("-part_enforce %s option not understood\n",
                       optarg);
            break;

        case 'W':
            opt.allow_both_pkeys = TRUE;
            break;

        case 'Q':
            opt.qos = TRUE;
            break;

        case 'Y':
            SET_STR_OPT(opt.qos_policy_file, optarg);
            printf(" QoS policy file \'%s\'\n", optarg);
            break;

        case 128:
            opt.congestion_control = TRUE;
            break;

        case 129:
            opt.cc_key = strtoull(optarg, NULL, 0);
            printf(" CC Key 0x%" PRIx64 "\n", opt.cc_key);
            break;

        case 'y':
            opt.exit_on_fatal = FALSE;
            printf(" Staying on fatal initialization errors\n");
            break;

        case 'v':
            opt.log_flags = (opt.log_flags << 1) | 1;
            printf(" Verbose option -v (log flags = 0x%X)\n",
                   opt.log_flags);
            break;

        case 'V':
            opt.log_flags = 0xFF;
            opt.force_log_flush = TRUE;
            printf(" Big V selected\n");
            break;

        case 'p':
            temp = strtoul(optarg, NULL, 0);
            if (temp > 15) {
                fprintf(stderr,
                    "ERROR: priority must be between 0 and 15\n");
                return -1;
            }
            opt.sm_priority = (uint8_t) temp;
            printf(" Priority = %d\n", temp);
            break;

        case 'k':
            sm_key = cl_hton64(strtoull(optarg, NULL, 16));
            printf(" SM Key <0x%" PRIx64 ">\n", cl_hton64(sm_key));
            opt.sm_key = sm_key;
            break;

        case 'R':
            SET_STR_OPT(opt.routing_engine_names, optarg);
            printf(" Activate \'%s\' routing engine(s)\n", optarg);
            break;

        case 'z':
            opt.connect_roots = TRUE;
            printf(" Connect roots option is on\n");
            break;

        case 'A':
            opt.use_ucast_cache = TRUE;
            printf(" Unicast routing cache option is on\n");
            break;

        case 'M':
            SET_STR_OPT(opt.lid_matrix_dump_file, optarg);
            printf(" Lid matrix dump file is \'%s\'\n", optarg);
            break;

        case 'U':
            SET_STR_OPT(opt.lfts_file, optarg);
            printf(" LFTs file is \'%s\'\n", optarg);
            break;

        case 'S':
            SET_STR_OPT(opt.sa_db_file, optarg);
            printf(" SA DB file is \'%s\'\n", optarg);
            break;

        case 'a':
            SET_STR_OPT(opt.root_guid_file, optarg);
            printf(" Root Guid File: %s\n", opt.root_guid_file);
            break;

        case 'u':
            SET_STR_OPT(opt.cn_guid_file, optarg);
            printf(" Compute Node Guid File: %s\n",
                   opt.cn_guid_file);
            break;

        case 'G':
            SET_STR_OPT(opt.io_guid_file, optarg);
            printf(" I/O Node Guid File: %s\n", opt.io_guid_file);
            break;
        case 11:
            opt.port_shifting = TRUE;
            printf(" Port Shifting is on\n");
            break;
        case 14:
            opt.scatter_ports = strtol(optarg, NULL, 0);
            printf(" Scatter Ports is on\n");
            break;
        case 'H':
            opt.max_reverse_hops = atoi(optarg);
            printf(" Max Reverse Hops: %d\n", opt.max_reverse_hops);
            break;
        case 'm':
            SET_STR_OPT(opt.ids_guid_file, optarg);
            printf(" IDs Guid File: %s\n", opt.ids_guid_file);
            break;

        case 'X':
            SET_STR_OPT(opt.guid_routing_order_file, optarg);
            printf(" GUID Routing Order File: %s\n",
                   opt.guid_routing_order_file);
            break;

        case 'x':
            opt.honor_guid2lid_file = TRUE;
            printf(" Honor guid2lid file, if possible\n");
            break;

        case 'B':
            opt.daemon = TRUE;
            printf(" Daemon mode\n");
            break;

        case 'I':
            opt.sm_inactive = TRUE;
            printf(" SM started in inactive state\n");
            break;

#ifdef ENABLE_OSM_PERF_MGR
        case 1:
            opt.perfmgr = TRUE;
            break;
        case 2:
            opt.perfmgr_sweep_time_s = atoi(optarg);
            break;
#endif                /* ENABLE_OSM_PERF_MGR */

        case 3:
            SET_STR_OPT(opt.prefix_routes_file, optarg);
            break;
        case 4:
            opt.consolidate_ipv6_snm_req = TRUE;
            break;
        case 5:
            opt.do_mesh_analysis = TRUE;
            break;
        case 6:
            temp = strtoul(optarg, NULL, 0);
            if (temp >= IB_MAX_NUM_VLS) {
                fprintf(stderr,
                    "ERROR: starting lash vl must be between 0 and 15\n");
                return -1;
            }
            opt.lash_start_vl = (uint8_t) temp;
            printf(" LASH starting VL = %d\n", opt.lash_start_vl);
            break;
        case 7:
            temp = strtoul(optarg, NULL, 0);
            if (temp > 15) {
                fprintf(stderr,
                    "ERROR: SM's SL must be between 0 and 15\n");
                return -1;
            }
            opt.sm_sl = (uint8_t) temp;
            printf(" SMSL = %d\n", opt.sm_sl);
            break;
        case 8:
            opt.transaction_retries = strtoul(optarg, NULL, 0);
            printf(" Transaction retries = %u\n",
                   opt.transaction_retries);
            break;
        case 9:
            SET_STR_OPT(opt.log_prefix, optarg);
            printf("Log prefix = %s\n", opt.log_prefix);
            break;
        case 10:
            SET_STR_OPT(opt.torus_conf_file, optarg);
            printf("Torus-2QoS config file = %s\n", opt.torus_conf_file);
            break;
        case 13:
            opt.guid_routing_order_no_scatter = TRUE;
            break;
        case 'h':
        case '?':
        case ':':
            show_usage();
            break;

        case -1:
            break;    /* done with option */
        default:    /* something wrong */
            abort();
        }
    } while (next_option != -1);

    if (opt.log_file != NULL)
        printf(" Log File: %s\n", opt.log_file);
    /* Done with options description */
    printf("-------------------------------------------------\n");

    if (conf_template) {
        status = osm_subn_write_conf_file(conf_template, &opt);
        if (status)
            printf("\nosm_subn_write_conf_file failed!\n");
        exit(status);
    }

    osm_subn_verify_config(&opt);

    if (vendor_debug)
        osm_vendor_set_debug(osm.p_vendor, vendor_debug);

    block_signals();

    if (opt.daemon) {
        if (INVALID_GUID == opt.guid) {
            fprintf(stderr,
                "ERROR: Invalid GUID specified; exiting because of daemon mode\n");
            return -1;
        }
        daemonize(&osm);
    }

    complib_init();

    status = osm_opensm_init(&osm, &opt);
    if (status != IB_SUCCESS) {
        const char *err_str = ib_get_err_str(status);
        if (err_str == NULL)
            err_str = "Unknown Error Type";
        printf("\nError from osm_opensm_init: %s.\n", err_str);
        /* We will just exit, and not go to Exit, since we don't
           want the destroy to be called. */
        complib_exit();
        return status;
    }

    /*
       If the user didn't specify a GUID on the command line,
       then get a port GUID value with which to bind.
     */
    if (opt.guid == 0 || cl_hton64(opt.guid) == CL_HTON64(INVALID_GUID))
        opt.guid = get_port_guid(&osm, opt.guid);

    if (opt.guid == 0)
        goto Exit2;

    status = osm_opensm_init_finish(&osm, &opt);
    if (status != IB_SUCCESS) {
        const char *err_str = ib_get_err_str(status);
        if (err_str == NULL)
            err_str = "Unknown Error Type";
        printf("\nError from osm_opensm_init_finish: %s.\n", err_str);
        goto Exit2;
    }

    status = osm_opensm_bind(&osm, opt.guid);
    if (status != IB_SUCCESS) {
        printf("\nError from osm_opensm_bind (0x%X)\n", status);
        printf
            ("Perhaps another instance of OpenSM is already running\n");
        goto Exit;
    }

    setup_signals();

    osm_opensm_sweep(&osm);

    if (run_once_flag == TRUE) {
        while (!osm_exit_flag) {
            status =
                osm_opensm_wait_for_subnet_up(&osm,
                              osm.subn.opt.
                              sweep_interval *
                              1000000, TRUE);
            if (!status)
                osm_exit_flag = 1;
        }
    } else {
        /*
         *         Sit here until signaled to exit
         */
        osm_manager_loop(&opt, &osm);
    }

    if (osm.mad_pool.mads_out) {
        fprintf(stdout,
            "There are still %u MADs out. Forcing the exit of the OpenSM application...\n",
            osm.mad_pool.mads_out);
#ifdef HAVE_LIBPTHREAD
        pthread_cond_signal(&osm.stats.cond);
#else
        cl_event_signal(&osm.stats.event);
#endif
    }

Exit:
    osm_opensm_destroy(&osm);
Exit2:
    osm_opensm_destroy_finish(&osm);
    complib_exit();
    remove_pidfile();

    exit(0);
}

文件列表(部分)

名称 大小 修改日期
opensm-3.3.200.00 KB2019-07-56
opensm-3.3.200.00 KB2019-07-58
aclocal.m434.00 KB2016-06-48
AUTHORS0.38 KB2013-02-28
autogen.sh1.91 KB2013-02-28
ChangeLog406.66 KB2016-06-18
complib0.00 KB2019-07-58
ChangeLog2.69 KB2013-02-28
cl_complib.c2.46 KB2013-02-28
cl_dispatcher.c10.23 KB2014-10-44
cl_event.c4.90 KB2013-02-28
cl_event_wheel.c17.00 KB2014-01-50
cl_list.c15.17 KB2013-02-28
cl_log.c3.33 KB2013-02-28
cl_map.c42.82 KB2013-02-28
cl_nodenamemap.c5.19 KB2014-01-50
cl_pool.c18.05 KB2013-02-28
cl_ptr_vector.c8.23 KB2013-02-28
cl_spinlock.c2.83 KB2013-02-28
cl_statustext.c2.20 KB2013-02-28
cl_thread.c3.80 KB2013-02-28
cl_threadpool.c4.19 KB2014-01-50
cl_timer.c11.77 KB2013-02-28
cl_vector.c13.25 KB2013-02-28
ib_statustext.c4.24 KB2013-02-28
libosmcomp.map3.18 KB2013-02-28
libosmcomp.ver0.33 KB2016-06-16
Makefile.am2.69 KB2014-01-50
Makefile.in39.83 KB2016-06-48
config0.00 KB2019-07-56
compile3.62 KB2014-07-46
config.guess41.05 KB2009-12-00

立即下载

相关下载

[如何查找哪个服务器运行opensm?] 这篇文章显示了如何找到网络中运行SM的服务器。 该文章是基础文章,适合有InfiniBand网络经验的初学者使用​
[opensm源码] 路由算法此版本为opensm3.5版本, 涉及到的路由算法有以下几种: 1. Min Hop算法 2. UPDN 路由算法 3. DNUP路由算法 4. Fat-tree路由算法 5. LASH 路由算法 6.DOR 路由算法 7.Torus-2QoS路由算法等等 UPDN算法极力推荐使用, 该算法旨在防止死锁在子网构成循环中发生。 死锁这种情况不再在任何两个主机之间发送数据中发生。 因此建议使用UPDN路由算法。胖树这种算法对于高负载的情况会发生。

评论列表 共有 0 条评论

暂无评论

微信捐赠

微信扫一扫体验

立即
上传
发表
评论
返回
顶部