├── BGP4-MIB.txt ├── COPYING.GPLv3 ├── README.md ├── adv_agentx.py ├── bird_bgp.py └── birdagent.py /BGP4-MIB.txt: -------------------------------------------------------------------------------- 1 | -- extracted from rfc4273.txt 2 | -- at Fri Jan 13 06:10:54 2006 3 | 4 | BGP4-MIB DEFINITIONS ::= BEGIN 5 | 6 | IMPORTS 7 | MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, 8 | IpAddress, Integer32, Counter32, Gauge32, mib-2 9 | FROM SNMPv2-SMI 10 | MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP 11 | FROM SNMPv2-CONF; 12 | 13 | bgp MODULE-IDENTITY 14 | LAST-UPDATED "200601110000Z" 15 | ORGANIZATION "IETF IDR Working Group" 16 | CONTACT-INFO "E-mail: idr@ietf.org 17 | 18 | Jeffrey Haas, Susan Hares (Editors) 19 | NextHop Technologies 20 | 825 Victors Way 21 | Suite 100 22 | Ann Arbor, MI 48108-2738 23 | Tel: +1 734 222-1600 24 | Fax: +1 734 222-1602 25 | E-mail: jhaas@nexthop.com 26 | skh@nexthop.com" 27 | 28 | DESCRIPTION 29 | "The MIB module for the BGP-4 protocol. 30 | 31 | Copyright (C) The Internet Society (2006). This 32 | version of this MIB module is part of RFC 4273; 33 | see the RFC itself for full legal notices." 34 | 35 | REVISION "200601110000Z" 36 | DESCRIPTION 37 | "Changes from RFC 1657: 38 | 39 | 1) Fixed the definitions of the notifications 40 | to make them equivalent to their initial 41 | definition in RFC 1269. 42 | 2) Added compliance and conformance info. 43 | 3) Updated information for the values of 44 | bgpPeerNegotiatedVersion, bgp4PathAttrLocalPref, 45 | bgp4PathAttrCalcLocalPref, 46 | bgp4PathAttrMultiExitDisc, 47 | bgp4PathAttrASPathSegement. 48 | 4) Added additional clarification comments where 49 | needed. 50 | 51 | 5) Noted where objects do not fully reflect 52 | the protocol as Known Issues. 53 | 6) Updated the DESCRIPTION for the 54 | bgp4PathAttrAtomicAggregate object. 55 | 7) The following objects have had their DESCRIPTION 56 | clause modified to remove the text that suggested 57 | (using 'should' verb) initializing the counter 58 | to zero on a transition to the established state: 59 | bgpPeerInUpdates, bgpPeerOutUpdates, 60 | bgpPeerInTotalMessages, bgpPeerOutTotalMessages 61 | Those implementations that still do this are 62 | still compliant with this new wording. 63 | Applications should not assume counters have 64 | started at zero. 65 | 66 | Published as RFC 4273." 67 | 68 | REVISION "199405050000Z" 69 | DESCRIPTION 70 | "Translated to SMIv2 and published as RFC 1657." 71 | 72 | REVISION "199110261839Z" 73 | DESCRIPTION 74 | "Initial version, published as RFC 1269." 75 | ::= { mib-2 15 } 76 | 77 | bgpVersion OBJECT-TYPE 78 | SYNTAX OCTET STRING (SIZE (1..255)) 79 | MAX-ACCESS read-only 80 | STATUS current 81 | DESCRIPTION 82 | "Vector of supported BGP protocol version 83 | numbers. Each peer negotiates the version 84 | from this vector. Versions are identified 85 | via the string of bits contained within this 86 | object. The first octet contains bits 0 to 87 | 7, the second octet contains bits 8 to 15, 88 | and so on, with the most significant bit 89 | referring to the lowest bit number in the 90 | octet (e.g., the MSB of the first octet 91 | refers to bit 0). If a bit, i, is present 92 | and set, then the version (i+1) of the BGP 93 | is supported." 94 | REFERENCE 95 | "RFC 4271, Section 4.2." 96 | ::= { bgp 1 } 97 | 98 | bgpLocalAs OBJECT-TYPE 99 | SYNTAX Integer32 (0..65535) 100 | MAX-ACCESS read-only 101 | STATUS current 102 | DESCRIPTION 103 | "The local autonomous system number." 104 | REFERENCE 105 | "RFC 4271, Section 4.2, 'My Autonomous System'." 106 | ::= { bgp 2 } 107 | 108 | -- BGP Peer table. This table contains, one entry per 109 | -- BGP peer, information about the BGP peer. 110 | 111 | bgpPeerTable OBJECT-TYPE 112 | SYNTAX SEQUENCE OF BgpPeerEntry 113 | MAX-ACCESS not-accessible 114 | STATUS current 115 | DESCRIPTION 116 | "BGP peer table. This table contains, 117 | one entry per BGP peer, information about the 118 | connections with BGP peers." 119 | ::= { bgp 3 } 120 | 121 | bgpPeerEntry OBJECT-TYPE 122 | SYNTAX BgpPeerEntry 123 | MAX-ACCESS not-accessible 124 | STATUS current 125 | DESCRIPTION 126 | "Entry containing information about the 127 | connection with a BGP peer." 128 | INDEX { bgpPeerRemoteAddr } 129 | ::= { bgpPeerTable 1 } 130 | 131 | BgpPeerEntry ::= SEQUENCE { 132 | bgpPeerIdentifier 133 | IpAddress, 134 | bgpPeerState 135 | INTEGER, 136 | bgpPeerAdminStatus 137 | INTEGER, 138 | bgpPeerNegotiatedVersion 139 | Integer32, 140 | bgpPeerLocalAddr 141 | IpAddress, 142 | bgpPeerLocalPort 143 | Integer32, 144 | bgpPeerRemoteAddr 145 | IpAddress, 146 | bgpPeerRemotePort 147 | Integer32, 148 | bgpPeerRemoteAs 149 | Integer32, 150 | bgpPeerInUpdates 151 | Counter32, 152 | bgpPeerOutUpdates 153 | Counter32, 154 | bgpPeerInTotalMessages 155 | Counter32, 156 | bgpPeerOutTotalMessages 157 | Counter32, 158 | bgpPeerLastError 159 | OCTET STRING, 160 | bgpPeerFsmEstablishedTransitions 161 | Counter32, 162 | bgpPeerFsmEstablishedTime 163 | Gauge32, 164 | bgpPeerConnectRetryInterval 165 | Integer32, 166 | bgpPeerHoldTime 167 | Integer32, 168 | bgpPeerKeepAlive 169 | Integer32, 170 | bgpPeerHoldTimeConfigured 171 | Integer32, 172 | bgpPeerKeepAliveConfigured 173 | Integer32, 174 | bgpPeerMinASOriginationInterval 175 | Integer32, 176 | bgpPeerMinRouteAdvertisementInterval 177 | Integer32, 178 | bgpPeerInUpdateElapsedTime 179 | Gauge32 180 | } 181 | 182 | bgpPeerIdentifier OBJECT-TYPE 183 | SYNTAX IpAddress 184 | MAX-ACCESS read-only 185 | STATUS current 186 | DESCRIPTION 187 | "The BGP Identifier of this entry's BGP peer. 188 | This entry MUST be 0.0.0.0 unless the 189 | bgpPeerState is in the openconfirm or the 190 | established state." 191 | REFERENCE 192 | "RFC 4271, Section 4.2, 'BGP Identifier'." 193 | ::= { bgpPeerEntry 1 } 194 | 195 | bgpPeerState OBJECT-TYPE 196 | SYNTAX INTEGER { 197 | idle(1), 198 | connect(2), 199 | active(3), 200 | opensent(4), 201 | openconfirm(5), 202 | established(6) 203 | } 204 | MAX-ACCESS read-only 205 | STATUS current 206 | DESCRIPTION 207 | "The BGP peer connection state." 208 | REFERENCE 209 | "RFC 4271, Section 8.2.2." 210 | ::= { bgpPeerEntry 2 } 211 | 212 | bgpPeerAdminStatus OBJECT-TYPE 213 | SYNTAX INTEGER { 214 | stop(1), 215 | start(2) 216 | } 217 | MAX-ACCESS read-write 218 | STATUS current 219 | DESCRIPTION 220 | "The desired state of the BGP connection. 221 | A transition from 'stop' to 'start' will cause 222 | the BGP Manual Start Event to be generated. 223 | A transition from 'start' to 'stop' will cause 224 | the BGP Manual Stop Event to be generated. 225 | This parameter can be used to restart BGP peer 226 | connections. Care should be used in providing 227 | write access to this object without adequate 228 | authentication." 229 | REFERENCE 230 | "RFC 4271, Section 8.1.2." 231 | ::= { bgpPeerEntry 3 } 232 | 233 | bgpPeerNegotiatedVersion OBJECT-TYPE 234 | SYNTAX Integer32 235 | MAX-ACCESS read-only 236 | STATUS current 237 | DESCRIPTION 238 | "The negotiated version of BGP running between 239 | the two peers. 240 | 241 | This entry MUST be zero (0) unless the 242 | bgpPeerState is in the openconfirm or the 243 | established state. 244 | 245 | Note that legal values for this object are 246 | between 0 and 255." 247 | REFERENCE 248 | "RFC 4271, Section 4.2. 249 | RFC 4271, Section 7." 250 | ::= { bgpPeerEntry 4 } 251 | 252 | bgpPeerLocalAddr OBJECT-TYPE 253 | SYNTAX IpAddress 254 | MAX-ACCESS read-only 255 | STATUS current 256 | DESCRIPTION 257 | "The local IP address of this entry's BGP 258 | connection." 259 | ::= { bgpPeerEntry 5 } 260 | 261 | bgpPeerLocalPort OBJECT-TYPE 262 | SYNTAX Integer32 (0..65535) 263 | MAX-ACCESS read-only 264 | STATUS current 265 | DESCRIPTION 266 | "The local port for the TCP connection between 267 | the BGP peers." 268 | ::= { bgpPeerEntry 6 } 269 | 270 | bgpPeerRemoteAddr OBJECT-TYPE 271 | SYNTAX IpAddress 272 | MAX-ACCESS read-only 273 | STATUS current 274 | DESCRIPTION 275 | "The remote IP address of this entry's BGP 276 | peer." 277 | ::= { bgpPeerEntry 7 } 278 | 279 | bgpPeerRemotePort OBJECT-TYPE 280 | SYNTAX Integer32 (0..65535) 281 | MAX-ACCESS read-only 282 | STATUS current 283 | DESCRIPTION 284 | "The remote port for the TCP connection 285 | between the BGP peers. Note that the 286 | objects bgpPeerLocalAddr, 287 | bgpPeerLocalPort, bgpPeerRemoteAddr, and 288 | bgpPeerRemotePort provide the appropriate 289 | reference to the standard MIB TCP 290 | connection table." 291 | ::= { bgpPeerEntry 8 } 292 | 293 | bgpPeerRemoteAs OBJECT-TYPE 294 | SYNTAX Integer32 (0..65535) 295 | MAX-ACCESS read-only 296 | STATUS current 297 | DESCRIPTION 298 | "The remote autonomous system number received in 299 | the BGP OPEN message." 300 | REFERENCE 301 | "RFC 4271, Section 4.2." 302 | ::= { bgpPeerEntry 9 } 303 | 304 | bgpPeerInUpdates OBJECT-TYPE 305 | SYNTAX Counter32 306 | MAX-ACCESS read-only 307 | STATUS current 308 | DESCRIPTION 309 | "The number of BGP UPDATE messages 310 | received on this connection." 311 | REFERENCE 312 | "RFC 4271, Section 4.3." 313 | ::= { bgpPeerEntry 10 } 314 | 315 | bgpPeerOutUpdates OBJECT-TYPE 316 | SYNTAX Counter32 317 | MAX-ACCESS read-only 318 | STATUS current 319 | DESCRIPTION 320 | "The number of BGP UPDATE messages 321 | transmitted on this connection." 322 | REFERENCE 323 | "RFC 4271, Section 4.3." 324 | ::= { bgpPeerEntry 11 } 325 | 326 | bgpPeerInTotalMessages OBJECT-TYPE 327 | SYNTAX Counter32 328 | MAX-ACCESS read-only 329 | STATUS current 330 | DESCRIPTION 331 | "The total number of messages received 332 | from the remote peer on this connection." 333 | REFERENCE 334 | "RFC 4271, Section 4." 335 | ::= { bgpPeerEntry 12 } 336 | 337 | bgpPeerOutTotalMessages OBJECT-TYPE 338 | SYNTAX Counter32 339 | MAX-ACCESS read-only 340 | STATUS current 341 | DESCRIPTION 342 | "The total number of messages transmitted to 343 | the remote peer on this connection." 344 | REFERENCE 345 | "RFC 4271, Section 4." 346 | ::= { bgpPeerEntry 13 } 347 | 348 | bgpPeerLastError OBJECT-TYPE 349 | SYNTAX OCTET STRING (SIZE (2)) 350 | MAX-ACCESS read-only 351 | STATUS current 352 | DESCRIPTION 353 | "The last error code and subcode seen by this 354 | peer on this connection. If no error has 355 | occurred, this field is zero. Otherwise, the 356 | first byte of this two byte OCTET STRING 357 | contains the error code, and the second byte 358 | contains the subcode." 359 | REFERENCE 360 | "RFC 4271, Section 4.5." 361 | ::= { bgpPeerEntry 14 } 362 | 363 | bgpPeerFsmEstablishedTransitions OBJECT-TYPE 364 | SYNTAX Counter32 365 | MAX-ACCESS read-only 366 | STATUS current 367 | DESCRIPTION 368 | "The total number of times the BGP FSM 369 | transitioned into the established state 370 | for this peer." 371 | REFERENCE 372 | "RFC 4271, Section 8." 373 | ::= { bgpPeerEntry 15 } 374 | 375 | bgpPeerFsmEstablishedTime OBJECT-TYPE 376 | SYNTAX Gauge32 377 | UNITS "seconds" 378 | MAX-ACCESS read-only 379 | STATUS current 380 | DESCRIPTION 381 | "This timer indicates how long (in 382 | seconds) this peer has been in the 383 | established state or how long 384 | since this peer was last in the 385 | established state. It is set to zero when 386 | a new peer is configured or when the router is 387 | booted." 388 | REFERENCE 389 | "RFC 4271, Section 8." 390 | ::= { bgpPeerEntry 16 } 391 | 392 | bgpPeerConnectRetryInterval OBJECT-TYPE 393 | SYNTAX Integer32 (1..65535) 394 | UNITS "seconds" 395 | MAX-ACCESS read-write 396 | STATUS current 397 | DESCRIPTION 398 | "Time interval (in seconds) for the 399 | ConnectRetry timer. The suggested value 400 | for this timer is 120 seconds." 401 | REFERENCE 402 | "RFC 4271, Section 8.2.2. This is the value used 403 | to initialize the 'ConnectRetryTimer'." 404 | ::= { bgpPeerEntry 17 } 405 | 406 | bgpPeerHoldTime OBJECT-TYPE 407 | SYNTAX Integer32 ( 0 | 3..65535 ) 408 | UNITS "seconds" 409 | MAX-ACCESS read-only 410 | STATUS current 411 | DESCRIPTION 412 | "Time interval (in seconds) for the Hold 413 | Timer established with the peer. The 414 | value of this object is calculated by this 415 | BGP speaker, using the smaller of the 416 | values in bgpPeerHoldTimeConfigured and the 417 | Hold Time received in the OPEN message. 418 | 419 | This value must be at least three seconds 420 | if it is not zero (0). 421 | 422 | If the Hold Timer has not been established 423 | with the peer this object MUST have a value 424 | of zero (0). 425 | 426 | If the bgpPeerHoldTimeConfigured object has 427 | a value of (0), then this object MUST have a 428 | value of (0)." 429 | REFERENCE 430 | "RFC 4271, Section 4.2." 431 | ::= { bgpPeerEntry 18 } 432 | 433 | bgpPeerKeepAlive OBJECT-TYPE 434 | SYNTAX Integer32 ( 0 | 1..21845 ) 435 | UNITS "seconds" 436 | MAX-ACCESS read-only 437 | STATUS current 438 | DESCRIPTION 439 | "Time interval (in seconds) for the KeepAlive 440 | timer established with the peer. The value 441 | of this object is calculated by this BGP 442 | speaker such that, when compared with 443 | bgpPeerHoldTime, it has the same proportion 444 | that bgpPeerKeepAliveConfigured has, 445 | compared with bgpPeerHoldTimeConfigured. 446 | 447 | If the KeepAlive timer has not been established 448 | with the peer, this object MUST have a value 449 | of zero (0). 450 | 451 | If the of bgpPeerKeepAliveConfigured object 452 | has a value of (0), then this object MUST have 453 | a value of (0)." 454 | REFERENCE 455 | "RFC 4271, Section 4.4." 456 | ::= { bgpPeerEntry 19 } 457 | 458 | bgpPeerHoldTimeConfigured OBJECT-TYPE 459 | SYNTAX Integer32 ( 0 | 3..65535 ) 460 | UNITS "seconds" 461 | MAX-ACCESS read-write 462 | STATUS current 463 | DESCRIPTION 464 | "Time interval (in seconds) for the Hold Time 465 | configured for this BGP speaker with this 466 | peer. This value is placed in an OPEN 467 | message sent to this peer by this BGP 468 | speaker, and is compared with the Hold 469 | Time field in an OPEN message received 470 | from the peer when determining the Hold 471 | Time (bgpPeerHoldTime) with the peer. 472 | This value must not be less than three 473 | seconds if it is not zero (0). If it is 474 | zero (0), the Hold Time is NOT to be 475 | established with the peer. The suggested 476 | value for this timer is 90 seconds." 477 | REFERENCE 478 | "RFC 4271, Section 4.2. 479 | RFC 4271, Section 10." 480 | ::= { bgpPeerEntry 20 } 481 | 482 | bgpPeerKeepAliveConfigured OBJECT-TYPE 483 | SYNTAX Integer32 ( 0 | 1..21845 ) 484 | UNITS "seconds" 485 | MAX-ACCESS read-write 486 | STATUS current 487 | DESCRIPTION 488 | "Time interval (in seconds) for the 489 | KeepAlive timer configured for this BGP 490 | speaker with this peer. The value of this 491 | object will only determine the 492 | KEEPALIVE messages' frequency relative to 493 | the value specified in 494 | bgpPeerHoldTimeConfigured; the actual 495 | time interval for the KEEPALIVE messages is 496 | indicated by bgpPeerKeepAlive. A 497 | reasonable maximum value for this timer 498 | would be one third of that of 499 | bgpPeerHoldTimeConfigured. 500 | If the value of this object is zero (0), 501 | no periodical KEEPALIVE messages are sent 502 | to the peer after the BGP connection has 503 | been established. The suggested value for 504 | this timer is 30 seconds." 505 | REFERENCE 506 | "RFC 4271, Section 4.4. 507 | RFC 4271, Section 10." 508 | ::= { bgpPeerEntry 21 } 509 | 510 | bgpPeerMinASOriginationInterval OBJECT-TYPE 511 | SYNTAX Integer32 (1..65535) 512 | UNITS "seconds" 513 | MAX-ACCESS read-write 514 | STATUS current 515 | DESCRIPTION 516 | "Time interval (in seconds) for the 517 | MinASOriginationInterval timer. 518 | The suggested value for this timer is 15 519 | seconds." 520 | REFERENCE 521 | "RFC 4271, Section 9.2.1.2. 522 | RFC 4271, Section 10." 523 | ::= { bgpPeerEntry 22 } 524 | 525 | bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE 526 | SYNTAX Integer32 (1..65535) 527 | UNITS "seconds" 528 | MAX-ACCESS read-write 529 | STATUS current 530 | DESCRIPTION 531 | "Time interval (in seconds) for the 532 | MinRouteAdvertisementInterval timer. 533 | The suggested value for this timer is 30 534 | seconds for EBGP connections and 5 535 | seconds for IBGP connections." 536 | REFERENCE 537 | "RFC 4271, Section 9.2.1.1. 538 | RFC 4271, Section 10." 539 | ::= { bgpPeerEntry 23 } 540 | 541 | bgpPeerInUpdateElapsedTime OBJECT-TYPE 542 | SYNTAX Gauge32 543 | UNITS "seconds" 544 | MAX-ACCESS read-only 545 | STATUS current 546 | DESCRIPTION 547 | "Elapsed time (in seconds) since the last BGP 548 | UPDATE message was received from the peer. 549 | Each time bgpPeerInUpdates is incremented, 550 | the value of this object is set to zero (0)." 551 | REFERENCE 552 | "RFC 4271, Section 4.3. 553 | RFC 4271, Section 8.2.2, Established state." 554 | ::= { bgpPeerEntry 24 } 555 | 556 | bgpIdentifier OBJECT-TYPE 557 | SYNTAX IpAddress 558 | MAX-ACCESS read-only 559 | STATUS current 560 | DESCRIPTION 561 | "The BGP Identifier of the local system." 562 | REFERENCE 563 | "RFC 4271, Section 4.2." 564 | ::= { bgp 4 } 565 | 566 | -- BGP Received Path Attribute Table. This table contains 567 | -- one entry per path to a network, and path attributes 568 | -- received from all peers running BGP version 3 or less. 569 | -- This table is obsolete, having been replaced in 570 | -- functionality by the bgp4PathAttrTable. 571 | 572 | bgpRcvdPathAttrTable OBJECT-TYPE 573 | SYNTAX SEQUENCE OF BgpPathAttrEntry 574 | MAX-ACCESS not-accessible 575 | STATUS obsolete 576 | DESCRIPTION 577 | "The BGP Received Path Attribute Table 578 | contains information about paths to 579 | destination networks, received from all 580 | peers running BGP version 3 or less." 581 | ::= { bgp 5 } 582 | 583 | bgpPathAttrEntry OBJECT-TYPE 584 | SYNTAX BgpPathAttrEntry 585 | MAX-ACCESS not-accessible 586 | STATUS obsolete 587 | DESCRIPTION 588 | "Information about a path to a network." 589 | INDEX { bgpPathAttrDestNetwork, 590 | bgpPathAttrPeer } 591 | ::= { bgpRcvdPathAttrTable 1 } 592 | 593 | BgpPathAttrEntry ::= SEQUENCE { 594 | bgpPathAttrPeer 595 | IpAddress, 596 | bgpPathAttrDestNetwork 597 | IpAddress, 598 | bgpPathAttrOrigin 599 | INTEGER, 600 | bgpPathAttrASPath 601 | OCTET STRING, 602 | bgpPathAttrNextHop 603 | IpAddress, 604 | bgpPathAttrInterASMetric 605 | Integer32 606 | } 607 | 608 | bgpPathAttrPeer OBJECT-TYPE 609 | SYNTAX IpAddress 610 | MAX-ACCESS read-only 611 | STATUS obsolete 612 | DESCRIPTION 613 | "The IP address of the peer where the path 614 | information was learned." 615 | ::= { bgpPathAttrEntry 1 } 616 | 617 | bgpPathAttrDestNetwork OBJECT-TYPE 618 | SYNTAX IpAddress 619 | MAX-ACCESS read-only 620 | STATUS obsolete 621 | DESCRIPTION 622 | "The address of the destination network." 623 | REFERENCE 624 | "RFC 1267, Section 4.3." 625 | ::= { bgpPathAttrEntry 2 } 626 | 627 | bgpPathAttrOrigin OBJECT-TYPE 628 | SYNTAX INTEGER { 629 | igp(1),-- networks are interior 630 | egp(2),-- networks learned via the 631 | -- EGP protocol 632 | incomplete(3) -- networks that 633 | -- are learned by some other 634 | -- means 635 | } 636 | MAX-ACCESS read-only 637 | STATUS obsolete 638 | DESCRIPTION 639 | "The ultimate origin of the path information." 640 | REFERENCE 641 | "RFC 1267, Section 4.3. 642 | RFC 1267, Section 5." 643 | ::= { bgpPathAttrEntry 3 } 644 | 645 | bgpPathAttrASPath OBJECT-TYPE 646 | SYNTAX OCTET STRING (SIZE (2..255)) 647 | MAX-ACCESS read-only 648 | STATUS obsolete 649 | DESCRIPTION 650 | "The set of ASes that must be traversed to reach 651 | the network. This object is probably best 652 | represented as SEQUENCE OF INTEGER. For SMI 653 | compatibility, though, it is represented as 654 | OCTET STRING. Each AS is represented as a pair 655 | of octets according to the following algorithm: 656 | 657 | first-byte-of-pair = ASNumber / 256; 658 | second-byte-of-pair = ASNumber & 255;" 659 | REFERENCE 660 | "RFC 1267, Section 4.3. 661 | RFC 1267, Section 5." 662 | ::= { bgpPathAttrEntry 4 } 663 | 664 | bgpPathAttrNextHop OBJECT-TYPE 665 | SYNTAX IpAddress 666 | MAX-ACCESS read-only 667 | STATUS obsolete 668 | DESCRIPTION 669 | "The address of the border router that should 670 | be used for the destination network." 671 | REFERENCE 672 | "RFC 1267, Section 4.3. 673 | RFC 1267, Section 5." 674 | ::= { bgpPathAttrEntry 5 } 675 | 676 | bgpPathAttrInterASMetric OBJECT-TYPE 677 | SYNTAX Integer32 678 | MAX-ACCESS read-only 679 | STATUS obsolete 680 | DESCRIPTION 681 | "The optional inter-AS metric. If this 682 | attribute has not been provided for this route, 683 | the value for this object is 0." 684 | REFERENCE 685 | "RFC 1267, Section 4.3. 686 | RFC 1267, Section 5." 687 | ::= { bgpPathAttrEntry 6 } 688 | 689 | -- BGP-4 Received Path Attribute Table. This table 690 | -- contains one entry per path to a network, and path 691 | -- attributes received from all peers running BGP-4. 692 | 693 | bgp4PathAttrTable OBJECT-TYPE 694 | SYNTAX SEQUENCE OF Bgp4PathAttrEntry 695 | MAX-ACCESS not-accessible 696 | STATUS current 697 | DESCRIPTION 698 | "The BGP-4 Received Path Attribute Table 699 | contains information about paths to 700 | destination networks, received from all 701 | BGP4 peers." 702 | ::= { bgp 6 } 703 | 704 | bgp4PathAttrEntry OBJECT-TYPE 705 | SYNTAX Bgp4PathAttrEntry 706 | MAX-ACCESS not-accessible 707 | STATUS current 708 | DESCRIPTION 709 | "Information about a path to a network." 710 | INDEX { bgp4PathAttrIpAddrPrefix, 711 | bgp4PathAttrIpAddrPrefixLen, 712 | bgp4PathAttrPeer } 713 | ::= { bgp4PathAttrTable 1 } 714 | 715 | Bgp4PathAttrEntry ::= SEQUENCE { 716 | bgp4PathAttrPeer 717 | IpAddress, 718 | bgp4PathAttrIpAddrPrefixLen 719 | Integer32, 720 | bgp4PathAttrIpAddrPrefix 721 | IpAddress, 722 | bgp4PathAttrOrigin 723 | INTEGER, 724 | 725 | bgp4PathAttrASPathSegment 726 | OCTET STRING, 727 | bgp4PathAttrNextHop 728 | IpAddress, 729 | bgp4PathAttrMultiExitDisc 730 | Integer32, 731 | bgp4PathAttrLocalPref 732 | Integer32, 733 | bgp4PathAttrAtomicAggregate 734 | INTEGER, 735 | bgp4PathAttrAggregatorAS 736 | Integer32, 737 | bgp4PathAttrAggregatorAddr 738 | IpAddress, 739 | bgp4PathAttrCalcLocalPref 740 | Integer32, 741 | bgp4PathAttrBest 742 | INTEGER, 743 | bgp4PathAttrUnknown 744 | OCTET STRING 745 | } 746 | 747 | bgp4PathAttrPeer OBJECT-TYPE 748 | SYNTAX IpAddress 749 | MAX-ACCESS read-only 750 | STATUS current 751 | DESCRIPTION 752 | "The IP address of the peer where the path 753 | information was learned." 754 | ::= { bgp4PathAttrEntry 1 } 755 | 756 | bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE 757 | SYNTAX Integer32 (0..32) 758 | MAX-ACCESS read-only 759 | STATUS current 760 | DESCRIPTION 761 | "Length in bits of the IP address prefix in 762 | the Network Layer Reachability 763 | Information field." 764 | ::= { bgp4PathAttrEntry 2 } 765 | 766 | bgp4PathAttrIpAddrPrefix OBJECT-TYPE 767 | SYNTAX IpAddress 768 | MAX-ACCESS read-only 769 | STATUS current 770 | DESCRIPTION 771 | "An IP address prefix in the Network Layer 772 | Reachability Information field. This object 773 | is an IP address containing the prefix with 774 | length specified by 775 | bgp4PathAttrIpAddrPrefixLen. 776 | Any bits beyond the length specified by 777 | bgp4PathAttrIpAddrPrefixLen are zeroed." 778 | REFERENCE 779 | "RFC 4271, Section 4.3." 780 | ::= { bgp4PathAttrEntry 3 } 781 | 782 | bgp4PathAttrOrigin OBJECT-TYPE 783 | SYNTAX INTEGER { 784 | igp(1),-- networks are interior 785 | egp(2),-- networks learned via the 786 | -- EGP protocol 787 | incomplete(3) -- networks that 788 | -- are learned by some other 789 | -- means 790 | } 791 | MAX-ACCESS read-only 792 | STATUS current 793 | DESCRIPTION 794 | "The ultimate origin of the path 795 | information." 796 | REFERENCE 797 | "RFC 4271, Section 4.3. 798 | RFC 4271, Section 5.1.1." 799 | ::= { bgp4PathAttrEntry 4 } 800 | 801 | bgp4PathAttrASPathSegment OBJECT-TYPE 802 | SYNTAX OCTET STRING (SIZE (2..255)) 803 | MAX-ACCESS read-only 804 | STATUS current 805 | DESCRIPTION 806 | "The sequence of AS path segments. Each AS 807 | path segment is represented by a triple 808 | . 809 | 810 | The type is a 1-octet field that has two 811 | possible values: 812 | 1 AS_SET: unordered set of ASes that a 813 | route in the UPDATE message 814 | has traversed 815 | 816 | 2 AS_SEQUENCE: ordered set of ASes that 817 | a route in the UPDATE message 818 | has traversed. 819 | 820 | The length is a 1-octet field containing the 821 | number of ASes in the value field. 822 | 823 | The value field contains one or more AS 824 | numbers. Each AS is represented in the octet 825 | string as a pair of octets according to the 826 | following algorithm: 827 | 828 | first-byte-of-pair = ASNumber / 256; 829 | second-byte-of-pair = ASNumber & 255; 830 | 831 | Known Issues: 832 | o BGP Confederations will result in 833 | a type of either 3 or 4. 834 | o An AS Path may be longer than 255 octets. 835 | This may result in this object containing 836 | a truncated AS Path." 837 | REFERENCE 838 | "RFC 4271, Section 4.3. 839 | RFC 4271, Section 5.1.2." 840 | ::= { bgp4PathAttrEntry 5 } 841 | 842 | bgp4PathAttrNextHop OBJECT-TYPE 843 | SYNTAX IpAddress 844 | MAX-ACCESS read-only 845 | STATUS current 846 | DESCRIPTION 847 | "The address of the border router that 848 | should be used for the destination 849 | network. This address is the NEXT_HOP 850 | address received in the UPDATE packet." 851 | REFERENCE 852 | "RFC 4271, Section 4.3. 853 | RFC 4271, Section 5.1.3." 854 | ::= { bgp4PathAttrEntry 6 } 855 | 856 | bgp4PathAttrMultiExitDisc OBJECT-TYPE 857 | SYNTAX Integer32 (-1..2147483647) 858 | MAX-ACCESS read-only 859 | STATUS current 860 | DESCRIPTION 861 | "This metric is used to discriminate 862 | between multiple exit points to an 863 | adjacent autonomous system. A value of -1 864 | indicates the absence of this attribute. 865 | 866 | Known Issues: 867 | o The BGP-4 specification uses an 868 | unsigned 32 bit number. Thus, this 869 | object cannot represent the full 870 | range of the protocol." 871 | REFERENCE 872 | "RFC 4271, Section 4.3. 873 | RFC 4271, Section 5.1.4." 874 | ::= { bgp4PathAttrEntry 7 } 875 | 876 | bgp4PathAttrLocalPref OBJECT-TYPE 877 | SYNTAX Integer32 (-1..2147483647) 878 | MAX-ACCESS read-only 879 | STATUS current 880 | DESCRIPTION 881 | "The originating BGP4 speaker's degree of 882 | preference for an advertised route. A 883 | value of -1 indicates the absence of this 884 | attribute. 885 | 886 | Known Issues: 887 | o The BGP-4 specification uses an 888 | unsigned 32 bit number and thus this 889 | object cannot represent the full 890 | range of the protocol." 891 | REFERENCE 892 | "RFC 4271, Section 4.3. 893 | RFC 4271, Section 5.1.5." 894 | ::= { bgp4PathAttrEntry 8 } 895 | 896 | bgp4PathAttrAtomicAggregate OBJECT-TYPE 897 | SYNTAX INTEGER { 898 | lessSpecificRouteNotSelected(1), 899 | -- Typo corrected from RFC 1657 900 | lessSpecificRouteSelected(2) 901 | } 902 | MAX-ACCESS read-only 903 | STATUS current 904 | DESCRIPTION 905 | "If the ATOMIC_AGGREGATE attribute is present 906 | in the Path Attributes then this object MUST 907 | have a value of 'lessSpecificRouteNotSelected'. 908 | 909 | If the ATOMIC_AGGREGATE attribute is missing 910 | in the Path Attributes then this object MUST 911 | have a value of 'lessSpecificRouteSelected'. 912 | 913 | Note that ATOMIC_AGGREGATE is now a primarily 914 | informational attribute." 915 | REFERENCE 916 | "RFC 4271, Sections 5.1.6 and 9.1.4." 917 | ::= { bgp4PathAttrEntry 9 } 918 | 919 | bgp4PathAttrAggregatorAS OBJECT-TYPE 920 | SYNTAX Integer32 (0..65535) 921 | MAX-ACCESS read-only 922 | STATUS current 923 | DESCRIPTION 924 | "The AS number of the last BGP4 speaker that 925 | performed route aggregation. A value of 926 | zero (0) indicates the absence of this 927 | attribute. 928 | 929 | Note that propagation of AS of zero is illegal 930 | in the Internet." 931 | REFERENCE 932 | "RFC 4271, Section 5.1.7. 933 | RFC 4271, Section 9.2.2.2." 934 | ::= { bgp4PathAttrEntry 10 } 935 | 936 | bgp4PathAttrAggregatorAddr OBJECT-TYPE 937 | SYNTAX IpAddress 938 | MAX-ACCESS read-only 939 | STATUS current 940 | DESCRIPTION 941 | "The IP address of the last BGP4 speaker 942 | that performed route aggregation. A 943 | value of 0.0.0.0 indicates the absence 944 | of this attribute." 945 | REFERENCE 946 | "RFC 4271, Section 5.1.7. 947 | RFC 4271, Section 9.2.2.2." 948 | ::= { bgp4PathAttrEntry 11 } 949 | 950 | bgp4PathAttrCalcLocalPref OBJECT-TYPE 951 | SYNTAX Integer32 (-1..2147483647) 952 | MAX-ACCESS read-only 953 | STATUS current 954 | DESCRIPTION 955 | "The degree of preference calculated by the 956 | receiving BGP4 speaker for an advertised 957 | route. A value of -1 indicates the 958 | absence of this attribute. 959 | 960 | Known Issues: 961 | o The BGP-4 specification uses an 962 | unsigned 32 bit number and thus this 963 | object cannot represent the full 964 | range of the protocol." 965 | 966 | REFERENCE 967 | "RFC 4271, Section 9.1.1." 968 | ::= { bgp4PathAttrEntry 12 } 969 | 970 | bgp4PathAttrBest OBJECT-TYPE 971 | SYNTAX INTEGER { 972 | false(1),-- not chosen as best route 973 | true(2) -- chosen as best route 974 | } 975 | MAX-ACCESS read-only 976 | STATUS current 977 | DESCRIPTION 978 | "An indication of whether this route 979 | was chosen as the best BGP4 route for this 980 | destination." 981 | REFERENCE 982 | "RFC 4271, Section 9.1.2." 983 | ::= { bgp4PathAttrEntry 13 } 984 | 985 | bgp4PathAttrUnknown OBJECT-TYPE 986 | SYNTAX OCTET STRING (SIZE(0..255)) 987 | MAX-ACCESS read-only 988 | STATUS current 989 | DESCRIPTION 990 | "One or more path attributes not understood by 991 | this BGP4 speaker. 992 | 993 | Path attributes are recorded in the Update Path 994 | attribute format of type, length, value. 995 | 996 | Size zero (0) indicates the absence of such 997 | attributes. 998 | 999 | Octets beyond the maximum size, if any, are not 1000 | recorded by this object. 1001 | 1002 | Known Issues: 1003 | o Attributes understood by this speaker, but not 1004 | represented in this MIB, are unavailable to 1005 | the agent." 1006 | REFERENCE 1007 | "RFC 4271, Section 5." 1008 | ::= { bgp4PathAttrEntry 14 } 1009 | 1010 | -- Traps. 1011 | -- Note that in RFC 1657, bgpTraps was incorrectly 1012 | -- assigned a value of { bgp 7 } and each of the 1013 | -- traps had the bgpPeerRemoteAddr object inappropriately 1014 | -- removed from their OBJECTS clause. The following 1015 | -- definitions restore the semantics of the traps as 1016 | -- they were initially defined in RFC 1269. 1017 | 1018 | bgpNotification OBJECT IDENTIFIER ::= { bgp 0 } 1019 | 1020 | bgpEstablishedNotification NOTIFICATION-TYPE 1021 | OBJECTS { bgpPeerRemoteAddr, 1022 | bgpPeerLastError, 1023 | bgpPeerState } 1024 | STATUS current 1025 | DESCRIPTION 1026 | "The bgpEstablishedNotification event is generated 1027 | when the BGP FSM enters the established state. 1028 | 1029 | This Notification replaces the bgpEstablished 1030 | Notification." 1031 | ::= { bgpNotification 1 } 1032 | 1033 | bgpBackwardTransNotification NOTIFICATION-TYPE 1034 | OBJECTS { bgpPeerRemoteAddr, 1035 | bgpPeerLastError, 1036 | bgpPeerState } 1037 | STATUS current 1038 | DESCRIPTION 1039 | "The bgpBackwardTransNotification event is 1040 | generated when the BGP FSM moves from a higher 1041 | numbered state to a lower numbered state. 1042 | 1043 | This Notification replaces the 1044 | bgpBackwardsTransition Notification." 1045 | ::= { bgpNotification 2 } 1046 | 1047 | -- { bgp 7 } is deprecated. Do not allocate new objects or 1048 | -- notifications underneath this branch. 1049 | 1050 | bgpTraps OBJECT IDENTIFIER ::= { bgp 7 } -- deprecated 1051 | 1052 | bgpEstablished NOTIFICATION-TYPE 1053 | OBJECTS { bgpPeerLastError, 1054 | bgpPeerState } 1055 | STATUS deprecated 1056 | DESCRIPTION 1057 | "The bgpEstablished event is generated when 1058 | the BGP FSM enters the established state. 1059 | 1060 | This Notification has been replaced by the 1061 | bgpEstablishedNotification Notification." 1062 | ::= { bgpTraps 1 } 1063 | 1064 | bgpBackwardTransition NOTIFICATION-TYPE 1065 | OBJECTS { bgpPeerLastError, 1066 | bgpPeerState } 1067 | STATUS deprecated 1068 | DESCRIPTION 1069 | "The bgpBackwardTransition event is generated 1070 | when the BGP FSM moves from a higher numbered 1071 | state to a lower numbered state. 1072 | 1073 | This Notification has been replaced by the 1074 | bgpBackwardTransNotification Notification." 1075 | ::= { bgpTraps 2 } 1076 | 1077 | -- Conformance information 1078 | 1079 | bgp4MIBConformance OBJECT IDENTIFIER 1080 | ::= { bgp 8 } 1081 | bgp4MIBCompliances OBJECT IDENTIFIER 1082 | ::= { bgp4MIBConformance 1 } 1083 | bgp4MIBGroups OBJECT IDENTIFIER 1084 | ::= { bgp4MIBConformance 2 } 1085 | 1086 | -- Compliance statements 1087 | 1088 | bgp4MIBCompliance MODULE-COMPLIANCE 1089 | STATUS current 1090 | DESCRIPTION 1091 | "The compliance statement for entities which 1092 | implement the BGP4 mib." 1093 | MODULE -- this module 1094 | MANDATORY-GROUPS { bgp4MIBGlobalsGroup, 1095 | bgp4MIBPeerGroup, 1096 | bgp4MIBPathAttrGroup } 1097 | GROUP bgp4MIBNotificationGroup 1098 | DESCRIPTION 1099 | "Implementation of BGP Notifications are 1100 | completely optional in this MIB." 1101 | ::= { bgp4MIBCompliances 1 } 1102 | 1103 | bgp4MIBDeprecatedCompliances MODULE-COMPLIANCE 1104 | STATUS deprecated 1105 | DESCRIPTION 1106 | "The compliance statement documenting deprecated 1107 | objects in the BGP4 mib." 1108 | MODULE -- this module 1109 | GROUP bgp4MIBTrapGroup 1110 | DESCRIPTION 1111 | "Group containing TRAP objects that were 1112 | improperly converted from SMIv1 in RFC 1657. 1113 | The proper semantics have been restored 1114 | with the objects in bgp4MIBNotificationGroup." 1115 | ::= { bgp4MIBCompliances 2 } 1116 | 1117 | bgp4MIBObsoleteCompliances MODULE-COMPLIANCE 1118 | STATUS obsolete 1119 | DESCRIPTION 1120 | "The compliance statement documenting obsolete 1121 | objects in the BGP4 mib." 1122 | MODULE -- this module 1123 | GROUP bgpRcvdPathAttrGroup 1124 | DESCRIPTION 1125 | "Group containing objects relevant to BGP-3 1126 | and earlier objects." 1127 | ::= { bgp4MIBCompliances 3 } 1128 | 1129 | -- Units of conformance 1130 | 1131 | bgp4MIBGlobalsGroup OBJECT-GROUP 1132 | OBJECTS { bgpVersion, 1133 | bgpLocalAs, 1134 | bgpIdentifier } 1135 | STATUS current 1136 | DESCRIPTION 1137 | "A collection of objects providing 1138 | information on global BGP state." 1139 | ::= { bgp4MIBGroups 1 } 1140 | 1141 | bgp4MIBPeerGroup OBJECT-GROUP 1142 | OBJECTS { bgpPeerIdentifier, 1143 | bgpPeerState, 1144 | bgpPeerAdminStatus, 1145 | bgpPeerNegotiatedVersion, 1146 | bgpPeerLocalAddr, 1147 | bgpPeerLocalPort, 1148 | bgpPeerRemoteAddr, 1149 | bgpPeerRemotePort, 1150 | bgpPeerRemoteAs, 1151 | bgpPeerInUpdates, 1152 | bgpPeerOutUpdates, 1153 | bgpPeerInTotalMessages, 1154 | bgpPeerOutTotalMessages, 1155 | bgpPeerLastError, 1156 | bgpPeerFsmEstablishedTransitions, 1157 | bgpPeerFsmEstablishedTime, 1158 | bgpPeerConnectRetryInterval, 1159 | bgpPeerHoldTime, 1160 | bgpPeerKeepAlive, 1161 | bgpPeerHoldTimeConfigured, 1162 | bgpPeerKeepAliveConfigured, 1163 | bgpPeerMinASOriginationInterval, 1164 | bgpPeerMinRouteAdvertisementInterval, 1165 | bgpPeerInUpdateElapsedTime } 1166 | STATUS current 1167 | DESCRIPTION 1168 | "A collection of objects for managing 1169 | BGP peers." 1170 | ::= { bgp4MIBGroups 2 } 1171 | 1172 | bgpRcvdPathAttrGroup OBJECT-GROUP 1173 | OBJECTS { bgpPathAttrPeer, 1174 | bgpPathAttrDestNetwork, 1175 | bgpPathAttrOrigin, 1176 | bgpPathAttrASPath, 1177 | bgpPathAttrNextHop, 1178 | bgpPathAttrInterASMetric } 1179 | STATUS obsolete 1180 | DESCRIPTION 1181 | "A collection of objects for managing BGP-3 and 1182 | earlier path entries. 1183 | 1184 | This conformance group, like BGP-3, is obsolete." 1185 | ::= { bgp4MIBGroups 3 } 1186 | 1187 | bgp4MIBPathAttrGroup OBJECT-GROUP 1188 | OBJECTS { bgp4PathAttrPeer, 1189 | bgp4PathAttrIpAddrPrefixLen, 1190 | bgp4PathAttrIpAddrPrefix, 1191 | bgp4PathAttrOrigin, 1192 | bgp4PathAttrASPathSegment, 1193 | bgp4PathAttrNextHop, 1194 | bgp4PathAttrMultiExitDisc, 1195 | bgp4PathAttrLocalPref, 1196 | bgp4PathAttrAtomicAggregate, 1197 | bgp4PathAttrAggregatorAS, 1198 | bgp4PathAttrAggregatorAddr, 1199 | bgp4PathAttrCalcLocalPref, 1200 | bgp4PathAttrBest, 1201 | bgp4PathAttrUnknown } 1202 | STATUS current 1203 | DESCRIPTION 1204 | "A collection of objects for managing 1205 | BGP path entries." 1206 | ::= { bgp4MIBGroups 4 } 1207 | 1208 | bgp4MIBTrapGroup NOTIFICATION-GROUP 1209 | NOTIFICATIONS { bgpEstablished, 1210 | bgpBackwardTransition } 1211 | STATUS deprecated 1212 | DESCRIPTION 1213 | "A collection of notifications for signaling 1214 | changes in BGP peer relationships. 1215 | 1216 | Obsoleted by bgp4MIBNotificationGroup" 1217 | ::= { bgp4MIBGroups 5 } 1218 | 1219 | bgp4MIBNotificationGroup NOTIFICATION-GROUP 1220 | NOTIFICATIONS { bgpEstablishedNotification, 1221 | bgpBackwardTransNotification } 1222 | STATUS current 1223 | DESCRIPTION 1224 | "A collection of notifications for signaling 1225 | changes in BGP peer relationships. 1226 | 1227 | Obsoletes bgp4MIBTrapGroup." 1228 | ::= { bgp4MIBGroups 6 } 1229 | 1230 | END 1231 | 1232 | -- 1233 | -- Copyright (C) The Internet Society (2006). 1234 | -- 1235 | -- This document is subject to the rights, licenses and restrictions 1236 | -- contained in BCP 78, and except as set forth therein, the authors 1237 | -- retain all their rights. 1238 | -- 1239 | -- This document and the information contained herein are provided on an 1240 | -- "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS 1241 | -- OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET 1242 | -- ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, 1243 | -- INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE 1244 | -- INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 1245 | -- WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1246 | -- 1247 | -- Intellectual Property 1248 | -- 1249 | -- The IETF takes no position regarding the validity or scope of any 1250 | -- Intellectual Property Rights or other rights that might be claimed to 1251 | -- pertain to the implementation or use of the technology described in 1252 | -- this document or the extent to which any license under such rights 1253 | -- might or might not be available; nor does it represent that it has 1254 | -- made any independent effort to identify any such rights. Information 1255 | -- on the procedures with respect to rights in RFC documents can be 1256 | -- found in BCP 78 and BCP 79. 1257 | -- 1258 | -- Copies of IPR disclosures made to the IETF Secretariat and any 1259 | -- assurances of licenses to be made available, or the result of an 1260 | -- attempt made to obtain a general license or permission for the use of 1261 | -- such proprietary rights by implementers or users of this 1262 | -- specification can be obtained from the IETF on-line IPR repository at 1263 | -- http://www.ietf.org/ipr. 1264 | -- 1265 | -- The IETF invites any interested party to bring to its attention any 1266 | -- copyrights, patents or patent applications, or other proprietary 1267 | -- rights that may cover technology that may be required to implement 1268 | -- this standard. Please address the information to the IETF at 1269 | -- ietf-ipr@ietf.org. 1270 | -- 1271 | 1272 | -------------------------------------------------------------------------------- /COPYING.GPLv3: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## bird-snmp-agent 2 | 3 | Based on https://github.com/carosio/bird-snmp-agent 4 | 5 | Forked by Mike Nowak (https://github.com/mikenowak) 6 | 7 | ### What? 8 | 9 | * implements an SNMP-AgentX extension for the bird-routing-daemon 10 | 11 | ### How? 12 | 13 | To collect its data this agent: 14 | 15 | * uses `birdc` CLI of bird 16 | * calls `ss` to query information about used tcp-ports 17 | * reads bird's configuration files 18 | 19 | ## Dependencies 20 | 21 | The script depends on the following libraries: 22 | * dateutil 23 | * pytz 24 | * tzlocal 25 | * future 26 | 27 | It also expects the `snmp-mibs-downloader` package. 28 | 29 | All of these can be installed on Ubuntu as follows: 30 | 31 | `apt install python3-dateutil python3-tz python3-tzlocal python3-future snmp-mibs-downloader` 32 | 33 | ## Usage 34 | 35 | ### Enable agentx support in snmp 36 | 37 | Add the following line to `snmpd.conf`: 38 | 39 | ``` 40 | master agentx 41 | agentxperms 0770 0770 root snmp # if you intend to run this as an unprivileged user 42 | ``` 43 | 44 | ### Set bird's timestamp to iso8601 long 45 | 46 | The script expect the timestamps to be in the iso8601 long format (YYYY-MM-DD HH:MM:SS) 47 | 48 | To enable this, add the following to global section of `bird.conf`: 49 | 50 | ``` 51 | timeformat base iso long; 52 | timeformat log iso long; 53 | timeformat protocol iso long; 54 | timeformat route iso long; 55 | ``` 56 | 57 | NB: Only protocol line is needed, the rest are optional, but keep the output from birdc consistent. 58 | 59 | ### Add protocols in bird 60 | 61 | The scripts expects to find both neighbour and local lines per protocol as in the example below: 62 | 63 | ``` 64 | protocol bgp PROTOCOL_NAME { 65 | neighbor 192.168.1.200 as 65502; 66 | local 192.168.1.100 as 65501; 67 | [...] 68 | } 69 | ``` 70 | 71 | ## Settings 72 | 73 | The script takes the following environment variables: 74 | 75 | * BIRDCONF path to bird.conf (defaults to '/etc/bird/bird.conf') 76 | * BIRDCLI name of birdcli exacutable (defaults to '/usr/sbin/birdc') 77 | * SSCMD ss command syntax (defaults to "ss -tan -o state established '( dport = :bgp or sport = :bgp )'") 78 | * BGPMIBFILE location of the BGP-MIB4 file (defaults to '/var/lib/mibs/ietf/BGP4-MIB') 79 | * AGENTCACHEINTERVAL how long to keep results cached in seconds (defaults to '30') 80 | 81 | 82 | ## SystemD Unit File 83 | 84 | ``` 85 | [Unit] 86 | Description=BIRD SNMP Agent 87 | After=snmp.service 88 | [Service] 89 | PermissionsStartOnly = true 90 | User = snmp 91 | Group = snmp 92 | WorkingDirectory = /usr/local/bird-snmp-agent 93 | ExecStart = /usr/bin/env python3 /usr/local/bird-snmp-agent/bird_bgp.py 94 | ExecReload = /bin/kill -s HUP $MAINPID 95 | ExecStop = /bin/kill -s TERM $MAINPID 96 | PrivateTmp = true 97 | 98 | [Install] 99 | WantedBy=multi-user.target 100 | ``` 101 | 102 | NB1: The `snmp` user needs to be a member of the `bird` group in order to query bird. 103 | 104 | NB2: If you decide to run the script as a non-provileged user the following are also needed: 105 | 106 | ``` 107 | chgrp snmp /var/agentx 108 | chmod 0750 /var/agentx 109 | ``` 110 | -------------------------------------------------------------------------------- /adv_agentx.py: -------------------------------------------------------------------------------- 1 | # python-agentx module 2 | # 3 | # Copyright (C) 2010 Bozhin Zafirov, bozhin@abv.bg 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # 20 | # some adaption for SnmpGauge32/SnmpCounter32/SnmpIpAddress support: 21 | # by Tobias Hintze 22 | # Copyright (c) 2016 Travelping GmbH 23 | # (The original was imported from http://python-agentx.sf.net at r8) 24 | # 25 | from __future__ import print_function 26 | from builtins import map 27 | from builtins import object 28 | import ctypes 29 | import ctypes.util 30 | import time 31 | import signal 32 | import os 33 | import sys 34 | import socket # for inet_aton 35 | 36 | # export names 37 | __all__ = [ 38 | 'AgentX', 39 | ] 40 | 41 | # snmp agentx library 42 | snmp = None 43 | axl = None 44 | try: 45 | snmp = ctypes.cdll.LoadLibrary(ctypes.util.find_library('netsnmphelpers')) 46 | axl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('netsnmpagent')) 47 | except BaseException: 48 | print('ERROR: agentx module requires net-snmp libraries, terminating...') 49 | sys.exit(1) 50 | 51 | # constants 52 | NETSNMP_DS_APPLICATION_ID = 1 53 | NETSNMP_DS_AGENT_ROLE = 1 54 | 55 | # ASN constants 56 | ASN_BOOLEAN = 0x01 57 | ASN_INTEGER = 0x02 58 | ASN_BIT_STR = 0x03 59 | ASN_OCTET_STR = 0x04 60 | ASN_NULL = 0x05 61 | ASN_OBJECT_ID = 0x06 62 | ASN_SEQUENCE = 0x10 63 | ASN_SET = 0x11 64 | 65 | ASN_UNIVERSAL = 0x00 66 | ASN_APPLICATION = 0x40 67 | ASN_CONTEXT = 0x80 68 | ASN_PRIVATE = 0xC0 69 | 70 | ASN_PRIMITIVE = 0x00 71 | ASN_CONSTRUCTOR = 0x20 72 | 73 | ASN_LONG_LEN = 0x80 74 | ASN_EXTENSION_ID = 0x1F 75 | ASN_BIT8 = 0x80 76 | 77 | ASN_IPADDRESS = ASN_APPLICATION | 0x0 78 | ASN_COUNTER32 = ASN_APPLICATION | 0x1 79 | ASN_UNSIGNED = ASN_APPLICATION | 0x2 80 | ASN_TIMETICKS = ASN_APPLICATION | 0x3 81 | ASN_APP_FLOAT = ASN_APPLICATION | 0x8 82 | ASN_APP_DOUBLE = ASN_APPLICATION | 0x9 83 | 84 | 85 | # python lacks some primitive types to represent 86 | # some snmp types. define some wrapper types: 87 | class SnmpGauge32(int): 88 | pass 89 | 90 | 91 | class SnmpCounter32(int): 92 | pass 93 | 94 | 95 | class SnmpIpAddress(str): 96 | pass 97 | 98 | 99 | # asn opaque 100 | ASN_OPAQUE_TAG2 = 0x30 101 | ASN_OPAQUE_FLOAT = ASN_OPAQUE_TAG2 + ASN_APP_FLOAT 102 | ASN_OPAQUE_DOUBLE = ASN_OPAQUE_TAG2 + ASN_APP_DOUBLE 103 | 104 | # handler constants 105 | HANDLER_CAN_GETANDGETNEXT = 0x01 106 | HANDLER_CAN_SET = 0x02 107 | HANDLER_CAN_GETBULK = 0x04 108 | HANDLER_CAN_NOT_CREATE = 0x08 109 | HANDLER_CAN_BABY_STEP = 0x10 110 | HANDLER_CAN_STASH = 0x20 111 | 112 | HANDLER_CAN_RONLY = HANDLER_CAN_GETANDGETNEXT 113 | HANDLER_CAN_RWRITE = HANDLER_CAN_GETANDGETNEXT | HANDLER_CAN_SET 114 | HANDLER_CAN_SET_ONLY = HANDLER_CAN_SET | HANDLER_CAN_NOT_CREATE 115 | HANDLER_CAN_DEFAULT = HANDLER_CAN_RONLY | HANDLER_CAN_NOT_CREATE 116 | 117 | SNMP_ERR_NOERROR = 0 118 | SNMP_ERR_TOOBIG = 1 119 | SNMP_ERR_NOSUCHNAME = 2 120 | SNMP_ERR_BADVALUE = 3 121 | SNMP_ERR_READONLY = 4 122 | SNMP_ERR_GENERR = 5 123 | 124 | ASN_CONSTRUCTOR = 0x20 125 | 126 | SNMP_MSG_GET = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0 127 | SNMP_MSG_GETNEXT = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1 128 | SNMP_MSG_RESPONSE = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2 129 | SNMP_MSG_SET = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x3 130 | SNMP_MSG_TRAP = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x4 131 | SNMP_MSG_GETBULK = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x5 132 | SNMP_MSG_INFORM = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x6 133 | SNMP_MSG_TRAP2 = ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7 134 | 135 | SNMP_MSG_INTERNAL_SET_BEGIN = -1 136 | SNMP_MSG_INTERNAL_SET_RESERVE1 = 0 137 | SNMP_MSG_INTERNAL_SET_RESERVE2 = 1 138 | SNMP_MSG_INTERNAL_SET_ACTION = 2 139 | SNMP_MSG_INTERNAL_SET_COMMIT = 3 140 | SNMP_MSG_INTERNAL_SET_FREE = 4 141 | SNMP_MSG_INTERNAL_SET_UNDO = 5 142 | SNMP_MSG_INTERNAL_SET_MAX = 6 143 | 144 | 145 | MAX_OID_LEN = 128 146 | OID_LEN = MAX_OID_LEN * 2 + 1 147 | 148 | # --- agentx.py constants --- 149 | PAX_RO = 0x0 150 | PAX_WO = 0x1 151 | PAX_RW = 0x2 152 | 153 | # --- low level routines --- 154 | 155 | 156 | # types 157 | # oid type definition 158 | oid_t = ctypes.c_ulong 159 | oidOID_t = oid_t * MAX_OID_LEN 160 | strOID_t = ctypes.c_char * OID_LEN 161 | 162 | 163 | # structures 164 | 165 | # dummy structures (pointers only) 166 | class netsnmp_mib_handler(ctypes.Structure): 167 | pass 168 | 169 | 170 | class netsnmp_handler_registration(ctypes.Structure): 171 | pass 172 | 173 | 174 | class netsnmp_subtree(ctypes.Structure): 175 | pass 176 | 177 | 178 | class netsnmp_agent_session(ctypes.Structure): 179 | pass 180 | 181 | 182 | class counter64(ctypes.Structure): 183 | pass 184 | 185 | 186 | class netsnmp_vardata(ctypes.Union): 187 | _fields_ = [ 188 | ('integer', ctypes.POINTER(ctypes.c_long)), 189 | ('string', ctypes.c_char_p), 190 | ('objid', ctypes.POINTER(oid_t)), 191 | ('bitstring', ctypes.POINTER(ctypes.c_ubyte)), 192 | ('counter64', ctypes.POINTER(counter64)), 193 | ('floatVal', ctypes.POINTER(ctypes.c_float)), 194 | ('doubleVal', ctypes.POINTER(ctypes.c_double)), 195 | ] 196 | 197 | 198 | class netsnmp_variable_list(ctypes.Structure): 199 | pass 200 | 201 | 202 | netsnmp_variable_list._fields_ = [ 203 | ('next_variable', ctypes.POINTER(netsnmp_variable_list)), 204 | ('name', ctypes.POINTER(oid_t)), 205 | ('name_length', ctypes.c_size_t), 206 | ('type', ctypes.c_ubyte), 207 | ('val', netsnmp_vardata), 208 | ('val_len', ctypes.c_size_t), 209 | ('name_loc', oid_t * MAX_OID_LEN), 210 | ('buf', ctypes.c_ubyte * 40), 211 | ('data', ctypes.c_void_p), 212 | ('dataFreeHook', ctypes.c_void_p), 213 | ('index', ctypes.c_int), 214 | ] 215 | netsnmp_variable_list_p = ctypes.POINTER(netsnmp_variable_list) 216 | 217 | 218 | class netsnmp_data_list(ctypes.Structure): 219 | pass 220 | 221 | 222 | netsnmp_data_list._fields_ = [ 223 | ('next', ctypes.POINTER(netsnmp_data_list)), 224 | ('name', ctypes.c_char_p), 225 | ('data', ctypes.c_void_p), 226 | ('free_func', ctypes.c_void_p), 227 | ] 228 | 229 | 230 | class netsnmp_agent_request_info(ctypes.Structure): 231 | _fields_ = [ 232 | ('mode', ctypes.c_int), 233 | ('asp', ctypes.POINTER(netsnmp_agent_session)), 234 | ('agent_data', ctypes.POINTER(netsnmp_data_list)), 235 | ] 236 | 237 | 238 | class netsnmp_request_info(ctypes.Structure): 239 | pass 240 | 241 | 242 | netsnmp_request_info._fields_ = [ 243 | ('requestvb', ctypes.POINTER(netsnmp_variable_list)), 244 | ('parent_data', ctypes.POINTER(netsnmp_data_list)), 245 | ('agent_req_info', ctypes.POINTER(netsnmp_agent_request_info)), 246 | ('range_end', ctypes.POINTER(oid_t)), 247 | ('range_end_len', ctypes.c_size_t), 248 | ('delegated', ctypes.c_int), 249 | ('processed', ctypes.c_int), 250 | ('inclusive', ctypes.c_int), 251 | ('status', ctypes.c_int), 252 | ('index', ctypes.c_int), 253 | ('repeat', ctypes.c_int), 254 | ('orig_repeat', ctypes.c_int), 255 | ('requestvb_start', ctypes.POINTER(netsnmp_variable_list)), 256 | ('next', ctypes.POINTER(netsnmp_request_info)), 257 | ('prev', ctypes.POINTER(netsnmp_request_info)), 258 | ('subtree', ctypes.POINTER(netsnmp_subtree)), 259 | ] 260 | 261 | 262 | # various functions argument types 263 | axl.read_objid.argtypes = [ 264 | ctypes.c_char_p, 265 | ctypes.POINTER(oidOID_t), 266 | ctypes.POINTER( 267 | ctypes.c_size_t)] 268 | axl.snmp_set_var_typed_value.argtypes = [ 269 | ctypes.POINTER(netsnmp_variable_list), 270 | ctypes.c_ubyte, 271 | ctypes.POINTER( 272 | ctypes.c_ubyte), 273 | ctypes.c_int] 274 | axl.snprint_objid.argtypes = [ 275 | strOID_t, 276 | ctypes.c_int, 277 | ctypes.POINTER(oid_t), 278 | ctypes.c_int] 279 | axl.snmp_varlist_add_variable.argtypes = [ 280 | ctypes.POINTER(netsnmp_variable_list_p), 281 | ctypes.POINTER(oid_t), 282 | ctypes.c_long, 283 | ctypes.c_ubyte, 284 | ctypes.c_char_p, 285 | ctypes.c_long] 286 | axl.send_v2trap.argtypes = [netsnmp_variable_list_p] 287 | 288 | # convert text oid to oid list 289 | 290 | 291 | def ReadOID(TextOID): 292 | oidOID = oidOID_t() 293 | oidOID_len = ctypes.c_size_t(MAX_OID_LEN) 294 | if axl.read_objid( 295 | TextOID.encode('utf-8'), 296 | ctypes.byref(oidOID), 297 | ctypes.byref(oidOID_len)) == 0: 298 | raise OperationalError('Incorrect OID (%(oid)s)' % {'oid': TextOID}) 299 | newOID_t = oid_t * oidOID_len.value 300 | oid = newOID_t(*oidOID[0:oidOID_len.value]) 301 | return oid 302 | 303 | # convert to text oid 304 | 305 | 306 | def ReadTOID(oid): 307 | strOID = strOID_t() 308 | oid_list = list(map(int, oid.split('.'))) 309 | oid = (oid_t * len(oid_list))(*oid_list) 310 | axl.snprint_objid(strOID, OID_LEN, oid, len(oid)) 311 | return strOID.value 312 | 313 | # exceptions 314 | 315 | 316 | class OperationalError(Exception): 317 | pass 318 | 319 | 320 | # agentx data object 321 | class AgentXData(dict): 322 | def __init__(self): 323 | dict.__init__(self) 324 | self.ResponseLast = None 325 | self.container = None 326 | 327 | # clear data 328 | def Clear(self): 329 | self.clear() 330 | self.ResponseLast = None 331 | 332 | # register variable 333 | def RegisterVar(self, oid, value=None): 334 | # normalize 335 | oid = self.NormOID(oid) 336 | if self: 337 | self[self.ResponseLast]['noid'] = oid 338 | self.ResponseLast = oid 339 | self[oid] = {'value': value, 'noid': None} 340 | 341 | # prepare snmp table data 342 | def Table(self, entry, columns): 343 | self.RegisterVar('%(TableEntry)s.0' % {'TableEntry': entry}, 0) 344 | for column in columns: 345 | i = 1 346 | for value in columns[column]: 347 | self.RegisterVar('%(ColumnName)s.%(RowId)d' % 348 | {'ColumnName': column, 'RowId': i}, value) 349 | i += 1 350 | 351 | # get next object id 352 | def GetNext(self, oid): 353 | return self[oid]['noid'] 354 | 355 | # set value 356 | def Update(self, oid, value): 357 | if oid not in self: 358 | raise OperationalError( 359 | 'No such object registered: %(oid)s' % { 360 | 'oid': oid}) 361 | self[oid]["value"] = value 362 | 363 | # normalize text id 364 | def NormOID(self, tid): 365 | if tid.find('::') == -1: 366 | if not self.container: 367 | raise OperationalError( 368 | 'OID prefix is not yet available, run ax.Init first.') 369 | tid = '%(mib)s::%(oid)s' % {'mib': self.container, 'oid': tid} 370 | return tid 371 | 372 | 373 | # forward declaration 374 | AXObject = None 375 | 376 | # snmp agentx request object 377 | 378 | 379 | class RequestObject(object): 380 | __slots__ = [ 381 | 'oid', 382 | 'mode', 383 | 'value', 384 | 'data', 385 | '__ax', 386 | '__request', 387 | '__reqinfo'] 388 | # class constructor 389 | 390 | def __init__(self, ax, request, reqinfo): 391 | self.__ax = ax 392 | self.__request = request 393 | self.__reqinfo = reqinfo 394 | 395 | # set next object id 396 | def SetNext(self, objid): 397 | oidOID = ReadOID(objid) 398 | axl.snmp_set_var_objid(self.__request.requestvb, oidOID, len(oidOID)) 399 | self.oid = objid 400 | 401 | # get next objid 402 | def GetNext(self, oid=None): 403 | if not oid: 404 | oid = self.oid 405 | return self.__ax.AXData.GetNext(oid) 406 | 407 | # set value 408 | def SetValue(self, value): 409 | # set object type 410 | otype = None 411 | size = 8 412 | if isinstance(value, str): 413 | otype = ASN_OCTET_STR 414 | size = len(value) 415 | value = value.encode('utf-8') 416 | value = ctypes.c_char_p(value) 417 | elif isinstance(value, int): 418 | otype = ASN_INTEGER 419 | value = ctypes.pointer(ctypes.c_int(value)) 420 | elif isinstance(value, float): 421 | otype = ASN_APP_FLOAT 422 | value = ctypes.pointer(ctypes.c_float(value)) 423 | elif isinstance(value, SnmpIpAddress): 424 | otype = ASN_IPADDRESS 425 | size = 4 426 | value = ctypes.c_char_p(socket.inet_aton(value)) 427 | elif isinstance(value, SnmpCounter32): 428 | otype = ASN_COUNTER32 429 | value = ctypes.pointer(ctypes.c_uint(value)) 430 | elif isinstance(value, SnmpGauge32): 431 | otype = ASN_UNSIGNED 432 | value = ctypes.pointer(ctypes.c_uint(value)) 433 | try: 434 | axl.snmp_set_var_typed_value(self.__request.requestvb, otype, ctypes.cast( 435 | value, ctypes.POINTER(ctypes.c_ubyte)), size) 436 | self.value = value 437 | except Exception as e: 438 | print("WARNING: Unexpected error in SetValue(): %r" % e) 439 | 440 | # set error 441 | def SetError(self, error): 442 | axl.netsnmp_set_request_error(self.__reqinfo, self.__request, error) 443 | 444 | 445 | # callback function 446 | HandlerWrapperFunc = ctypes.CFUNCTYPE( 447 | ctypes.c_int, 448 | ctypes.POINTER(netsnmp_mib_handler), 449 | ctypes.POINTER(netsnmp_handler_registration), 450 | ctypes.POINTER(netsnmp_agent_request_info), 451 | ctypes.POINTER(netsnmp_request_info) 452 | ) 453 | # high level handler 454 | 455 | 456 | def _handler_wrapper(handler, reginfo, reqinfo, requests): 457 | r = requests.contents 458 | # get current time 459 | timestamp = time.time() 460 | if AXObject.CacheInterval and timestamp - \ 461 | AXObject.UpdateTime > AXObject.CacheInterval: 462 | # need to update data now 463 | AXObject.AXData.Clear() 464 | AXObject.GlobalsRun('OnUpdate') 465 | AXObject.UpdateTime = timestamp 466 | # handler loop 467 | while True: 468 | # get object id 469 | strOID = strOID_t() 470 | axl.snprint_objid( 471 | strOID, 472 | OID_LEN, 473 | r.requestvb.contents.name, 474 | r.requestvb.contents.name_length) 475 | 476 | # do some magic here 477 | req = RequestObject(AXObject, r, reqinfo) 478 | req.oid = strOID.value 479 | # python 3.x stores oid in bytes object 480 | if not isinstance(req.oid, str): 481 | req.oid = req.oid.decode() 482 | req.mode = reqinfo.contents.mode 483 | 484 | if req.mode == SNMP_MSG_GET: 485 | if req.oid in AXObject.AXData: 486 | req.SetValue(AXObject.AXData[req.oid]['value']) 487 | # run read-write and read-only handlers 488 | for handler in AXObject.RequestHandlers[PAX_RW] + \ 489 | AXObject.RequestHandlers[PAX_RO]: 490 | value = handler(req, AXObject, AXObject.AXData) 491 | if value: 492 | req.SetValue(value) 493 | elif req.mode == SNMP_MSG_GETNEXT: 494 | if req.oid in AXObject.AXData: 495 | if AXObject.AXData[req.oid]['noid'] is None: 496 | # only set current objid 497 | req.SetNext(req.oid) 498 | else: 499 | # req.SetNext changes req.oid value 500 | req.SetNext(AXObject.AXData[req.oid]['noid']) 501 | req.SetValue(AXObject.AXData[req.oid]['value']) 502 | # run read-write and read-only handlers 503 | for handler in AXObject.RequestHandlers[PAX_RW] + \ 504 | AXObject.RequestHandlers[PAX_RO]: 505 | value = handler(req, AXObject, AXObject.AXData) 506 | if value: 507 | req.SetValue(value) 508 | elif req.mode == SNMP_MSG_INTERNAL_SET_COMMIT: 509 | # FIXME: MAX-ACCESS is now ignored :( 510 | if r.requestvb.contents.type in (ASN_INTEGER, ASN_UNSIGNED): 511 | req.value = r.requestvb.contents.val.integer.contents.value 512 | elif r.requestvb.contents.type == ASN_OCTET_STR: 513 | req.value = r.requestvb.contents.val.string 514 | elif r.requestvb.contents.type in (ASN_OPAQUE_FLOAT, ASN_OPAQUE_DOUBLE): 515 | req.value = r.requestvb.contents.val.floatVal.contents.value 516 | # check special case oids 517 | if AXObject.ReloadOID and AXObject.ReloadOID == req.oid and req.value == 1: 518 | # reload requested by snmp 519 | AXObject.GlobalsRun('OnReload') 520 | if AXObject.StopOID and AXObject.StopOID == req.oid and req.value == 1: 521 | # stop agent 522 | AXObject.Shutdown() 523 | # run read-write and write-only handlers 524 | for handler in AXObject.RequestHandlers[PAX_RW] + \ 525 | AXObject.RequestHandlers[PAX_WO]: 526 | value = handler(req, AXObject, AXObject.AXData) 527 | if value: 528 | req.value = value 529 | # save value 530 | try: 531 | AXObject.AXData.Update(req.oid, req.value) 532 | except OperationalError: 533 | AXObject.AXData.RegisterVar(req.oid, req.value) 534 | if not r.next: 535 | break 536 | r = r.next.contents 537 | return SNMP_ERR_NOERROR 538 | 539 | 540 | # low level handler 541 | handler_wrapper = HandlerWrapperFunc(_handler_wrapper) 542 | 543 | 544 | # AgentX object declaration 545 | class AgentX(object): 546 | def __init__(self, Globals, **args): 547 | self.alarm = 0 548 | self.loop = False 549 | self.AXData = AgentXData() 550 | self.Globals = Globals 551 | self.UpdateTime = 0 552 | 553 | # save global constants in object's namespace 554 | for c in globals(): 555 | for prefix in ('ASN_', 'SNMP_', 'HANDLER_', 'PAX_'): 556 | if c.startswith(prefix): 557 | setattr(self, c, globals()[c]) 558 | break 559 | 560 | # default settings 561 | defaults = { 562 | 'Name': os.path.splitext(os.path.basename(sys.argv[0]))[0], 563 | 'CacheInterval': 30, 564 | 'TimerInterval': 30, 565 | 'Master': False, 566 | 'MIBFile': (), 567 | 'RootOID': None, 568 | 'ReloadOID': None, 569 | 'StopOID': None, 570 | } 571 | 572 | # initialize variables 573 | for key in defaults: 574 | setattr(self, key, args.get(key, defaults[key])) 575 | 576 | # request handlers 577 | self.RequestHandlers = { 578 | PAX_RO: [], 579 | PAX_WO: [], 580 | PAX_RW: [], 581 | } 582 | 583 | # set global object reference 584 | global AXObject 585 | AXObject = self 586 | 587 | # initialize agentx 588 | # setup log facility 589 | axl.snmp_enable_stderrlog() 590 | if not self.Master: 591 | axl.netsnmp_ds_set_boolean( 592 | NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1) 593 | # init agent module 594 | # for win32: winsock_startup() 595 | axl.init_agent(self.Name) 596 | axl.init_snmp(self.Name) 597 | # register agent 598 | if not type(self.MIBFile) in (list, tuple): 599 | self.MIBFile = (self.MIBFile,) 600 | for mib in self.MIBFile: 601 | axl.read_mib(mib) 602 | 603 | # install low level handler 604 | if self.RootOID: 605 | self.AXData.container = self.RootOID.split('::', 1)[0] 606 | # register handler callback 607 | oidOID = ReadOID(self.RootOID) 608 | 609 | axl.netsnmp_create_handler_registration.restype = ctypes.POINTER( 610 | netsnmp_handler_registration) 611 | h = axl.netsnmp_create_handler_registration( 612 | self.Name, 613 | handler_wrapper, 614 | oidOID, len(oidOID), 615 | HANDLER_CAN_RWRITE, 616 | ) 617 | if axl.netsnmp_register_handler(h) != 0: 618 | raise OperationalError('SNMP handler registration failure.') 619 | # register custom handlers 620 | for HandlerName, HandlerMode in ( 621 | ('OnSnmpRequest', PAX_RW), ('OnSnmpRead', PAX_RO), ('OnSnmpWrite', PAX_WO)): 622 | if HandlerName in self.Globals and '__call__' in dir( 623 | self.Globals[HandlerName]): 624 | self.RegisterHandler(self.Globals[HandlerName], HandlerMode) 625 | # ReloadOID and StopOID 626 | if self.ReloadOID: 627 | self.ReloadOID = self.AXData.NormOID(self.ReloadOID) 628 | if self.StopOID: 629 | self.StopOID = self.AXData.NormOID(self.StopOID) 630 | 631 | # attach HUP signal 632 | def HupHandler(signum, frame): 633 | # reload requested by HUP signal 634 | self.GlobalsRun('OnReload') 635 | signal.signal(signal.SIGHUP, HupHandler) 636 | 637 | # run custom init routine 638 | self.GlobalsRun('OnInit') 639 | if not self.loop: 640 | # start timer 641 | self.TimerStart(self.TimerInterval) 642 | self.loop = True 643 | while self.loop: 644 | self.GlobalsRun('OnTimer') 645 | self.Process() 646 | 647 | # register custom handler 648 | def RegisterHandler(self, handler, mode=PAX_RW): 649 | assert '__call__' in dir(handler), 'Callable object is required' 650 | self.RequestHandlers[mode].append(handler) 651 | 652 | # start itimer 653 | def TimerStart(self, interval): 654 | try: 655 | signal.setitimer(signal.ITIMER_REAL, interval, interval) 656 | except BaseException: 657 | # fallback to alarm clock which is more inacurate 658 | self.alarm = int(interval) 659 | if not self.alarm: 660 | self.alarm = 1 661 | return self.alarm 662 | return interval 663 | 664 | # stop alarm timer 665 | def TimerStop(self): 666 | try: 667 | signal.setitimer(signal.ITIMER_REAL, 0) 668 | except BaseException: 669 | self.alarm = 0 670 | 671 | # process snmp requests 672 | def Process(self, block=True): 673 | alarm_triggered = False 674 | loop = True 675 | result = True 676 | 677 | if self.alarm: 678 | # start alarm 679 | signal.alarm(self.alarm) 680 | block = True 681 | 682 | # alarm handler 683 | def sigalrm_handler(signum, frame): 684 | alarm_triggered = True 685 | 686 | # attach alarm signal handler 687 | signal.signal(signal.SIGALRM, sigalrm_handler) 688 | 689 | # process loop 690 | while loop and self.loop: 691 | r = axl.agent_check_and_process(block) 692 | if r == -1: 693 | if not alarm_triggered: 694 | result = False 695 | loop = False 696 | elif r == 0 and not block: 697 | loop = False 698 | 699 | # detach alarm signal 700 | signal.signal(signal.SIGALRM, signal.SIG_DFL) 701 | # stop alarm timer 702 | if self.alarm: 703 | signal.alarm(0) 704 | return result 705 | 706 | # run globals routine 707 | def GlobalsRun(self, name, *args): 708 | if name in self.Globals and '__call__' in dir(self.Globals[name]): 709 | # call 710 | if args: 711 | self.Globals[name](self, self.AXData, *args) 712 | else: 713 | self.Globals[name](self, self.AXData) 714 | 715 | # end main loop 716 | def Shutdown(self): 717 | self.loop = False 718 | 719 | # send trap from within agentx module 720 | def Trap(self, oid, *args): 721 | sysUpTimeOID = (oid_t * 9)(1, 3, 6, 1, 2, 1, 722 | 1, 3, 0) # sysUpTimeInstance 723 | snmpTrapOID = (oid_t * 11)(1, 3, 6, 1, 6, 3, 724 | 1, 1, 4, 1, 0) # snmpTrapOID.0 725 | TrapOID = ReadOID(self.AXData.NormOID(oid)) 726 | 727 | TrapVars = netsnmp_variable_list_p() 728 | uptime = ctypes.c_long(axl.netsnmp_get_agent_uptime()) 729 | 730 | # agent uptime 731 | axl.snmp_varlist_add_variable( 732 | ctypes.byref(TrapVars), 733 | ctypes.cast( 734 | ctypes.byref(sysUpTimeOID), 735 | ctypes.POINTER(oid_t)), 736 | len(sysUpTimeOID), 737 | ASN_TIMETICKS, 738 | ctypes.cast( 739 | ctypes.byref(uptime), 740 | ctypes.c_char_p), 741 | ctypes.sizeof(uptime), 742 | ) 743 | 744 | # agent trap 745 | axl.snmp_varlist_add_variable( 746 | ctypes.byref(TrapVars), 747 | ctypes.cast( 748 | ctypes.byref(snmpTrapOID), 749 | ctypes.POINTER(oid_t)), 750 | len(snmpTrapOID), 751 | ASN_OBJECT_ID, 752 | ctypes.cast( 753 | ctypes.byref(TrapOID), 754 | ctypes.c_char_p), 755 | len(TrapOID) * 756 | ctypes.sizeof(oid_t), 757 | ) 758 | 759 | # add variable 760 | for ArgOID, ArgData in args: 761 | ArgOID = ReadOID( 762 | self.AXData.NormOID(ArgOID) 763 | ) 764 | 765 | ArgDataLen = 0 766 | ObjType = None 767 | if isinstance(ArgData, str): 768 | ObjType = ASN_OCTET_STR 769 | ArgDataLen = len(ArgData) 770 | ArgData = ctypes.c_char_p(ArgData) 771 | elif isinstance(ArgData, int): 772 | ObjType = ASN_INTEGER 773 | ArgData = ctypes.c_int(ArgData) 774 | ArgDataLen = ctypes.sizeof(ArgData) 775 | ArgData = ctypes.cast(ctypes.byref(ArgData), ctypes.c_char_p) 776 | elif isinstance(ArgData, float): 777 | ObjType = ASN_APP_FLOAT 778 | ArgData = ctypes.c_float(ArgData) 779 | ArgDataLen = ctypes.sizeof(ArgData) 780 | ArgData = ctypes.cast(ctypes.byref(ArgData), ctypes.c_char_p) 781 | 782 | # add variable 783 | axl.snmp_varlist_add_variable( 784 | ctypes.byref(TrapVars), 785 | ctypes.cast(ctypes.byref(ArgOID), 786 | ctypes.POINTER(oid_t)), len(ArgOID), 787 | ObjType, 788 | ctypes.cast(ArgData, ctypes.c_char_p), ArgDataLen, 789 | ) 790 | 791 | # send trap 792 | axl.send_v2trap(TrapVars) 793 | axl.snmp_free_varbind(TrapVars) 794 | -------------------------------------------------------------------------------- /bird_bgp.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Travelping GmbH 3 | # by Tobias Hintze 4 | # 5 | # This code is inspired and partially copied from 6 | # https://r3blog.nl/index.php/archives/2011/02/24/bgp4-mib-support-for-bird/ 7 | # That original code does not clearly declare any license. 8 | # 9 | # This code also uses python-agentx library licensed under GPLv3 10 | # (see agentx.py for details) 11 | # 12 | # So this code is licensed under the GPLv3 (see COPYING.GPLv3). 13 | # 14 | 15 | from __future__ import print_function 16 | from adv_agentx import AgentX 17 | from adv_agentx import SnmpGauge32, SnmpCounter32 18 | import time 19 | import os 20 | import functools 21 | 22 | from birdagent import BirdAgent 23 | 24 | # handle get and getnext requests 25 | 26 | 27 | def OnSnmpRead(req, ax, axd): 28 | pass 29 | 30 | # handle set requests 31 | 32 | 33 | def OnSnmpWrite(req, ax, axd): 34 | pass 35 | 36 | # handle get, getnext and set requests 37 | 38 | 39 | def OnSnmpRequest(req, ax, axd): 40 | pass 41 | 42 | # initialize any ax and axd dependant code here 43 | 44 | 45 | def OnInit(ax, axd): 46 | pass 47 | 48 | # register some variables 49 | # this function is called when a new snmp request has been received and 50 | # if CacheInterval has expired at that time 51 | 52 | 53 | def OnUpdate(ax, axd, state): 54 | print('updated bird-bgp state: {0}'.format(time.time())) 55 | 56 | # register variables 57 | axd.RegisterVar('bgp', 0) 58 | axd.RegisterVar('bgpVersion', "10") 59 | axd.RegisterVar('bgpLocalAs', 0) 60 | axd.RegisterVar('bgpLocalAs.0', state.get("bgpLocalAs")) 61 | 62 | # reindex by bgpPeerRemoteAddr 63 | peers = {} 64 | for peer in list(state["bgp-peers"].values()): 65 | peers[peer.get("bgpPeerRemoteAddr")] = peer 66 | 67 | for snmpkey in BirdAgent.bgp_keys: 68 | axd.RegisterVar(snmpkey, 0) 69 | for peer in sorted(list(peers.keys()), key=functools.cmp_to_key(BirdAgent.ipCompare)): 70 | oid = "%s.%s" % (snmpkey, peer) 71 | if snmpkey in peers[peer]: 72 | axd.RegisterVar(oid, peers[peer][snmpkey]) 73 | else: 74 | axd.RegisterVar(oid, BirdAgent.bgp_defaults[snmpkey]) 75 | return 76 | 77 | 78 | # main program 79 | if __name__ == '__main__': 80 | print('bird-bgp-agent AgentX starting') 81 | 82 | bird = BirdAgent( 83 | os.environ.get("BIRDCONF") or "/etc/bird/bird.conf", 84 | os.environ.get("BIRDCLI") or "/usr/sbin/birdc", 85 | os.environ.get("SSCMD") or "ss -tan -o state established '( dport = :bgp or sport = :bgp )'") 86 | 87 | callbacks = { 88 | "OnSnmpRead": OnSnmpRead, 89 | "OnSnmpWrite": OnSnmpWrite, 90 | "OnSnmpRequest": OnSnmpRequest, 91 | "OnInit": OnInit, 92 | "OnUpdate": lambda ax, axd: OnUpdate(ax, axd, bird.getBGPState()) 93 | } 94 | 95 | # initialize agentx module and run main loop 96 | try: 97 | AgentX( 98 | callbacks, 99 | Name='bird-bgp', 100 | MIBFile=os.environ.get( 101 | "BGPMIBFILE") or "/var/lib/mibs/ietf/BGP4-MIB", 102 | RootOID='BGP4-MIB::bgp', # https://tools.ietf.org/html/draft-ietf-idr-bgp4-mib-06 103 | CacheInterval=int(os.environ.get("AGENTCACHEINTERVAL") or "30") 104 | ) 105 | except KeyboardInterrupt: 106 | print('bird-bgp-agent AgentX terminating') 107 | -------------------------------------------------------------------------------- /birdagent.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Travelping GmbH 3 | # by Tobias Hintze 4 | # 5 | # This code is inspired and partially copied from 6 | # https://r3blog.nl/index.php/archives/2011/02/24/bgp4-mib-support-for-bird/ 7 | # That original code does not clearly declare any license. 8 | # 9 | # This code also uses python-agentx library licensed under GPLv3 10 | # (see agentx.py for details) 11 | # 12 | # So this code is licensed under the GPLv3 (see COPYING.GPLv3). 13 | # 14 | 15 | """ 16 | birdagent - agentx code for the bird routing daemon 17 | used by bird_bgp - for the bgp4-mib 18 | """ 19 | from __future__ import print_function 20 | 21 | from past.builtins import cmp 22 | from builtins import object 23 | from adv_agentx import AgentX 24 | from adv_agentx import SnmpGauge32, SnmpCounter32, SnmpIpAddress 25 | import sys 26 | import re 27 | import subprocess 28 | import glob 29 | import dateutil.parser 30 | from datetime import datetime 31 | import pytz 32 | from tzlocal import get_localzone 33 | 34 | 35 | class BirdAgent(object): 36 | 37 | def __init__(self, cfgfile, birdcli, sscmd): 38 | self.cfgfile = cfgfile 39 | self.birdcli = birdcli 40 | self.sscmd = sscmd 41 | 42 | bgp_states = { 43 | "idle": 1, 44 | "connect": 2, 45 | "active": 3, 46 | "opensent": 4, 47 | "openconfirm": 5, 48 | "established": 6, 49 | } 50 | 51 | _re_config_include = re.compile("^include\s*\"(/[^\"]*)\".*$") 52 | _re_config_bgp_proto_begin = re.compile( 53 | "^protocol bgp ([a-zA-Z0-9_]+).*\{$") 54 | _re_config_local_as = re.compile( 55 | "local ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) as ([0-9]+);") 56 | _re_config_bgp_holdtime = re.compile("hold time ([0-9]+);") 57 | _re_config_bgp_keepalive = re.compile("keepalive time ([0-9]+);") 58 | _re_config_remote_peer = re.compile( 59 | "neighbor ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) as ([0-9]+);") 60 | _re_config_timeformat = re.compile( 61 | "\s*timeformat\s+protocol\s+iso\s+long\s+;") 62 | _re_config_proto_end = re.compile("^\}$") 63 | 64 | _re_birdcli_bgp_begin = re.compile( 65 | "^([a-zA-Z0-9_]+)\s+BGP\s+[a-zA-Z0-9-_]+\s+[a-zA-Z0-9]+\s+(\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d).*$") 66 | _re_birdcli_bgp_peer = { 67 | "bgpPeerIdentifier": re.compile("^\s+Neighbor ID:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$"), 68 | "bgpPeerState": re.compile("^\s+BGP state:\s+([a-zA-Z]+)$"), 69 | "bgpPeerLocalAddr": re.compile("^\s+Source address:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$"), 70 | "bgpPeerRemoteAddr": re.compile("^\s+Neighbor address:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$"), 71 | "bgpPeerRemoteAs": re.compile("^\s+Neighbor AS:\s+([0-9]+)$"), 72 | "bgpPeerInUpdates": re.compile("^\s+Import updates:\s+([0-9]+)\s+[0-9\-]+\s+[0-9\-]+\s+[0-9\-]+\s+[0-9\-]+$"), 73 | "bgpPeerOutUpdates": re.compile("^\s+Export updates:\s+([0-9]+)\s+[0-9\-]+\s+[0-9\-]+\s+[0-9\-]+\s+[0-9\-]+$"), 74 | "bgpPeerHoldTime": re.compile("^\s+Hold timer:\s+([0-9]+)\/[0-9]+$"), 75 | "bgpPeerHoldTimeConfigured": re.compile("^\s+Hold timer:\s+[0-9]+\/([0-9]+)$"), 76 | "bgpPeerKeepAlive": re.compile("^\s+Keepalive timer:\s+([0-9]+)\/[0-9]+$"), 77 | "bgpPeerKeepAliveConfigured": re.compile("^\s+Keepalive timer:\s+[0-9]+\/([0-9]+)$"), 78 | "bgpPeerLastError": re.compile("^\s+Last error:\s+([a-zA-Z0-9-_\ ]+)$")} 79 | _re_birdcli_bgp_end = re.compile("^$") 80 | 81 | _re_ss = re.compile( 82 | "^[0-9]+\s+[0-9]+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?:%[a-z0-9-\.]+)?:([0-9]+)\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?:%[a-z0-9-\.]+?)?:([0-9]+)") 83 | 84 | bgp_keys = [ 85 | 'bgpPeerIdentifier', 86 | 'bgpPeerState', 87 | 'bgpPeerAdminStatus', 88 | 'bgpPeerNegotiatedVersion', 89 | 'bgpPeerLocalAddr', 90 | 'bgpPeerLocalPort', 91 | 'bgpPeerRemoteAddr', 92 | 'bgpPeerRemotePort', 93 | 'bgpPeerRemoteAs', 94 | 'bgpPeerInUpdates', 95 | 'bgpPeerOutUpdates', 96 | 'bgpPeerInTotalMessages', 97 | 'bgpPeerOutTotalMessages', 98 | 'bgpPeerLastError', 99 | 'bgpPeerFsmEstablishedTransitions', 100 | 'bgpPeerFsmEstablishedTime', 101 | 'bgpPeerConnectRetryInterval', 102 | 'bgpPeerHoldTime', 103 | 'bgpPeerKeepAlive', 104 | 'bgpPeerHoldTimeConfigured', 105 | 'bgpPeerKeepAliveConfigured', 106 | 'bgpPeerMinASOriginationInterval', 107 | 'bgpPeerMinRouteAdvertisementInterval', 108 | 'bgpPeerInUpdateElapsedTime', 109 | ] 110 | 111 | bgp_defaults = { 112 | 'bgpPeerIdentifier': SnmpIpAddress("0.0.0.0"), 113 | 'bgpPeerLocalAddr': SnmpIpAddress("0.0.0.0"), 114 | 'bgpPeerLocalPort': 0, 115 | 'bgpPeerRemoteAs': 0, 116 | 'bgpPeerRemotePort': 0, 117 | 'bgpPeerHoldTime': 0, 118 | 'bgpPeerHoldTimeConfigured': 0, 119 | 'bgpPeerKeepAlive': 0, 120 | 'bgpPeerKeepAliveConfigured': 0, 121 | 'bgpPeerState': 1, 122 | 'bgpPeerInUpdates': SnmpCounter32(0), 123 | 'bgpPeerOutUpdates': SnmpCounter32(0), 124 | 'bgpPeerAdminStatus': 2, 125 | 'bgpPeerConnectRetryInterval': 0, 126 | 'bgpPeerFsmEstablishedTime': SnmpGauge32(0), 127 | 'bgpPeerFsmEstablishedTransitions': SnmpCounter32(0), 128 | 'bgpPeerInTotalMessages': SnmpCounter32(0), 129 | 'bgpPeerInUpdateElapsedTime': SnmpGauge32(0), 130 | 'bgpPeerLastError': '0', 131 | 'bgpPeerMinASOriginationInterval': 15, 132 | 'bgpPeerMinRouteAdvertisementInterval': 30, 133 | 'bgpPeerNegotiatedVersion': 0, 134 | 'bgpPeerOutTotalMessages': SnmpCounter32(0), 135 | } 136 | 137 | @staticmethod 138 | def ipCompare(ip1, ip2): 139 | lst1 = "%3s.%3s.%3s.%3s" % tuple(ip1.split(".")) 140 | lst2 = "%3s.%3s.%3s.%3s" % tuple(ip2.split(".")) 141 | return cmp(lst1, lst2) 142 | 143 | @staticmethod 144 | def combinedConfigLines(filename): 145 | """ 146 | yield the whole bird configuration file line by line; 147 | all include-statements are resolved/unrolled 148 | """ 149 | try: 150 | with open(filename, "r") as bird_conf: 151 | for line in bird_conf: 152 | line = line.strip() 153 | match = BirdAgent._re_config_include.search(line) 154 | if not match: 155 | yield line 156 | else: 157 | for subconf in glob.glob(match.group(1)): 158 | yield "# subconf: %s (from %s)" % (subconf, line) 159 | for subline in BirdAgent.combinedConfigLines(subconf): 160 | yield subline 161 | except IOError: 162 | print("ERROR: Unable to open %s, terminating..." % filename) 163 | sys.exit(1) 164 | except Exception as e: 165 | print( 166 | "ERROR: Unexpected error in combinedConfigLines(): [%s], terminating" % e) 167 | sys.exit(1) 168 | 169 | @staticmethod 170 | def bgpKeys(): 171 | return BirdAgent.bgp_keys 172 | 173 | def getBGPState(self): 174 | """ 175 | fetch BGP-related state from: 176 | * parsing configuration file 177 | * parsing `birdc show protocols all` output 178 | * parsing `ss` output 179 | """ 180 | 181 | timezone = get_localzone() 182 | current_time = datetime.now(pytz.utc) 183 | 184 | # fetch some data from the configuration: 185 | cfg = {} 186 | cfg["bgp-peers"] = {} 187 | proto = None 188 | for line in BirdAgent.combinedConfigLines(self.cfgfile): 189 | if self._re_config_timeformat: 190 | cfg["timeformat"] = True 191 | match = self._re_config_bgp_proto_begin.search(line) 192 | if match: 193 | proto = match.group(1) 194 | cfg["bgp-peers"][proto] = {} 195 | if proto: 196 | match = self._re_config_local_as.search(line) 197 | if match: 198 | cfg["bgp-peers"][proto]["bgpPeerLocalAddr"] = SnmpIpAddress( 199 | match.group(1)) 200 | cfg["bgp-peers"][proto]["bgpPeerLocalAs"] = int( 201 | match.group(2)) 202 | if "bgpLocalAs" not in cfg: 203 | cfg["bgpLocalAs"] = int(match.group(2)) 204 | elif cfg["bgpLocalAs"] != int(match.group(2)): 205 | print("WARNING: multiple local AS: %i/%i" % 206 | (cfg["bgpLocalAs"], int(match.group(2)))) 207 | 208 | match = self._re_config_remote_peer.search(line) 209 | if match: 210 | cfg["bgp-peers"][proto]["bgpPeerRemoteAddr"] = SnmpIpAddress( 211 | match.group(1)) 212 | cfg["bgp-peers"][proto]["bgpPeerRemoteAs"] = int( 213 | match.group(2)) 214 | 215 | match = self._re_config_bgp_holdtime.search(line) 216 | if match: 217 | cfg["bgp-peers"][proto]["bgpPeerHoldTimeConfigured"] = int( 218 | match.group(1)) 219 | 220 | match = self._re_config_bgp_keepalive.search(line) 221 | if match: 222 | cfg["bgp-peers"][proto]["bgpPeerKeepAliveConfigured"] = int( 223 | match.group(1)) 224 | 225 | if self._re_config_proto_end.search(line): 226 | proto = None 227 | 228 | if "timeformat" not in cfg: 229 | print("ERROR: timeformat not configured for this agent's use, terminating...") 230 | sys.exit(1) 231 | 232 | # Validate protocol's config 233 | for proto in cfg["bgp-peers"]: 234 | if not cfg["bgp-peers"][proto]: continue 235 | if "bgpPeerLocalAddr" not in cfg["bgp-peers"][proto] and \ 236 | "bgpPeerLocalAs" not in cfg["bgp-peers"][proto]: 237 | print( 238 | "WARNING: Protocol \"%s\" does not have a properly formated 'local as ;' line in the config" % proto) 239 | 240 | if "bgpPeerRemoteAddr" not in cfg["bgp-peers"][proto] and \ 241 | "bgpPeerRemoteAs" not in cfg["bgp-peers"][proto]: 242 | print( 243 | "WARNING: Protocol \"%s\" does not have a properly formated 'neighbor as ;' line in the config" % proto) 244 | 245 | state = cfg.copy() 246 | bgp_proto = None 247 | # "with"-context-manager for Popen not available in python < 3.2 248 | birdc = subprocess.Popen([self.birdcli, "show", "protocols", "all"], 249 | stdout=subprocess.PIPE) 250 | output = birdc.communicate()[0].decode('utf-8', 'ignore') 251 | if birdc.returncode != 0: 252 | print( 253 | "ERROR: bird-CLI %s failed: %i" % 254 | (self.birdcli, birdc.returncode)) 255 | 256 | for line in output.split("\n"): 257 | match = self._re_birdcli_bgp_begin.search(line) 258 | if match: 259 | bgp_proto = match.group(1) 260 | timestamp = dateutil.parser.parse(match.group(2)) 261 | if not timestamp.tzinfo: 262 | timestamp = timezone.localize(timestamp) 263 | if bgp_proto not in state["bgp-peers"]: 264 | print( 265 | "WARNING: proto \"%s\" not in config, skipping" % 266 | bgp_proto) 267 | continue 268 | state["bgp-peers"][bgp_proto]["bgpPeerFsmEstablishedTime"] = SnmpGauge32( 269 | abs(current_time - timestamp).total_seconds()) 270 | if bgp_proto: 271 | try: 272 | for peerprop_name, peerprop_re in list( 273 | self._re_birdcli_bgp_peer.items()): 274 | match = peerprop_re.search(line) 275 | if match: 276 | if peerprop_name == 'bgpPeerState': 277 | if not match.group(1).lower() == 'down': 278 | state["bgp-peers"][bgp_proto][peerprop_name] = \ 279 | self.bgp_states[match.group(1).lower()] 280 | else: 281 | # handle disabled (down) protocols 282 | state["bgp-peers"][bgp_proto][peerprop_name] = int( 283 | 1) 284 | state["bgp-peers"][bgp_proto]["bgpPeerAdminStatus"] = int( 285 | 1) 286 | state["bgp-peers"][bgp_proto]["bgpPeerFsmEstablishedTime"] = int( 287 | 0) 288 | 289 | elif peerprop_name in [ 290 | 'bgpPeerIdentifier', 291 | 'bgpPeerLocalAddr', 292 | 'bgpPeerRemoteAddr']: 293 | state["bgp-peers"][bgp_proto][peerprop_name] = SnmpIpAddress( 294 | match.group(1)) 295 | elif peerprop_name in [ 296 | 'bgpPeerInUpdates', 297 | 'bgpPeerOutUpdates']: 298 | state["bgp-peers"][bgp_proto][peerprop_name] = SnmpCounter32( 299 | match.group(1)) 300 | else: 301 | state["bgp-peers"][bgp_proto][peerprop_name] = int( 302 | match.group(1)) 303 | except: 304 | print("WARNING: Unable to process \"%s\" as \"%s\" for protocol \"%s\"" % 305 | (match.group(1), peerprop_name, bgp_proto)) 306 | 307 | if self._re_birdcli_bgp_end.search(line): 308 | bgp_proto = None 309 | 310 | # use ss to query for source and destination ports of the bgp protocols 311 | bgp_sessions = {} 312 | try: 313 | ss = subprocess.Popen(self.sscmd, shell=True, 314 | stdout=subprocess.PIPE) 315 | 316 | for line in ss.communicate()[0].decode('utf-8', 'ignore').split("\n"): 317 | match = self._re_ss.search(line) 318 | if not match: 319 | continue 320 | # key 4-tuples by remote ip: src-addr, src-port, dst-addr, dst-port 321 | bgp_sessions[match.group(3)] = match.groups() 322 | except subprocess.CalledProcessError as e: 323 | print( 324 | "ERROR: Error executing \"ss\" command [%s], terminating..." % e) 325 | sys.exit(1) 326 | 327 | # match the connection 4-tuples with bgp-state 328 | for proto in list(state["bgp-peers"].keys()): 329 | if not state["bgp-peers"][proto]: continue 330 | 331 | # enrich the state by local+remote ports 332 | try: 333 | srcip, srcport, dstip, dstport = bgp_sessions[state["bgp-peers"][ 334 | proto]["bgpPeerRemoteAddr"]] 335 | except: 336 | print("INFO: Protocol \"%s\" has no active BGP session." % proto) 337 | try: 338 | state["bgp-peers"][proto]["bgpPeerRemoteAddr"] = \ 339 | cfg["bgp-peers"][proto]["bgpPeerRemoteAddr"] 340 | continue 341 | except: 342 | state["bgp-peers"][proto]["bgpPeerRemoteAddr"] = SnmpIpAddress( 343 | "0.0.0.0") 344 | continue 345 | 346 | # Check for mismatch between config and ss output 347 | if srcip != state["bgp-peers"][proto]["bgpPeerLocalAddr"] or \ 348 | dstip != state["bgp-peers"][proto]["bgpPeerRemoteAddr"]: 349 | print( 350 | "WARNING: Protocol \"%s\" has mismatch between the configuration file (local: %s, neighbor %s) and the active BGP session (local: %s, neighbor: %s)" % 351 | (proto, state["bgp-peers"][proto]["bgpPeerLocalAddr"], state["bgp-peers"][proto]["bgpPeerRemoteAddr"], srcip, dstip)) 352 | continue 353 | 354 | # populate the ports 355 | state["bgp-peers"][proto]["bgpPeerLocalPort"] = int(srcport) 356 | state["bgp-peers"][proto]["bgpPeerRemotePort"] = int(dstport) 357 | 358 | return state 359 | --------------------------------------------------------------------------------