1 /* $OpenBSD: printconf.c,v 1.97 2016/07/13 20:07:38 benno Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA, PROFITS OR MIND, WHETHER IN 15 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <limits.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "bgpd.h" 25 #include "mrt.h" 26 #include "session.h" 27 #include "rde.h" 28 29 void print_op(enum comp_ops); 30 void print_community(int, int); 31 void print_extcommunity(struct filter_extcommunity *); 32 void print_origin(u_int8_t); 33 void print_set(struct filter_set_head *); 34 void print_mainconf(struct bgpd_config *); 35 void print_rdomain_targets(struct filter_set_head *, const char *); 36 void print_rdomain(struct rdomain *); 37 const char *print_af(u_int8_t); 38 void print_network(struct network_config *, const char *); 39 void print_peer(struct peer_config *, struct bgpd_config *, 40 const char *); 41 const char *print_auth_alg(u_int8_t); 42 const char *print_enc_alg(u_int8_t); 43 void print_announce(struct peer_config *, const char *); 44 void print_as(struct filter_rule *); 45 void print_rule(struct peer *, struct filter_rule *); 46 const char *mrt_type(enum mrt_type); 47 void print_mrt(struct bgpd_config *, u_int32_t, u_int32_t, 48 const char *, const char *); 49 void print_groups(struct bgpd_config *, struct peer *); 50 int peer_compare(const void *, const void *); 51 52 void 53 print_op(enum comp_ops op) 54 { 55 switch (op) { 56 case OP_RANGE: 57 printf("-"); 58 break; 59 case OP_XRANGE: 60 printf("><"); 61 break; 62 case OP_EQ: 63 printf("="); 64 break; 65 case OP_NE: 66 printf("!="); 67 break; 68 case OP_LE: 69 printf("<="); 70 break; 71 case OP_LT: 72 printf("<"); 73 break; 74 case OP_GE: 75 printf(">="); 76 break; 77 case OP_GT: 78 printf(">"); 79 break; 80 default: 81 printf("?"); 82 break; 83 } 84 } 85 86 void 87 print_community(int as, int type) 88 { 89 if (as == COMMUNITY_ANY) 90 printf("*:"); 91 else if (as == COMMUNITY_NEIGHBOR_AS) 92 printf("neighbor-as:"); 93 else 94 printf("%u:", (unsigned int)as); 95 96 if (type == COMMUNITY_ANY) 97 printf("* "); 98 else if (type == COMMUNITY_NEIGHBOR_AS) 99 printf("neighbor-as "); 100 else 101 printf("%d ", type); 102 } 103 104 void 105 print_extcommunity(struct filter_extcommunity *c) 106 { 107 switch (c->type & EXT_COMMUNITY_VALUE) { 108 case EXT_COMMUNITY_TWO_AS: 109 printf("%s %hu:%u ", log_ext_subtype(c->subtype), 110 c->data.ext_as.as, c->data.ext_as.val); 111 break; 112 case EXT_COMMUNITY_IPV4: 113 printf("%s %s:%u ", log_ext_subtype(c->subtype), 114 inet_ntoa(c->data.ext_ip.addr), c->data.ext_ip.val); 115 break; 116 case EXT_COMMUNITY_FOUR_AS: 117 printf("%s %s:%u ", log_ext_subtype(c->subtype), 118 log_as(c->data.ext_as4.as4), c->data.ext_as.val); 119 break; 120 case EXT_COMMUNITY_OPAQUE: 121 printf("%s 0x%llx ", log_ext_subtype(c->subtype), 122 c->data.ext_opaq); 123 break; 124 default: 125 printf("0x%x 0x%llx ", c->type, c->data.ext_opaq); 126 break; 127 } 128 } 129 130 void 131 print_origin(u_int8_t o) 132 { 133 if (o == ORIGIN_IGP) 134 printf("igp "); 135 else if (o == ORIGIN_EGP) 136 printf("egp "); 137 else if (o == ORIGIN_INCOMPLETE) 138 printf("incomplete "); 139 else 140 printf("%u ", o); 141 } 142 143 void 144 print_set(struct filter_set_head *set) 145 { 146 struct filter_set *s; 147 148 if (TAILQ_EMPTY(set)) 149 return; 150 151 printf("set { "); 152 TAILQ_FOREACH(s, set, entry) { 153 switch (s->type) { 154 case ACTION_SET_LOCALPREF: 155 printf("localpref %u ", s->action.metric); 156 break; 157 case ACTION_SET_RELATIVE_LOCALPREF: 158 printf("localpref %+d ", s->action.relative); 159 break; 160 case ACTION_SET_MED: 161 printf("metric %u ", s->action.metric); 162 break; 163 case ACTION_SET_RELATIVE_MED: 164 printf("metric %+d ", s->action.relative); 165 break; 166 case ACTION_SET_WEIGHT: 167 printf("weight %u ", s->action.metric); 168 break; 169 case ACTION_SET_RELATIVE_WEIGHT: 170 printf("weight %+d ", s->action.relative); 171 break; 172 case ACTION_SET_NEXTHOP: 173 printf("nexthop %s ", log_addr(&s->action.nexthop)); 174 break; 175 case ACTION_SET_NEXTHOP_REJECT: 176 printf("nexthop reject "); 177 break; 178 case ACTION_SET_NEXTHOP_BLACKHOLE: 179 printf("nexthop blackhole "); 180 break; 181 case ACTION_SET_NEXTHOP_NOMODIFY: 182 printf("nexthop no-modify "); 183 break; 184 case ACTION_SET_NEXTHOP_SELF: 185 printf("nexthop self "); 186 break; 187 case ACTION_SET_PREPEND_SELF: 188 printf("prepend-self %u ", s->action.prepend); 189 break; 190 case ACTION_SET_PREPEND_PEER: 191 printf("prepend-neighbor %u ", s->action.prepend); 192 break; 193 case ACTION_DEL_COMMUNITY: 194 printf("community delete "); 195 print_community(s->action.community.as, 196 s->action.community.type); 197 printf(" "); 198 break; 199 case ACTION_SET_COMMUNITY: 200 printf("community "); 201 print_community(s->action.community.as, 202 s->action.community.type); 203 printf(" "); 204 break; 205 case ACTION_PFTABLE: 206 printf("pftable %s ", s->action.pftable); 207 break; 208 case ACTION_RTLABEL: 209 printf("rtlabel %s ", s->action.rtlabel); 210 break; 211 case ACTION_SET_ORIGIN: 212 printf("origin "); 213 print_origin(s->action.origin); 214 break; 215 case ACTION_RTLABEL_ID: 216 case ACTION_PFTABLE_ID: 217 /* not possible */ 218 printf("king bula saiz: config broken"); 219 break; 220 case ACTION_SET_EXT_COMMUNITY: 221 printf("ext-community "); 222 print_extcommunity(&s->action.ext_community); 223 break; 224 case ACTION_DEL_EXT_COMMUNITY: 225 printf("ext-community delete "); 226 print_extcommunity(&s->action.ext_community); 227 break; 228 } 229 } 230 printf("}"); 231 } 232 233 void 234 print_mainconf(struct bgpd_config *conf) 235 { 236 struct in_addr ina; 237 struct listen_addr *la; 238 239 printf("AS %s", log_as(conf->as)); 240 if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS) 241 printf(" %u", conf->short_as); 242 ina.s_addr = conf->bgpid; 243 printf("\nrouter-id %s\n", inet_ntoa(ina)); 244 245 printf("socket \"%s\"\n", conf->csock); 246 if (conf->rcsock) 247 printf("socket \"%s\" restricted\n", conf->rcsock); 248 if (conf->holdtime) 249 printf("holdtime %u\n", conf->holdtime); 250 if (conf->min_holdtime) 251 printf("holdtime min %u\n", conf->min_holdtime); 252 if (conf->connectretry) 253 printf("connect-retry %u\n", conf->connectretry); 254 255 if (conf->flags & BGPD_FLAG_NO_EVALUATE) 256 printf("route-collector yes\n"); 257 258 if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE) 259 printf("rde route-age evaluate\n"); 260 261 if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS) 262 printf("rde med compare always\n"); 263 264 if (conf->log & BGPD_LOG_UPDATES) 265 printf("log updates\n"); 266 267 TAILQ_FOREACH(la, conf->listen_addrs, entry) 268 printf("listen on %s\n", 269 log_sockaddr((struct sockaddr *)&la->sa)); 270 271 if (conf->flags & BGPD_FLAG_NEXTHOP_BGP) 272 printf("nexthop qualify via bgp\n"); 273 if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT) 274 printf("nexthop qualify via default\n"); 275 printf("fib-priority %hhu", conf->fib_priority); 276 } 277 278 void 279 print_rdomain_targets(struct filter_set_head *set, const char *tgt) 280 { 281 struct filter_set *s; 282 TAILQ_FOREACH(s, set, entry) { 283 printf("\t%s ", tgt); 284 print_extcommunity(&s->action.ext_community); 285 printf("\n"); 286 } 287 } 288 289 void 290 print_rdomain(struct rdomain *r) 291 { 292 struct network *n; 293 294 printf("rdomain %u {\n", r->rtableid); 295 if (*r->descr) 296 printf("\tdescr \"%s\"\n", r->descr); 297 if (r->flags & F_RIB_NOFIBSYNC) 298 printf("\tfib-update no\n"); 299 else 300 printf("\tfib-update yes\n"); 301 printf("\tdepend on %s\n", r->ifmpe); 302 303 TAILQ_FOREACH(n, &r->net_l, entry) 304 print_network(&n->net, "\t"); 305 306 printf("\n\t%s\n", log_rd(r->rd)); 307 308 print_rdomain_targets(&r->export, "export-target"); 309 print_rdomain_targets(&r->import, "import-target"); 310 311 printf("}\n"); 312 } 313 314 const char * 315 print_af(u_int8_t aid) 316 { 317 /* 318 * Hack around the fact that aid2str() will return "IPv4 unicast" 319 * for AID_INET. AID_INET and AID_INET6 need special handling and 320 * the other AID should never end up here (at least for now). 321 */ 322 if (aid == AID_INET) 323 return ("inet"); 324 if (aid == AID_INET6) 325 return ("inet6"); 326 return (aid2str(aid)); 327 } 328 329 void 330 print_network(struct network_config *n, const char *c) 331 { 332 switch (n->type) { 333 case NETWORK_STATIC: 334 printf("%snetwork %s static", c, print_af(n->prefix.aid)); 335 break; 336 case NETWORK_CONNECTED: 337 printf("%snetwork %s connected", c, print_af(n->prefix.aid)); 338 break; 339 default: 340 printf("%snetwork %s/%u", c, log_addr(&n->prefix), 341 n->prefixlen); 342 break; 343 } 344 if (!TAILQ_EMPTY(&n->attrset)) 345 printf(" "); 346 print_set(&n->attrset); 347 printf("\n"); 348 } 349 350 void 351 print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) 352 { 353 char *method; 354 struct in_addr ina; 355 356 if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) || 357 (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128)) 358 printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr), 359 p->remote_masklen); 360 else 361 printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr)); 362 if (p->descr[0]) 363 printf("%s\tdescr \"%s\"\n", c, p->descr); 364 if (p->rib[0]) 365 printf("%s\trib \"%s\"\n", c, p->rib); 366 if (p->remote_as) 367 printf("%s\tremote-as %s\n", c, log_as(p->remote_as)); 368 if (p->down) 369 printf("%s\tdown\n", c); 370 if (p->distance > 1) 371 printf("%s\tmultihop %u\n", c, p->distance); 372 if (p->passive) 373 printf("%s\tpassive\n", c); 374 if (p->local_addr.aid) 375 printf("%s\tlocal-address %s\n", c, log_addr(&p->local_addr)); 376 if (p->max_prefix) { 377 printf("%s\tmax-prefix %u", c, p->max_prefix); 378 if (p->max_prefix_restart) 379 printf(" restart %u", p->max_prefix_restart); 380 printf("\n"); 381 } 382 if (p->holdtime) 383 printf("%s\tholdtime %u\n", c, p->holdtime); 384 if (p->min_holdtime) 385 printf("%s\tholdtime min %u\n", c, p->min_holdtime); 386 if (p->announce_capa == 0) 387 printf("%s\tannounce capabilities no\n", c); 388 if (p->capabilities.refresh == 0) 389 printf("%s\tannounce refresh no\n", c); 390 if (p->capabilities.grestart.restart == 0) 391 printf("%s\tannounce restart no\n", c); 392 if (p->capabilities.as4byte == 0) 393 printf("%s\tannounce as4byte no\n", c); 394 if (p->announce_type == ANNOUNCE_SELF) 395 printf("%s\tannounce self\n", c); 396 else if (p->announce_type == ANNOUNCE_NONE) 397 printf("%s\tannounce none\n", c); 398 else if (p->announce_type == ANNOUNCE_ALL) 399 printf("%s\tannounce all\n", c); 400 else if (p->announce_type == ANNOUNCE_DEFAULT_ROUTE) 401 printf("%s\tannounce default-route\n", c); 402 else 403 printf("%s\tannounce ???\n", c); 404 if (p->enforce_as == ENFORCE_AS_ON) 405 printf("%s\tenforce neighbor-as yes\n", c); 406 else 407 printf("%s\tenforce neighbor-as no\n", c); 408 if (p->reflector_client) { 409 if (conf->clusterid == 0) 410 printf("%s\troute-reflector\n", c); 411 else { 412 ina.s_addr = conf->clusterid; 413 printf("%s\troute-reflector %s\n", c, 414 inet_ntoa(ina)); 415 } 416 } 417 if (p->demote_group[0]) 418 printf("%s\tdemote %s\n", c, p->demote_group); 419 if (p->if_depend[0]) 420 printf("%s\tdepend on \"%s\"\n", c, p->if_depend); 421 if (p->flags & PEERFLAG_TRANS_AS) 422 printf("%s\ttransparent-as yes\n", c); 423 424 if (p->flags & PEERFLAG_LOG_UPDATES) 425 printf("%s\tlog updates\n", c); 426 427 if (p->auth.method == AUTH_MD5SIG) 428 printf("%s\ttcp md5sig\n", c); 429 else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP || 430 p->auth.method == AUTH_IPSEC_MANUAL_AH) { 431 if (p->auth.method == AUTH_IPSEC_MANUAL_ESP) 432 method = "esp"; 433 else 434 method = "ah"; 435 436 printf("%s\tipsec %s in spi %u %s XXXXXX", c, method, 437 p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in)); 438 if (p->auth.enc_alg_in) 439 printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in)); 440 printf("\n"); 441 442 printf("%s\tipsec %s out spi %u %s XXXXXX", c, method, 443 p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out)); 444 if (p->auth.enc_alg_out) 445 printf(" %s XXXXXX", 446 print_enc_alg(p->auth.enc_alg_out)); 447 printf("\n"); 448 } else if (p->auth.method == AUTH_IPSEC_IKE_AH) 449 printf("%s\tipsec ah ike\n", c); 450 else if (p->auth.method == AUTH_IPSEC_IKE_ESP) 451 printf("%s\tipsec esp ike\n", c); 452 453 if (p->ttlsec) 454 printf("%s\tttl-security yes\n", c); 455 456 print_announce(p, c); 457 458 if (p->softreconfig_in == 1) 459 printf("%s\tsoftreconfig in yes\n", c); 460 else 461 printf("%s\tsoftreconfig in no\n", c); 462 463 if (p->softreconfig_out == 1) 464 printf("%s\tsoftreconfig out yes\n", c); 465 else 466 printf("%s\tsoftreconfig out no\n", c); 467 468 469 print_mrt(conf, p->id, p->groupid, c, "\t"); 470 471 printf("%s}\n", c); 472 } 473 474 const char * 475 print_auth_alg(u_int8_t alg) 476 { 477 switch (alg) { 478 case SADB_AALG_SHA1HMAC: 479 return ("sha1"); 480 case SADB_AALG_MD5HMAC: 481 return ("md5"); 482 default: 483 return ("???"); 484 } 485 } 486 487 const char * 488 print_enc_alg(u_int8_t alg) 489 { 490 switch (alg) { 491 case SADB_EALG_3DESCBC: 492 return ("3des"); 493 case SADB_X_EALG_AES: 494 return ("aes"); 495 default: 496 return ("???"); 497 } 498 } 499 500 void 501 print_announce(struct peer_config *p, const char *c) 502 { 503 u_int8_t aid; 504 505 for (aid = 0; aid < AID_MAX; aid++) 506 if (p->capabilities.mp[aid]) 507 printf("%s\tannounce %s\n", c, aid2str(aid)); 508 } 509 510 void print_as(struct filter_rule *r) 511 { 512 switch(r->match.as.op) { 513 case OP_RANGE: 514 printf("%s - ", log_as(r->match.as.as_min)); 515 printf("%s ", log_as(r->match.as.as_max)); 516 break; 517 case OP_XRANGE: 518 printf("%s >< ", log_as(r->match.as.as_min)); 519 printf("%s ", log_as(r->match.as.as_max)); 520 break; 521 case OP_NE: 522 printf("!= %s ", log_as(r->match.as.as)); 523 break; 524 default: 525 printf("%s ", log_as(r->match.as.as)); 526 break; 527 } 528 } 529 530 void 531 print_rule(struct peer *peer_l, struct filter_rule *r) 532 { 533 struct peer *p; 534 535 if (r->action == ACTION_ALLOW) 536 printf("allow "); 537 else if (r->action == ACTION_DENY) 538 printf("deny "); 539 else 540 printf("match "); 541 if (r->quick) 542 printf("quick "); 543 544 if (r->rib[0]) 545 printf("rib %s ", r->rib); 546 547 if (r->dir == DIR_IN) 548 printf("from "); 549 else if (r->dir == DIR_OUT) 550 printf("to "); 551 else 552 printf("eeeeeeeps. "); 553 554 if (r->peer.peerid) { 555 for (p = peer_l; p != NULL && p->conf.id != r->peer.peerid; 556 p = p->next) 557 ; /* nothing */ 558 if (p == NULL) 559 printf("? "); 560 else 561 printf("%s ", log_addr(&p->conf.remote_addr)); 562 } else if (r->peer.groupid) { 563 for (p = peer_l; p != NULL && 564 p->conf.groupid != r->peer.groupid; p = p->next) 565 ; /* nothing */ 566 if (p == NULL) 567 printf("group ? "); 568 else 569 printf("group \"%s\" ", p->conf.group); 570 } else if (r->peer.remote_as) { 571 printf("AS %s ", log_as(r->peer.remote_as)); 572 } else 573 printf("any "); 574 575 if (r->match.prefix.addr.aid) 576 printf("prefix %s/%u ", log_addr(&r->match.prefix.addr), 577 r->match.prefix.len); 578 579 if (r->match.prefix.op) { 580 if (r->match.prefix.op == OP_RANGE || 581 r->match.prefix.op == OP_XRANGE) { 582 printf("prefixlen %u ", r->match.prefix.len_min); 583 print_op(r->match.prefix.op); 584 printf(" %u ", r->match.prefix.len_max); 585 } else { 586 printf("prefixlen "); 587 print_op(r->match.prefix.op); 588 printf(" %u ", r->match.prefix.len_min); 589 } 590 } 591 592 if (r->match.nexthop.flags) { 593 if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR) 594 printf("nexthop neighbor "); 595 else 596 printf("nexthop %s ", log_addr(&r->match.nexthop.addr)); 597 } 598 599 if (r->match.as.type) { 600 if (r->match.as.type == AS_ALL) 601 printf("AS "); 602 else if (r->match.as.type == AS_SOURCE) 603 printf("source-as "); 604 else if (r->match.as.type == AS_TRANSIT) 605 printf("transit-as "); 606 else if (r->match.as.type == AS_PEER) 607 printf("peer-as "); 608 else 609 printf("unfluffy-as "); 610 print_as(r); 611 } 612 613 if (r->match.aslen.type) { 614 printf("%s %u ", r->match.aslen.type == ASLEN_MAX ? 615 "max-as-len" : "max-as-seq", r->match.aslen.aslen); 616 } 617 618 if (r->match.community.as != COMMUNITY_UNSET) { 619 printf("community "); 620 print_community(r->match.community.as, 621 r->match.community.type); 622 } 623 if (r->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID) { 624 printf("ext-community "); 625 print_extcommunity(&r->match.ext_community); 626 } 627 628 print_set(&r->set); 629 630 printf("\n"); 631 } 632 633 const char * 634 mrt_type(enum mrt_type t) 635 { 636 switch (t) { 637 case MRT_NONE: 638 break; 639 case MRT_TABLE_DUMP: 640 return "table"; 641 case MRT_TABLE_DUMP_MP: 642 return "table-mp"; 643 case MRT_TABLE_DUMP_V2: 644 return "table-v2"; 645 case MRT_ALL_IN: 646 return "all in"; 647 case MRT_ALL_OUT: 648 return "all out"; 649 case MRT_UPDATE_IN: 650 return "updates in"; 651 case MRT_UPDATE_OUT: 652 return "updates out"; 653 } 654 return "unfluffy MRT"; 655 } 656 657 void 658 print_mrt(struct bgpd_config *conf, u_int32_t pid, u_int32_t gid, 659 const char *prep, const char *prep2) 660 { 661 struct mrt *m; 662 663 if (conf->mrt == NULL) 664 return; 665 666 LIST_FOREACH(m, conf->mrt, entry) 667 if ((gid != 0 && m->group_id == gid) || 668 (m->peer_id == pid && m->group_id == gid)) { 669 printf("%s%sdump ", prep, prep2); 670 if (m->rib[0]) 671 printf("rib %s ", m->rib); 672 printf("%s \"%s\"", mrt_type(m->type), 673 MRT2MC(m)->name); 674 if (MRT2MC(m)->ReopenTimerInterval == 0) 675 printf("\n"); 676 else 677 printf(" %d\n", MRT2MC(m)->ReopenTimerInterval); 678 } 679 } 680 681 void 682 print_groups(struct bgpd_config *conf, struct peer *peer_l) 683 { 684 struct peer_config **peerlist; 685 struct peer *p; 686 u_int peer_cnt, i; 687 u_int32_t prev_groupid; 688 const char *tab = "\t"; 689 const char *nada = ""; 690 const char *c; 691 692 peer_cnt = 0; 693 for (p = peer_l; p != NULL; p = p->next) 694 peer_cnt++; 695 696 if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL) 697 fatal("print_groups calloc"); 698 699 i = 0; 700 for (p = peer_l; p != NULL; p = p->next) 701 peerlist[i++] = &p->conf; 702 703 qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare); 704 705 prev_groupid = 0; 706 for (i = 0; i < peer_cnt; i++) { 707 if (peerlist[i]->groupid) { 708 c = tab; 709 if (peerlist[i]->groupid != prev_groupid) { 710 if (prev_groupid) 711 printf("}\n\n"); 712 printf("group \"%s\" {\n", peerlist[i]->group); 713 prev_groupid = peerlist[i]->groupid; 714 } 715 } else 716 c = nada; 717 718 print_peer(peerlist[i], conf, c); 719 } 720 721 if (prev_groupid) 722 printf("}\n\n"); 723 724 free(peerlist); 725 } 726 727 int 728 peer_compare(const void *aa, const void *bb) 729 { 730 const struct peer_config * const *a; 731 const struct peer_config * const *b; 732 733 a = aa; 734 b = bb; 735 736 return ((*a)->groupid - (*b)->groupid); 737 } 738 739 void 740 print_config(struct bgpd_config *conf, struct rib_names *rib_l, 741 struct network_head *net_l, struct peer *peer_l, 742 struct filter_head *rules_l, struct mrt_head *mrt_l, 743 struct rdomain_head *rdom_l) 744 { 745 struct filter_rule *r; 746 struct network *n; 747 struct rde_rib *rr; 748 struct rdomain *rd; 749 750 print_mainconf(conf); 751 printf("\n"); 752 TAILQ_FOREACH(n, net_l, entry) 753 print_network(&n->net, ""); 754 printf("\n"); 755 SIMPLEQ_FOREACH(rd, rdom_l, entry) 756 print_rdomain(rd); 757 printf("\n"); 758 SIMPLEQ_FOREACH(rr, rib_l, entry) { 759 if (rr->flags & F_RIB_NOEVALUATE) 760 printf("rde rib %s no evaluate\n", rr->name); 761 else if (rr->flags & F_RIB_NOFIB) 762 printf("rde rib %s\n", rr->name); 763 else 764 printf("rde rib %s rtable %u fib-update %s\n", rr->name, 765 rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ? 766 "no" : "yes"); 767 } 768 printf("\n"); 769 print_mrt(conf, 0, 0, "", ""); 770 printf("\n"); 771 print_groups(conf, peer_l); 772 printf("\n"); 773 TAILQ_FOREACH(r, rules_l, entry) 774 print_rule(peer_l, r); 775 } 776